1 : /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2 : /* cairo - a vector graphics library with display and print output
3 : *
4 : * Copyright © 2004 David Reveman
5 : * Copyright © 2005 Red Hat, Inc.
6 : *
7 : * Permission to use, copy, modify, distribute, and sell this software
8 : * and its documentation for any purpose is hereby granted without
9 : * fee, provided that the above copyright notice appear in all copies
10 : * and that both that copyright notice and this permission notice
11 : * appear in supporting documentation, and that the name of David
12 : * Reveman not be used in advertising or publicity pertaining to
13 : * distribution of the software without specific, written prior
14 : * permission. David Reveman makes no representations about the
15 : * suitability of this software for any purpose. It is provided "as
16 : * is" without express or implied warranty.
17 : *
18 : * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
19 : * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 : * FITNESS, IN NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL,
21 : * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
22 : * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
23 : * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
24 : * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
25 : *
26 : * Authors: David Reveman <davidr@novell.com>
27 : * Keith Packard <keithp@keithp.com>
28 : * Carl Worth <cworth@cworth.org>
29 : */
30 :
31 : #include "cairoint.h"
32 : #include "cairo-error-private.h"
33 : #include "cairo-freed-pool-private.h"
34 :
35 : /**
36 : * SECTION:cairo-pattern
37 : * @Title: cairo_pattern_t
38 : * @Short_Description: Sources for drawing
39 : * @See_Also: #cairo_t, #cairo_surface_t
40 : *
41 : * #cairo_pattern_t is the paint with which cairo draws.
42 : * The primary use of patterns is as the source for all cairo drawing
43 : * operations, although they can also be used as masks, that is, as the
44 : * brush too.
45 : *
46 : * A cairo pattern is created by using one of the many constructors,
47 : * of the form cairo_pattern_create_<emphasis>type</emphasis>()
48 : * or implicitly through
49 : * cairo_set_source_<emphasis>type</emphasis>() functions.
50 : */
51 :
52 : #if HAS_FREED_POOL
53 : static freed_pool_t freed_pattern_pool[4];
54 : #endif
55 :
56 : static const cairo_solid_pattern_t _cairo_pattern_nil = {
57 : { CAIRO_PATTERN_TYPE_SOLID, /* type */
58 : CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
59 : CAIRO_STATUS_NO_MEMORY, /* status */
60 : { 0, 0, 0, NULL }, /* user_data */
61 : { 1., 0., 0., 1., 0., 0., }, /* matrix */
62 : CAIRO_FILTER_DEFAULT, /* filter */
63 : CAIRO_EXTEND_GRADIENT_DEFAULT }, /* extend */
64 : };
65 :
66 : static const cairo_solid_pattern_t _cairo_pattern_nil_null_pointer = {
67 : { CAIRO_PATTERN_TYPE_SOLID, /* type */
68 : CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
69 : CAIRO_STATUS_NULL_POINTER, /* status */
70 : { 0, 0, 0, NULL }, /* user_data */
71 : { 1., 0., 0., 1., 0., 0., }, /* matrix */
72 : CAIRO_FILTER_DEFAULT, /* filter */
73 : CAIRO_EXTEND_GRADIENT_DEFAULT }, /* extend */
74 : };
75 :
76 : const cairo_solid_pattern_t _cairo_pattern_black = {
77 : { CAIRO_PATTERN_TYPE_SOLID, /* type */
78 : CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
79 : CAIRO_STATUS_SUCCESS, /* status */
80 : { 0, 0, 0, NULL }, /* user_data */
81 : { 1., 0., 0., 1., 0., 0., }, /* matrix */
82 : CAIRO_FILTER_DEFAULT, /* filter */
83 : CAIRO_EXTEND_GRADIENT_DEFAULT}, /* extend */
84 : { 0., 0., 0., 1., 0, 0, 0, 0xffff },/* color (double rgba, short rgba) */
85 : };
86 :
87 : const cairo_solid_pattern_t _cairo_pattern_clear = {
88 : { CAIRO_PATTERN_TYPE_SOLID, /* type */
89 : CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
90 : CAIRO_STATUS_SUCCESS, /* status */
91 : { 0, 0, 0, NULL }, /* user_data */
92 : { 1., 0., 0., 1., 0., 0., }, /* matrix */
93 : CAIRO_FILTER_DEFAULT, /* filter */
94 : CAIRO_EXTEND_GRADIENT_DEFAULT}, /* extend */
95 : { 0., 0., 0., 0., 0, 0, 0, 0 },/* color (double rgba, short rgba) */
96 : };
97 :
98 : const cairo_solid_pattern_t _cairo_pattern_white = {
99 : { CAIRO_PATTERN_TYPE_SOLID, /* type */
100 : CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */
101 : CAIRO_STATUS_SUCCESS, /* status */
102 : { 0, 0, 0, NULL }, /* user_data */
103 : { 1., 0., 0., 1., 0., 0., }, /* matrix */
104 : CAIRO_FILTER_DEFAULT, /* filter */
105 : CAIRO_EXTEND_GRADIENT_DEFAULT}, /* extend */
106 : { 1., 1., 1., 1., 0xffff, 0xffff, 0xffff, 0xffff },/* color (double rgba, short rgba) */
107 : };
108 :
109 : /**
110 : * _cairo_pattern_set_error:
111 : * @pattern: a pattern
112 : * @status: a status value indicating an error
113 : *
114 : * Atomically sets pattern->status to @status and calls _cairo_error;
115 : * Does nothing if status is %CAIRO_STATUS_SUCCESS.
116 : *
117 : * All assignments of an error status to pattern->status should happen
118 : * through _cairo_pattern_set_error(). Note that due to the nature of
119 : * the atomic operation, it is not safe to call this function on the nil
120 : * objects.
121 : *
122 : * The purpose of this function is to allow the user to set a
123 : * breakpoint in _cairo_error() to generate a stack trace for when the
124 : * user causes cairo to detect an error.
125 : **/
126 : static cairo_status_t
127 0 : _cairo_pattern_set_error (cairo_pattern_t *pattern,
128 : cairo_status_t status)
129 : {
130 0 : if (status == CAIRO_STATUS_SUCCESS)
131 0 : return status;
132 :
133 : /* Don't overwrite an existing error. This preserves the first
134 : * error, which is the most significant. */
135 0 : _cairo_status_set_error (&pattern->status, status);
136 :
137 0 : return _cairo_error (status);
138 : }
139 :
140 : static void
141 47 : _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type)
142 : {
143 : #if HAVE_VALGRIND
144 : switch (type) {
145 : case CAIRO_PATTERN_TYPE_SOLID:
146 : VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_solid_pattern_t));
147 : break;
148 : case CAIRO_PATTERN_TYPE_SURFACE:
149 : VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_surface_pattern_t));
150 : break;
151 : case CAIRO_PATTERN_TYPE_LINEAR:
152 : VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_linear_pattern_t));
153 : break;
154 : case CAIRO_PATTERN_TYPE_RADIAL:
155 : VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_radial_pattern_t));
156 : break;
157 : }
158 : #endif
159 :
160 47 : pattern->type = type;
161 47 : pattern->status = CAIRO_STATUS_SUCCESS;
162 :
163 : /* Set the reference count to zero for on-stack patterns.
164 : * Callers needs to explicitly increment the count for heap allocations. */
165 47 : CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 0);
166 :
167 47 : _cairo_user_data_array_init (&pattern->user_data);
168 :
169 47 : if (type == CAIRO_PATTERN_TYPE_SURFACE)
170 47 : pattern->extend = CAIRO_EXTEND_SURFACE_DEFAULT;
171 : else
172 0 : pattern->extend = CAIRO_EXTEND_GRADIENT_DEFAULT;
173 :
174 47 : pattern->filter = CAIRO_FILTER_DEFAULT;
175 :
176 47 : pattern->has_component_alpha = FALSE;
177 :
178 47 : cairo_matrix_init_identity (&pattern->matrix);
179 47 : }
180 :
181 : static cairo_status_t
182 0 : _cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern,
183 : const cairo_gradient_pattern_t *other)
184 : {
185 : if (CAIRO_INJECT_FAULT ())
186 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
187 :
188 0 : if (other->base.type == CAIRO_PATTERN_TYPE_LINEAR)
189 : {
190 0 : cairo_linear_pattern_t *dst = (cairo_linear_pattern_t *) pattern;
191 0 : cairo_linear_pattern_t *src = (cairo_linear_pattern_t *) other;
192 :
193 0 : *dst = *src;
194 : }
195 : else
196 : {
197 0 : cairo_radial_pattern_t *dst = (cairo_radial_pattern_t *) pattern;
198 0 : cairo_radial_pattern_t *src = (cairo_radial_pattern_t *) other;
199 :
200 0 : *dst = *src;
201 : }
202 :
203 0 : if (other->stops == other->stops_embedded)
204 0 : pattern->stops = pattern->stops_embedded;
205 0 : else if (other->stops)
206 : {
207 0 : pattern->stops = _cairo_malloc_ab (other->stops_size,
208 : sizeof (cairo_gradient_stop_t));
209 0 : if (unlikely (pattern->stops == NULL)) {
210 0 : pattern->stops_size = 0;
211 0 : pattern->n_stops = 0;
212 0 : return _cairo_pattern_set_error (&pattern->base, CAIRO_STATUS_NO_MEMORY);
213 : }
214 :
215 0 : memcpy (pattern->stops, other->stops,
216 0 : other->n_stops * sizeof (cairo_gradient_stop_t));
217 : }
218 :
219 0 : return CAIRO_STATUS_SUCCESS;
220 : }
221 :
222 : cairo_status_t
223 0 : _cairo_pattern_init_copy (cairo_pattern_t *pattern,
224 : const cairo_pattern_t *other)
225 : {
226 0 : if (other->status)
227 0 : return _cairo_pattern_set_error (pattern, other->status);
228 :
229 0 : switch (other->type) {
230 : case CAIRO_PATTERN_TYPE_SOLID: {
231 0 : cairo_solid_pattern_t *dst = (cairo_solid_pattern_t *) pattern;
232 0 : cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) other;
233 :
234 : VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_solid_pattern_t)));
235 :
236 0 : *dst = *src;
237 0 : } break;
238 : case CAIRO_PATTERN_TYPE_SURFACE: {
239 0 : cairo_surface_pattern_t *dst = (cairo_surface_pattern_t *) pattern;
240 0 : cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) other;
241 :
242 : VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_surface_pattern_t)));
243 :
244 0 : *dst = *src;
245 0 : cairo_surface_reference (dst->surface);
246 0 : } break;
247 : case CAIRO_PATTERN_TYPE_LINEAR:
248 : case CAIRO_PATTERN_TYPE_RADIAL: {
249 0 : cairo_gradient_pattern_t *dst = (cairo_gradient_pattern_t *) pattern;
250 0 : cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) other;
251 : cairo_status_t status;
252 :
253 0 : if (other->type == CAIRO_PATTERN_TYPE_LINEAR) {
254 : VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_linear_pattern_t)));
255 : } else {
256 : VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_radial_pattern_t)));
257 : }
258 :
259 0 : status = _cairo_gradient_pattern_init_copy (dst, src);
260 0 : if (unlikely (status))
261 0 : return status;
262 :
263 0 : } break;
264 : }
265 :
266 : /* The reference count and user_data array are unique to the copy. */
267 0 : CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 0);
268 0 : _cairo_user_data_array_init (&pattern->user_data);
269 :
270 0 : return CAIRO_STATUS_SUCCESS;
271 : }
272 :
273 : void
274 47 : _cairo_pattern_init_static_copy (cairo_pattern_t *pattern,
275 : const cairo_pattern_t *other)
276 : {
277 : int size;
278 :
279 47 : assert (other->status == CAIRO_STATUS_SUCCESS);
280 :
281 47 : switch (other->type) {
282 : default:
283 0 : ASSERT_NOT_REACHED;
284 : case CAIRO_PATTERN_TYPE_SOLID:
285 0 : size = sizeof (cairo_solid_pattern_t);
286 0 : break;
287 : case CAIRO_PATTERN_TYPE_SURFACE:
288 47 : size = sizeof (cairo_surface_pattern_t);
289 47 : break;
290 : case CAIRO_PATTERN_TYPE_LINEAR:
291 0 : size = sizeof (cairo_linear_pattern_t);
292 0 : break;
293 : case CAIRO_PATTERN_TYPE_RADIAL:
294 0 : size = sizeof (cairo_radial_pattern_t);
295 0 : break;
296 : }
297 :
298 47 : memcpy (pattern, other, size);
299 :
300 47 : CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 0);
301 47 : _cairo_user_data_array_init (&pattern->user_data);
302 47 : }
303 :
304 : cairo_status_t
305 0 : _cairo_pattern_init_snapshot (cairo_pattern_t *pattern,
306 : const cairo_pattern_t *other)
307 : {
308 : cairo_status_t status;
309 :
310 : /* We don't bother doing any fancy copy-on-write implementation
311 : * for the pattern's data. It's generally quite tiny. */
312 0 : status = _cairo_pattern_init_copy (pattern, other);
313 0 : if (unlikely (status))
314 0 : return status;
315 :
316 : /* But we do let the surface snapshot stuff be as fancy as it
317 : * would like to be. */
318 0 : if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
319 0 : cairo_surface_pattern_t *surface_pattern =
320 : (cairo_surface_pattern_t *) pattern;
321 0 : cairo_surface_t *surface = surface_pattern->surface;
322 :
323 0 : surface_pattern->surface = _cairo_surface_snapshot (surface);
324 :
325 0 : cairo_surface_destroy (surface);
326 :
327 0 : if (surface_pattern->surface->status)
328 0 : return surface_pattern->surface->status;
329 : }
330 :
331 0 : return CAIRO_STATUS_SUCCESS;
332 : }
333 :
334 : void
335 47 : _cairo_pattern_fini (cairo_pattern_t *pattern)
336 : {
337 47 : _cairo_user_data_array_fini (&pattern->user_data);
338 :
339 47 : switch (pattern->type) {
340 : case CAIRO_PATTERN_TYPE_SOLID:
341 0 : break;
342 : case CAIRO_PATTERN_TYPE_SURFACE: {
343 47 : cairo_surface_pattern_t *surface_pattern =
344 : (cairo_surface_pattern_t *) pattern;
345 :
346 47 : cairo_surface_destroy (surface_pattern->surface);
347 47 : } break;
348 : case CAIRO_PATTERN_TYPE_LINEAR:
349 : case CAIRO_PATTERN_TYPE_RADIAL: {
350 0 : cairo_gradient_pattern_t *gradient =
351 : (cairo_gradient_pattern_t *) pattern;
352 :
353 0 : if (gradient->stops && gradient->stops != gradient->stops_embedded)
354 0 : free (gradient->stops);
355 0 : } break;
356 : }
357 :
358 : #if HAVE_VALGRIND
359 : switch (pattern->type) {
360 : case CAIRO_PATTERN_TYPE_SOLID:
361 : VALGRIND_MAKE_MEM_NOACCESS (pattern, sizeof (cairo_solid_pattern_t));
362 : break;
363 : case CAIRO_PATTERN_TYPE_SURFACE:
364 : VALGRIND_MAKE_MEM_NOACCESS (pattern, sizeof (cairo_surface_pattern_t));
365 : break;
366 : case CAIRO_PATTERN_TYPE_LINEAR:
367 : VALGRIND_MAKE_MEM_NOACCESS (pattern, sizeof (cairo_linear_pattern_t));
368 : break;
369 : case CAIRO_PATTERN_TYPE_RADIAL:
370 : VALGRIND_MAKE_MEM_NOACCESS (pattern, sizeof (cairo_radial_pattern_t));
371 : break;
372 : }
373 : #endif
374 47 : }
375 :
376 : cairo_status_t
377 0 : _cairo_pattern_create_copy (cairo_pattern_t **pattern_out,
378 : const cairo_pattern_t *other)
379 : {
380 : cairo_pattern_t *pattern;
381 : cairo_status_t status;
382 :
383 0 : if (other->status)
384 0 : return other->status;
385 :
386 0 : switch (other->type) {
387 : case CAIRO_PATTERN_TYPE_SOLID:
388 0 : pattern = malloc (sizeof (cairo_solid_pattern_t));
389 0 : break;
390 : case CAIRO_PATTERN_TYPE_SURFACE:
391 0 : pattern = malloc (sizeof (cairo_surface_pattern_t));
392 0 : break;
393 : case CAIRO_PATTERN_TYPE_LINEAR:
394 0 : pattern = malloc (sizeof (cairo_linear_pattern_t));
395 0 : break;
396 : case CAIRO_PATTERN_TYPE_RADIAL:
397 0 : pattern = malloc (sizeof (cairo_radial_pattern_t));
398 0 : break;
399 : default:
400 0 : ASSERT_NOT_REACHED;
401 0 : return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
402 : }
403 0 : if (unlikely (pattern == NULL))
404 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
405 :
406 0 : status = _cairo_pattern_init_copy (pattern, other);
407 0 : if (unlikely (status)) {
408 0 : free (pattern);
409 0 : return status;
410 : }
411 :
412 0 : CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 1);
413 0 : *pattern_out = pattern;
414 0 : return CAIRO_STATUS_SUCCESS;
415 : }
416 :
417 :
418 : void
419 0 : _cairo_pattern_init_solid (cairo_solid_pattern_t *pattern,
420 : const cairo_color_t *color)
421 : {
422 0 : _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SOLID);
423 0 : pattern->color = *color;
424 0 : }
425 :
426 : void
427 47 : _cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern,
428 : cairo_surface_t *surface)
429 : {
430 47 : if (surface->status) {
431 : /* Force to solid to simplify the pattern_fini process. */
432 0 : _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SOLID);
433 0 : _cairo_pattern_set_error (&pattern->base, surface->status);
434 0 : return;
435 : }
436 :
437 47 : _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SURFACE);
438 :
439 47 : pattern->surface = cairo_surface_reference (surface);
440 : }
441 :
442 : static void
443 0 : _cairo_pattern_init_gradient (cairo_gradient_pattern_t *pattern,
444 : cairo_pattern_type_t type)
445 : {
446 0 : _cairo_pattern_init (&pattern->base, type);
447 :
448 0 : pattern->n_stops = 0;
449 0 : pattern->stops_size = 0;
450 0 : pattern->stops = NULL;
451 0 : }
452 :
453 : void
454 0 : _cairo_pattern_init_linear (cairo_linear_pattern_t *pattern,
455 : double x0, double y0, double x1, double y1)
456 : {
457 0 : _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_TYPE_LINEAR);
458 :
459 0 : pattern->p1.x = _cairo_fixed_from_double (x0);
460 0 : pattern->p1.y = _cairo_fixed_from_double (y0);
461 0 : pattern->p2.x = _cairo_fixed_from_double (x1);
462 0 : pattern->p2.y = _cairo_fixed_from_double (y1);
463 0 : }
464 :
465 : void
466 0 : _cairo_pattern_init_radial (cairo_radial_pattern_t *pattern,
467 : double cx0, double cy0, double radius0,
468 : double cx1, double cy1, double radius1)
469 : {
470 0 : _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_TYPE_RADIAL);
471 :
472 0 : pattern->c1.x = _cairo_fixed_from_double (cx0);
473 0 : pattern->c1.y = _cairo_fixed_from_double (cy0);
474 0 : pattern->r1 = _cairo_fixed_from_double (fabs (radius0));
475 0 : pattern->c2.x = _cairo_fixed_from_double (cx1);
476 0 : pattern->c2.y = _cairo_fixed_from_double (cy1);
477 0 : pattern->r2 = _cairo_fixed_from_double (fabs (radius1));
478 0 : }
479 :
480 : cairo_pattern_t *
481 0 : _cairo_pattern_create_solid (const cairo_color_t *color)
482 : {
483 : cairo_solid_pattern_t *pattern;
484 :
485 0 : pattern =
486 : _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SOLID]);
487 0 : if (unlikely (pattern == NULL)) {
488 : /* None cached, need to create a new pattern. */
489 0 : pattern = malloc (sizeof (cairo_solid_pattern_t));
490 0 : if (unlikely (pattern == NULL)) {
491 0 : _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
492 0 : return (cairo_pattern_t *) &_cairo_pattern_nil;
493 : }
494 : }
495 :
496 0 : _cairo_pattern_init_solid (pattern, color);
497 0 : CAIRO_REFERENCE_COUNT_INIT (&pattern->base.ref_count, 1);
498 :
499 0 : return &pattern->base;
500 : }
501 :
502 : cairo_pattern_t *
503 0 : _cairo_pattern_create_in_error (cairo_status_t status)
504 : {
505 : cairo_pattern_t *pattern;
506 :
507 0 : if (status == CAIRO_STATUS_NO_MEMORY)
508 0 : return (cairo_pattern_t *)&_cairo_pattern_nil.base;
509 :
510 : CAIRO_MUTEX_INITIALIZE ();
511 :
512 0 : pattern = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK);
513 0 : if (pattern->status == CAIRO_STATUS_SUCCESS)
514 0 : status = _cairo_pattern_set_error (pattern, status);
515 :
516 0 : return pattern;
517 : }
518 :
519 : /**
520 : * cairo_pattern_create_rgb:
521 : * @red: red component of the color
522 : * @green: green component of the color
523 : * @blue: blue component of the color
524 : *
525 : * Creates a new #cairo_pattern_t corresponding to an opaque color. The
526 : * color components are floating point numbers in the range 0 to 1.
527 : * If the values passed in are outside that range, they will be
528 : * clamped.
529 : *
530 : * Return value: the newly created #cairo_pattern_t if successful, or
531 : * an error pattern in case of no memory. The caller owns the
532 : * returned object and should call cairo_pattern_destroy() when
533 : * finished with it.
534 : *
535 : * This function will always return a valid pointer, but if an error
536 : * occurred the pattern status will be set to an error. To inspect
537 : * the status of a pattern use cairo_pattern_status().
538 : **/
539 : cairo_pattern_t *
540 0 : cairo_pattern_create_rgb (double red, double green, double blue)
541 : {
542 : cairo_color_t color;
543 :
544 0 : red = _cairo_restrict_value (red, 0.0, 1.0);
545 0 : green = _cairo_restrict_value (green, 0.0, 1.0);
546 0 : blue = _cairo_restrict_value (blue, 0.0, 1.0);
547 :
548 0 : _cairo_color_init_rgb (&color, red, green, blue);
549 :
550 : CAIRO_MUTEX_INITIALIZE ();
551 :
552 0 : return _cairo_pattern_create_solid (&color);
553 : }
554 : slim_hidden_def (cairo_pattern_create_rgb);
555 :
556 : /**
557 : * cairo_pattern_create_rgba:
558 : * @red: red component of the color
559 : * @green: green component of the color
560 : * @blue: blue component of the color
561 : * @alpha: alpha component of the color
562 : *
563 : * Creates a new #cairo_pattern_t corresponding to a translucent color.
564 : * The color components are floating point numbers in the range 0 to
565 : * 1. If the values passed in are outside that range, they will be
566 : * clamped.
567 : *
568 : * Return value: the newly created #cairo_pattern_t if successful, or
569 : * an error pattern in case of no memory. The caller owns the
570 : * returned object and should call cairo_pattern_destroy() when
571 : * finished with it.
572 : *
573 : * This function will always return a valid pointer, but if an error
574 : * occurred the pattern status will be set to an error. To inspect
575 : * the status of a pattern use cairo_pattern_status().
576 : **/
577 : cairo_pattern_t *
578 0 : cairo_pattern_create_rgba (double red, double green, double blue,
579 : double alpha)
580 : {
581 : cairo_color_t color;
582 :
583 0 : red = _cairo_restrict_value (red, 0.0, 1.0);
584 0 : green = _cairo_restrict_value (green, 0.0, 1.0);
585 0 : blue = _cairo_restrict_value (blue, 0.0, 1.0);
586 0 : alpha = _cairo_restrict_value (alpha, 0.0, 1.0);
587 :
588 0 : _cairo_color_init_rgba (&color, red, green, blue, alpha);
589 :
590 : CAIRO_MUTEX_INITIALIZE ();
591 :
592 0 : return _cairo_pattern_create_solid (&color);
593 : }
594 : slim_hidden_def (cairo_pattern_create_rgba);
595 :
596 : /**
597 : * cairo_pattern_create_for_surface:
598 : * @surface: the surface
599 : *
600 : * Create a new #cairo_pattern_t for the given surface.
601 : *
602 : * Return value: the newly created #cairo_pattern_t if successful, or
603 : * an error pattern in case of no memory. The caller owns the
604 : * returned object and should call cairo_pattern_destroy() when
605 : * finished with it.
606 : *
607 : * This function will always return a valid pointer, but if an error
608 : * occurred the pattern status will be set to an error. To inspect
609 : * the status of a pattern use cairo_pattern_status().
610 : **/
611 : cairo_pattern_t *
612 47 : cairo_pattern_create_for_surface (cairo_surface_t *surface)
613 : {
614 : cairo_surface_pattern_t *pattern;
615 :
616 47 : if (surface == NULL) {
617 0 : _cairo_error_throw (CAIRO_STATUS_NULL_POINTER);
618 0 : return (cairo_pattern_t*) &_cairo_pattern_nil_null_pointer;
619 : }
620 :
621 47 : if (surface->status)
622 0 : return _cairo_pattern_create_in_error (surface->status);
623 :
624 47 : pattern =
625 : _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SURFACE]);
626 47 : if (unlikely (pattern == NULL)) {
627 47 : pattern = malloc (sizeof (cairo_surface_pattern_t));
628 47 : if (unlikely (pattern == NULL)) {
629 0 : _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
630 0 : return (cairo_pattern_t *)&_cairo_pattern_nil.base;
631 : }
632 : }
633 :
634 : CAIRO_MUTEX_INITIALIZE ();
635 :
636 47 : _cairo_pattern_init_for_surface (pattern, surface);
637 47 : CAIRO_REFERENCE_COUNT_INIT (&pattern->base.ref_count, 1);
638 :
639 47 : return &pattern->base;
640 : }
641 : slim_hidden_def (cairo_pattern_create_for_surface);
642 :
643 : /**
644 : * cairo_pattern_create_linear:
645 : * @x0: x coordinate of the start point
646 : * @y0: y coordinate of the start point
647 : * @x1: x coordinate of the end point
648 : * @y1: y coordinate of the end point
649 : *
650 : * Create a new linear gradient #cairo_pattern_t along the line defined
651 : * by (x0, y0) and (x1, y1). Before using the gradient pattern, a
652 : * number of color stops should be defined using
653 : * cairo_pattern_add_color_stop_rgb() or
654 : * cairo_pattern_add_color_stop_rgba().
655 : *
656 : * Note: The coordinates here are in pattern space. For a new pattern,
657 : * pattern space is identical to user space, but the relationship
658 : * between the spaces can be changed with cairo_pattern_set_matrix().
659 : *
660 : * Return value: the newly created #cairo_pattern_t if successful, or
661 : * an error pattern in case of no memory. The caller owns the
662 : * returned object and should call cairo_pattern_destroy() when
663 : * finished with it.
664 : *
665 : * This function will always return a valid pointer, but if an error
666 : * occurred the pattern status will be set to an error. To inspect
667 : * the status of a pattern use cairo_pattern_status().
668 : **/
669 : cairo_pattern_t *
670 0 : cairo_pattern_create_linear (double x0, double y0, double x1, double y1)
671 : {
672 : cairo_linear_pattern_t *pattern;
673 :
674 0 : pattern =
675 : _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_LINEAR]);
676 0 : if (unlikely (pattern == NULL)) {
677 0 : pattern = malloc (sizeof (cairo_linear_pattern_t));
678 0 : if (unlikely (pattern == NULL)) {
679 0 : _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
680 0 : return (cairo_pattern_t *) &_cairo_pattern_nil.base;
681 : }
682 : }
683 :
684 : CAIRO_MUTEX_INITIALIZE ();
685 :
686 0 : _cairo_pattern_init_linear (pattern, x0, y0, x1, y1);
687 0 : CAIRO_REFERENCE_COUNT_INIT (&pattern->base.base.ref_count, 1);
688 :
689 0 : return &pattern->base.base;
690 : }
691 :
692 : /**
693 : * cairo_pattern_create_radial:
694 : * @cx0: x coordinate for the center of the start circle
695 : * @cy0: y coordinate for the center of the start circle
696 : * @radius0: radius of the start circle
697 : * @cx1: x coordinate for the center of the end circle
698 : * @cy1: y coordinate for the center of the end circle
699 : * @radius1: radius of the end circle
700 : *
701 : * Creates a new radial gradient #cairo_pattern_t between the two
702 : * circles defined by (cx0, cy0, radius0) and (cx1, cy1, radius1). Before using the
703 : * gradient pattern, a number of color stops should be defined using
704 : * cairo_pattern_add_color_stop_rgb() or
705 : * cairo_pattern_add_color_stop_rgba().
706 : *
707 : * Note: The coordinates here are in pattern space. For a new pattern,
708 : * pattern space is identical to user space, but the relationship
709 : * between the spaces can be changed with cairo_pattern_set_matrix().
710 : *
711 : * Return value: the newly created #cairo_pattern_t if successful, or
712 : * an error pattern in case of no memory. The caller owns the
713 : * returned object and should call cairo_pattern_destroy() when
714 : * finished with it.
715 : *
716 : * This function will always return a valid pointer, but if an error
717 : * occurred the pattern status will be set to an error. To inspect
718 : * the status of a pattern use cairo_pattern_status().
719 : **/
720 : cairo_pattern_t *
721 0 : cairo_pattern_create_radial (double cx0, double cy0, double radius0,
722 : double cx1, double cy1, double radius1)
723 : {
724 : cairo_radial_pattern_t *pattern;
725 :
726 0 : pattern =
727 : _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_RADIAL]);
728 0 : if (unlikely (pattern == NULL)) {
729 0 : pattern = malloc (sizeof (cairo_radial_pattern_t));
730 0 : if (unlikely (pattern == NULL)) {
731 0 : _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
732 0 : return (cairo_pattern_t *) &_cairo_pattern_nil.base;
733 : }
734 : }
735 :
736 : CAIRO_MUTEX_INITIALIZE ();
737 :
738 0 : _cairo_pattern_init_radial (pattern, cx0, cy0, radius0, cx1, cy1, radius1);
739 0 : CAIRO_REFERENCE_COUNT_INIT (&pattern->base.base.ref_count, 1);
740 :
741 0 : return &pattern->base.base;
742 : }
743 :
744 : /**
745 : * cairo_pattern_reference:
746 : * @pattern: a #cairo_pattern_t
747 : *
748 : * Increases the reference count on @pattern by one. This prevents
749 : * @pattern from being destroyed until a matching call to
750 : * cairo_pattern_destroy() is made.
751 : *
752 : * The number of references to a #cairo_pattern_t can be get using
753 : * cairo_pattern_get_reference_count().
754 : *
755 : * Return value: the referenced #cairo_pattern_t.
756 : **/
757 : cairo_pattern_t *
758 75 : cairo_pattern_reference (cairo_pattern_t *pattern)
759 : {
760 150 : if (pattern == NULL ||
761 75 : CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count))
762 28 : return pattern;
763 :
764 47 : assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&pattern->ref_count));
765 :
766 47 : _cairo_reference_count_inc (&pattern->ref_count);
767 :
768 47 : return pattern;
769 : }
770 : slim_hidden_def (cairo_pattern_reference);
771 :
772 : /**
773 : * cairo_pattern_get_type:
774 : * @pattern: a #cairo_pattern_t
775 : *
776 : * This function returns the type a pattern.
777 : * See #cairo_pattern_type_t for available types.
778 : *
779 : * Return value: The type of @pattern.
780 : *
781 : * Since: 1.2
782 : **/
783 : cairo_pattern_type_t
784 0 : cairo_pattern_get_type (cairo_pattern_t *pattern)
785 : {
786 0 : return pattern->type;
787 : }
788 :
789 : /**
790 : * cairo_pattern_status:
791 : * @pattern: a #cairo_pattern_t
792 : *
793 : * Checks whether an error has previously occurred for this
794 : * pattern.
795 : *
796 : * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_STATUS_NO_MEMORY, or
797 : * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH.
798 : **/
799 : cairo_status_t
800 0 : cairo_pattern_status (cairo_pattern_t *pattern)
801 : {
802 0 : return pattern->status;
803 : }
804 :
805 : /**
806 : * cairo_pattern_destroy:
807 : * @pattern: a #cairo_pattern_t
808 : *
809 : * Decreases the reference count on @pattern by one. If the result is
810 : * zero, then @pattern and all associated resources are freed. See
811 : * cairo_pattern_reference().
812 : **/
813 : void
814 186 : cairo_pattern_destroy (cairo_pattern_t *pattern)
815 : {
816 : cairo_pattern_type_t type;
817 :
818 372 : if (pattern == NULL ||
819 186 : CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count))
820 92 : return;
821 :
822 94 : assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&pattern->ref_count));
823 :
824 94 : if (! _cairo_reference_count_dec_and_test (&pattern->ref_count))
825 47 : return;
826 :
827 47 : type = pattern->type;
828 47 : _cairo_pattern_fini (pattern);
829 :
830 : /* maintain a small cache of freed patterns */
831 47 : _freed_pool_put (&freed_pattern_pool[type], pattern);
832 : }
833 : slim_hidden_def (cairo_pattern_destroy);
834 :
835 : /**
836 : * cairo_pattern_get_reference_count:
837 : * @pattern: a #cairo_pattern_t
838 : *
839 : * Returns the current reference count of @pattern.
840 : *
841 : * Return value: the current reference count of @pattern. If the
842 : * object is a nil object, 0 will be returned.
843 : *
844 : * Since: 1.4
845 : **/
846 : unsigned int
847 0 : cairo_pattern_get_reference_count (cairo_pattern_t *pattern)
848 : {
849 0 : if (pattern == NULL ||
850 0 : CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count))
851 0 : return 0;
852 :
853 0 : return CAIRO_REFERENCE_COUNT_GET_VALUE (&pattern->ref_count);
854 : }
855 :
856 : /**
857 : * cairo_pattern_get_user_data:
858 : * @pattern: a #cairo_pattern_t
859 : * @key: the address of the #cairo_user_data_key_t the user data was
860 : * attached to
861 : *
862 : * Return user data previously attached to @pattern using the
863 : * specified key. If no user data has been attached with the given
864 : * key this function returns %NULL.
865 : *
866 : * Return value: the user data previously attached or %NULL.
867 : *
868 : * Since: 1.4
869 : **/
870 : void *
871 0 : cairo_pattern_get_user_data (cairo_pattern_t *pattern,
872 : const cairo_user_data_key_t *key)
873 : {
874 0 : return _cairo_user_data_array_get_data (&pattern->user_data,
875 : key);
876 : }
877 :
878 : /**
879 : * cairo_pattern_set_user_data:
880 : * @pattern: a #cairo_pattern_t
881 : * @key: the address of a #cairo_user_data_key_t to attach the user data to
882 : * @user_data: the user data to attach to the #cairo_pattern_t
883 : * @destroy: a #cairo_destroy_func_t which will be called when the
884 : * #cairo_t is destroyed or when new user data is attached using the
885 : * same key.
886 : *
887 : * Attach user data to @pattern. To remove user data from a surface,
888 : * call this function with the key that was used to set it and %NULL
889 : * for @data.
890 : *
891 : * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
892 : * slot could not be allocated for the user data.
893 : *
894 : * Since: 1.4
895 : **/
896 : cairo_status_t
897 0 : cairo_pattern_set_user_data (cairo_pattern_t *pattern,
898 : const cairo_user_data_key_t *key,
899 : void *user_data,
900 : cairo_destroy_func_t destroy)
901 : {
902 0 : if (CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count))
903 0 : return pattern->status;
904 :
905 0 : return _cairo_user_data_array_set_data (&pattern->user_data,
906 : key, user_data, destroy);
907 : }
908 :
909 : /* make room for at least one more color stop */
910 : static cairo_status_t
911 0 : _cairo_pattern_gradient_grow (cairo_gradient_pattern_t *pattern)
912 : {
913 : cairo_gradient_stop_t *new_stops;
914 0 : int old_size = pattern->stops_size;
915 0 : int embedded_size = ARRAY_LENGTH (pattern->stops_embedded);
916 0 : int new_size = 2 * MAX (old_size, 4);
917 :
918 : /* we have a local buffer at pattern->stops_embedded. try to fulfill the request
919 : * from there. */
920 0 : if (old_size < embedded_size) {
921 0 : pattern->stops = pattern->stops_embedded;
922 0 : pattern->stops_size = embedded_size;
923 0 : return CAIRO_STATUS_SUCCESS;
924 : }
925 :
926 : if (CAIRO_INJECT_FAULT ())
927 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
928 :
929 0 : assert (pattern->n_stops <= pattern->stops_size);
930 :
931 0 : if (pattern->stops == pattern->stops_embedded) {
932 0 : new_stops = _cairo_malloc_ab (new_size, sizeof (cairo_gradient_stop_t));
933 0 : if (new_stops)
934 0 : memcpy (new_stops, pattern->stops, old_size * sizeof (cairo_gradient_stop_t));
935 : } else {
936 0 : new_stops = _cairo_realloc_ab (pattern->stops,
937 : new_size,
938 : sizeof (cairo_gradient_stop_t));
939 : }
940 :
941 0 : if (unlikely (new_stops == NULL))
942 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
943 :
944 0 : pattern->stops = new_stops;
945 0 : pattern->stops_size = new_size;
946 :
947 0 : return CAIRO_STATUS_SUCCESS;
948 : }
949 :
950 : static void
951 0 : _cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern,
952 : double offset,
953 : double red,
954 : double green,
955 : double blue,
956 : double alpha)
957 : {
958 : cairo_gradient_stop_t *stops;
959 : unsigned int i;
960 :
961 0 : if (pattern->n_stops >= pattern->stops_size) {
962 0 : cairo_status_t status = _cairo_pattern_gradient_grow (pattern);
963 0 : if (unlikely (status)) {
964 0 : status = _cairo_pattern_set_error (&pattern->base, status);
965 0 : return;
966 : }
967 : }
968 :
969 0 : stops = pattern->stops;
970 :
971 0 : for (i = 0; i < pattern->n_stops; i++)
972 : {
973 0 : if (offset < stops[i].offset)
974 : {
975 0 : memmove (&stops[i + 1], &stops[i],
976 0 : sizeof (cairo_gradient_stop_t) * (pattern->n_stops - i));
977 :
978 0 : break;
979 : }
980 : }
981 :
982 0 : stops[i].offset = offset;
983 :
984 0 : stops[i].color.red = red;
985 0 : stops[i].color.green = green;
986 0 : stops[i].color.blue = blue;
987 0 : stops[i].color.alpha = alpha;
988 :
989 0 : stops[i].color.red_short = _cairo_color_double_to_short (red);
990 0 : stops[i].color.green_short = _cairo_color_double_to_short (green);
991 0 : stops[i].color.blue_short = _cairo_color_double_to_short (blue);
992 0 : stops[i].color.alpha_short = _cairo_color_double_to_short (alpha);
993 :
994 0 : pattern->n_stops++;
995 : }
996 :
997 : /**
998 : * cairo_pattern_add_color_stop_rgb:
999 : * @pattern: a #cairo_pattern_t
1000 : * @offset: an offset in the range [0.0 .. 1.0]
1001 : * @red: red component of color
1002 : * @green: green component of color
1003 : * @blue: blue component of color
1004 : *
1005 : * Adds an opaque color stop to a gradient pattern. The offset
1006 : * specifies the location along the gradient's control vector. For
1007 : * example, a linear gradient's control vector is from (x0,y0) to
1008 : * (x1,y1) while a radial gradient's control vector is from any point
1009 : * on the start circle to the corresponding point on the end circle.
1010 : *
1011 : * The color is specified in the same way as in cairo_set_source_rgb().
1012 : *
1013 : * If two (or more) stops are specified with identical offset values,
1014 : * they will be sorted according to the order in which the stops are
1015 : * added, (stops added earlier will compare less than stops added
1016 : * later). This can be useful for reliably making sharp color
1017 : * transitions instead of the typical blend.
1018 : *
1019 : *
1020 : * Note: If the pattern is not a gradient pattern, (eg. a linear or
1021 : * radial pattern), then the pattern will be put into an error status
1022 : * with a status of %CAIRO_STATUS_PATTERN_TYPE_MISMATCH.
1023 : **/
1024 : void
1025 0 : cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern,
1026 : double offset,
1027 : double red,
1028 : double green,
1029 : double blue)
1030 : {
1031 0 : if (pattern->status)
1032 0 : return;
1033 :
1034 0 : if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR &&
1035 0 : pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
1036 : {
1037 0 : _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
1038 0 : return;
1039 : }
1040 :
1041 0 : offset = _cairo_restrict_value (offset, 0.0, 1.0);
1042 0 : red = _cairo_restrict_value (red, 0.0, 1.0);
1043 0 : green = _cairo_restrict_value (green, 0.0, 1.0);
1044 0 : blue = _cairo_restrict_value (blue, 0.0, 1.0);
1045 :
1046 0 : _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern,
1047 : offset, red, green, blue, 1.0);
1048 : }
1049 :
1050 : /**
1051 : * cairo_pattern_add_color_stop_rgba:
1052 : * @pattern: a #cairo_pattern_t
1053 : * @offset: an offset in the range [0.0 .. 1.0]
1054 : * @red: red component of color
1055 : * @green: green component of color
1056 : * @blue: blue component of color
1057 : * @alpha: alpha component of color
1058 : *
1059 : * Adds a translucent color stop to a gradient pattern. The offset
1060 : * specifies the location along the gradient's control vector. For
1061 : * example, a linear gradient's control vector is from (x0,y0) to
1062 : * (x1,y1) while a radial gradient's control vector is from any point
1063 : * on the start circle to the corresponding point on the end circle.
1064 : *
1065 : * The color is specified in the same way as in cairo_set_source_rgba().
1066 : *
1067 : * If two (or more) stops are specified with identical offset values,
1068 : * they will be sorted according to the order in which the stops are
1069 : * added, (stops added earlier will compare less than stops added
1070 : * later). This can be useful for reliably making sharp color
1071 : * transitions instead of the typical blend.
1072 : *
1073 : * Note: If the pattern is not a gradient pattern, (eg. a linear or
1074 : * radial pattern), then the pattern will be put into an error status
1075 : * with a status of %CAIRO_STATUS_PATTERN_TYPE_MISMATCH.
1076 : */
1077 : void
1078 0 : cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern,
1079 : double offset,
1080 : double red,
1081 : double green,
1082 : double blue,
1083 : double alpha)
1084 : {
1085 0 : if (pattern->status)
1086 0 : return;
1087 :
1088 0 : if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR &&
1089 0 : pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
1090 : {
1091 0 : _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
1092 0 : return;
1093 : }
1094 :
1095 0 : offset = _cairo_restrict_value (offset, 0.0, 1.0);
1096 0 : red = _cairo_restrict_value (red, 0.0, 1.0);
1097 0 : green = _cairo_restrict_value (green, 0.0, 1.0);
1098 0 : blue = _cairo_restrict_value (blue, 0.0, 1.0);
1099 0 : alpha = _cairo_restrict_value (alpha, 0.0, 1.0);
1100 :
1101 0 : _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern,
1102 : offset, red, green, blue, alpha);
1103 : }
1104 :
1105 : /**
1106 : * cairo_pattern_set_matrix:
1107 : * @pattern: a #cairo_pattern_t
1108 : * @matrix: a #cairo_matrix_t
1109 : *
1110 : * Sets the pattern's transformation matrix to @matrix. This matrix is
1111 : * a transformation from user space to pattern space.
1112 : *
1113 : * When a pattern is first created it always has the identity matrix
1114 : * for its transformation matrix, which means that pattern space is
1115 : * initially identical to user space.
1116 : *
1117 : * Important: Please note that the direction of this transformation
1118 : * matrix is from user space to pattern space. This means that if you
1119 : * imagine the flow from a pattern to user space (and on to device
1120 : * space), then coordinates in that flow will be transformed by the
1121 : * inverse of the pattern matrix.
1122 : *
1123 : * For example, if you want to make a pattern appear twice as large as
1124 : * it does by default the correct code to use is:
1125 : *
1126 : * <informalexample><programlisting>
1127 : * cairo_matrix_init_scale (&matrix, 0.5, 0.5);
1128 : * cairo_pattern_set_matrix (pattern, &matrix);
1129 : * </programlisting></informalexample>
1130 : *
1131 : * Meanwhile, using values of 2.0 rather than 0.5 in the code above
1132 : * would cause the pattern to appear at half of its default size.
1133 : *
1134 : * Also, please note the discussion of the user-space locking
1135 : * semantics of cairo_set_source().
1136 : **/
1137 : void
1138 28 : cairo_pattern_set_matrix (cairo_pattern_t *pattern,
1139 : const cairo_matrix_t *matrix)
1140 : {
1141 : cairo_matrix_t inverse;
1142 : cairo_status_t status;
1143 :
1144 28 : if (pattern->status)
1145 0 : return;
1146 :
1147 28 : if (memcmp (&pattern->matrix, matrix, sizeof (cairo_matrix_t)) == 0)
1148 0 : return;
1149 :
1150 28 : pattern->matrix = *matrix;
1151 :
1152 28 : inverse = *matrix;
1153 28 : status = cairo_matrix_invert (&inverse);
1154 28 : if (unlikely (status))
1155 0 : status = _cairo_pattern_set_error (pattern, status);
1156 : }
1157 : slim_hidden_def (cairo_pattern_set_matrix);
1158 :
1159 : /**
1160 : * cairo_pattern_get_matrix:
1161 : * @pattern: a #cairo_pattern_t
1162 : * @matrix: return value for the matrix
1163 : *
1164 : * Stores the pattern's transformation matrix into @matrix.
1165 : **/
1166 : void
1167 0 : cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix)
1168 : {
1169 0 : *matrix = pattern->matrix;
1170 0 : }
1171 :
1172 : /**
1173 : * cairo_pattern_set_filter:
1174 : * @pattern: a #cairo_pattern_t
1175 : * @filter: a #cairo_filter_t describing the filter to use for resizing
1176 : * the pattern
1177 : *
1178 : * Sets the filter to be used for resizing when using this pattern.
1179 : * See #cairo_filter_t for details on each filter.
1180 : *
1181 : * * Note that you might want to control filtering even when you do not
1182 : * have an explicit #cairo_pattern_t object, (for example when using
1183 : * cairo_set_source_surface()). In these cases, it is convenient to
1184 : * use cairo_get_source() to get access to the pattern that cairo
1185 : * creates implicitly. For example:
1186 : *
1187 : * <informalexample><programlisting>
1188 : * cairo_set_source_surface (cr, image, x, y);
1189 : * cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST);
1190 : * </programlisting></informalexample>
1191 : **/
1192 : void
1193 0 : cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter)
1194 : {
1195 0 : if (pattern->status)
1196 0 : return;
1197 :
1198 0 : pattern->filter = filter;
1199 : }
1200 :
1201 : /**
1202 : * cairo_pattern_get_filter:
1203 : * @pattern: a #cairo_pattern_t
1204 : *
1205 : * Gets the current filter for a pattern. See #cairo_filter_t
1206 : * for details on each filter.
1207 : *
1208 : * Return value: the current filter used for resizing the pattern.
1209 : **/
1210 : cairo_filter_t
1211 0 : cairo_pattern_get_filter (cairo_pattern_t *pattern)
1212 : {
1213 0 : return pattern->filter;
1214 : }
1215 :
1216 : /**
1217 : * cairo_pattern_set_extend:
1218 : * @pattern: a #cairo_pattern_t
1219 : * @extend: a #cairo_extend_t describing how the area outside of the
1220 : * pattern will be drawn
1221 : *
1222 : * Sets the mode to be used for drawing outside the area of a pattern.
1223 : * See #cairo_extend_t for details on the semantics of each extend
1224 : * strategy.
1225 : *
1226 : * The default extend mode is %CAIRO_EXTEND_NONE for surface patterns
1227 : * and %CAIRO_EXTEND_PAD for gradient patterns.
1228 : **/
1229 : void
1230 0 : cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend)
1231 : {
1232 0 : if (pattern->status)
1233 0 : return;
1234 :
1235 0 : pattern->extend = extend;
1236 : }
1237 :
1238 : /**
1239 : * cairo_pattern_get_extend:
1240 : * @pattern: a #cairo_pattern_t
1241 : *
1242 : * Gets the current extend mode for a pattern. See #cairo_extend_t
1243 : * for details on the semantics of each extend strategy.
1244 : *
1245 : * Return value: the current extend strategy used for drawing the
1246 : * pattern.
1247 : **/
1248 : cairo_extend_t
1249 0 : cairo_pattern_get_extend (cairo_pattern_t *pattern)
1250 : {
1251 0 : return pattern->extend;
1252 : }
1253 : slim_hidden_def (cairo_pattern_get_extend);
1254 :
1255 : void
1256 10 : _cairo_pattern_transform (cairo_pattern_t *pattern,
1257 : const cairo_matrix_t *ctm_inverse)
1258 : {
1259 10 : if (pattern->status)
1260 0 : return;
1261 :
1262 10 : cairo_matrix_multiply (&pattern->matrix, ctm_inverse, &pattern->matrix);
1263 : }
1264 :
1265 : static void
1266 0 : _cairo_linear_pattern_classify (cairo_linear_pattern_t *pattern,
1267 : double offset_x,
1268 : double offset_y,
1269 : int width,
1270 : int height,
1271 : cairo_bool_t *is_horizontal,
1272 : cairo_bool_t *is_vertical)
1273 : {
1274 : cairo_point_double_t point0, point1;
1275 : double a, b, c, d, tx, ty;
1276 : double scale, start, dx, dy;
1277 : cairo_fixed_t factors[3];
1278 : int i;
1279 :
1280 : /* To classify a pattern as horizontal or vertical, we first
1281 : * compute the (fixed point) factors at the corners of the
1282 : * pattern. We actually only need 3/4 corners, so we skip the
1283 : * fourth.
1284 : */
1285 0 : point0.x = _cairo_fixed_to_double (pattern->p1.x);
1286 0 : point0.y = _cairo_fixed_to_double (pattern->p1.y);
1287 0 : point1.x = _cairo_fixed_to_double (pattern->p2.x);
1288 0 : point1.y = _cairo_fixed_to_double (pattern->p2.y);
1289 :
1290 0 : _cairo_matrix_get_affine (&pattern->base.base.matrix,
1291 : &a, &b, &c, &d, &tx, &ty);
1292 :
1293 0 : dx = point1.x - point0.x;
1294 0 : dy = point1.y - point0.y;
1295 0 : scale = dx * dx + dy * dy;
1296 0 : scale = (scale) ? 1.0 / scale : 1.0;
1297 :
1298 0 : start = dx * point0.x + dy * point0.y;
1299 :
1300 0 : for (i = 0; i < 3; i++) {
1301 0 : double qx_device = (i % 2) * (width - 1) + offset_x;
1302 0 : double qy_device = (i / 2) * (height - 1) + offset_y;
1303 :
1304 : /* transform fragment into pattern space */
1305 0 : double qx = a * qx_device + c * qy_device + tx;
1306 0 : double qy = b * qx_device + d * qy_device + ty;
1307 :
1308 0 : factors[i] = _cairo_fixed_from_double (((dx * qx + dy * qy) - start) * scale);
1309 : }
1310 :
1311 : /* We consider a pattern to be vertical if the fixed point factor
1312 : * at the two upper corners is the same. We could accept a small
1313 : * change, but determining what change is acceptable would require
1314 : * sorting the stops in the pattern and looking at the differences.
1315 : *
1316 : * Horizontal works the same way with the two left corners.
1317 : */
1318 :
1319 0 : *is_vertical = factors[1] == factors[0];
1320 0 : *is_horizontal = factors[2] == factors[0];
1321 0 : }
1322 :
1323 : static cairo_int_status_t
1324 0 : _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pattern,
1325 : cairo_surface_t *dst,
1326 : int x,
1327 : int y,
1328 : unsigned int width,
1329 : unsigned int height,
1330 : cairo_surface_t **out,
1331 : cairo_surface_attributes_t *attr)
1332 : {
1333 : cairo_image_surface_t *image;
1334 : pixman_image_t *pixman_image;
1335 : pixman_transform_t pixman_transform;
1336 : cairo_status_t status;
1337 0 : cairo_bool_t repeat = FALSE;
1338 0 : cairo_bool_t opaque = TRUE;
1339 :
1340 : pixman_gradient_stop_t pixman_stops_static[2];
1341 0 : pixman_gradient_stop_t *pixman_stops = pixman_stops_static;
1342 : unsigned int i;
1343 : int clone_offset_x, clone_offset_y;
1344 0 : cairo_matrix_t matrix = pattern->base.matrix;
1345 :
1346 : if (CAIRO_INJECT_FAULT ())
1347 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1348 :
1349 0 : if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) {
1350 0 : pixman_stops = _cairo_malloc_ab (pattern->n_stops,
1351 : sizeof(pixman_gradient_stop_t));
1352 0 : if (unlikely (pixman_stops == NULL))
1353 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1354 : }
1355 :
1356 0 : for (i = 0; i < pattern->n_stops; i++) {
1357 0 : pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset);
1358 0 : pixman_stops[i].color.red = pattern->stops[i].color.red_short;
1359 0 : pixman_stops[i].color.green = pattern->stops[i].color.green_short;
1360 0 : pixman_stops[i].color.blue = pattern->stops[i].color.blue_short;
1361 0 : pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short;
1362 0 : if (! CAIRO_ALPHA_SHORT_IS_OPAQUE (pixman_stops[i].color.alpha))
1363 0 : opaque = FALSE;
1364 : }
1365 :
1366 0 : if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR)
1367 : {
1368 0 : cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern;
1369 : pixman_point_fixed_t p1, p2;
1370 : cairo_fixed_t xdim, ydim;
1371 :
1372 0 : xdim = linear->p2.x - linear->p1.x;
1373 0 : ydim = linear->p2.y - linear->p1.y;
1374 :
1375 : /*
1376 : * Transform the matrix to avoid overflow when converting between
1377 : * cairo_fixed_t and pixman_fixed_t (without incurring performance
1378 : * loss when the transformation is unnecessary).
1379 : *
1380 : * XXX: Consider converting out-of-range co-ordinates and transforms.
1381 : * Having a function to compute the required transformation to
1382 : * "normalize" a given bounding box would be generally useful -
1383 : * cf linear patterns, gradient patterns, surface patterns...
1384 : */
1385 : #define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
1386 0 : if (_cairo_fixed_integer_ceil (xdim) > PIXMAN_MAX_INT ||
1387 0 : _cairo_fixed_integer_ceil (ydim) > PIXMAN_MAX_INT)
1388 0 : {
1389 : double sf;
1390 :
1391 0 : if (xdim > ydim)
1392 0 : sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (xdim);
1393 : else
1394 0 : sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (ydim);
1395 :
1396 0 : p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.x) * sf);
1397 0 : p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.y) * sf);
1398 0 : p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.x) * sf);
1399 0 : p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.y) * sf);
1400 :
1401 0 : cairo_matrix_scale (&matrix, sf, sf);
1402 : }
1403 : else
1404 : {
1405 0 : p1.x = _cairo_fixed_to_16_16 (linear->p1.x);
1406 0 : p1.y = _cairo_fixed_to_16_16 (linear->p1.y);
1407 0 : p2.x = _cairo_fixed_to_16_16 (linear->p2.x);
1408 0 : p2.y = _cairo_fixed_to_16_16 (linear->p2.y);
1409 : }
1410 :
1411 0 : pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
1412 : pixman_stops,
1413 0 : pattern->n_stops);
1414 : }
1415 : else
1416 : {
1417 0 : cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
1418 : pixman_point_fixed_t c1, c2;
1419 : pixman_fixed_t r1, r2;
1420 :
1421 0 : c1.x = _cairo_fixed_to_16_16 (radial->c1.x);
1422 0 : c1.y = _cairo_fixed_to_16_16 (radial->c1.y);
1423 0 : r1 = _cairo_fixed_to_16_16 (radial->r1);
1424 :
1425 0 : c2.x = _cairo_fixed_to_16_16 (radial->c2.x);
1426 0 : c2.y = _cairo_fixed_to_16_16 (radial->c2.y);
1427 0 : r2 = _cairo_fixed_to_16_16 (radial->r2);
1428 :
1429 0 : pixman_image = pixman_image_create_radial_gradient (&c1, &c2,
1430 : r1, r2,
1431 : pixman_stops,
1432 0 : pattern->n_stops);
1433 : }
1434 :
1435 0 : if (pixman_stops != pixman_stops_static)
1436 0 : free (pixman_stops);
1437 :
1438 0 : if (unlikely (pixman_image == NULL))
1439 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1440 :
1441 0 : if (_cairo_surface_is_image (dst))
1442 : {
1443 0 : image = (cairo_image_surface_t *)
1444 0 : _cairo_image_surface_create_for_pixman_image (pixman_image,
1445 : PIXMAN_a8r8g8b8);
1446 0 : if (image->base.status)
1447 : {
1448 0 : pixman_image_unref (pixman_image);
1449 0 : return image->base.status;
1450 : }
1451 :
1452 0 : attr->x_offset = attr->y_offset = 0;
1453 0 : attr->matrix = matrix;
1454 0 : attr->extend = pattern->base.extend;
1455 0 : attr->filter = CAIRO_FILTER_NEAREST;
1456 0 : attr->has_component_alpha = pattern->base.has_component_alpha;
1457 :
1458 0 : *out = &image->base;
1459 :
1460 0 : return CAIRO_STATUS_SUCCESS;
1461 : }
1462 :
1463 0 : if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
1464 : cairo_bool_t is_horizontal;
1465 : cairo_bool_t is_vertical;
1466 :
1467 0 : _cairo_linear_pattern_classify ((cairo_linear_pattern_t *)pattern,
1468 : x, y, width, height,
1469 : &is_horizontal, &is_vertical);
1470 0 : if (is_horizontal) {
1471 0 : height = 1;
1472 0 : repeat = TRUE;
1473 : }
1474 : /* width-1 repeating patterns are quite slow with scan-line based
1475 : * compositing code, so we use a wider strip and spend some extra
1476 : * expense in computing the gradient. It's possible that for narrow
1477 : * gradients we'd be better off using a 2 or 4 pixel strip; the
1478 : * wider the gradient, the more it's worth spending extra time
1479 : * computing a sample.
1480 : */
1481 0 : if (is_vertical && width > 8) {
1482 0 : width = 8;
1483 0 : repeat = TRUE;
1484 : }
1485 : }
1486 :
1487 0 : if (! pixman_image_set_filter (pixman_image, PIXMAN_FILTER_BILINEAR,
1488 : NULL, 0))
1489 : {
1490 0 : pixman_image_unref (pixman_image);
1491 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1492 : }
1493 :
1494 0 : image = (cairo_image_surface_t *)
1495 0 : cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
1496 0 : if (image->base.status) {
1497 0 : pixman_image_unref (pixman_image);
1498 0 : return image->base.status;
1499 : }
1500 :
1501 0 : _cairo_matrix_to_pixman_matrix (&matrix, &pixman_transform,
1502 : width/2., height/2.);
1503 0 : if (!pixman_image_set_transform (pixman_image, &pixman_transform)) {
1504 0 : cairo_surface_destroy (&image->base);
1505 0 : pixman_image_unref (pixman_image);
1506 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1507 : }
1508 :
1509 0 : switch (pattern->base.extend) {
1510 : case CAIRO_EXTEND_NONE:
1511 0 : pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_NONE);
1512 0 : break;
1513 : case CAIRO_EXTEND_REPEAT:
1514 0 : pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_NORMAL);
1515 0 : break;
1516 : case CAIRO_EXTEND_REFLECT:
1517 0 : pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_REFLECT);
1518 0 : break;
1519 : case CAIRO_EXTEND_PAD:
1520 0 : pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_PAD);
1521 0 : break;
1522 : }
1523 :
1524 0 : pixman_image_composite32 (PIXMAN_OP_SRC,
1525 : pixman_image,
1526 : NULL,
1527 : image->pixman_image,
1528 : x, y,
1529 : 0, 0,
1530 : 0, 0,
1531 : width, height);
1532 :
1533 0 : pixman_image_unref (pixman_image);
1534 :
1535 : _cairo_debug_check_image_surface_is_defined (&image->base);
1536 :
1537 0 : status = _cairo_surface_clone_similar (dst, &image->base,
1538 : 0, 0, width, height,
1539 : &clone_offset_x,
1540 : &clone_offset_y,
1541 : out);
1542 :
1543 0 : cairo_surface_destroy (&image->base);
1544 :
1545 0 : attr->x_offset = -x;
1546 0 : attr->y_offset = -y;
1547 0 : cairo_matrix_init_identity (&attr->matrix);
1548 0 : attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE;
1549 0 : attr->filter = CAIRO_FILTER_NEAREST;
1550 0 : attr->has_component_alpha = pattern->base.has_component_alpha;
1551 :
1552 0 : return status;
1553 : }
1554 :
1555 : /* We maintain a small cache here, because we don't want to constantly
1556 : * recreate surfaces for simple solid colors. */
1557 : #define MAX_SURFACE_CACHE_SIZE 16
1558 : static struct {
1559 : struct _cairo_pattern_solid_surface_cache{
1560 : cairo_color_t color;
1561 : cairo_surface_t *surface;
1562 : } cache[MAX_SURFACE_CACHE_SIZE];
1563 : int size;
1564 : } solid_surface_cache;
1565 :
1566 : static cairo_bool_t
1567 0 : _cairo_pattern_solid_surface_matches (
1568 : const struct _cairo_pattern_solid_surface_cache *cache,
1569 : const cairo_solid_pattern_t *pattern,
1570 : cairo_surface_t *dst)
1571 : {
1572 0 : if (cairo_surface_get_content (cache->surface) != _cairo_color_get_content (&pattern->color))
1573 0 : return FALSE;
1574 :
1575 0 : if (CAIRO_REFERENCE_COUNT_GET_VALUE (&cache->surface->ref_count) != 1)
1576 0 : return FALSE;
1577 :
1578 0 : if (! _cairo_surface_is_similar (cache->surface, dst))
1579 0 : return FALSE;
1580 :
1581 0 : return TRUE;
1582 : }
1583 :
1584 : static cairo_bool_t
1585 0 : _cairo_pattern_solid_surface_matches_color (
1586 : const struct _cairo_pattern_solid_surface_cache *cache,
1587 : const cairo_solid_pattern_t *pattern,
1588 : cairo_surface_t *dst)
1589 : {
1590 0 : if (! _cairo_color_equal (&cache->color, &pattern->color))
1591 0 : return FALSE;
1592 :
1593 0 : return _cairo_pattern_solid_surface_matches (cache, pattern, dst);
1594 : }
1595 :
1596 : static cairo_int_status_t
1597 0 : _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *pattern,
1598 : cairo_surface_t *dst,
1599 : int x,
1600 : int y,
1601 : unsigned int width,
1602 : unsigned int height,
1603 : cairo_surface_t **out,
1604 : cairo_surface_attributes_t *attribs)
1605 : {
1606 : static int i;
1607 :
1608 0 : cairo_surface_t *surface, *to_destroy = NULL;
1609 : cairo_status_t status;
1610 :
1611 : CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
1612 :
1613 : /* Check cache first */
1614 0 : if (i < solid_surface_cache.size &&
1615 0 : _cairo_pattern_solid_surface_matches_color (&solid_surface_cache.cache[i],
1616 : pattern,
1617 : dst))
1618 : {
1619 0 : goto DONE;
1620 : }
1621 :
1622 0 : for (i = 0 ; i < solid_surface_cache.size; i++) {
1623 0 : if (_cairo_pattern_solid_surface_matches_color (&solid_surface_cache.cache[i],
1624 : pattern,
1625 : dst))
1626 : {
1627 0 : goto DONE;
1628 : }
1629 : }
1630 :
1631 : /* Choose a surface to repaint/evict */
1632 0 : surface = NULL;
1633 0 : if (solid_surface_cache.size == MAX_SURFACE_CACHE_SIZE) {
1634 0 : i = rand () % MAX_SURFACE_CACHE_SIZE;
1635 0 : surface = solid_surface_cache.cache[i].surface;
1636 :
1637 0 : if (_cairo_pattern_solid_surface_matches (&solid_surface_cache.cache[i],
1638 : pattern,
1639 : dst))
1640 : {
1641 : /* Reuse the surface instead of evicting */
1642 0 : status = _cairo_surface_repaint_solid_pattern_surface (dst, surface, pattern);
1643 0 : if (unlikely (status))
1644 0 : goto EVICT;
1645 :
1646 0 : cairo_surface_reference (surface);
1647 : }
1648 : else
1649 : {
1650 : EVICT:
1651 0 : surface = NULL;
1652 : }
1653 : }
1654 :
1655 0 : if (surface == NULL) {
1656 : /* Not cached, need to create new */
1657 0 : surface = _cairo_surface_create_solid_pattern_surface (dst, pattern);
1658 0 : if (surface == NULL) {
1659 0 : status = CAIRO_INT_STATUS_UNSUPPORTED;
1660 0 : goto UNLOCK;
1661 : }
1662 0 : if (unlikely (surface->status)) {
1663 0 : status = surface->status;
1664 0 : goto UNLOCK;
1665 : }
1666 :
1667 0 : if (unlikely (! _cairo_surface_is_similar (surface, dst)))
1668 : {
1669 : /* In the rare event of a substitute surface being returned,
1670 : * don't cache the fallback.
1671 : */
1672 0 : *out = surface;
1673 0 : goto NOCACHE;
1674 : }
1675 : }
1676 :
1677 0 : if (i == solid_surface_cache.size)
1678 0 : solid_surface_cache.size++;
1679 :
1680 0 : to_destroy = solid_surface_cache.cache[i].surface;
1681 0 : solid_surface_cache.cache[i].surface = surface;
1682 0 : solid_surface_cache.cache[i].color = pattern->color;
1683 :
1684 : DONE:
1685 0 : *out = cairo_surface_reference (solid_surface_cache.cache[i].surface);
1686 :
1687 : NOCACHE:
1688 0 : attribs->x_offset = attribs->y_offset = 0;
1689 0 : cairo_matrix_init_identity (&attribs->matrix);
1690 0 : attribs->extend = CAIRO_EXTEND_REPEAT;
1691 0 : attribs->filter = CAIRO_FILTER_NEAREST;
1692 0 : attribs->has_component_alpha = pattern->base.has_component_alpha;
1693 :
1694 0 : status = CAIRO_STATUS_SUCCESS;
1695 :
1696 : UNLOCK:
1697 : CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
1698 :
1699 0 : if (to_destroy)
1700 0 : cairo_surface_destroy (to_destroy);
1701 :
1702 0 : return status;
1703 : }
1704 :
1705 : static void
1706 3 : _cairo_pattern_reset_solid_surface_cache (void)
1707 : {
1708 : CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
1709 :
1710 : /* remove surfaces starting from the end so that solid_surface_cache.cache
1711 : * is always in a consistent state when we release the mutex. */
1712 6 : while (solid_surface_cache.size) {
1713 : cairo_surface_t *surface;
1714 :
1715 0 : solid_surface_cache.size--;
1716 0 : surface = solid_surface_cache.cache[solid_surface_cache.size].surface;
1717 0 : solid_surface_cache.cache[solid_surface_cache.size].surface = NULL;
1718 :
1719 : /* release the lock to avoid the possibility of a recursive
1720 : * deadlock when the surface destroy closure gets called */
1721 : CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
1722 0 : cairo_surface_destroy (surface);
1723 : CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
1724 : }
1725 :
1726 : CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
1727 3 : }
1728 :
1729 : static void
1730 0 : _extents_to_linear_parameter (const cairo_linear_pattern_t *linear,
1731 : const cairo_rectangle_int_t *extents,
1732 : double t[2])
1733 : {
1734 : double t0, tdx, tdy;
1735 : double p1x, p1y, pdx, pdy, invsqnorm;
1736 :
1737 0 : p1x = _cairo_fixed_to_double (linear->p1.x);
1738 0 : p1y = _cairo_fixed_to_double (linear->p1.y);
1739 0 : pdx = _cairo_fixed_to_double (linear->p2.x) - p1x;
1740 0 : pdy = _cairo_fixed_to_double (linear->p2.y) - p1y;
1741 0 : invsqnorm = 1.0 / (pdx * pdx + pdy * pdy);
1742 0 : pdx *= invsqnorm;
1743 0 : pdy *= invsqnorm;
1744 :
1745 0 : t0 = (extents->x - p1x) * pdx + (extents->y - p1y) * pdy;
1746 0 : tdx = extents->width * pdx;
1747 0 : tdy = extents->height * pdy;
1748 :
1749 0 : t[0] = t[1] = t0;
1750 0 : if (tdx < 0)
1751 0 : t[0] += tdx;
1752 : else
1753 0 : t[1] += tdx;
1754 :
1755 0 : if (tdy < 0)
1756 0 : t[0] += tdy;
1757 : else
1758 0 : t[1] += tdy;
1759 0 : }
1760 :
1761 : static cairo_bool_t
1762 0 : _linear_pattern_is_degenerate (const cairo_linear_pattern_t *linear)
1763 : {
1764 0 : return linear->p1.x == linear->p2.x && linear->p1.y == linear->p2.y;
1765 : }
1766 :
1767 : static cairo_bool_t
1768 0 : _radial_pattern_is_degenerate (const cairo_radial_pattern_t *radial)
1769 : {
1770 0 : return radial->r1 == radial->r2 &&
1771 0 : (radial->r1 == 0 /* && radial->r2 == 0 */ ||
1772 0 : (radial->c1.x == radial->c2.x && radial->c1.y == radial->c2.y));
1773 : }
1774 :
1775 : static cairo_bool_t
1776 0 : _gradient_is_clear (const cairo_gradient_pattern_t *gradient,
1777 : const cairo_rectangle_int_t *extents)
1778 : {
1779 : unsigned int i;
1780 :
1781 0 : assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
1782 : gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
1783 :
1784 0 : if (gradient->n_stops == 0 ||
1785 0 : (gradient->base.extend == CAIRO_EXTEND_NONE &&
1786 0 : gradient->stops[0].offset == gradient->stops[gradient->n_stops - 1].offset))
1787 0 : return TRUE;
1788 :
1789 : /* Check if the extents intersect the drawn part of the pattern. */
1790 0 : if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
1791 0 : if (gradient->base.extend == CAIRO_EXTEND_NONE) {
1792 0 : cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
1793 : /* EXTEND_NONE degenerate linear gradients are clear */
1794 0 : if (_linear_pattern_is_degenerate (linear))
1795 0 : return TRUE;
1796 :
1797 0 : if (extents != NULL) {
1798 : double t[2];
1799 0 : _extents_to_linear_parameter (linear, extents, t);
1800 0 : if ((t[0] <= 0.0 && t[1] <= 0.0) || (t[0] >= 1.0 && t[1] >= 1.0))
1801 0 : return TRUE;
1802 : }
1803 : }
1804 : } else {
1805 0 : cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) gradient;
1806 : /* degenerate radial gradients are clear */
1807 0 : if (_radial_pattern_is_degenerate (radial) && FALSE)
1808 : return TRUE;
1809 : /* TODO: check actual intersection */
1810 : }
1811 :
1812 0 : for (i = 0; i < gradient->n_stops; i++)
1813 0 : if (! CAIRO_COLOR_IS_CLEAR (&gradient->stops[i].color))
1814 0 : return FALSE;
1815 :
1816 0 : return TRUE;
1817 : }
1818 :
1819 : /**
1820 : * _cairo_gradient_pattern_is_solid
1821 : *
1822 : * Convenience function to determine whether a gradient pattern is
1823 : * a solid color within the given extents. In this case the color
1824 : * argument is initialized to the color the pattern represents.
1825 : * This functions doesn't handle completely transparent gradients,
1826 : * thus it should be called only after _cairo_pattern_is_clear has
1827 : * returned FALSE.
1828 : *
1829 : * Return value: %TRUE if the pattern is a solid color.
1830 : **/
1831 : cairo_bool_t
1832 0 : _cairo_gradient_pattern_is_solid (const cairo_gradient_pattern_t *gradient,
1833 : const cairo_rectangle_int_t *extents,
1834 : cairo_color_t *color)
1835 : {
1836 : unsigned int i;
1837 :
1838 0 : assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
1839 : gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
1840 :
1841 : /* TODO: radial, degenerate linear */
1842 0 : if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
1843 0 : if (gradient->base.extend == CAIRO_EXTEND_NONE) {
1844 0 : cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
1845 : double t[2];
1846 :
1847 : /* We already know that the pattern is not clear, thus if some
1848 : * part of it is clear, the whole is not solid.
1849 : */
1850 :
1851 0 : if (extents == NULL)
1852 0 : return FALSE;
1853 :
1854 0 : _extents_to_linear_parameter (linear, extents, t);
1855 0 : if (t[0] < 0.0 || t[1] > 1.0)
1856 0 : return FALSE;
1857 : }
1858 : }
1859 :
1860 0 : for (i = 1; i < gradient->n_stops; i++)
1861 0 : if (! _cairo_color_stop_equal (&gradient->stops[0].color,
1862 0 : &gradient->stops[i].color))
1863 0 : return FALSE;
1864 :
1865 0 : _cairo_color_init_rgba (color,
1866 0 : gradient->stops[0].color.red,
1867 0 : gradient->stops[0].color.green,
1868 0 : gradient->stops[0].color.blue,
1869 0 : gradient->stops[0].color.alpha);
1870 :
1871 0 : return TRUE;
1872 : }
1873 :
1874 : /**
1875 : * _cairo_pattern_is_opaque_solid
1876 : *
1877 : * Convenience function to determine whether a pattern is an opaque
1878 : * (alpha==1.0) solid color pattern. This is done by testing whether
1879 : * the pattern's alpha value when converted to a byte is 255, so if a
1880 : * backend actually supported deep alpha channels this function might
1881 : * not do the right thing.
1882 : *
1883 : * Return value: %TRUE if the pattern is an opaque, solid color.
1884 : **/
1885 : cairo_bool_t
1886 0 : _cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern)
1887 : {
1888 : cairo_solid_pattern_t *solid;
1889 :
1890 0 : if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
1891 0 : return FALSE;
1892 :
1893 0 : solid = (cairo_solid_pattern_t *) pattern;
1894 :
1895 0 : return CAIRO_COLOR_IS_OPAQUE (&solid->color);
1896 : }
1897 :
1898 : static cairo_bool_t
1899 0 : _surface_is_opaque (const cairo_surface_pattern_t *pattern,
1900 : const cairo_rectangle_int_t *r)
1901 : {
1902 0 : if (pattern->surface->content & CAIRO_CONTENT_ALPHA)
1903 0 : return FALSE;
1904 :
1905 0 : if (pattern->base.extend != CAIRO_EXTEND_NONE)
1906 0 : return TRUE;
1907 :
1908 0 : if (r != NULL) {
1909 : cairo_rectangle_int_t extents;
1910 :
1911 0 : if (! _cairo_surface_get_extents (pattern->surface, &extents))
1912 0 : return TRUE;
1913 :
1914 0 : if (r->x >= extents.x &&
1915 0 : r->y >= extents.y &&
1916 0 : r->x + r->width <= extents.x + extents.width &&
1917 0 : r->y + r->height <= extents.y + extents.height)
1918 : {
1919 0 : return TRUE;
1920 : }
1921 : }
1922 :
1923 0 : return FALSE;
1924 : }
1925 :
1926 : static cairo_bool_t
1927 47 : _surface_is_clear (const cairo_surface_pattern_t *pattern)
1928 : {
1929 : cairo_rectangle_int_t extents;
1930 :
1931 94 : if (_cairo_surface_get_extents (pattern->surface, &extents) &&
1932 94 : (extents.width == 0 || extents.height == 0))
1933 0 : return TRUE;
1934 :
1935 47 : return pattern->surface->is_clear &&
1936 0 : pattern->surface->content & CAIRO_CONTENT_ALPHA;
1937 : }
1938 :
1939 : static cairo_bool_t
1940 0 : _gradient_is_opaque (const cairo_gradient_pattern_t *gradient,
1941 : const cairo_rectangle_int_t *extents)
1942 : {
1943 : unsigned int i;
1944 :
1945 0 : assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
1946 : gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
1947 :
1948 0 : if (gradient->n_stops == 0 ||
1949 0 : (gradient->base.extend == CAIRO_EXTEND_NONE &&
1950 0 : gradient->stops[0].offset == gradient->stops[gradient->n_stops - 1].offset))
1951 0 : return FALSE;
1952 :
1953 0 : if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
1954 0 : if (gradient->base.extend == CAIRO_EXTEND_NONE) {
1955 : double t[2];
1956 0 : cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
1957 :
1958 : /* EXTEND_NONE degenerate radial gradients are clear */
1959 0 : if (_linear_pattern_is_degenerate (linear))
1960 0 : return FALSE;
1961 :
1962 0 : if (extents == NULL)
1963 0 : return FALSE;
1964 :
1965 0 : _extents_to_linear_parameter (linear, extents, t);
1966 0 : if (t[0] < 0.0 || t[1] > 1.0)
1967 0 : return FALSE;
1968 : }
1969 : }
1970 :
1971 0 : for (i = 0; i < gradient->n_stops; i++)
1972 0 : if (! CAIRO_COLOR_IS_OPAQUE (&gradient->stops[i].color))
1973 0 : return FALSE;
1974 :
1975 0 : return TRUE;
1976 : }
1977 :
1978 : /**
1979 : * _cairo_pattern_is_opaque
1980 : *
1981 : * Convenience function to determine whether a pattern is an opaque
1982 : * pattern (of any type). The same caveats that apply to
1983 : * _cairo_pattern_is_opaque_solid apply here as well.
1984 : *
1985 : * Return value: %TRUE if the pattern is a opaque.
1986 : **/
1987 : cairo_bool_t
1988 0 : _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern,
1989 : const cairo_rectangle_int_t *extents)
1990 : {
1991 : const cairo_pattern_union_t *pattern;
1992 :
1993 0 : if (abstract_pattern->has_component_alpha)
1994 0 : return FALSE;
1995 :
1996 0 : pattern = (cairo_pattern_union_t *) abstract_pattern;
1997 0 : switch (pattern->base.type) {
1998 : case CAIRO_PATTERN_TYPE_SOLID:
1999 0 : return _cairo_pattern_is_opaque_solid (abstract_pattern);
2000 : case CAIRO_PATTERN_TYPE_SURFACE:
2001 0 : return _surface_is_opaque (&pattern->surface, extents);
2002 : case CAIRO_PATTERN_TYPE_LINEAR:
2003 : case CAIRO_PATTERN_TYPE_RADIAL:
2004 0 : return _gradient_is_opaque (&pattern->gradient.base, extents);
2005 : }
2006 :
2007 0 : ASSERT_NOT_REACHED;
2008 0 : return FALSE;
2009 : }
2010 :
2011 : cairo_bool_t
2012 47 : _cairo_pattern_is_clear (const cairo_pattern_t *abstract_pattern)
2013 : {
2014 : const cairo_pattern_union_t *pattern;
2015 :
2016 47 : if (abstract_pattern->has_component_alpha)
2017 0 : return FALSE;
2018 :
2019 47 : pattern = (cairo_pattern_union_t *) abstract_pattern;
2020 47 : switch (pattern->type) {
2021 : case CAIRO_PATTERN_TYPE_SOLID:
2022 0 : return CAIRO_COLOR_IS_CLEAR (&pattern->solid.color);
2023 : case CAIRO_PATTERN_TYPE_SURFACE:
2024 47 : return _surface_is_clear (&pattern->surface);
2025 : case CAIRO_PATTERN_TYPE_LINEAR:
2026 : case CAIRO_PATTERN_TYPE_RADIAL:
2027 0 : return _gradient_is_clear (&pattern->gradient.base, NULL);
2028 : }
2029 :
2030 0 : ASSERT_NOT_REACHED;
2031 0 : return FALSE;
2032 : }
2033 :
2034 : /**
2035 : * _cairo_pattern_analyze_filter:
2036 : * @pattern: surface pattern
2037 : * @pad_out: location to store necessary padding in the source image, or %NULL
2038 : * Returns: the optimized #cairo_filter_t to use with @pattern.
2039 : *
2040 : * Analyze the filter to determine how much extra needs to be sampled
2041 : * from the source image to account for the filter radius and whether
2042 : * we can optimize the filter to a simpler value.
2043 : *
2044 : * XXX: We don't actually have any way of querying the backend for
2045 : * the filter radius, so we just guess base on what we know that
2046 : * backends do currently (see bug #10508)
2047 : */
2048 : cairo_filter_t
2049 94 : _cairo_pattern_analyze_filter (const cairo_pattern_t *pattern,
2050 : double *pad_out)
2051 : {
2052 : double pad;
2053 : cairo_filter_t optimized_filter;
2054 :
2055 94 : switch (pattern->filter) {
2056 : case CAIRO_FILTER_GOOD:
2057 : case CAIRO_FILTER_BEST:
2058 : case CAIRO_FILTER_BILINEAR:
2059 : /* If source pixels map 1:1 onto destination pixels, we do
2060 : * not need to filter (and do not want to filter, since it
2061 : * will cause blurriness)
2062 : */
2063 94 : if (_cairo_matrix_is_pixel_exact (&pattern->matrix)) {
2064 74 : pad = 0.;
2065 74 : optimized_filter = CAIRO_FILTER_NEAREST;
2066 : } else {
2067 : /* 0.5 is enough for a bilinear filter. It's possible we
2068 : * should defensively use more for CAIRO_FILTER_BEST, but
2069 : * without a single example, it's hard to know how much
2070 : * more would be defensive...
2071 : */
2072 20 : pad = 0.5;
2073 20 : optimized_filter = pattern->filter;
2074 : }
2075 94 : break;
2076 :
2077 : case CAIRO_FILTER_FAST:
2078 : case CAIRO_FILTER_NEAREST:
2079 : case CAIRO_FILTER_GAUSSIAN:
2080 : default:
2081 0 : pad = 0.;
2082 0 : optimized_filter = pattern->filter;
2083 0 : break;
2084 : }
2085 :
2086 94 : if (pad_out)
2087 94 : *pad_out = pad;
2088 :
2089 94 : return optimized_filter;
2090 : }
2091 :
2092 :
2093 : static double
2094 0 : _pixman_nearest_sample (double d)
2095 : {
2096 0 : return ceil (d - .5);
2097 : }
2098 :
2099 : static cairo_int_status_t
2100 0 : _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pattern,
2101 : cairo_surface_t *dst,
2102 : int x,
2103 : int y,
2104 : unsigned int width,
2105 : unsigned int height,
2106 : unsigned int flags,
2107 : cairo_surface_t **out,
2108 : cairo_surface_attributes_t *attr)
2109 : {
2110 : cairo_surface_t *surface;
2111 : cairo_rectangle_int_t extents;
2112 : cairo_rectangle_int_t sampled_area;
2113 : double x1, y1, x2, y2;
2114 : int tx, ty;
2115 : double pad;
2116 : cairo_bool_t is_identity;
2117 : cairo_bool_t is_empty;
2118 : cairo_bool_t is_bounded;
2119 : cairo_int_status_t status;
2120 :
2121 0 : surface = cairo_surface_reference (pattern->surface);
2122 :
2123 0 : is_identity = FALSE;
2124 0 : attr->matrix = pattern->base.matrix;
2125 0 : attr->extend = pattern->base.extend;
2126 0 : attr->filter = _cairo_pattern_analyze_filter (&pattern->base, &pad);
2127 0 : attr->has_component_alpha = pattern->base.has_component_alpha;
2128 :
2129 0 : attr->x_offset = attr->y_offset = tx = ty = 0;
2130 0 : if (_cairo_matrix_is_integer_translation (&attr->matrix, &tx, &ty)) {
2131 0 : cairo_matrix_init_identity (&attr->matrix);
2132 0 : attr->x_offset = tx;
2133 0 : attr->y_offset = ty;
2134 0 : is_identity = TRUE;
2135 0 : } else if (attr->filter == CAIRO_FILTER_NEAREST) {
2136 : /*
2137 : * For NEAREST, we can remove the fractional translation component
2138 : * from the transformation - this ensures that the pattern will always
2139 : * hit fast-paths in the backends for simple transformations that
2140 : * become (almost) identity, without loss of quality.
2141 : */
2142 0 : attr->matrix.x0 = 0;
2143 0 : attr->matrix.y0 = 0;
2144 0 : if (_cairo_matrix_is_pixel_exact (&attr->matrix)) {
2145 : /* The rounding here is rather peculiar as it needs to match the
2146 : * rounding performed on the sample coordinate used by pixman.
2147 : */
2148 0 : attr->matrix.x0 = _pixman_nearest_sample (pattern->base.matrix.x0);
2149 0 : attr->matrix.y0 = _pixman_nearest_sample (pattern->base.matrix.y0);
2150 : } else {
2151 0 : attr->matrix.x0 = pattern->base.matrix.x0;
2152 0 : attr->matrix.y0 = pattern->base.matrix.y0;
2153 : }
2154 :
2155 0 : if (_cairo_matrix_is_integer_translation (&attr->matrix, &tx, &ty)) {
2156 0 : cairo_matrix_init_identity (&attr->matrix);
2157 0 : attr->x_offset = tx;
2158 0 : attr->y_offset = ty;
2159 0 : is_identity = TRUE;
2160 : }
2161 : }
2162 :
2163 : /* XXX: Hack:
2164 : *
2165 : * The way we currently support CAIRO_EXTEND_REFLECT is to create
2166 : * an image twice bigger on each side, and create a pattern of four
2167 : * images such that the new image, when repeated, has the same effect
2168 : * of reflecting the original pattern.
2169 : */
2170 0 : if (flags & CAIRO_PATTERN_ACQUIRE_NO_REFLECT &&
2171 0 : attr->extend == CAIRO_EXTEND_REFLECT)
2172 : {
2173 : cairo_t *cr;
2174 : cairo_surface_t *src;
2175 : int w, h;
2176 :
2177 0 : is_bounded = _cairo_surface_get_extents (surface, &extents);
2178 0 : assert (is_bounded);
2179 :
2180 0 : status = _cairo_surface_clone_similar (dst, surface,
2181 : extents.x, extents.y,
2182 : extents.width, extents.height,
2183 : &extents.x, &extents.y, &src);
2184 0 : if (unlikely (status))
2185 0 : goto BAIL;
2186 :
2187 0 : w = 2 * extents.width;
2188 0 : h = 2 * extents.height;
2189 :
2190 0 : if (is_identity) {
2191 0 : attr->x_offset = -x;
2192 0 : x += tx;
2193 0 : while (x <= -w)
2194 0 : x += w;
2195 0 : while (x >= w)
2196 0 : x -= w;
2197 0 : extents.x += x;
2198 0 : tx = x = 0;
2199 :
2200 0 : attr->y_offset = -y;
2201 0 : y += ty;
2202 0 : while (y <= -h)
2203 0 : y += h;
2204 0 : while (y >= h)
2205 0 : y -= h;
2206 0 : extents.y += y;
2207 0 : ty = y = 0;
2208 : }
2209 :
2210 0 : cairo_surface_destroy (surface);
2211 0 : surface = _cairo_surface_create_similar_solid (dst,
2212 : dst->content, w, h,
2213 : CAIRO_COLOR_TRANSPARENT,
2214 : FALSE);
2215 0 : if (surface == NULL)
2216 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
2217 0 : if (unlikely (surface->status)) {
2218 0 : cairo_surface_destroy (src);
2219 0 : return surface->status;
2220 : }
2221 :
2222 0 : surface->device_transform = pattern->surface->device_transform;
2223 0 : surface->device_transform_inverse = pattern->surface->device_transform_inverse;
2224 :
2225 0 : cr = cairo_create (surface);
2226 :
2227 0 : cairo_set_source_surface (cr, src, -extents.x, -extents.y);
2228 0 : cairo_paint (cr);
2229 :
2230 0 : cairo_scale (cr, -1, +1);
2231 0 : cairo_set_source_surface (cr, src, extents.x-w, -extents.y);
2232 0 : cairo_paint (cr);
2233 0 : cairo_set_source_surface (cr, src, extents.x, -extents.y);
2234 0 : cairo_paint (cr);
2235 :
2236 0 : cairo_scale (cr, +1, -1);
2237 0 : cairo_set_source_surface (cr, src, extents.x-w, extents.y-h);
2238 0 : cairo_paint (cr);
2239 0 : cairo_set_source_surface (cr, src, extents.x, extents.y-h);
2240 0 : cairo_paint (cr);
2241 0 : cairo_set_source_surface (cr, src, extents.x-w, extents.y);
2242 0 : cairo_paint (cr);
2243 0 : cairo_set_source_surface (cr, src, extents.x, extents.y);
2244 0 : cairo_paint (cr);
2245 :
2246 0 : cairo_scale (cr, -1, +1);
2247 0 : cairo_set_source_surface (cr, src, -extents.x, extents.y-h);
2248 0 : cairo_paint (cr);
2249 0 : cairo_set_source_surface (cr, src, -extents.x, extents.y);
2250 0 : cairo_paint (cr);
2251 :
2252 0 : status = cairo_status (cr);
2253 0 : cairo_destroy (cr);
2254 :
2255 0 : cairo_surface_destroy (src);
2256 :
2257 0 : if (unlikely (status))
2258 0 : goto BAIL;
2259 :
2260 0 : attr->extend = CAIRO_EXTEND_REPEAT;
2261 : }
2262 :
2263 : /* We first transform the rectangle to the coordinate space of the
2264 : * source surface so that we only need to clone that portion of the
2265 : * surface that will be read.
2266 : */
2267 0 : x1 = x;
2268 0 : y1 = y;
2269 0 : x2 = x + (int) width;
2270 0 : y2 = y + (int) height;
2271 0 : if (! is_identity) {
2272 0 : _cairo_matrix_transform_bounding_box (&attr->matrix,
2273 : &x1, &y1, &x2, &y2,
2274 : NULL);
2275 : }
2276 :
2277 0 : sampled_area.x = floor (x1 - pad);
2278 0 : sampled_area.y = floor (y1 - pad);
2279 0 : sampled_area.width = ceil (x2 + pad) - sampled_area.x;
2280 0 : sampled_area.height = ceil (y2 + pad) - sampled_area.y;
2281 :
2282 0 : sampled_area.x += tx;
2283 0 : sampled_area.y += ty;
2284 :
2285 0 : if ( _cairo_surface_get_extents (surface, &extents)) {
2286 0 : if (attr->extend == CAIRO_EXTEND_NONE) {
2287 : /* Never acquire a larger area than the source itself */
2288 0 : is_empty = _cairo_rectangle_intersect (&extents, &sampled_area);
2289 : } else {
2290 0 : int trim = 0;
2291 :
2292 0 : if (sampled_area.x >= extents.x &&
2293 0 : sampled_area.x + (int) sampled_area.width <= extents.x + (int) extents.width)
2294 : {
2295 : /* source is horizontally contained within extents, trim */
2296 0 : extents.x = sampled_area.x;
2297 0 : extents.width = sampled_area.width;
2298 0 : trim |= 0x1;
2299 : }
2300 :
2301 0 : if (sampled_area.y >= extents.y &&
2302 0 : sampled_area.y + (int) sampled_area.height <= extents.y + (int) extents.height)
2303 : {
2304 : /* source is vertically contained within extents, trim */
2305 0 : extents.y = sampled_area.y;
2306 0 : extents.height = sampled_area.height;
2307 0 : trim |= 0x2;
2308 : }
2309 :
2310 0 : if (trim == 0x3) {
2311 : /* source is wholly contained within extents, drop the REPEAT */
2312 0 : attr->extend = CAIRO_EXTEND_NONE;
2313 : }
2314 :
2315 0 : is_empty = extents.width == 0 || extents.height == 0;
2316 : }
2317 : }
2318 :
2319 : /* XXX can we use is_empty? */
2320 :
2321 0 : status = _cairo_surface_clone_similar (dst, surface,
2322 : extents.x, extents.y,
2323 : extents.width, extents.height,
2324 : &x, &y, out);
2325 0 : if (unlikely (status))
2326 0 : goto BAIL;
2327 :
2328 0 : if (x != 0 || y != 0) {
2329 0 : if (is_identity) {
2330 0 : attr->x_offset -= x;
2331 0 : attr->y_offset -= y;
2332 : } else {
2333 : cairo_matrix_t m;
2334 :
2335 0 : x -= attr->x_offset;
2336 0 : y -= attr->y_offset;
2337 0 : attr->x_offset = 0;
2338 0 : attr->y_offset = 0;
2339 :
2340 0 : cairo_matrix_init_translate (&m, -x, -y);
2341 0 : cairo_matrix_multiply (&attr->matrix, &attr->matrix, &m);
2342 : }
2343 : }
2344 :
2345 : /* reduce likelihood of range overflow with large downscaling */
2346 0 : if (! is_identity) {
2347 : cairo_matrix_t m;
2348 : cairo_status_t invert_status;
2349 :
2350 0 : m = attr->matrix;
2351 0 : invert_status = cairo_matrix_invert (&m);
2352 0 : assert (invert_status == CAIRO_STATUS_SUCCESS);
2353 :
2354 0 : if (m.x0 != 0. || m.y0 != 0.) {
2355 : /* pixman also limits the [xy]_offset to 16 bits so evenly
2356 : * spread the bits between the two.
2357 : */
2358 0 : x = floor (m.x0 / 2);
2359 0 : y = floor (m.y0 / 2);
2360 0 : attr->x_offset -= x;
2361 0 : attr->y_offset -= y;
2362 0 : cairo_matrix_init_translate (&m, x, y);
2363 0 : cairo_matrix_multiply (&attr->matrix, &m, &attr->matrix);
2364 : }
2365 : }
2366 :
2367 : BAIL:
2368 0 : cairo_surface_destroy (surface);
2369 0 : return status;
2370 : }
2371 :
2372 : /**
2373 : * _cairo_pattern_acquire_surface:
2374 : * @pattern: a #cairo_pattern_t
2375 : * @dst: destination surface
2376 : * @x: X coordinate in source corresponding to left side of destination area
2377 : * @y: Y coordinate in source corresponding to top side of destination area
2378 : * @width: width of destination area
2379 : * @height: height of destination area
2380 : * @surface_out: location to store a pointer to a surface
2381 : * @attributes: surface attributes that destination backend should apply to
2382 : * the returned surface
2383 : *
2384 : * A convenience function to obtain a surface to use as the source for
2385 : * drawing on @dst.
2386 : *
2387 : * Note that this function is only suitable for use when the destination
2388 : * surface is pixel based and 1 device unit maps to one pixel.
2389 : *
2390 : * Return value: %CAIRO_STATUS_SUCCESS if a surface was stored in @surface_out.
2391 : **/
2392 : cairo_int_status_t
2393 0 : _cairo_pattern_acquire_surface (const cairo_pattern_t *pattern,
2394 : cairo_surface_t *dst,
2395 : int x,
2396 : int y,
2397 : unsigned int width,
2398 : unsigned int height,
2399 : unsigned int flags,
2400 : cairo_surface_t **surface_out,
2401 : cairo_surface_attributes_t *attributes)
2402 : {
2403 0 : if (unlikely (pattern->status)) {
2404 0 : *surface_out = NULL;
2405 0 : return pattern->status;
2406 : }
2407 :
2408 0 : switch (pattern->type) {
2409 : case CAIRO_PATTERN_TYPE_SOLID:
2410 0 : return _cairo_pattern_acquire_surface_for_solid ((cairo_solid_pattern_t *) pattern,
2411 : dst, x, y, width, height,
2412 : surface_out,
2413 : attributes);
2414 :
2415 : case CAIRO_PATTERN_TYPE_LINEAR:
2416 : case CAIRO_PATTERN_TYPE_RADIAL:
2417 0 : return _cairo_pattern_acquire_surface_for_gradient ((cairo_gradient_pattern_t *) pattern,
2418 : dst, x, y, width, height,
2419 : surface_out,
2420 : attributes);
2421 :
2422 : case CAIRO_PATTERN_TYPE_SURFACE:
2423 0 : return _cairo_pattern_acquire_surface_for_surface ((cairo_surface_pattern_t *) pattern,
2424 : dst, x, y, width, height,
2425 : flags,
2426 : surface_out,
2427 : attributes);
2428 :
2429 : default:
2430 0 : ASSERT_NOT_REACHED;
2431 0 : return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
2432 : }
2433 : }
2434 :
2435 : /**
2436 : * _cairo_pattern_release_surface:
2437 : * @pattern: a #cairo_pattern_t
2438 : * @surface: a surface obtained by _cairo_pattern_acquire_surface
2439 : * @attributes: attributes obtained by _cairo_pattern_acquire_surface
2440 : *
2441 : * Releases resources obtained by _cairo_pattern_acquire_surface.
2442 : **/
2443 : void
2444 0 : _cairo_pattern_release_surface (const cairo_pattern_t *pattern,
2445 : cairo_surface_t *surface,
2446 : cairo_surface_attributes_t *attributes)
2447 : {
2448 0 : cairo_surface_destroy (surface);
2449 0 : }
2450 :
2451 : cairo_int_status_t
2452 0 : _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src,
2453 : const cairo_pattern_t *mask,
2454 : cairo_surface_t *dst,
2455 : int src_x,
2456 : int src_y,
2457 : int mask_x,
2458 : int mask_y,
2459 : unsigned int width,
2460 : unsigned int height,
2461 : unsigned int flags,
2462 : cairo_surface_t **src_out,
2463 : cairo_surface_t **mask_out,
2464 : cairo_surface_attributes_t *src_attributes,
2465 : cairo_surface_attributes_t *mask_attributes)
2466 : {
2467 : cairo_int_status_t status;
2468 : cairo_pattern_union_t src_tmp;
2469 :
2470 0 : if (unlikely (src->status))
2471 0 : return src->status;
2472 0 : if (unlikely (mask != NULL && mask->status))
2473 0 : return mask->status;
2474 :
2475 : /* If src and mask are both solid, then the mask alpha can be
2476 : * combined into src and mask can be ignored. */
2477 :
2478 0 : if (src->type == CAIRO_PATTERN_TYPE_SOLID &&
2479 0 : mask &&
2480 0 : ! mask->has_component_alpha &&
2481 0 : mask->type == CAIRO_PATTERN_TYPE_SOLID)
2482 : {
2483 : cairo_color_t combined;
2484 0 : cairo_solid_pattern_t *src_solid = (cairo_solid_pattern_t *) src;
2485 0 : cairo_solid_pattern_t *mask_solid = (cairo_solid_pattern_t *) mask;
2486 :
2487 0 : combined = src_solid->color;
2488 0 : _cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
2489 :
2490 0 : _cairo_pattern_init_solid (&src_tmp.solid, &combined);
2491 :
2492 0 : src = &src_tmp.base;
2493 0 : mask = NULL;
2494 : }
2495 :
2496 0 : status = _cairo_pattern_acquire_surface (src, dst,
2497 : src_x, src_y,
2498 : width, height,
2499 : flags,
2500 : src_out, src_attributes);
2501 0 : if (unlikely (status))
2502 0 : goto BAIL;
2503 :
2504 0 : if (mask == NULL) {
2505 0 : *mask_out = NULL;
2506 0 : goto BAIL;
2507 : }
2508 :
2509 0 : status = _cairo_pattern_acquire_surface (mask, dst,
2510 : mask_x, mask_y,
2511 : width, height,
2512 : flags,
2513 : mask_out, mask_attributes);
2514 0 : if (unlikely (status))
2515 0 : _cairo_pattern_release_surface (src, *src_out, src_attributes);
2516 :
2517 : BAIL:
2518 0 : if (src == &src_tmp.base)
2519 0 : _cairo_pattern_fini (&src_tmp.base);
2520 :
2521 0 : return status;
2522 : }
2523 :
2524 : /**
2525 : * _cairo_pattern_get_extents:
2526 : *
2527 : * Return the "target-space" extents of @pattern in @extents.
2528 : *
2529 : * For unbounded patterns, the @extents will be initialized with
2530 : * "infinite" extents, (minimum and maximum fixed-point values).
2531 : *
2532 : * XXX: Currently, bounded gradient patterns will also return
2533 : * "infinite" extents, though it would be possible to optimize these
2534 : * with a little more work.
2535 : **/
2536 : void
2537 64 : _cairo_pattern_get_extents (const cairo_pattern_t *pattern,
2538 : cairo_rectangle_int_t *extents)
2539 : {
2540 : double x1, y1, x2, y2;
2541 : cairo_status_t status;
2542 :
2543 64 : switch (pattern->type) {
2544 : case CAIRO_PATTERN_TYPE_SOLID:
2545 17 : goto UNBOUNDED;
2546 :
2547 : case CAIRO_PATTERN_TYPE_SURFACE:
2548 : {
2549 : cairo_rectangle_int_t surface_extents;
2550 47 : const cairo_surface_pattern_t *surface_pattern =
2551 : (const cairo_surface_pattern_t *) pattern;
2552 47 : cairo_surface_t *surface = surface_pattern->surface;
2553 : double pad;
2554 :
2555 47 : if (! _cairo_surface_get_extents (surface, &surface_extents))
2556 0 : goto UNBOUNDED;
2557 :
2558 47 : if (surface_extents.width == 0 || surface_extents.height == 0)
2559 : goto EMPTY;
2560 :
2561 47 : if (pattern->extend != CAIRO_EXTEND_NONE)
2562 0 : goto UNBOUNDED;
2563 :
2564 : /* The filter can effectively enlarge the extents of the
2565 : * pattern, so extend as necessary.
2566 : */
2567 47 : _cairo_pattern_analyze_filter (&surface_pattern->base, &pad);
2568 47 : x1 = surface_extents.x - pad;
2569 47 : y1 = surface_extents.y - pad;
2570 47 : x2 = surface_extents.x + (int) surface_extents.width + pad;
2571 47 : y2 = surface_extents.y + (int) surface_extents.height + pad;
2572 : }
2573 47 : break;
2574 :
2575 : case CAIRO_PATTERN_TYPE_RADIAL:
2576 : {
2577 0 : const cairo_radial_pattern_t *radial =
2578 : (const cairo_radial_pattern_t *) pattern;
2579 : double cx1, cy1;
2580 : double cx2, cy2;
2581 : double r, D;
2582 :
2583 0 : if (radial->r1 == 0 && radial->r2 == 0)
2584 0 : goto EMPTY;
2585 :
2586 0 : cx1 = _cairo_fixed_to_double (radial->c1.x);
2587 0 : cy1 = _cairo_fixed_to_double (radial->c1.y);
2588 0 : r = _cairo_fixed_to_double (radial->r1);
2589 0 : x1 = cx1 - r; x2 = cx1 + r;
2590 0 : y1 = cy1 - r; y2 = cy1 + r;
2591 :
2592 0 : cx2 = _cairo_fixed_to_double (radial->c2.x);
2593 0 : cy2 = _cairo_fixed_to_double (radial->c2.y);
2594 0 : r = fabs (_cairo_fixed_to_double (radial->r2));
2595 :
2596 0 : if (pattern->extend != CAIRO_EXTEND_NONE)
2597 0 : goto UNBOUNDED;
2598 :
2599 : /* We need to be careful, as if the circles are not
2600 : * self-contained, then the solution is actually unbounded.
2601 : */
2602 0 : D = (cx1-cx2)*(cx1-cx2) + (cy1-cy2)*(cy1-cy2);
2603 0 : if (D > r*r - 1e-5)
2604 0 : goto UNBOUNDED;
2605 :
2606 0 : if (cx2 - r < x1)
2607 0 : x1 = cx2 - r;
2608 0 : if (cx2 + r > x2)
2609 0 : x2 = cx2 + r;
2610 :
2611 0 : if (cy2 - r < y1)
2612 0 : y1 = cy2 - r;
2613 0 : if (cy2 + r > y2)
2614 0 : y2 = cy2 + r;
2615 : }
2616 0 : break;
2617 :
2618 : case CAIRO_PATTERN_TYPE_LINEAR:
2619 : {
2620 0 : const cairo_linear_pattern_t *linear =
2621 : (const cairo_linear_pattern_t *) pattern;
2622 :
2623 0 : if (pattern->extend != CAIRO_EXTEND_NONE)
2624 0 : goto UNBOUNDED;
2625 :
2626 0 : if (linear->p1.x == linear->p2.x && linear->p1.y == linear->p2.y)
2627 0 : goto EMPTY;
2628 :
2629 0 : if (pattern->matrix.xy != 0. || pattern->matrix.yx != 0.)
2630 : goto UNBOUNDED;
2631 :
2632 0 : if (linear->p1.x == linear->p2.x) {
2633 0 : x1 = -HUGE_VAL;
2634 0 : x2 = HUGE_VAL;
2635 0 : y1 = _cairo_fixed_to_double (MIN (linear->p1.y, linear->p2.y));
2636 0 : y2 = _cairo_fixed_to_double (MAX (linear->p1.y, linear->p2.y));
2637 0 : } else if (linear->p1.y == linear->p2.y) {
2638 0 : x1 = _cairo_fixed_to_double (MIN (linear->p1.x, linear->p2.x));
2639 0 : x2 = _cairo_fixed_to_double (MAX (linear->p1.x, linear->p2.x));
2640 0 : y1 = -HUGE_VAL;
2641 0 : y2 = HUGE_VAL;
2642 : } else {
2643 0 : goto UNBOUNDED;
2644 : }
2645 : }
2646 0 : break;
2647 :
2648 : default:
2649 0 : ASSERT_NOT_REACHED;
2650 : }
2651 :
2652 47 : if (_cairo_matrix_is_translation (&pattern->matrix)) {
2653 37 : x1 -= pattern->matrix.x0; x2 -= pattern->matrix.x0;
2654 37 : y1 -= pattern->matrix.y0; y2 -= pattern->matrix.y0;
2655 : } else {
2656 : cairo_matrix_t imatrix;
2657 :
2658 10 : imatrix = pattern->matrix;
2659 10 : status = cairo_matrix_invert (&imatrix);
2660 : /* cairo_pattern_set_matrix ensures the matrix is invertible */
2661 10 : assert (status == CAIRO_STATUS_SUCCESS);
2662 :
2663 10 : _cairo_matrix_transform_bounding_box (&imatrix,
2664 : &x1, &y1, &x2, &y2,
2665 : NULL);
2666 : }
2667 :
2668 47 : x1 = floor (x1);
2669 47 : if (x1 < CAIRO_RECT_INT_MIN)
2670 0 : x1 = CAIRO_RECT_INT_MIN;
2671 47 : y1 = floor (y1);
2672 47 : if (y1 < CAIRO_RECT_INT_MIN)
2673 0 : y1 = CAIRO_RECT_INT_MIN;
2674 :
2675 47 : x2 = ceil (x2);
2676 47 : if (x2 > CAIRO_RECT_INT_MAX)
2677 0 : x2 = CAIRO_RECT_INT_MAX;
2678 47 : y2 = ceil (y2);
2679 47 : if (y2 > CAIRO_RECT_INT_MAX)
2680 0 : y2 = CAIRO_RECT_INT_MAX;
2681 :
2682 47 : extents->x = x1; extents->width = x2 - x1;
2683 47 : extents->y = y1; extents->height = y2 - y1;
2684 47 : return;
2685 :
2686 : UNBOUNDED:
2687 : /* unbounded patterns -> 'infinite' extents */
2688 17 : _cairo_unbounded_rectangle_init (extents);
2689 17 : return;
2690 :
2691 : EMPTY:
2692 0 : extents->x = extents->y = 0;
2693 0 : extents->width = extents->height = 0;
2694 0 : return;
2695 : }
2696 :
2697 :
2698 : static unsigned long
2699 0 : _cairo_solid_pattern_hash (unsigned long hash,
2700 : const cairo_pattern_t *pattern)
2701 : {
2702 0 : const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
2703 :
2704 0 : hash = _cairo_hash_bytes (hash, &solid->color, sizeof (solid->color));
2705 :
2706 0 : return hash;
2707 : }
2708 :
2709 : static unsigned long
2710 0 : _cairo_gradient_color_stops_hash (unsigned long hash,
2711 : const cairo_gradient_pattern_t *gradient)
2712 : {
2713 : unsigned int n;
2714 :
2715 0 : hash = _cairo_hash_bytes (hash,
2716 0 : &gradient->n_stops,
2717 : sizeof (gradient->n_stops));
2718 :
2719 0 : for (n = 0; n < gradient->n_stops; n++) {
2720 0 : hash = _cairo_hash_bytes (hash,
2721 0 : &gradient->stops[n].offset,
2722 : sizeof (double));
2723 0 : hash = _cairo_hash_bytes (hash,
2724 0 : &gradient->stops[n].color,
2725 : sizeof (cairo_color_t));
2726 : }
2727 :
2728 0 : return hash;
2729 : }
2730 :
2731 : unsigned long
2732 0 : _cairo_linear_pattern_hash (unsigned long hash,
2733 : const cairo_linear_pattern_t *linear)
2734 : {
2735 0 : hash = _cairo_hash_bytes (hash, &linear->p1, sizeof (linear->p1));
2736 0 : hash = _cairo_hash_bytes (hash, &linear->p2, sizeof (linear->p2));
2737 :
2738 0 : return _cairo_gradient_color_stops_hash (hash, &linear->base);
2739 : }
2740 :
2741 : unsigned long
2742 0 : _cairo_radial_pattern_hash (unsigned long hash,
2743 : const cairo_radial_pattern_t *radial)
2744 : {
2745 0 : hash = _cairo_hash_bytes (hash, &radial->c1, sizeof (radial->c1));
2746 0 : hash = _cairo_hash_bytes (hash, &radial->r1, sizeof (radial->r1));
2747 0 : hash = _cairo_hash_bytes (hash, &radial->c2, sizeof (radial->c2));
2748 0 : hash = _cairo_hash_bytes (hash, &radial->r2, sizeof (radial->r2));
2749 :
2750 0 : return _cairo_gradient_color_stops_hash (hash, &radial->base);
2751 : }
2752 :
2753 : static unsigned long
2754 0 : _cairo_surface_pattern_hash (unsigned long hash,
2755 : const cairo_pattern_t *pattern)
2756 : {
2757 0 : const cairo_surface_pattern_t *surface = (cairo_surface_pattern_t *) pattern;
2758 :
2759 0 : hash ^= surface->surface->unique_id;
2760 :
2761 0 : return hash;
2762 : }
2763 :
2764 : unsigned long
2765 0 : _cairo_pattern_hash (const cairo_pattern_t *pattern)
2766 : {
2767 0 : unsigned long hash = _CAIRO_HASH_INIT_VALUE;
2768 :
2769 0 : if (pattern->status)
2770 0 : return 0;
2771 :
2772 0 : hash = _cairo_hash_bytes (hash, &pattern->type, sizeof (pattern->type));
2773 0 : if (pattern->type != CAIRO_PATTERN_TYPE_SOLID) {
2774 0 : hash = _cairo_hash_bytes (hash,
2775 0 : &pattern->matrix, sizeof (pattern->matrix));
2776 0 : hash = _cairo_hash_bytes (hash,
2777 0 : &pattern->filter, sizeof (pattern->filter));
2778 0 : hash = _cairo_hash_bytes (hash,
2779 0 : &pattern->extend, sizeof (pattern->extend));
2780 0 : hash = _cairo_hash_bytes (hash,
2781 0 : &pattern->has_component_alpha,
2782 : sizeof (pattern->has_component_alpha));
2783 : }
2784 :
2785 0 : switch (pattern->type) {
2786 : case CAIRO_PATTERN_TYPE_SOLID:
2787 0 : return _cairo_solid_pattern_hash (hash, pattern);
2788 : case CAIRO_PATTERN_TYPE_LINEAR:
2789 0 : return _cairo_linear_pattern_hash (hash, (cairo_linear_pattern_t *) pattern);
2790 : case CAIRO_PATTERN_TYPE_RADIAL:
2791 0 : return _cairo_radial_pattern_hash (hash, (cairo_radial_pattern_t *) pattern);
2792 : case CAIRO_PATTERN_TYPE_SURFACE:
2793 0 : return _cairo_surface_pattern_hash (hash, pattern);
2794 : default:
2795 0 : ASSERT_NOT_REACHED;
2796 0 : return FALSE;
2797 : }
2798 : }
2799 :
2800 : static unsigned long
2801 0 : _cairo_gradient_pattern_color_stops_size (const cairo_pattern_t *pattern)
2802 : {
2803 0 : cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern;
2804 :
2805 0 : return gradient->n_stops * (sizeof (double) + sizeof (cairo_color_t));
2806 : }
2807 :
2808 : unsigned long
2809 0 : _cairo_pattern_size (const cairo_pattern_t *pattern)
2810 : {
2811 0 : if (pattern->status)
2812 0 : return 0;
2813 :
2814 : /* XXX */
2815 0 : switch (pattern->type) {
2816 : case CAIRO_PATTERN_TYPE_SOLID:
2817 0 : return sizeof (cairo_solid_pattern_t);
2818 : break;
2819 : case CAIRO_PATTERN_TYPE_SURFACE:
2820 0 : return sizeof (cairo_surface_pattern_t);
2821 : break;
2822 : case CAIRO_PATTERN_TYPE_LINEAR:
2823 0 : return sizeof (cairo_linear_pattern_t) +
2824 0 : _cairo_gradient_pattern_color_stops_size (pattern);
2825 : break;
2826 : case CAIRO_PATTERN_TYPE_RADIAL:
2827 0 : return sizeof (cairo_radial_pattern_t) +
2828 0 : _cairo_gradient_pattern_color_stops_size (pattern);
2829 : default:
2830 0 : ASSERT_NOT_REACHED;
2831 0 : return 0;
2832 : }
2833 : }
2834 :
2835 :
2836 : static cairo_bool_t
2837 0 : _cairo_solid_pattern_equal (const cairo_pattern_t *A,
2838 : const cairo_pattern_t *B)
2839 : {
2840 0 : const cairo_solid_pattern_t *a = (cairo_solid_pattern_t *) A;
2841 0 : const cairo_solid_pattern_t *b = (cairo_solid_pattern_t *) B;
2842 :
2843 0 : return _cairo_color_equal (&a->color, &b->color);
2844 : }
2845 :
2846 : static cairo_bool_t
2847 0 : _cairo_gradient_color_stops_equal (const cairo_gradient_pattern_t *a,
2848 : const cairo_gradient_pattern_t *b)
2849 : {
2850 : unsigned int n;
2851 :
2852 0 : if (a->n_stops != b->n_stops)
2853 0 : return FALSE;
2854 :
2855 0 : for (n = 0; n < a->n_stops; n++) {
2856 0 : if (a->stops[n].offset != b->stops[n].offset)
2857 0 : return FALSE;
2858 0 : if (! _cairo_color_stop_equal (&a->stops[n].color, &b->stops[n].color))
2859 0 : return FALSE;
2860 : }
2861 :
2862 0 : return TRUE;
2863 : }
2864 :
2865 : cairo_bool_t
2866 0 : _cairo_linear_pattern_equal (const cairo_linear_pattern_t *a,
2867 : const cairo_linear_pattern_t *b)
2868 : {
2869 0 : if (a->p1.x != b->p1.x)
2870 0 : return FALSE;
2871 :
2872 0 : if (a->p1.y != b->p1.y)
2873 0 : return FALSE;
2874 :
2875 0 : if (a->p2.x != b->p2.x)
2876 0 : return FALSE;
2877 :
2878 0 : if (a->p2.y != b->p2.y)
2879 0 : return FALSE;
2880 :
2881 0 : return _cairo_gradient_color_stops_equal (&a->base, &b->base);
2882 : }
2883 :
2884 : cairo_bool_t
2885 0 : _cairo_radial_pattern_equal (const cairo_radial_pattern_t *a,
2886 : const cairo_radial_pattern_t *b)
2887 : {
2888 0 : if (a->c1.x != b->c1.x)
2889 0 : return FALSE;
2890 :
2891 0 : if (a->c1.y != b->c1.y)
2892 0 : return FALSE;
2893 :
2894 0 : if (a->r1 != b->r1)
2895 0 : return FALSE;
2896 :
2897 0 : if (a->c2.x != b->c2.x)
2898 0 : return FALSE;
2899 :
2900 0 : if (a->c2.y != b->c2.y)
2901 0 : return FALSE;
2902 :
2903 0 : if (a->r2 != b->r2)
2904 0 : return FALSE;
2905 :
2906 0 : return _cairo_gradient_color_stops_equal (&a->base, &b->base);
2907 : }
2908 :
2909 : static cairo_bool_t
2910 0 : _cairo_surface_pattern_equal (const cairo_pattern_t *A,
2911 : const cairo_pattern_t *B)
2912 : {
2913 0 : const cairo_surface_pattern_t *a = (cairo_surface_pattern_t *) A;
2914 0 : const cairo_surface_pattern_t *b = (cairo_surface_pattern_t *) B;
2915 :
2916 0 : return a->surface->unique_id == b->surface->unique_id;
2917 : }
2918 :
2919 : cairo_bool_t
2920 0 : _cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b)
2921 : {
2922 0 : if (a->status || b->status)
2923 0 : return FALSE;
2924 :
2925 0 : if (a == b)
2926 0 : return TRUE;
2927 :
2928 0 : if (a->type != b->type)
2929 0 : return FALSE;
2930 :
2931 0 : if (a->has_component_alpha != b->has_component_alpha)
2932 0 : return FALSE;
2933 :
2934 0 : if (a->type != CAIRO_PATTERN_TYPE_SOLID) {
2935 0 : if (memcmp (&a->matrix, &b->matrix, sizeof (cairo_matrix_t)))
2936 0 : return FALSE;
2937 :
2938 0 : if (a->filter != b->filter)
2939 0 : return FALSE;
2940 :
2941 0 : if (a->extend != b->extend)
2942 0 : return FALSE;
2943 : }
2944 :
2945 0 : switch (a->type) {
2946 : case CAIRO_PATTERN_TYPE_SOLID:
2947 0 : return _cairo_solid_pattern_equal (a, b);
2948 : case CAIRO_PATTERN_TYPE_LINEAR:
2949 0 : return _cairo_linear_pattern_equal ((cairo_linear_pattern_t *) a,
2950 : (cairo_linear_pattern_t *) b);
2951 : case CAIRO_PATTERN_TYPE_RADIAL:
2952 0 : return _cairo_radial_pattern_equal ((cairo_radial_pattern_t *) a,
2953 : (cairo_radial_pattern_t *) b);
2954 : case CAIRO_PATTERN_TYPE_SURFACE:
2955 0 : return _cairo_surface_pattern_equal (a, b);
2956 : default:
2957 0 : ASSERT_NOT_REACHED;
2958 0 : return FALSE;
2959 : }
2960 : }
2961 :
2962 : /**
2963 : * cairo_pattern_get_rgba
2964 : * @pattern: a #cairo_pattern_t
2965 : * @red: return value for red component of color, or %NULL
2966 : * @green: return value for green component of color, or %NULL
2967 : * @blue: return value for blue component of color, or %NULL
2968 : * @alpha: return value for alpha component of color, or %NULL
2969 : *
2970 : * Gets the solid color for a solid color pattern.
2971 : *
2972 : * Return value: %CAIRO_STATUS_SUCCESS, or
2973 : * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if the pattern is not a solid
2974 : * color pattern.
2975 : *
2976 : * Since: 1.4
2977 : **/
2978 : cairo_status_t
2979 0 : cairo_pattern_get_rgba (cairo_pattern_t *pattern,
2980 : double *red, double *green,
2981 : double *blue, double *alpha)
2982 : {
2983 0 : cairo_solid_pattern_t *solid = (cairo_solid_pattern_t*) pattern;
2984 : double r0, g0, b0, a0;
2985 :
2986 0 : if (pattern->status)
2987 0 : return pattern->status;
2988 :
2989 0 : if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
2990 0 : return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
2991 :
2992 0 : _cairo_color_get_rgba (&solid->color, &r0, &g0, &b0, &a0);
2993 :
2994 0 : if (red)
2995 0 : *red = r0;
2996 0 : if (green)
2997 0 : *green = g0;
2998 0 : if (blue)
2999 0 : *blue = b0;
3000 0 : if (alpha)
3001 0 : *alpha = a0;
3002 :
3003 0 : return CAIRO_STATUS_SUCCESS;
3004 : }
3005 :
3006 : /**
3007 : * cairo_pattern_get_surface
3008 : * @pattern: a #cairo_pattern_t
3009 : * @surface: return value for surface of pattern, or %NULL
3010 : *
3011 : * Gets the surface of a surface pattern. The reference returned in
3012 : * @surface is owned by the pattern; the caller should call
3013 : * cairo_surface_reference() if the surface is to be retained.
3014 : *
3015 : * Return value: %CAIRO_STATUS_SUCCESS, or
3016 : * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if the pattern is not a surface
3017 : * pattern.
3018 : *
3019 : * Since: 1.4
3020 : **/
3021 : cairo_status_t
3022 0 : cairo_pattern_get_surface (cairo_pattern_t *pattern,
3023 : cairo_surface_t **surface)
3024 : {
3025 0 : cairo_surface_pattern_t *spat = (cairo_surface_pattern_t*) pattern;
3026 :
3027 0 : if (pattern->status)
3028 0 : return pattern->status;
3029 :
3030 0 : if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
3031 0 : return CAIRO_STATUS_PATTERN_TYPE_MISMATCH;
3032 :
3033 0 : if (surface)
3034 0 : *surface = spat->surface;
3035 :
3036 0 : return CAIRO_STATUS_SUCCESS;
3037 : }
3038 :
3039 : /**
3040 : * cairo_pattern_get_color_stop_rgba
3041 : * @pattern: a #cairo_pattern_t
3042 : * @index: index of the stop to return data for
3043 : * @offset: return value for the offset of the stop, or %NULL
3044 : * @red: return value for red component of color, or %NULL
3045 : * @green: return value for green component of color, or %NULL
3046 : * @blue: return value for blue component of color, or %NULL
3047 : * @alpha: return value for alpha component of color, or %NULL
3048 : *
3049 : * Gets the color and offset information at the given @index for a
3050 : * gradient pattern. Values of @index are 0 to 1 less than the number
3051 : * returned by cairo_pattern_get_color_stop_count().
3052 : *
3053 : * Return value: %CAIRO_STATUS_SUCCESS, or %CAIRO_STATUS_INVALID_INDEX
3054 : * if @index is not valid for the given pattern. If the pattern is
3055 : * not a gradient pattern, %CAIRO_STATUS_PATTERN_TYPE_MISMATCH is
3056 : * returned.
3057 : *
3058 : * Since: 1.4
3059 : **/
3060 : cairo_status_t
3061 0 : cairo_pattern_get_color_stop_rgba (cairo_pattern_t *pattern,
3062 : int index, double *offset,
3063 : double *red, double *green,
3064 : double *blue, double *alpha)
3065 : {
3066 0 : cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t*) pattern;
3067 :
3068 0 : if (pattern->status)
3069 0 : return pattern->status;
3070 :
3071 0 : if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR &&
3072 0 : pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
3073 0 : return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
3074 :
3075 0 : if (index < 0 || (unsigned int) index >= gradient->n_stops)
3076 0 : return _cairo_error (CAIRO_STATUS_INVALID_INDEX);
3077 :
3078 0 : if (offset)
3079 0 : *offset = gradient->stops[index].offset;
3080 0 : if (red)
3081 0 : *red = gradient->stops[index].color.red;
3082 0 : if (green)
3083 0 : *green = gradient->stops[index].color.green;
3084 0 : if (blue)
3085 0 : *blue = gradient->stops[index].color.blue;
3086 0 : if (alpha)
3087 0 : *alpha = gradient->stops[index].color.alpha;
3088 :
3089 0 : return CAIRO_STATUS_SUCCESS;
3090 : }
3091 :
3092 : /**
3093 : * cairo_pattern_get_color_stop_count
3094 : * @pattern: a #cairo_pattern_t
3095 : * @count: return value for the number of color stops, or %NULL
3096 : *
3097 : * Gets the number of color stops specified in the given gradient
3098 : * pattern.
3099 : *
3100 : * Return value: %CAIRO_STATUS_SUCCESS, or
3101 : * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a gradient
3102 : * pattern.
3103 : *
3104 : * Since: 1.4
3105 : */
3106 : cairo_status_t
3107 0 : cairo_pattern_get_color_stop_count (cairo_pattern_t *pattern,
3108 : int *count)
3109 : {
3110 0 : cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t*) pattern;
3111 :
3112 0 : if (pattern->status)
3113 0 : return pattern->status;
3114 :
3115 0 : if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR &&
3116 0 : pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
3117 0 : return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
3118 :
3119 0 : if (count)
3120 0 : *count = gradient->n_stops;
3121 :
3122 0 : return CAIRO_STATUS_SUCCESS;
3123 : }
3124 :
3125 : /**
3126 : * cairo_pattern_get_linear_points
3127 : * @pattern: a #cairo_pattern_t
3128 : * @x0: return value for the x coordinate of the first point, or %NULL
3129 : * @y0: return value for the y coordinate of the first point, or %NULL
3130 : * @x1: return value for the x coordinate of the second point, or %NULL
3131 : * @y1: return value for the y coordinate of the second point, or %NULL
3132 : *
3133 : * Gets the gradient endpoints for a linear gradient.
3134 : *
3135 : * Return value: %CAIRO_STATUS_SUCCESS, or
3136 : * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a linear
3137 : * gradient pattern.
3138 : *
3139 : * Since: 1.4
3140 : **/
3141 : cairo_status_t
3142 0 : cairo_pattern_get_linear_points (cairo_pattern_t *pattern,
3143 : double *x0, double *y0,
3144 : double *x1, double *y1)
3145 : {
3146 0 : cairo_linear_pattern_t *linear = (cairo_linear_pattern_t*) pattern;
3147 :
3148 0 : if (pattern->status)
3149 0 : return pattern->status;
3150 :
3151 0 : if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR)
3152 0 : return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
3153 :
3154 0 : if (x0)
3155 0 : *x0 = _cairo_fixed_to_double (linear->p1.x);
3156 0 : if (y0)
3157 0 : *y0 = _cairo_fixed_to_double (linear->p1.y);
3158 0 : if (x1)
3159 0 : *x1 = _cairo_fixed_to_double (linear->p2.x);
3160 0 : if (y1)
3161 0 : *y1 = _cairo_fixed_to_double (linear->p2.y);
3162 :
3163 0 : return CAIRO_STATUS_SUCCESS;
3164 : }
3165 :
3166 : /**
3167 : * cairo_pattern_get_radial_circles
3168 : * @pattern: a #cairo_pattern_t
3169 : * @x0: return value for the x coordinate of the center of the first circle, or %NULL
3170 : * @y0: return value for the y coordinate of the center of the first circle, or %NULL
3171 : * @r0: return value for the radius of the first circle, or %NULL
3172 : * @x1: return value for the x coordinate of the center of the second circle, or %NULL
3173 : * @y1: return value for the y coordinate of the center of the second circle, or %NULL
3174 : * @r1: return value for the radius of the second circle, or %NULL
3175 : *
3176 : * Gets the gradient endpoint circles for a radial gradient, each
3177 : * specified as a center coordinate and a radius.
3178 : *
3179 : * Return value: %CAIRO_STATUS_SUCCESS, or
3180 : * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a radial
3181 : * gradient pattern.
3182 : *
3183 : * Since: 1.4
3184 : **/
3185 : cairo_status_t
3186 0 : cairo_pattern_get_radial_circles (cairo_pattern_t *pattern,
3187 : double *x0, double *y0, double *r0,
3188 : double *x1, double *y1, double *r1)
3189 : {
3190 0 : cairo_radial_pattern_t *radial = (cairo_radial_pattern_t*) pattern;
3191 :
3192 0 : if (pattern->status)
3193 0 : return pattern->status;
3194 :
3195 0 : if (pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
3196 0 : return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
3197 :
3198 0 : if (x0)
3199 0 : *x0 = _cairo_fixed_to_double (radial->c1.x);
3200 0 : if (y0)
3201 0 : *y0 = _cairo_fixed_to_double (radial->c1.y);
3202 0 : if (r0)
3203 0 : *r0 = _cairo_fixed_to_double (radial->r1);
3204 0 : if (x1)
3205 0 : *x1 = _cairo_fixed_to_double (radial->c2.x);
3206 0 : if (y1)
3207 0 : *y1 = _cairo_fixed_to_double (radial->c2.y);
3208 0 : if (r1)
3209 0 : *r1 = _cairo_fixed_to_double (radial->r2);
3210 :
3211 0 : return CAIRO_STATUS_SUCCESS;
3212 : }
3213 :
3214 : void
3215 3 : _cairo_pattern_reset_static_data (void)
3216 : {
3217 : #if HAS_FREED_POOL
3218 : int i;
3219 :
3220 : for (i = 0; i < ARRAY_LENGTH (freed_pattern_pool); i++)
3221 : _freed_pool_reset (&freed_pattern_pool[i]);
3222 : #endif
3223 :
3224 3 : _cairo_pattern_reset_solid_surface_cache ();
3225 3 : }
|