~ubuntu-branches/ubuntu/jaunty/libgdiplus/jaunty-updates

« back to all changes in this revision

Viewing changes to cairo/src/cairo-pattern.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastian Dröge
  • Date: 2007-05-17 13:38:42 UTC
  • mfrom: (1.1.13 upstream)
  • Revision ID: james.westby@ubuntu.com-20070517133842-t8b8d4lxmhb3vnp0
Tags: 1.2.4-1ubuntu1
* Sync with Debian:
  + debian/control:
    - Add sparc to archs
    - Set Maintainer field...

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
1
2
/* cairo - a vector graphics library with display and print output
2
3
 *
3
4
 * Copyright © 2004 David Reveman
33
34
    { CAIRO_PATTERN_TYPE_SOLID,         /* type */
34
35
      CAIRO_REF_COUNT_INVALID,          /* ref_count */
35
36
      CAIRO_STATUS_NO_MEMORY,   /* status */
 
37
      { 0, 0, 0, NULL },                /* user_data */
36
38
      { 1., 0., 0., 1., 0., 0., }, /* matrix */
37
39
      CAIRO_FILTER_DEFAULT,     /* filter */
38
40
      CAIRO_EXTEND_GRADIENT_DEFAULT },  /* extend */
42
44
    { CAIRO_PATTERN_TYPE_SOLID,         /* type */
43
45
      CAIRO_REF_COUNT_INVALID,          /* ref_count */
44
46
      CAIRO_STATUS_NULL_POINTER,/* status */
 
47
      { 0, 0, 0, NULL },                /* user_data */
45
48
      { 1., 0., 0., 1., 0., 0., }, /* matrix */
46
49
      CAIRO_FILTER_DEFAULT,     /* filter */
47
50
      CAIRO_EXTEND_GRADIENT_DEFAULT },  /* extend */
83
86
    pattern->ref_count = 1;
84
87
    pattern->status    = CAIRO_STATUS_SUCCESS;
85
88
 
 
89
    _cairo_user_data_array_init (&pattern->user_data);
 
90
 
86
91
    if (type == CAIRO_PATTERN_TYPE_SURFACE)
87
92
        pattern->extend = CAIRO_EXTEND_SURFACE_DEFAULT;
88
93
    else
112
117
        *dst = *src;
113
118
    }
114
119
 
115
 
    if (other->n_stops)
 
120
    if (other->stops == other->stops_embedded)
 
121
        pattern->stops = pattern->stops_embedded;
 
122
    else if (other->stops)
116
123
    {
117
 
        pattern->stops = malloc (other->n_stops *
 
124
        pattern->stops = malloc (other->stops_size *
118
125
                                 sizeof (pixman_gradient_stop_t));
119
126
        if (pattern->stops == NULL) {
 
127
            pattern->stops_size = 0;
 
128
            pattern->n_stops = 0;
120
129
            _cairo_pattern_set_error (&pattern->base, CAIRO_STATUS_NO_MEMORY);
121
130
            return;
122
131
        }
164
173
void
165
174
_cairo_pattern_fini (cairo_pattern_t *pattern)
166
175
{
 
176
    _cairo_user_data_array_fini (&pattern->user_data);
 
177
 
167
178
    switch (pattern->type) {
168
179
    case CAIRO_PATTERN_TYPE_SOLID:
169
180
        break;
178
189
        cairo_gradient_pattern_t *gradient =
179
190
            (cairo_gradient_pattern_t *) pattern;
180
191
 
181
 
        if (gradient->stops)
 
192
        if (gradient->stops && gradient->stops != gradient->stops_embedded)
182
193
            free (gradient->stops);
183
194
    } break;
184
195
    }
214
225
{
215
226
    _cairo_pattern_init (&pattern->base, type);
216
227
 
217
 
    pattern->stops   = NULL;
218
 
    pattern->n_stops = 0;
 
228
    pattern->n_stops    = 0;
 
229
    pattern->stops_size = 0;
 
230
    pattern->stops      = NULL;
219
231
}
220
232
 
221
233
void
237
249
{
238
250
    _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_TYPE_RADIAL);
239
251
 
240
 
    pattern->gradient.inner.x      = _cairo_fixed_from_double (cx0);
241
 
    pattern->gradient.inner.y      = _cairo_fixed_from_double (cy0);
242
 
    pattern->gradient.inner.radius = _cairo_fixed_from_double (fabs (radius0));
243
 
    pattern->gradient.outer.x      = _cairo_fixed_from_double (cx1);
244
 
    pattern->gradient.outer.y      = _cairo_fixed_from_double (cy1);
245
 
    pattern->gradient.outer.radius = _cairo_fixed_from_double (fabs (radius1));
 
252
    pattern->gradient.c1.x         = _cairo_fixed_from_double (cx0);
 
253
    pattern->gradient.c1.y         = _cairo_fixed_from_double (cy0);
 
254
    pattern->gradient.c1.radius = _cairo_fixed_from_double (fabs (radius0));
 
255
    pattern->gradient.c2.x         = _cairo_fixed_from_double (cx1);
 
256
    pattern->gradient.c2.y         = _cairo_fixed_from_double (cy1);
 
257
    pattern->gradient.c2.radius = _cairo_fixed_from_double (fabs (radius1));
246
258
}
247
259
 
248
260
cairo_pattern_t *
260
272
}
261
273
 
262
274
static const cairo_pattern_t *
263
 
_cairo_pattern_create_for_status (cairo_status_t status)
 
275
_cairo_pattern_create_in_error (cairo_status_t status)
264
276
{
265
277
    cairo_pattern_t *pattern;
266
278
 
284
296
 * If the values passed in are outside that range, they will be
285
297
 * clamped.
286
298
 *
287
 
 * Return value: the newly created #cairo_pattern_t if succesful, or
 
299
 * Return value: the newly created #cairo_pattern_t if successful, or
288
300
 * an error pattern in case of no memory.  The caller owns the
289
301
 * returned object and should call cairo_pattern_destroy() when
290
302
 * finished with it.
325
337
 * 1.  If the values passed in are outside that range, they will be
326
338
 * clamped.
327
339
 *
328
 
 * Return value: the newly created #cairo_pattern_t if succesful, or
 
340
 * Return value: the newly created #cairo_pattern_t if successful, or
329
341
 * an error pattern in case of no memory.  The caller owns the
330
342
 * returned object and should call cairo_pattern_destroy() when
331
343
 * finished with it.
362
374
 *
363
375
 * Create a new cairo_pattern_t for the given surface.
364
376
 *
365
 
 * Return value: the newly created #cairo_pattern_t if succesful, or
 
377
 * Return value: the newly created #cairo_pattern_t if successful, or
366
378
 * an error pattern in case of no memory.  The caller owns the
367
379
 * returned object and should call cairo_pattern_destroy() when
368
380
 * finished with it.
380
392
        return (cairo_pattern_t*) &cairo_pattern_nil_null_pointer;
381
393
 
382
394
    if (surface->status)
383
 
        return (cairo_pattern_t*) _cairo_pattern_create_for_status (surface->status);
 
395
        return (cairo_pattern_t*) _cairo_pattern_create_in_error (surface->status);
384
396
 
385
397
    pattern = malloc (sizeof (cairo_surface_pattern_t));
386
398
    if (pattern == NULL) {
411
423
 * pattern space is identical to user space, but the relationship
412
424
 * between the spaces can be changed with cairo_pattern_set_matrix().
413
425
 *
414
 
 * Return value: the newly created #cairo_pattern_t if succesful, or
 
426
 * Return value: the newly created #cairo_pattern_t if successful, or
415
427
 * an error pattern in case of no memory.  The caller owns the
416
428
 * returned object and should call cairo_pattern_destroy() when
417
429
 * finished with it.
440
452
 * cairo_pattern_create_radial:
441
453
 * @cx0: x coordinate for the center of the start circle
442
454
 * @cy0: y coordinate for the center of the start circle
443
 
 * @radius0: radius of the start cirle
 
455
 * @radius0: radius of the start circle
444
456
 * @cx1: x coordinate for the center of the end circle
445
457
 * @cy1: y coordinate for the center of the end circle
446
 
 * @radius1: radius of the end cirle
 
458
 * @radius1: radius of the end circle
447
459
 *
448
460
 * Creates a new radial gradient cairo_pattern_t between the two
449
461
 * circles defined by (x0, y0, c0) and (x1, y1, c0).  Before using the
455
467
 * pattern space is identical to user space, but the relationship
456
468
 * between the spaces can be changed with cairo_pattern_set_matrix().
457
469
 *
458
 
 * Return value: the newly created #cairo_pattern_t if succesful, or
 
470
 * Return value: the newly created #cairo_pattern_t if successful, or
459
471
 * an error pattern in case of no memory.  The caller owns the
460
472
 * returned object and should call cairo_pattern_destroy() when
461
473
 * finished with it.
489
501
 * @pattern from being destroyed until a matching call to
490
502
 * cairo_pattern_destroy() is made.
491
503
 *
 
504
 * The number of references to a #cairo_pattern_t can be get using
 
505
 * cairo_pattern_get_reference_count().
 
506
 *
492
507
 * Return value: the referenced #cairo_pattern_t.
493
508
 **/
494
509
cairo_pattern_t *
495
510
cairo_pattern_reference (cairo_pattern_t *pattern)
496
511
{
497
 
    if (pattern == NULL)
498
 
        return NULL;
499
 
 
500
 
    if (pattern->ref_count == CAIRO_REF_COUNT_INVALID)
 
512
    if (pattern == NULL || pattern->ref_count == CAIRO_REF_COUNT_INVALID)
501
513
        return pattern;
502
514
 
503
515
    assert (pattern->ref_count > 0);
554
566
void
555
567
cairo_pattern_destroy (cairo_pattern_t *pattern)
556
568
{
557
 
    if (pattern == NULL)
558
 
        return;
559
 
 
560
 
    if (pattern->ref_count == CAIRO_REF_COUNT_INVALID)
 
569
    if (pattern == NULL || pattern->ref_count == CAIRO_REF_COUNT_INVALID)
561
570
        return;
562
571
 
563
572
    assert (pattern->ref_count > 0);
571
580
}
572
581
slim_hidden_def (cairo_pattern_destroy);
573
582
 
 
583
/**
 
584
 * cairo_pattern_get_reference_count:
 
585
 * @pattern: a #cairo_pattern_t
 
586
 *
 
587
 * Returns the current reference count of @pattern.
 
588
 *
 
589
 * Return value: the current reference count of @pattern.  If the
 
590
 * object is a nil object, 0 will be returned.
 
591
 *
 
592
 * Since: 1.4
 
593
 **/
 
594
unsigned int
 
595
cairo_pattern_get_reference_count (cairo_pattern_t *pattern)
 
596
{
 
597
    if (pattern == NULL || pattern->ref_count == CAIRO_REF_COUNT_INVALID)
 
598
        return 0;
 
599
 
 
600
    return pattern->ref_count;
 
601
}
 
602
 
 
603
/**
 
604
 * cairo_pattern_get_user_data:
 
605
 * @pattern: a #cairo_pattern_t
 
606
 * @key: the address of the #cairo_user_data_key_t the user data was
 
607
 * attached to
 
608
 *
 
609
 * Return user data previously attached to @pattern using the
 
610
 * specified key.  If no user data has been attached with the given
 
611
 * key this function returns %NULL.
 
612
 *
 
613
 * Return value: the user data previously attached or %NULL.
 
614
 *
 
615
 * Since: 1.4
 
616
 **/
 
617
void *
 
618
cairo_pattern_get_user_data (cairo_pattern_t             *pattern,
 
619
                             const cairo_user_data_key_t *key)
 
620
{
 
621
    return _cairo_user_data_array_get_data (&pattern->user_data,
 
622
                                            key);
 
623
}
 
624
 
 
625
/**
 
626
 * cairo_pattern_set_user_data:
 
627
 * @pattern: a #cairo_pattern_t
 
628
 * @key: the address of a #cairo_user_data_key_t to attach the user data to
 
629
 * @user_data: the user data to attach to the #cairo_pattern_t
 
630
 * @destroy: a #cairo_destroy_func_t which will be called when the
 
631
 * #cairo_t is destroyed or when new user data is attached using the
 
632
 * same key.
 
633
 *
 
634
 * Attach user data to @pattern.  To remove user data from a surface,
 
635
 * call this function with the key that was used to set it and %NULL
 
636
 * for @data.
 
637
 *
 
638
 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
 
639
 * slot could not be allocated for the user data.
 
640
 *
 
641
 * Since: 1.4
 
642
 **/
 
643
cairo_status_t
 
644
cairo_pattern_set_user_data (cairo_pattern_t             *pattern,
 
645
                             const cairo_user_data_key_t *key,
 
646
                             void                        *user_data,
 
647
                             cairo_destroy_func_t         destroy)
 
648
{
 
649
    if (pattern->ref_count == CAIRO_REF_COUNT_INVALID)
 
650
        return CAIRO_STATUS_NO_MEMORY;
 
651
 
 
652
    return _cairo_user_data_array_set_data (&pattern->user_data,
 
653
                                            key, user_data, destroy);
 
654
}
 
655
 
 
656
/* make room for at least one more color stop */
 
657
static cairo_status_t
 
658
_cairo_pattern_gradient_grow (cairo_gradient_pattern_t *pattern)
 
659
{
 
660
    pixman_gradient_stop_t *new_stops;
 
661
    int old_size = pattern->stops_size;
 
662
    int embedded_size = sizeof (pattern->stops_embedded) / sizeof (pattern->stops_embedded[0]);
 
663
    int new_size = 2 * MAX (old_size, 4);
 
664
 
 
665
    /* we have a local buffer at pattern->stops_embedded.  try to fulfill the request
 
666
     * from there. */
 
667
    if (old_size < embedded_size) {
 
668
        pattern->stops = pattern->stops_embedded;
 
669
        pattern->stops_size = embedded_size;
 
670
        return CAIRO_STATUS_SUCCESS;
 
671
    }
 
672
 
 
673
    assert (pattern->n_stops <= pattern->stops_size);
 
674
 
 
675
    if (pattern->stops == pattern->stops_embedded) {
 
676
        new_stops = malloc (new_size * sizeof (pixman_gradient_stop_t));
 
677
        if (new_stops)
 
678
            memcpy (new_stops, pattern->stops, old_size * sizeof (pixman_gradient_stop_t));
 
679
    } else {
 
680
        new_stops = realloc (pattern->stops, new_size * sizeof (pixman_gradient_stop_t));
 
681
    }
 
682
 
 
683
    if (new_stops == NULL) {
 
684
        return CAIRO_STATUS_NO_MEMORY;
 
685
    }
 
686
 
 
687
    pattern->stops = new_stops;
 
688
    pattern->stops_size = new_size;
 
689
 
 
690
    return CAIRO_STATUS_SUCCESS;
 
691
}
 
692
 
574
693
static void
575
694
_cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern,
576
695
                               double                    offset,
579
698
                               double                    blue,
580
699
                               double                    alpha)
581
700
{
582
 
    pixman_gradient_stop_t *new_stops;
 
701
    pixman_gradient_stop_t *stops;
583
702
    cairo_fixed_t          x;
584
703
    unsigned int           i;
585
704
 
586
 
    new_stops = realloc (pattern->stops, (pattern->n_stops + 1) *
587
 
                         sizeof (pixman_gradient_stop_t));
588
 
    if (new_stops == NULL)
589
 
    {
590
 
        _cairo_pattern_set_error (&pattern->base, CAIRO_STATUS_NO_MEMORY);
591
 
        return;
 
705
    if (pattern->n_stops >= pattern->stops_size) {
 
706
        cairo_status_t status = _cairo_pattern_gradient_grow (pattern);
 
707
        if (status) {
 
708
            _cairo_pattern_set_error (&pattern->base, CAIRO_STATUS_NO_MEMORY);
 
709
            return;
 
710
        }
592
711
    }
593
712
 
594
 
    pattern->stops = new_stops;
 
713
    stops = pattern->stops;
595
714
 
596
715
    x = _cairo_fixed_from_double (offset);
597
716
    for (i = 0; i < pattern->n_stops; i++)
598
717
    {
599
 
        if (x < new_stops[i].x)
 
718
        if (x < stops[i].x)
600
719
        {
601
 
            memmove (&new_stops[i + 1], &new_stops[i],
 
720
            memmove (&stops[i + 1], &stops[i],
602
721
                     sizeof (pixman_gradient_stop_t) * (pattern->n_stops - i));
603
722
 
604
723
            break;
605
724
        }
606
725
    }
607
726
 
608
 
    new_stops[i].x = x;
 
727
    stops[i].x = x;
609
728
 
610
 
    new_stops[i].color.red   = red   * 65535.0;
611
 
    new_stops[i].color.green = green * 65535.0;
612
 
    new_stops[i].color.blue  = blue  * 65535.0;
613
 
    new_stops[i].color.alpha = alpha * 65535.0;
 
729
    stops[i].color.red   = _cairo_color_double_to_short (red);
 
730
    stops[i].color.green = _cairo_color_double_to_short (green);
 
731
    stops[i].color.blue  = _cairo_color_double_to_short (blue);
 
732
    stops[i].color.alpha = _cairo_color_double_to_short (alpha);
614
733
 
615
734
    pattern->n_stops++;
616
735
}
766
885
    *matrix = pattern->matrix;
767
886
}
768
887
 
 
888
/**
 
889
 * cairo_pattern_set_filter:
 
890
 * @pattern: a #cairo_pattern_t
 
891
 * @filter: a #cairo_filter_t describing the filter to use for resizing
 
892
 * the pattern
 
893
 *
 
894
 * Sets the filter to be used for resizing when using this pattern.
 
895
 * See #cairo_filter_t for details on each filter.
 
896
 **/
769
897
void
770
898
cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter)
771
899
{
775
903
    pattern->filter = filter;
776
904
}
777
905
 
 
906
/**
 
907
 * cairo_pattern_get_filter:
 
908
 * @pattern: a #cairo_pattern_t
 
909
 *
 
910
 * Gets the current filter for a pattern.  See #cairo_filter_t
 
911
 * for details on each filter.
 
912
 *
 
913
 * Return value: the current filter used for resizing the pattern.
 
914
 **/
778
915
cairo_filter_t
779
916
cairo_pattern_get_filter (cairo_pattern_t *pattern)
780
917
{
1004
1141
 
1005
1142
    pixman_image_destroy (pixman_image);
1006
1143
 
1007
 
    status = _cairo_surface_clone_similar (dst, &image->base, out);
 
1144
    status = _cairo_surface_clone_similar (dst, &image->base,
 
1145
                                           0, 0, width, height, out);
1008
1146
 
1009
1147
    cairo_surface_destroy (&image->base);
1010
1148
 
1124
1262
 
1125
1263
    attr->acquired = FALSE;
1126
1264
 
1127
 
    if (_cairo_surface_is_image (dst))
1128
 
    {
1129
 
        cairo_image_surface_t *image;
1130
 
 
1131
 
        status = _cairo_surface_acquire_source_image (pattern->surface,
1132
 
                                                      &image,
1133
 
                                                      &attr->extra);
1134
 
        if (status)
1135
 
            return status;
1136
 
 
1137
 
        *out = &image->base;
1138
 
        attr->acquired = TRUE;
1139
 
    }
1140
 
    else
1141
 
    {
1142
 
        status = _cairo_surface_clone_similar (dst, pattern->surface, out);
1143
 
    }
1144
 
 
1145
1265
    attr->extend = pattern->base.extend;
1146
1266
    attr->filter = pattern->base.filter;
1147
1267
    if (_cairo_matrix_is_integer_translation (&pattern->base.matrix,
1156
1276
    {
1157
1277
        attr->matrix = pattern->base.matrix;
1158
1278
        attr->x_offset = attr->y_offset = 0;
 
1279
        tx = 0;
 
1280
        ty = 0;
 
1281
    }
 
1282
 
 
1283
    /* XXX: Hack:
 
1284
     *
 
1285
     * The way we currently support CAIRO_EXTEND_REFLECT is to create
 
1286
     * an image twice bigger on each side, and create a pattern of four
 
1287
     * images such that the new image, when repeated, has the same effect
 
1288
     * of reflecting the original pattern.
 
1289
     *
 
1290
     * This is because the reflect support in pixman is broken and we
 
1291
     * pass repeat instead of reflect to pixman.  See
 
1292
     * _cairo_image_surface_set_attributes() for that.
 
1293
     */
 
1294
    if (attr->extend == CAIRO_EXTEND_REFLECT) {
 
1295
        cairo_t *cr;
 
1296
        int w,h;
 
1297
 
 
1298
        cairo_rectangle_int16_t extents;
 
1299
        status = _cairo_surface_get_extents (pattern->surface, &extents);
 
1300
        if (status)
 
1301
            return status;
 
1302
 
 
1303
        attr->extend = CAIRO_EXTEND_REPEAT;
 
1304
 
 
1305
        x = extents.x;
 
1306
        y = extents.y;
 
1307
        w = 2 * extents.width;
 
1308
        h = 2 * extents.height;
 
1309
 
 
1310
        *out = cairo_surface_create_similar (dst, dst->content, w, h);
 
1311
        if (!*out)
 
1312
            return CAIRO_STATUS_NO_MEMORY;
 
1313
 
 
1314
        (*out)->device_transform = pattern->surface->device_transform;
 
1315
        (*out)->device_transform_inverse = pattern->surface->device_transform_inverse;
 
1316
 
 
1317
        cr = cairo_create (*out);
 
1318
 
 
1319
        cairo_set_source_surface (cr, pattern->surface, -x, -y);
 
1320
        cairo_paint (cr);
 
1321
 
 
1322
        cairo_scale (cr, -1, +1);
 
1323
        cairo_set_source_surface (cr, pattern->surface, x-w, -y);
 
1324
        cairo_paint (cr);
 
1325
 
 
1326
        cairo_scale (cr, +1, -1);
 
1327
        cairo_set_source_surface (cr, pattern->surface, x-w, y-h);
 
1328
        cairo_paint (cr);
 
1329
 
 
1330
        cairo_scale (cr, -1, +1);
 
1331
        cairo_set_source_surface (cr, pattern->surface, -x, y-h);
 
1332
        cairo_paint (cr);
 
1333
 
 
1334
        status = cairo_status (cr);
 
1335
        cairo_destroy (cr);
 
1336
 
 
1337
        return status;
 
1338
    }
 
1339
 
 
1340
    if (_cairo_surface_is_image (dst))
 
1341
    {
 
1342
        cairo_image_surface_t *image;
 
1343
 
 
1344
        status = _cairo_surface_acquire_source_image (pattern->surface,
 
1345
                                                      &image,
 
1346
                                                      &attr->extra);
 
1347
        if (status)
 
1348
            return status;
 
1349
 
 
1350
        *out = &image->base;
 
1351
        attr->acquired = TRUE;
 
1352
    }
 
1353
    else
 
1354
    {
 
1355
        cairo_rectangle_int16_t extents;
 
1356
        status = _cairo_surface_get_extents (pattern->surface, &extents);
 
1357
        if (status)
 
1358
            return status;
 
1359
 
 
1360
        /* If we're repeating, we just play it safe and clone the entire surface. */
 
1361
        /* If requested width and height are -1, clone the entire surface.
 
1362
         * This is relied on in the svg backend. */
 
1363
        if (attr->extend == CAIRO_EXTEND_REPEAT ||
 
1364
            (width == (unsigned int) -1 && height == (unsigned int) -1)) {
 
1365
            x = extents.x;
 
1366
            y = extents.y;
 
1367
            width = extents.width;
 
1368
            height = extents.height;
 
1369
        } else {
 
1370
            /* Otherwise, we first transform the rectangle to the
 
1371
             * coordinate space of the source surface so that we can
 
1372
             * clone only that portion of the surface that will be
 
1373
             * read. */
 
1374
            if (! _cairo_matrix_is_identity (&attr->matrix)) {
 
1375
                double x1 = x;
 
1376
                double y1 = y;
 
1377
                double x2 = x + width;
 
1378
                double y2 = y + height;
 
1379
                cairo_bool_t is_tight;
 
1380
 
 
1381
                _cairo_matrix_transform_bounding_box  (&attr->matrix,
 
1382
                                                       &x1, &y1, &x2, &y2,
 
1383
                                                       &is_tight);
 
1384
 
 
1385
                /* The transform_bounding_box call may have resulted
 
1386
                 * in a region larger than the surface, but we never
 
1387
                 * want to clone more than the surface itself, (we
 
1388
                 * know we're not repeating at this point due to the
 
1389
                 * above. */
 
1390
                x = MAX (0, floor (x1));
 
1391
                y = MAX (0, floor (y1));
 
1392
                width = MIN (extents.width, ceil (x2)) - x;
 
1393
                height = MIN (extents.height, ceil (y2)) - y;
 
1394
            }
 
1395
            x += tx;
 
1396
            y += ty;
 
1397
        }
 
1398
 
 
1399
        status = _cairo_surface_clone_similar (dst, pattern->surface,
 
1400
                                               x, y, width, height, out);
 
1401
 
 
1402
        if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
 
1403
 
 
1404
            cairo_t *cr;
 
1405
 
 
1406
            *out = cairo_surface_create_similar (dst, dst->content,
 
1407
                                                 width, height);
 
1408
            if (!*out)
 
1409
                return CAIRO_STATUS_NO_MEMORY;
 
1410
 
 
1411
            (*out)->device_transform = pattern->surface->device_transform;
 
1412
            (*out)->device_transform_inverse = pattern->surface->device_transform_inverse;
 
1413
 
 
1414
            /* XXX Use _cairo_surface_composite directly */
 
1415
            cr = cairo_create (*out);
 
1416
 
 
1417
            cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
 
1418
            cairo_set_source_surface (cr, pattern->surface, -x, -y);
 
1419
            cairo_paint (cr);
 
1420
 
 
1421
            status = cairo_status (cr);
 
1422
            cairo_destroy (cr);
 
1423
        }
1159
1424
    }
1160
1425
 
1161
1426
    return status;
1219
1484
                cairo_color_t color;
1220
1485
 
1221
1486
                _cairo_color_init_rgba (&color,
1222
 
                                        src->stops->color.red / 65536.0,
1223
 
                                        src->stops->color.green / 65536.0,
1224
 
                                        src->stops->color.blue / 65536.0,
1225
 
                                        src->stops->color.alpha / 65536.0);
 
1487
                                        src->stops->color.red / 65535.0,
 
1488
                                        src->stops->color.green / 65535.0,
 
1489
                                        src->stops->color.blue / 65535.0,
 
1490
                                        src->stops->color.alpha / 65535.0);
1226
1491
 
1227
1492
                _cairo_pattern_init_solid (&solid, &color);
1228
1493
            }
1414
1679
        imatrix = pattern->matrix;
1415
1680
        cairo_matrix_invert (&imatrix);
1416
1681
 
 
1682
        /* XXX Use _cairo_matrix_transform_bounding_box here */
1417
1683
        for (sy = 0; sy <= 1; sy++) {
1418
1684
            for (sx = 0; sx <= 1; sx++) {
1419
1685
                x = surface_extents.x + sx * surface_extents.width;
1456
1722
 
1457
1723
    return CAIRO_STATUS_SUCCESS;
1458
1724
}
 
1725
 
 
1726
/**
 
1727
 * cairo_pattern_get_rgba
 
1728
 * @pattern: a #cairo_pattern_t
 
1729
 * @red: return value for red component of color, or %NULL
 
1730
 * @green: return value for green component of color, or %NULL
 
1731
 * @blue: return value for blue component of color, or %NULL
 
1732
 * @alpha: return value for alpha component of color, or %NULL
 
1733
 *
 
1734
 * Gets the solid color for a solid color pattern.
 
1735
 *
 
1736
 * Return value: %CAIRO_STATUS_SUCCESS, or
 
1737
 * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if the pattern is not a solid
 
1738
 * color pattern.
 
1739
 *
 
1740
 * Since: 1.4
 
1741
 **/
 
1742
cairo_status_t
 
1743
cairo_pattern_get_rgba (cairo_pattern_t *pattern,
 
1744
                        double *red, double *green,
 
1745
                        double *blue, double *alpha)
 
1746
{
 
1747
    cairo_solid_pattern_t *solid = (cairo_solid_pattern_t*) pattern;
 
1748
    double r0, g0, b0, a0;
 
1749
 
 
1750
    if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
 
1751
        return CAIRO_STATUS_PATTERN_TYPE_MISMATCH;
 
1752
 
 
1753
    _cairo_color_get_rgba (&solid->color, &r0, &g0, &b0, &a0);
 
1754
 
 
1755
    if (red)
 
1756
        *red = r0;
 
1757
    if (green)
 
1758
        *green = g0;
 
1759
    if (blue)
 
1760
        *blue = b0;
 
1761
    if (alpha)
 
1762
        *alpha = a0;
 
1763
 
 
1764
    return CAIRO_STATUS_SUCCESS;
 
1765
}
 
1766
 
 
1767
/**
 
1768
 * cairo_pattern_get_surface
 
1769
 * @pattern: a #cairo_pattern_t
 
1770
 * @surface: return value for surface of pattern, or %NULL
 
1771
 * 
 
1772
 * Gets the surface of a surface pattern.  The reference returned in
 
1773
 * @surface is owned by the pattern; the caller should call
 
1774
 * cairo_surface_reference() if the surface is to be retained.
 
1775
 *
 
1776
 * Return value: %CAIRO_STATUS_SUCCESS, or
 
1777
 * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if the pattern is not a surface
 
1778
 * pattern.
 
1779
 *
 
1780
 * Since: 1.4
 
1781
 **/
 
1782
cairo_status_t
 
1783
cairo_pattern_get_surface (cairo_pattern_t *pattern,
 
1784
                           cairo_surface_t **surface)
 
1785
{
 
1786
    cairo_surface_pattern_t *spat = (cairo_surface_pattern_t*) pattern;
 
1787
 
 
1788
    if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
 
1789
        return CAIRO_STATUS_PATTERN_TYPE_MISMATCH;
 
1790
 
 
1791
    if (surface)
 
1792
        *surface = spat->surface;
 
1793
 
 
1794
    return CAIRO_STATUS_SUCCESS;
 
1795
}
 
1796
 
 
1797
/**
 
1798
 * cairo_pattern_get_color_stop_rgba
 
1799
 * @pattern: a #cairo_pattern_t
 
1800
 * @index: index of the stop to return data for
 
1801
 * @offset: return value for the offset of the stop, or %NULL
 
1802
 * @red: return value for red component of color, or %NULL
 
1803
 * @green: return value for green component of color, or %NULL
 
1804
 * @blue: return value for blue component of color, or %NULL
 
1805
 * @alpha: return value for alpha component of color, or %NULL
 
1806
 *
 
1807
 * Gets the color and offset information at the given @index for a
 
1808
 * gradient pattern.  Values of @index are 0 to 1 less than the number
 
1809
 * returned by cairo_pattern_get_color_stop_count().
 
1810
 *
 
1811
 * Return value: %CAIRO_STATUS_SUCCESS, or %CAIRO_STATUS_INVALID_INDEX
 
1812
 * if @index is not valid for the given pattern.  If the pattern is
 
1813
 * not a gradient pattern, %CAIRO_STATUS_PATTERN_TYPE_MISMATCH is
 
1814
 * returned.
 
1815
 *
 
1816
 * Since: 1.4
 
1817
 **/
 
1818
cairo_status_t
 
1819
cairo_pattern_get_color_stop_rgba (cairo_pattern_t *pattern,
 
1820
                                   int index, double *offset,
 
1821
                                   double *red, double *green,
 
1822
                                   double *blue, double *alpha)
 
1823
{
 
1824
    cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t*) pattern;
 
1825
 
 
1826
    if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR &&
 
1827
        pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
 
1828
        return CAIRO_STATUS_PATTERN_TYPE_MISMATCH;
 
1829
 
 
1830
    if (index < 0 || (unsigned int) index >= gradient->n_stops)
 
1831
        return CAIRO_STATUS_INVALID_INDEX;
 
1832
 
 
1833
    if (offset)
 
1834
        *offset = _cairo_fixed_to_double(gradient->stops[index].x);
 
1835
    if (red)
 
1836
        *red = gradient->stops[index].color.red / (double) 0xffff;
 
1837
    if (green)
 
1838
        *green = gradient->stops[index].color.green / (double) 0xffff;
 
1839
    if (blue)
 
1840
        *blue = gradient->stops[index].color.blue / (double) 0xffff;
 
1841
    if (alpha)
 
1842
        *alpha = gradient->stops[index].color.alpha / (double) 0xffff;
 
1843
 
 
1844
    return CAIRO_STATUS_SUCCESS;
 
1845
}
 
1846
 
 
1847
/**
 
1848
 * cairo_pattern_get_color_stop_count
 
1849
 * @pattern: a #cairo_pattern_t
 
1850
 * @count: return value for the number of color stops, or %NULL
 
1851
 *
 
1852
 * Gets the number of color stops specified in the given gradient
 
1853
 * pattern.
 
1854
 *
 
1855
 * Return value: %CAIRO_STATUS_SUCCESS, or
 
1856
 * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a gradient
 
1857
 * pattern.
 
1858
 *
 
1859
 * Since: 1.4
 
1860
 */
 
1861
cairo_status_t
 
1862
cairo_pattern_get_color_stop_count (cairo_pattern_t *pattern,
 
1863
                                    int *count)
 
1864
{
 
1865
    cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t*) pattern;
 
1866
 
 
1867
    if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR &&
 
1868
        pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
 
1869
        return CAIRO_STATUS_PATTERN_TYPE_MISMATCH;
 
1870
 
 
1871
    if (count)
 
1872
        *count = gradient->n_stops;
 
1873
 
 
1874
    return CAIRO_STATUS_SUCCESS;
 
1875
}
 
1876
 
 
1877
/**
 
1878
 * cairo_pattern_get_linear_points
 
1879
 * @pattern: a #cairo_pattern_t
 
1880
 * @x0: return value for the x coordinate of the first point, or %NULL
 
1881
 * @y0: return value for the y coordinate of the first point, or %NULL
 
1882
 * @x1: return value for the x coordinate of the second point, or %NULL
 
1883
 * @y1: return value for the y coordinate of the second point, or %NULL
 
1884
 *
 
1885
 * Gets the gradient endpoints for a linear gradient.
 
1886
 *
 
1887
 * Return value: %CAIRO_STATUS_SUCCESS, or
 
1888
 * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a linear
 
1889
 * gradient pattern.
 
1890
 *
 
1891
 * Since: 1.4
 
1892
 **/
 
1893
cairo_status_t
 
1894
cairo_pattern_get_linear_points (cairo_pattern_t *pattern,
 
1895
                                 double *x0, double *y0,
 
1896
                                 double *x1, double *y1)
 
1897
{
 
1898
    cairo_linear_pattern_t *linear = (cairo_linear_pattern_t*) pattern;
 
1899
 
 
1900
    if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR)
 
1901
        return CAIRO_STATUS_PATTERN_TYPE_MISMATCH;
 
1902
 
 
1903
    if (x0)
 
1904
        *x0 = _cairo_fixed_to_double (linear->gradient.p1.x);
 
1905
    if (y0)
 
1906
        *y0 = _cairo_fixed_to_double (linear->gradient.p1.y);
 
1907
    if (x1)
 
1908
        *x1 = _cairo_fixed_to_double (linear->gradient.p2.x);
 
1909
    if (y1)
 
1910
        *y1 = _cairo_fixed_to_double (linear->gradient.p2.y);
 
1911
 
 
1912
    return CAIRO_STATUS_SUCCESS;
 
1913
}
 
1914
 
 
1915
/**
 
1916
 * cairo_pattern_get_radial_circles
 
1917
 * @pattern: a #cairo_pattern_t
 
1918
 * @x0: return value for the x coordinate of the center of the first circle, or %NULL
 
1919
 * @y0: return value for the y coordinate of the center of the first circle, or %NULL
 
1920
 * @r0: return value for the radius of the first circle, or %NULL
 
1921
 * @x1: return value for the x coordinate of the center of the second circle, or %NULL
 
1922
 * @y1: return value for the y coordinate of the center of the second circle, or %NULL
 
1923
 * @r1: return value for the radius of the second circle, or %NULL
 
1924
 *
 
1925
 * Gets the gradient endpoint circles for a radial gradient, each
 
1926
 * specified as a center coordinate and a radius.
 
1927
 *
 
1928
 * Return value: %CAIRO_STATUS_SUCCESS, or
 
1929
 * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a radial
 
1930
 * gradient pattern.
 
1931
 *
 
1932
 * Since: 1.4
 
1933
 **/
 
1934
cairo_status_t
 
1935
cairo_pattern_get_radial_circles (cairo_pattern_t *pattern,
 
1936
                                  double *x0, double *y0, double *r0,
 
1937
                                  double *x1, double *y1, double *r1)
 
1938
{
 
1939
    cairo_radial_pattern_t *radial = (cairo_radial_pattern_t*) pattern;
 
1940
 
 
1941
    if (pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
 
1942
        return CAIRO_STATUS_PATTERN_TYPE_MISMATCH;
 
1943
 
 
1944
    if (x0)
 
1945
        *x0 = _cairo_fixed_to_double (radial->gradient.c1.x);
 
1946
    if (y0)
 
1947
        *y0 = _cairo_fixed_to_double (radial->gradient.c1.y);
 
1948
    if (r0)
 
1949
        *r0 = _cairo_fixed_to_double (radial->gradient.c1.radius);
 
1950
    if (x1)
 
1951
        *x1 = _cairo_fixed_to_double (radial->gradient.c2.x);
 
1952
    if (y1)
 
1953
        *y1 = _cairo_fixed_to_double (radial->gradient.c2.y);
 
1954
    if (r1)
 
1955
        *r1 = _cairo_fixed_to_double (radial->gradient.c2.radius);
 
1956
 
 
1957
    return CAIRO_STATUS_SUCCESS;
 
1958
}