Line data Source code
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 0 : _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 0 : pattern->type = type;
161 0 : 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 0 : CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 0);
166 :
167 0 : _cairo_user_data_array_init (&pattern->user_data);
168 :
169 0 : if (type == CAIRO_PATTERN_TYPE_SURFACE)
170 0 : pattern->extend = CAIRO_EXTEND_SURFACE_DEFAULT;
171 : else
172 0 : pattern->extend = CAIRO_EXTEND_GRADIENT_DEFAULT;
173 :
174 0 : pattern->filter = CAIRO_FILTER_DEFAULT;
175 :
176 0 : pattern->has_component_alpha = FALSE;
177 :
178 0 : cairo_matrix_init_identity (&pattern->matrix);
179 0 : }
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 0 : _cairo_pattern_init_static_copy (cairo_pattern_t *pattern,
275 : const cairo_pattern_t *other)
276 : {
277 : int size;
278 :
279 0 : assert (other->status == CAIRO_STATUS_SUCCESS);
280 :
281 0 : 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 0 : size = sizeof (cairo_surface_pattern_t);
289 0 : 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 0 : memcpy (pattern, other, size);
299 :
300 0 : CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 0);
301 0 : _cairo_user_data_array_init (&pattern->user_data);
302 0 : }
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 0 : _cairo_pattern_fini (cairo_pattern_t *pattern)
336 : {
337 0 : _cairo_user_data_array_fini (&pattern->user_data);
338 :
339 0 : switch (pattern->type) {
340 : case CAIRO_PATTERN_TYPE_SOLID:
341 0 : break;
342 : case CAIRO_PATTERN_TYPE_SURFACE: {
343 0 : cairo_surface_pattern_t *surface_pattern =
344 : (cairo_surface_pattern_t *) pattern;
345 :
346 0 : cairo_surface_destroy (surface_pattern->surface);
347 0 : } 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 0 : }
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 0 : _cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern,
428 : cairo_surface_t *surface)
429 : {
430 0 : 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 0 : _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SURFACE);
438 :
439 0 : 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 0 : cairo_pattern_create_for_surface (cairo_surface_t *surface)
613 : {
614 : cairo_surface_pattern_t *pattern;
615 :
616 0 : 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 0 : if (surface->status)
622 0 : return _cairo_pattern_create_in_error (surface->status);
623 :
624 0 : pattern =
625 : _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SURFACE]);
626 0 : if (unlikely (pattern == NULL)) {
627 0 : pattern = malloc (sizeof (cairo_surface_pattern_t));
628 0 : 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 0 : _cairo_pattern_init_for_surface (pattern, surface);
637 0 : CAIRO_REFERENCE_COUNT_INIT (&pattern->base.ref_count, 1);
638 :
639 0 : 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 0 : cairo_pattern_reference (cairo_pattern_t *pattern)
759 : {
760 0 : if (pattern == NULL ||
761 0 : CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count))
762 0 : return pattern;
763 :
764 0 : assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&pattern->ref_count));
765 :
766 0 : _cairo_reference_count_inc (&pattern->ref_count);
767 :
768 0 : 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 0 : cairo_pattern_destroy (cairo_pattern_t *pattern)
815 : {
816 : cairo_pattern_type_t type;
817 :
818 0 : if (pattern == NULL ||
819 0 : CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count))
820 0 : return;
821 :
822 0 : assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&pattern->ref_count));
823 :
824 0 : if (! _cairo_reference_count_dec_and_test (&pattern->ref_count))
825 0 : return;
826 :
827 0 : type = pattern->type;
828 0 : _cairo_pattern_fini (pattern);
829 :
830 : /* maintain a small cache of freed patterns */
831 0 : _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 0 : 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 0 : if (pattern->status)
1145 0 : return;
1146 :
1147 0 : if (memcmp (&pattern->matrix, matrix, sizeof (cairo_matrix_t)) == 0)
1148 0 : return;
1149 :
1150 0 : pattern->matrix = *matrix;
1151 :
1152 0 : inverse = *matrix;
1153 0 : status = cairo_matrix_invert (&inverse);
1154 0 : 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 0 : _cairo_pattern_transform (cairo_pattern_t *pattern,
1257 : const cairo_matrix_t *ctm_inverse)
1258 : {
1259 0 : if (pattern->status)
1260 0 : return;
1261 :
1262 0 : 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 : double x0, y0, x1, y1, maxabs;
1371 :
1372 : /*
1373 : * Transform the matrix to avoid overflow when converting between
1374 : * cairo_fixed_t and pixman_fixed_t (without incurring performance
1375 : * loss when the transformation is unnecessary).
1376 : *
1377 : * Having a function to compute the required transformation to
1378 : * "normalize" a given bounding box would be generally useful -
1379 : * cf linear patterns, gradient patterns, surface patterns...
1380 : */
1381 0 : x0 = _cairo_fixed_to_double (linear->p1.x);
1382 0 : y0 = _cairo_fixed_to_double (linear->p1.y);
1383 0 : x1 = _cairo_fixed_to_double (linear->p2.x);
1384 0 : y1 = _cairo_fixed_to_double (linear->p2.y);
1385 0 : cairo_matrix_transform_point (&matrix, &x0, &y0);
1386 0 : cairo_matrix_transform_point (&matrix, &x1, &y1);
1387 0 : maxabs = MAX (MAX (fabs (x0), fabs (x1)), MAX (fabs (y0), fabs (y1)));
1388 :
1389 : #define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */
1390 0 : if (maxabs > PIXMAN_MAX_INT)
1391 : {
1392 : double sf;
1393 : cairo_matrix_t scale;
1394 :
1395 0 : sf = PIXMAN_MAX_INT / maxabs;
1396 :
1397 0 : p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.x) * sf);
1398 0 : p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.y) * sf);
1399 0 : p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.x) * sf);
1400 0 : p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.y) * sf);
1401 :
1402 : /* cairo_matrix_scale does a pre-scale, we want a post-scale */
1403 0 : cairo_matrix_init_scale (&scale, sf, sf);
1404 0 : cairo_matrix_multiply (&matrix, &matrix, &scale);
1405 : }
1406 : else
1407 : {
1408 0 : p1.x = _cairo_fixed_to_16_16 (linear->p1.x);
1409 0 : p1.y = _cairo_fixed_to_16_16 (linear->p1.y);
1410 0 : p2.x = _cairo_fixed_to_16_16 (linear->p2.x);
1411 0 : p2.y = _cairo_fixed_to_16_16 (linear->p2.y);
1412 : }
1413 :
1414 0 : pixman_image = pixman_image_create_linear_gradient (&p1, &p2,
1415 : pixman_stops,
1416 0 : pattern->n_stops);
1417 : }
1418 : else
1419 : {
1420 0 : cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern;
1421 : pixman_point_fixed_t c1, c2;
1422 : pixman_fixed_t r1, r2;
1423 :
1424 0 : c1.x = _cairo_fixed_to_16_16 (radial->c1.x);
1425 0 : c1.y = _cairo_fixed_to_16_16 (radial->c1.y);
1426 0 : r1 = _cairo_fixed_to_16_16 (radial->r1);
1427 :
1428 0 : c2.x = _cairo_fixed_to_16_16 (radial->c2.x);
1429 0 : c2.y = _cairo_fixed_to_16_16 (radial->c2.y);
1430 0 : r2 = _cairo_fixed_to_16_16 (radial->r2);
1431 :
1432 0 : pixman_image = pixman_image_create_radial_gradient (&c1, &c2,
1433 : r1, r2,
1434 : pixman_stops,
1435 0 : pattern->n_stops);
1436 : }
1437 :
1438 0 : if (pixman_stops != pixman_stops_static)
1439 0 : free (pixman_stops);
1440 :
1441 0 : if (unlikely (pixman_image == NULL))
1442 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1443 :
1444 0 : if (_cairo_surface_is_image (dst))
1445 : {
1446 0 : image = (cairo_image_surface_t *)
1447 : _cairo_image_surface_create_for_pixman_image (pixman_image,
1448 : PIXMAN_a8r8g8b8);
1449 0 : if (image->base.status)
1450 : {
1451 0 : pixman_image_unref (pixman_image);
1452 0 : return image->base.status;
1453 : }
1454 :
1455 0 : attr->x_offset = attr->y_offset = 0;
1456 0 : attr->matrix = matrix;
1457 0 : attr->extend = pattern->base.extend;
1458 0 : attr->filter = CAIRO_FILTER_NEAREST;
1459 0 : attr->has_component_alpha = pattern->base.has_component_alpha;
1460 :
1461 0 : *out = &image->base;
1462 :
1463 0 : return CAIRO_STATUS_SUCCESS;
1464 : }
1465 :
1466 0 : if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
1467 : cairo_bool_t is_horizontal;
1468 : cairo_bool_t is_vertical;
1469 :
1470 0 : _cairo_linear_pattern_classify ((cairo_linear_pattern_t *)pattern,
1471 : x, y, width, height,
1472 : &is_horizontal, &is_vertical);
1473 0 : if (is_horizontal) {
1474 0 : height = 1;
1475 0 : repeat = TRUE;
1476 : }
1477 : /* width-1 repeating patterns are quite slow with scan-line based
1478 : * compositing code, so we use a wider strip and spend some extra
1479 : * expense in computing the gradient. It's possible that for narrow
1480 : * gradients we'd be better off using a 2 or 4 pixel strip; the
1481 : * wider the gradient, the more it's worth spending extra time
1482 : * computing a sample.
1483 : */
1484 0 : if (is_vertical && width > 8) {
1485 0 : width = 8;
1486 0 : repeat = TRUE;
1487 : }
1488 : }
1489 :
1490 0 : if (! pixman_image_set_filter (pixman_image, PIXMAN_FILTER_BILINEAR,
1491 : NULL, 0))
1492 : {
1493 0 : pixman_image_unref (pixman_image);
1494 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1495 : }
1496 :
1497 0 : image = (cairo_image_surface_t *)
1498 0 : cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
1499 0 : if (image->base.status) {
1500 0 : pixman_image_unref (pixman_image);
1501 0 : return image->base.status;
1502 : }
1503 :
1504 0 : _cairo_matrix_to_pixman_matrix (&matrix, &pixman_transform,
1505 : width/2., height/2.);
1506 0 : if (!pixman_image_set_transform (pixman_image, &pixman_transform)) {
1507 0 : cairo_surface_destroy (&image->base);
1508 0 : pixman_image_unref (pixman_image);
1509 0 : return _cairo_error (CAIRO_STATUS_NO_MEMORY);
1510 : }
1511 :
1512 0 : switch (pattern->base.extend) {
1513 : case CAIRO_EXTEND_NONE:
1514 0 : pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_NONE);
1515 0 : break;
1516 : case CAIRO_EXTEND_REPEAT:
1517 0 : pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_NORMAL);
1518 0 : break;
1519 : case CAIRO_EXTEND_REFLECT:
1520 0 : pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_REFLECT);
1521 0 : break;
1522 : case CAIRO_EXTEND_PAD:
1523 0 : pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_PAD);
1524 0 : break;
1525 : }
1526 :
1527 0 : pixman_image_composite32 (PIXMAN_OP_SRC,
1528 : pixman_image,
1529 : NULL,
1530 : image->pixman_image,
1531 : x, y,
1532 : 0, 0,
1533 : 0, 0,
1534 : width, height);
1535 :
1536 0 : pixman_image_unref (pixman_image);
1537 :
1538 : _cairo_debug_check_image_surface_is_defined (&image->base);
1539 :
1540 0 : status = _cairo_surface_clone_similar (dst, &image->base,
1541 : 0, 0, width, height,
1542 : &clone_offset_x,
1543 : &clone_offset_y,
1544 : out);
1545 :
1546 0 : cairo_surface_destroy (&image->base);
1547 :
1548 0 : attr->x_offset = -x;
1549 0 : attr->y_offset = -y;
1550 0 : cairo_matrix_init_identity (&attr->matrix);
1551 0 : attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE;
1552 0 : attr->filter = CAIRO_FILTER_NEAREST;
1553 0 : attr->has_component_alpha = pattern->base.has_component_alpha;
1554 :
1555 0 : return status;
1556 : }
1557 :
1558 : /* We maintain a small cache here, because we don't want to constantly
1559 : * recreate surfaces for simple solid colors. */
1560 : #define MAX_SURFACE_CACHE_SIZE 16
1561 : static struct {
1562 : struct _cairo_pattern_solid_surface_cache{
1563 : cairo_color_t color;
1564 : cairo_surface_t *surface;
1565 : } cache[MAX_SURFACE_CACHE_SIZE];
1566 : int size;
1567 : } solid_surface_cache;
1568 :
1569 : static cairo_bool_t
1570 0 : _cairo_pattern_solid_surface_matches (
1571 : const struct _cairo_pattern_solid_surface_cache *cache,
1572 : const cairo_solid_pattern_t *pattern,
1573 : cairo_surface_t *dst)
1574 : {
1575 0 : if (cairo_surface_get_content (cache->surface) != _cairo_color_get_content (&pattern->color))
1576 0 : return FALSE;
1577 :
1578 0 : if (CAIRO_REFERENCE_COUNT_GET_VALUE (&cache->surface->ref_count) != 1)
1579 0 : return FALSE;
1580 :
1581 0 : if (! _cairo_surface_is_similar (cache->surface, dst))
1582 0 : return FALSE;
1583 :
1584 0 : return TRUE;
1585 : }
1586 :
1587 : static cairo_bool_t
1588 0 : _cairo_pattern_solid_surface_matches_color (
1589 : const struct _cairo_pattern_solid_surface_cache *cache,
1590 : const cairo_solid_pattern_t *pattern,
1591 : cairo_surface_t *dst)
1592 : {
1593 0 : if (! _cairo_color_equal (&cache->color, &pattern->color))
1594 0 : return FALSE;
1595 :
1596 0 : return _cairo_pattern_solid_surface_matches (cache, pattern, dst);
1597 : }
1598 :
1599 : static cairo_int_status_t
1600 0 : _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *pattern,
1601 : cairo_surface_t *dst,
1602 : int x,
1603 : int y,
1604 : unsigned int width,
1605 : unsigned int height,
1606 : cairo_surface_t **out,
1607 : cairo_surface_attributes_t *attribs)
1608 : {
1609 : static int i;
1610 :
1611 0 : cairo_surface_t *surface, *to_destroy = NULL;
1612 : cairo_status_t status;
1613 :
1614 0 : CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
1615 :
1616 : /* Check cache first */
1617 0 : if (i < solid_surface_cache.size &&
1618 0 : _cairo_pattern_solid_surface_matches_color (&solid_surface_cache.cache[i],
1619 : pattern,
1620 : dst))
1621 : {
1622 0 : goto DONE;
1623 : }
1624 :
1625 0 : for (i = 0 ; i < solid_surface_cache.size; i++) {
1626 0 : if (_cairo_pattern_solid_surface_matches_color (&solid_surface_cache.cache[i],
1627 : pattern,
1628 : dst))
1629 : {
1630 0 : goto DONE;
1631 : }
1632 : }
1633 :
1634 : /* Choose a surface to repaint/evict */
1635 0 : surface = NULL;
1636 0 : if (solid_surface_cache.size == MAX_SURFACE_CACHE_SIZE) {
1637 0 : i = rand () % MAX_SURFACE_CACHE_SIZE;
1638 0 : surface = solid_surface_cache.cache[i].surface;
1639 :
1640 0 : if (_cairo_pattern_solid_surface_matches (&solid_surface_cache.cache[i],
1641 : pattern,
1642 : dst))
1643 : {
1644 : /* Reuse the surface instead of evicting */
1645 0 : status = _cairo_surface_repaint_solid_pattern_surface (dst, surface, pattern);
1646 0 : if (unlikely (status))
1647 0 : goto EVICT;
1648 :
1649 0 : cairo_surface_reference (surface);
1650 : }
1651 : else
1652 : {
1653 : EVICT:
1654 0 : surface = NULL;
1655 : }
1656 : }
1657 :
1658 0 : if (surface == NULL) {
1659 : /* Not cached, need to create new */
1660 0 : surface = _cairo_surface_create_solid_pattern_surface (dst, pattern);
1661 0 : if (surface == NULL) {
1662 0 : status = CAIRO_INT_STATUS_UNSUPPORTED;
1663 0 : goto UNLOCK;
1664 : }
1665 0 : if (unlikely (surface->status)) {
1666 0 : status = surface->status;
1667 0 : goto UNLOCK;
1668 : }
1669 :
1670 0 : if (unlikely (! _cairo_surface_is_similar (surface, dst)))
1671 : {
1672 : /* In the rare event of a substitute surface being returned,
1673 : * don't cache the fallback.
1674 : */
1675 0 : *out = surface;
1676 0 : goto NOCACHE;
1677 : }
1678 : }
1679 :
1680 0 : if (i == solid_surface_cache.size)
1681 0 : solid_surface_cache.size++;
1682 :
1683 0 : to_destroy = solid_surface_cache.cache[i].surface;
1684 0 : solid_surface_cache.cache[i].surface = surface;
1685 0 : solid_surface_cache.cache[i].color = pattern->color;
1686 :
1687 : DONE:
1688 0 : *out = cairo_surface_reference (solid_surface_cache.cache[i].surface);
1689 :
1690 : NOCACHE:
1691 0 : attribs->x_offset = attribs->y_offset = 0;
1692 0 : cairo_matrix_init_identity (&attribs->matrix);
1693 0 : attribs->extend = CAIRO_EXTEND_REPEAT;
1694 0 : attribs->filter = CAIRO_FILTER_NEAREST;
1695 0 : attribs->has_component_alpha = pattern->base.has_component_alpha;
1696 :
1697 0 : status = CAIRO_STATUS_SUCCESS;
1698 :
1699 : UNLOCK:
1700 0 : CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
1701 :
1702 0 : if (to_destroy)
1703 0 : cairo_surface_destroy (to_destroy);
1704 :
1705 0 : return status;
1706 : }
1707 :
1708 : static void
1709 0 : _cairo_pattern_reset_solid_surface_cache (void)
1710 : {
1711 0 : CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
1712 :
1713 : /* remove surfaces starting from the end so that solid_surface_cache.cache
1714 : * is always in a consistent state when we release the mutex. */
1715 0 : while (solid_surface_cache.size) {
1716 : cairo_surface_t *surface;
1717 :
1718 0 : solid_surface_cache.size--;
1719 0 : surface = solid_surface_cache.cache[solid_surface_cache.size].surface;
1720 0 : solid_surface_cache.cache[solid_surface_cache.size].surface = NULL;
1721 :
1722 : /* release the lock to avoid the possibility of a recursive
1723 : * deadlock when the surface destroy closure gets called */
1724 0 : CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
1725 0 : cairo_surface_destroy (surface);
1726 0 : CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock);
1727 : }
1728 :
1729 0 : CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock);
1730 0 : }
1731 :
1732 : static void
1733 0 : _extents_to_linear_parameter (const cairo_linear_pattern_t *linear,
1734 : const cairo_rectangle_int_t *extents,
1735 : double t[2])
1736 : {
1737 : double t0, tdx, tdy;
1738 : double p1x, p1y, pdx, pdy, invsqnorm;
1739 :
1740 0 : p1x = _cairo_fixed_to_double (linear->p1.x);
1741 0 : p1y = _cairo_fixed_to_double (linear->p1.y);
1742 0 : pdx = _cairo_fixed_to_double (linear->p2.x) - p1x;
1743 0 : pdy = _cairo_fixed_to_double (linear->p2.y) - p1y;
1744 0 : invsqnorm = 1.0 / (pdx * pdx + pdy * pdy);
1745 0 : pdx *= invsqnorm;
1746 0 : pdy *= invsqnorm;
1747 :
1748 0 : t0 = (extents->x - p1x) * pdx + (extents->y - p1y) * pdy;
1749 0 : tdx = extents->width * pdx;
1750 0 : tdy = extents->height * pdy;
1751 :
1752 0 : t[0] = t[1] = t0;
1753 0 : if (tdx < 0)
1754 0 : t[0] += tdx;
1755 : else
1756 0 : t[1] += tdx;
1757 :
1758 0 : if (tdy < 0)
1759 0 : t[0] += tdy;
1760 : else
1761 0 : t[1] += tdy;
1762 0 : }
1763 :
1764 : static cairo_bool_t
1765 0 : _linear_pattern_is_degenerate (const cairo_linear_pattern_t *linear)
1766 : {
1767 0 : return linear->p1.x == linear->p2.x && linear->p1.y == linear->p2.y;
1768 : }
1769 :
1770 : static cairo_bool_t
1771 0 : _radial_pattern_is_degenerate (const cairo_radial_pattern_t *radial)
1772 : {
1773 0 : return radial->r1 == radial->r2 &&
1774 0 : (radial->r1 == 0 /* && radial->r2 == 0 */ ||
1775 0 : (radial->c1.x == radial->c2.x && radial->c1.y == radial->c2.y));
1776 : }
1777 :
1778 : static cairo_bool_t
1779 0 : _gradient_is_clear (const cairo_gradient_pattern_t *gradient,
1780 : const cairo_rectangle_int_t *extents)
1781 : {
1782 : unsigned int i;
1783 :
1784 0 : assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
1785 : gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
1786 :
1787 0 : if (gradient->n_stops == 0 ||
1788 0 : (gradient->base.extend == CAIRO_EXTEND_NONE &&
1789 0 : gradient->stops[0].offset == gradient->stops[gradient->n_stops - 1].offset))
1790 0 : return TRUE;
1791 :
1792 : /* Check if the extents intersect the drawn part of the pattern. */
1793 0 : if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
1794 0 : if (gradient->base.extend == CAIRO_EXTEND_NONE) {
1795 0 : cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
1796 : /* EXTEND_NONE degenerate linear gradients are clear */
1797 0 : if (_linear_pattern_is_degenerate (linear))
1798 0 : return TRUE;
1799 :
1800 0 : if (extents != NULL) {
1801 : double t[2];
1802 0 : _extents_to_linear_parameter (linear, extents, t);
1803 0 : if ((t[0] <= 0.0 && t[1] <= 0.0) || (t[0] >= 1.0 && t[1] >= 1.0))
1804 0 : return TRUE;
1805 : }
1806 : }
1807 : } else {
1808 0 : cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) gradient;
1809 : /* degenerate radial gradients are clear */
1810 0 : if (_radial_pattern_is_degenerate (radial) && FALSE)
1811 : return TRUE;
1812 : /* TODO: check actual intersection */
1813 : }
1814 :
1815 0 : for (i = 0; i < gradient->n_stops; i++)
1816 0 : if (! CAIRO_COLOR_IS_CLEAR (&gradient->stops[i].color))
1817 0 : return FALSE;
1818 :
1819 0 : return TRUE;
1820 : }
1821 :
1822 : /**
1823 : * _cairo_gradient_pattern_is_solid
1824 : *
1825 : * Convenience function to determine whether a gradient pattern is
1826 : * a solid color within the given extents. In this case the color
1827 : * argument is initialized to the color the pattern represents.
1828 : * This functions doesn't handle completely transparent gradients,
1829 : * thus it should be called only after _cairo_pattern_is_clear has
1830 : * returned FALSE.
1831 : *
1832 : * Return value: %TRUE if the pattern is a solid color.
1833 : **/
1834 : cairo_bool_t
1835 0 : _cairo_gradient_pattern_is_solid (const cairo_gradient_pattern_t *gradient,
1836 : const cairo_rectangle_int_t *extents,
1837 : cairo_color_t *color)
1838 : {
1839 : unsigned int i;
1840 :
1841 0 : assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
1842 : gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
1843 :
1844 : /* TODO: radial, degenerate linear */
1845 0 : if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
1846 0 : if (gradient->base.extend == CAIRO_EXTEND_NONE) {
1847 0 : cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
1848 : double t[2];
1849 :
1850 : /* We already know that the pattern is not clear, thus if some
1851 : * part of it is clear, the whole is not solid.
1852 : */
1853 :
1854 0 : if (extents == NULL)
1855 0 : return FALSE;
1856 :
1857 0 : _extents_to_linear_parameter (linear, extents, t);
1858 0 : if (t[0] < 0.0 || t[1] > 1.0)
1859 0 : return FALSE;
1860 : }
1861 : }
1862 :
1863 0 : for (i = 1; i < gradient->n_stops; i++)
1864 0 : if (! _cairo_color_stop_equal (&gradient->stops[0].color,
1865 0 : &gradient->stops[i].color))
1866 0 : return FALSE;
1867 :
1868 0 : _cairo_color_init_rgba (color,
1869 0 : gradient->stops[0].color.red,
1870 0 : gradient->stops[0].color.green,
1871 0 : gradient->stops[0].color.blue,
1872 0 : gradient->stops[0].color.alpha);
1873 :
1874 0 : return TRUE;
1875 : }
1876 :
1877 : /**
1878 : * _cairo_pattern_is_opaque_solid
1879 : *
1880 : * Convenience function to determine whether a pattern is an opaque
1881 : * (alpha==1.0) solid color pattern. This is done by testing whether
1882 : * the pattern's alpha value when converted to a byte is 255, so if a
1883 : * backend actually supported deep alpha channels this function might
1884 : * not do the right thing.
1885 : *
1886 : * Return value: %TRUE if the pattern is an opaque, solid color.
1887 : **/
1888 : cairo_bool_t
1889 0 : _cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern)
1890 : {
1891 : cairo_solid_pattern_t *solid;
1892 :
1893 0 : if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
1894 0 : return FALSE;
1895 :
1896 0 : solid = (cairo_solid_pattern_t *) pattern;
1897 :
1898 0 : return CAIRO_COLOR_IS_OPAQUE (&solid->color);
1899 : }
1900 :
1901 : static cairo_bool_t
1902 0 : _surface_is_opaque (const cairo_surface_pattern_t *pattern,
1903 : const cairo_rectangle_int_t *r)
1904 : {
1905 0 : if (pattern->surface->content & CAIRO_CONTENT_ALPHA)
1906 0 : return FALSE;
1907 :
1908 0 : if (pattern->base.extend != CAIRO_EXTEND_NONE)
1909 0 : return TRUE;
1910 :
1911 0 : if (r != NULL) {
1912 : cairo_rectangle_int_t extents;
1913 :
1914 0 : if (! _cairo_surface_get_extents (pattern->surface, &extents))
1915 0 : return TRUE;
1916 :
1917 0 : if (r->x >= extents.x &&
1918 0 : r->y >= extents.y &&
1919 0 : r->x + r->width <= extents.x + extents.width &&
1920 0 : r->y + r->height <= extents.y + extents.height)
1921 : {
1922 0 : return TRUE;
1923 : }
1924 : }
1925 :
1926 0 : return FALSE;
1927 : }
1928 :
1929 : static cairo_bool_t
1930 0 : _surface_is_clear (const cairo_surface_pattern_t *pattern)
1931 : {
1932 : cairo_rectangle_int_t extents;
1933 :
1934 0 : if (_cairo_surface_get_extents (pattern->surface, &extents) &&
1935 0 : (extents.width == 0 || extents.height == 0))
1936 0 : return TRUE;
1937 :
1938 0 : return pattern->surface->is_clear &&
1939 0 : pattern->surface->content & CAIRO_CONTENT_ALPHA;
1940 : }
1941 :
1942 : static cairo_bool_t
1943 0 : _gradient_is_opaque (const cairo_gradient_pattern_t *gradient,
1944 : const cairo_rectangle_int_t *extents)
1945 : {
1946 : unsigned int i;
1947 :
1948 0 : assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR ||
1949 : gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL);
1950 :
1951 0 : if (gradient->n_stops == 0 ||
1952 0 : (gradient->base.extend == CAIRO_EXTEND_NONE &&
1953 0 : gradient->stops[0].offset == gradient->stops[gradient->n_stops - 1].offset))
1954 0 : return FALSE;
1955 :
1956 0 : if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) {
1957 0 : if (gradient->base.extend == CAIRO_EXTEND_NONE) {
1958 : double t[2];
1959 0 : cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
1960 :
1961 : /* EXTEND_NONE degenerate radial gradients are clear */
1962 0 : if (_linear_pattern_is_degenerate (linear))
1963 0 : return FALSE;
1964 :
1965 0 : if (extents == NULL)
1966 0 : return FALSE;
1967 :
1968 0 : _extents_to_linear_parameter (linear, extents, t);
1969 0 : if (t[0] < 0.0 || t[1] > 1.0)
1970 0 : return FALSE;
1971 : }
1972 : }
1973 :
1974 0 : for (i = 0; i < gradient->n_stops; i++)
1975 0 : if (! CAIRO_COLOR_IS_OPAQUE (&gradient->stops[i].color))
1976 0 : return FALSE;
1977 :
1978 0 : return TRUE;
1979 : }
1980 :
1981 : /**
1982 : * _cairo_pattern_is_opaque
1983 : *
1984 : * Convenience function to determine whether a pattern is an opaque
1985 : * pattern (of any type). The same caveats that apply to
1986 : * _cairo_pattern_is_opaque_solid apply here as well.
1987 : *
1988 : * Return value: %TRUE if the pattern is a opaque.
1989 : **/
1990 : cairo_bool_t
1991 0 : _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern,
1992 : const cairo_rectangle_int_t *extents)
1993 : {
1994 : const cairo_pattern_union_t *pattern;
1995 :
1996 0 : if (abstract_pattern->has_component_alpha)
1997 0 : return FALSE;
1998 :
1999 0 : pattern = (cairo_pattern_union_t *) abstract_pattern;
2000 0 : switch (pattern->base.type) {
2001 : case CAIRO_PATTERN_TYPE_SOLID:
2002 0 : return _cairo_pattern_is_opaque_solid (abstract_pattern);
2003 : case CAIRO_PATTERN_TYPE_SURFACE:
2004 0 : return _surface_is_opaque (&pattern->surface, extents);
2005 : case CAIRO_PATTERN_TYPE_LINEAR:
2006 : case CAIRO_PATTERN_TYPE_RADIAL:
2007 0 : return _gradient_is_opaque (&pattern->gradient.base, extents);
2008 : }
2009 :
2010 0 : ASSERT_NOT_REACHED;
2011 0 : return FALSE;
2012 : }
2013 :
2014 : cairo_bool_t
2015 0 : _cairo_pattern_is_clear (const cairo_pattern_t *abstract_pattern)
2016 : {
2017 : const cairo_pattern_union_t *pattern;
2018 :
2019 0 : if (abstract_pattern->has_component_alpha)
2020 0 : return FALSE;
2021 :
2022 0 : pattern = (cairo_pattern_union_t *) abstract_pattern;
2023 0 : switch (pattern->type) {
2024 : case CAIRO_PATTERN_TYPE_SOLID:
2025 0 : return CAIRO_COLOR_IS_CLEAR (&pattern->solid.color);
2026 : case CAIRO_PATTERN_TYPE_SURFACE:
2027 0 : return _surface_is_clear (&pattern->surface);
2028 : case CAIRO_PATTERN_TYPE_LINEAR:
2029 : case CAIRO_PATTERN_TYPE_RADIAL:
2030 0 : return _gradient_is_clear (&pattern->gradient.base, NULL);
2031 : }
2032 :
2033 0 : ASSERT_NOT_REACHED;
2034 0 : return FALSE;
2035 : }
2036 :
2037 : /**
2038 : * _cairo_pattern_analyze_filter:
2039 : * @pattern: surface pattern
2040 : * @pad_out: location to store necessary padding in the source image, or %NULL
2041 : * Returns: the optimized #cairo_filter_t to use with @pattern.
2042 : *
2043 : * Analyze the filter to determine how much extra needs to be sampled
2044 : * from the source image to account for the filter radius and whether
2045 : * we can optimize the filter to a simpler value.
2046 : *
2047 : * XXX: We don't actually have any way of querying the backend for
2048 : * the filter radius, so we just guess base on what we know that
2049 : * backends do currently (see bug #10508)
2050 : */
2051 : cairo_filter_t
2052 0 : _cairo_pattern_analyze_filter (const cairo_pattern_t *pattern,
2053 : double *pad_out)
2054 : {
2055 : double pad;
2056 : cairo_filter_t optimized_filter;
2057 :
2058 0 : switch (pattern->filter) {
2059 : case CAIRO_FILTER_GOOD:
2060 : case CAIRO_FILTER_BEST:
2061 : case CAIRO_FILTER_BILINEAR:
2062 : /* If source pixels map 1:1 onto destination pixels, we do
2063 : * not need to filter (and do not want to filter, since it
2064 : * will cause blurriness)
2065 : */
2066 0 : if (_cairo_matrix_is_pixel_exact (&pattern->matrix)) {
2067 0 : pad = 0.;
2068 0 : optimized_filter = CAIRO_FILTER_NEAREST;
2069 : } else {
2070 : /* 0.5 is enough for a bilinear filter. It's possible we
2071 : * should defensively use more for CAIRO_FILTER_BEST, but
2072 : * without a single example, it's hard to know how much
2073 : * more would be defensive...
2074 : */
2075 0 : pad = 0.5;
2076 0 : optimized_filter = pattern->filter;
2077 : }
2078 0 : break;
2079 :
2080 : case CAIRO_FILTER_FAST:
2081 : case CAIRO_FILTER_NEAREST:
2082 : case CAIRO_FILTER_GAUSSIAN:
2083 : default:
2084 0 : pad = 0.;
2085 0 : optimized_filter = pattern->filter;
2086 0 : break;
2087 : }
2088 :
2089 0 : if (pad_out)
2090 0 : *pad_out = pad;
2091 :
2092 0 : return optimized_filter;
2093 : }
2094 :
2095 :
2096 : static double
2097 0 : _pixman_nearest_sample (double d)
2098 : {
2099 0 : return ceil (d - .5);
2100 : }
2101 :
2102 : static cairo_int_status_t
2103 0 : _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pattern,
2104 : cairo_surface_t *dst,
2105 : int x,
2106 : int y,
2107 : unsigned int width,
2108 : unsigned int height,
2109 : unsigned int flags,
2110 : cairo_surface_t **out,
2111 : cairo_surface_attributes_t *attr)
2112 : {
2113 : cairo_surface_t *surface;
2114 : cairo_rectangle_int_t extents;
2115 : cairo_rectangle_int_t sampled_area;
2116 : double x1, y1, x2, y2;
2117 : int tx, ty;
2118 : double pad;
2119 : cairo_bool_t is_identity;
2120 : cairo_bool_t is_empty;
2121 : cairo_bool_t is_bounded;
2122 : cairo_int_status_t status;
2123 :
2124 0 : surface = cairo_surface_reference (pattern->surface);
2125 :
2126 0 : is_identity = FALSE;
2127 0 : attr->matrix = pattern->base.matrix;
2128 0 : attr->extend = pattern->base.extend;
2129 0 : attr->filter = _cairo_pattern_analyze_filter (&pattern->base, &pad);
2130 0 : attr->has_component_alpha = pattern->base.has_component_alpha;
2131 :
2132 0 : attr->x_offset = attr->y_offset = tx = ty = 0;
2133 0 : if (_cairo_matrix_is_integer_translation (&attr->matrix, &tx, &ty)) {
2134 0 : cairo_matrix_init_identity (&attr->matrix);
2135 0 : attr->x_offset = tx;
2136 0 : attr->y_offset = ty;
2137 0 : is_identity = TRUE;
2138 0 : } else if (attr->filter == CAIRO_FILTER_NEAREST) {
2139 : /*
2140 : * For NEAREST, we can remove the fractional translation component
2141 : * from the transformation - this ensures that the pattern will always
2142 : * hit fast-paths in the backends for simple transformations that
2143 : * become (almost) identity, without loss of quality.
2144 : */
2145 0 : attr->matrix.x0 = 0;
2146 0 : attr->matrix.y0 = 0;
2147 0 : if (_cairo_matrix_is_pixel_exact (&attr->matrix)) {
2148 : /* The rounding here is rather peculiar as it needs to match the
2149 : * rounding performed on the sample coordinate used by pixman.
2150 : */
2151 0 : attr->matrix.x0 = _pixman_nearest_sample (pattern->base.matrix.x0);
2152 0 : attr->matrix.y0 = _pixman_nearest_sample (pattern->base.matrix.y0);
2153 : } else {
2154 0 : attr->matrix.x0 = pattern->base.matrix.x0;
2155 0 : attr->matrix.y0 = pattern->base.matrix.y0;
2156 : }
2157 :
2158 0 : if (_cairo_matrix_is_integer_translation (&attr->matrix, &tx, &ty)) {
2159 0 : cairo_matrix_init_identity (&attr->matrix);
2160 0 : attr->x_offset = tx;
2161 0 : attr->y_offset = ty;
2162 0 : is_identity = TRUE;
2163 : }
2164 : }
2165 :
2166 : /* XXX: Hack:
2167 : *
2168 : * The way we currently support CAIRO_EXTEND_REFLECT is to create
2169 : * an image twice bigger on each side, and create a pattern of four
2170 : * images such that the new image, when repeated, has the same effect
2171 : * of reflecting the original pattern.
2172 : */
2173 0 : if (flags & CAIRO_PATTERN_ACQUIRE_NO_REFLECT &&
2174 0 : attr->extend == CAIRO_EXTEND_REFLECT)
2175 : {
2176 : cairo_t *cr;
2177 : cairo_surface_t *src;
2178 : int w, h;
2179 :
2180 0 : is_bounded = _cairo_surface_get_extents (surface, &extents);
2181 0 : assert (is_bounded);
2182 :
2183 0 : status = _cairo_surface_clone_similar (dst, surface,
2184 : extents.x, extents.y,
2185 : extents.width, extents.height,
2186 : &extents.x, &extents.y, &src);
2187 0 : if (unlikely (status))
2188 0 : goto BAIL;
2189 :
2190 0 : w = 2 * extents.width;
2191 0 : h = 2 * extents.height;
2192 :
2193 0 : if (is_identity) {
2194 0 : attr->x_offset = -x;
2195 0 : x += tx;
2196 0 : while (x <= -w)
2197 0 : x += w;
2198 0 : while (x >= w)
2199 0 : x -= w;
2200 0 : extents.x += x;
2201 0 : tx = x = 0;
2202 :
2203 0 : attr->y_offset = -y;
2204 0 : y += ty;
2205 0 : while (y <= -h)
2206 0 : y += h;
2207 0 : while (y >= h)
2208 0 : y -= h;
2209 0 : extents.y += y;
2210 0 : ty = y = 0;
2211 : }
2212 :
2213 0 : cairo_surface_destroy (surface);
2214 0 : surface = _cairo_surface_create_similar_solid (dst,
2215 : dst->content, w, h,
2216 : CAIRO_COLOR_TRANSPARENT,
2217 : FALSE);
2218 0 : if (surface == NULL)
2219 0 : return CAIRO_INT_STATUS_UNSUPPORTED;
2220 0 : if (unlikely (surface->status)) {
2221 0 : cairo_surface_destroy (src);
2222 0 : return surface->status;
2223 : }
2224 :
2225 0 : surface->device_transform = pattern->surface->device_transform;
2226 0 : surface->device_transform_inverse = pattern->surface->device_transform_inverse;
2227 :
2228 0 : cr = cairo_create (surface);
2229 :
2230 0 : cairo_set_source_surface (cr, src, -extents.x, -extents.y);
2231 0 : cairo_paint (cr);
2232 :
2233 0 : cairo_scale (cr, -1, +1);
2234 0 : cairo_set_source_surface (cr, src, extents.x-w, -extents.y);
2235 0 : cairo_paint (cr);
2236 0 : cairo_set_source_surface (cr, src, extents.x, -extents.y);
2237 0 : cairo_paint (cr);
2238 :
2239 0 : cairo_scale (cr, +1, -1);
2240 0 : cairo_set_source_surface (cr, src, extents.x-w, extents.y-h);
2241 0 : cairo_paint (cr);
2242 0 : cairo_set_source_surface (cr, src, extents.x, extents.y-h);
2243 0 : cairo_paint (cr);
2244 0 : cairo_set_source_surface (cr, src, extents.x-w, extents.y);
2245 0 : cairo_paint (cr);
2246 0 : cairo_set_source_surface (cr, src, extents.x, extents.y);
2247 0 : cairo_paint (cr);
2248 :
2249 0 : cairo_scale (cr, -1, +1);
2250 0 : cairo_set_source_surface (cr, src, -extents.x, extents.y-h);
2251 0 : cairo_paint (cr);
2252 0 : cairo_set_source_surface (cr, src, -extents.x, extents.y);
2253 0 : cairo_paint (cr);
2254 :
2255 0 : status = cairo_status (cr);
2256 0 : cairo_destroy (cr);
2257 :
2258 0 : cairo_surface_destroy (src);
2259 :
2260 0 : if (unlikely (status))
2261 0 : goto BAIL;
2262 :
2263 0 : attr->extend = CAIRO_EXTEND_REPEAT;
2264 : }
2265 :
2266 : /* We first transform the rectangle to the coordinate space of the
2267 : * source surface so that we only need to clone that portion of the
2268 : * surface that will be read.
2269 : */
2270 0 : x1 = x;
2271 0 : y1 = y;
2272 0 : x2 = x + (int) width;
2273 0 : y2 = y + (int) height;
2274 0 : if (! is_identity) {
2275 0 : _cairo_matrix_transform_bounding_box (&attr->matrix,
2276 : &x1, &y1, &x2, &y2,
2277 : NULL);
2278 : }
2279 :
2280 0 : sampled_area.x = floor (x1 - pad);
2281 0 : sampled_area.y = floor (y1 - pad);
2282 0 : sampled_area.width = ceil (x2 + pad) - sampled_area.x;
2283 0 : sampled_area.height = ceil (y2 + pad) - sampled_area.y;
2284 :
2285 0 : sampled_area.x += tx;
2286 0 : sampled_area.y += ty;
2287 :
2288 0 : if ( _cairo_surface_get_extents (surface, &extents)) {
2289 0 : if (attr->extend == CAIRO_EXTEND_NONE) {
2290 : /* Never acquire a larger area than the source itself */
2291 0 : is_empty = _cairo_rectangle_intersect (&extents, &sampled_area);
2292 : } else {
2293 0 : int trim = 0;
2294 :
2295 0 : if (sampled_area.x >= extents.x &&
2296 0 : sampled_area.x + (int) sampled_area.width <= extents.x + (int) extents.width)
2297 : {
2298 : /* source is horizontally contained within extents, trim */
2299 0 : extents.x = sampled_area.x;
2300 0 : extents.width = sampled_area.width;
2301 0 : trim |= 0x1;
2302 : }
2303 :
2304 0 : if (sampled_area.y >= extents.y &&
2305 0 : sampled_area.y + (int) sampled_area.height <= extents.y + (int) extents.height)
2306 : {
2307 : /* source is vertically contained within extents, trim */
2308 0 : extents.y = sampled_area.y;
2309 0 : extents.height = sampled_area.height;
2310 0 : trim |= 0x2;
2311 : }
2312 :
2313 0 : if (trim == 0x3) {
2314 : /* source is wholly contained within extents, drop the REPEAT */
2315 0 : attr->extend = CAIRO_EXTEND_NONE;
2316 : }
2317 :
2318 0 : is_empty = extents.width == 0 || extents.height == 0;
2319 : }
2320 : }
2321 :
2322 : /* XXX can we use is_empty? */
2323 :
2324 0 : status = _cairo_surface_clone_similar (dst, surface,
2325 : extents.x, extents.y,
2326 : extents.width, extents.height,
2327 : &x, &y, out);
2328 0 : if (unlikely (status))
2329 0 : goto BAIL;
2330 :
2331 0 : if (x != 0 || y != 0) {
2332 0 : if (is_identity) {
2333 0 : attr->x_offset -= x;
2334 0 : attr->y_offset -= y;
2335 : } else {
2336 : cairo_matrix_t m;
2337 :
2338 0 : x -= attr->x_offset;
2339 0 : y -= attr->y_offset;
2340 0 : attr->x_offset = 0;
2341 0 : attr->y_offset = 0;
2342 :
2343 0 : cairo_matrix_init_translate (&m, -x, -y);
2344 0 : cairo_matrix_multiply (&attr->matrix, &attr->matrix, &m);
2345 : }
2346 : }
2347 :
2348 : /* reduce likelihood of range overflow with large downscaling */
2349 0 : if (! is_identity) {
2350 : cairo_matrix_t m;
2351 : cairo_status_t invert_status;
2352 :
2353 0 : m = attr->matrix;
2354 0 : invert_status = cairo_matrix_invert (&m);
2355 0 : assert (invert_status == CAIRO_STATUS_SUCCESS);
2356 :
2357 0 : if (m.x0 != 0. || m.y0 != 0.) {
2358 : /* pixman also limits the [xy]_offset to 16 bits so evenly
2359 : * spread the bits between the two.
2360 : */
2361 0 : x = floor (m.x0 / 2);
2362 0 : y = floor (m.y0 / 2);
2363 0 : attr->x_offset -= x;
2364 0 : attr->y_offset -= y;
2365 0 : cairo_matrix_init_translate (&m, x, y);
2366 0 : cairo_matrix_multiply (&attr->matrix, &m, &attr->matrix);
2367 : }
2368 : }
2369 :
2370 : BAIL:
2371 0 : cairo_surface_destroy (surface);
2372 0 : return status;
2373 : }
2374 :
2375 : /**
2376 : * _cairo_pattern_acquire_surface:
2377 : * @pattern: a #cairo_pattern_t
2378 : * @dst: destination surface
2379 : * @x: X coordinate in source corresponding to left side of destination area
2380 : * @y: Y coordinate in source corresponding to top side of destination area
2381 : * @width: width of destination area
2382 : * @height: height of destination area
2383 : * @surface_out: location to store a pointer to a surface
2384 : * @attributes: surface attributes that destination backend should apply to
2385 : * the returned surface
2386 : *
2387 : * A convenience function to obtain a surface to use as the source for
2388 : * drawing on @dst.
2389 : *
2390 : * Note that this function is only suitable for use when the destination
2391 : * surface is pixel based and 1 device unit maps to one pixel.
2392 : *
2393 : * Return value: %CAIRO_STATUS_SUCCESS if a surface was stored in @surface_out.
2394 : **/
2395 : cairo_int_status_t
2396 0 : _cairo_pattern_acquire_surface (const cairo_pattern_t *pattern,
2397 : cairo_surface_t *dst,
2398 : int x,
2399 : int y,
2400 : unsigned int width,
2401 : unsigned int height,
2402 : unsigned int flags,
2403 : cairo_surface_t **surface_out,
2404 : cairo_surface_attributes_t *attributes)
2405 : {
2406 0 : if (unlikely (pattern->status)) {
2407 0 : *surface_out = NULL;
2408 0 : return pattern->status;
2409 : }
2410 :
2411 0 : switch (pattern->type) {
2412 : case CAIRO_PATTERN_TYPE_SOLID:
2413 0 : return _cairo_pattern_acquire_surface_for_solid ((cairo_solid_pattern_t *) pattern,
2414 : dst, x, y, width, height,
2415 : surface_out,
2416 : attributes);
2417 :
2418 : case CAIRO_PATTERN_TYPE_LINEAR:
2419 : case CAIRO_PATTERN_TYPE_RADIAL:
2420 0 : return _cairo_pattern_acquire_surface_for_gradient ((cairo_gradient_pattern_t *) pattern,
2421 : dst, x, y, width, height,
2422 : surface_out,
2423 : attributes);
2424 :
2425 : case CAIRO_PATTERN_TYPE_SURFACE:
2426 0 : return _cairo_pattern_acquire_surface_for_surface ((cairo_surface_pattern_t *) pattern,
2427 : dst, x, y, width, height,
2428 : flags,
2429 : surface_out,
2430 : attributes);
2431 :
2432 : default:
2433 0 : ASSERT_NOT_REACHED;
2434 0 : return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
2435 : }
2436 : }
2437 :
2438 : /**
2439 : * _cairo_pattern_release_surface:
2440 : * @pattern: a #cairo_pattern_t
2441 : * @surface: a surface obtained by _cairo_pattern_acquire_surface
2442 : * @attributes: attributes obtained by _cairo_pattern_acquire_surface
2443 : *
2444 : * Releases resources obtained by _cairo_pattern_acquire_surface.
2445 : **/
2446 : void
2447 0 : _cairo_pattern_release_surface (const cairo_pattern_t *pattern,
2448 : cairo_surface_t *surface,
2449 : cairo_surface_attributes_t *attributes)
2450 : {
2451 0 : cairo_surface_destroy (surface);
2452 0 : }
2453 :
2454 : cairo_int_status_t
2455 0 : _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src,
2456 : const cairo_pattern_t *mask,
2457 : cairo_surface_t *dst,
2458 : int src_x,
2459 : int src_y,
2460 : int mask_x,
2461 : int mask_y,
2462 : unsigned int width,
2463 : unsigned int height,
2464 : unsigned int flags,
2465 : cairo_surface_t **src_out,
2466 : cairo_surface_t **mask_out,
2467 : cairo_surface_attributes_t *src_attributes,
2468 : cairo_surface_attributes_t *mask_attributes)
2469 : {
2470 : cairo_int_status_t status;
2471 : cairo_pattern_union_t src_tmp;
2472 :
2473 0 : if (unlikely (src->status))
2474 0 : return src->status;
2475 0 : if (unlikely (mask != NULL && mask->status))
2476 0 : return mask->status;
2477 :
2478 : /* If src and mask are both solid, then the mask alpha can be
2479 : * combined into src and mask can be ignored. */
2480 :
2481 0 : if (src->type == CAIRO_PATTERN_TYPE_SOLID &&
2482 0 : mask &&
2483 0 : ! mask->has_component_alpha &&
2484 0 : mask->type == CAIRO_PATTERN_TYPE_SOLID)
2485 : {
2486 : cairo_color_t combined;
2487 0 : cairo_solid_pattern_t *src_solid = (cairo_solid_pattern_t *) src;
2488 0 : cairo_solid_pattern_t *mask_solid = (cairo_solid_pattern_t *) mask;
2489 :
2490 0 : combined = src_solid->color;
2491 0 : _cairo_color_multiply_alpha (&combined, mask_solid->color.alpha);
2492 :
2493 0 : _cairo_pattern_init_solid (&src_tmp.solid, &combined);
2494 :
2495 0 : src = &src_tmp.base;
2496 0 : mask = NULL;
2497 : }
2498 :
2499 0 : status = _cairo_pattern_acquire_surface (src, dst,
2500 : src_x, src_y,
2501 : width, height,
2502 : flags,
2503 : src_out, src_attributes);
2504 0 : if (unlikely (status))
2505 0 : goto BAIL;
2506 :
2507 0 : if (mask == NULL) {
2508 0 : *mask_out = NULL;
2509 0 : goto BAIL;
2510 : }
2511 :
2512 0 : status = _cairo_pattern_acquire_surface (mask, dst,
2513 : mask_x, mask_y,
2514 : width, height,
2515 : flags,
2516 : mask_out, mask_attributes);
2517 0 : if (unlikely (status))
2518 0 : _cairo_pattern_release_surface (src, *src_out, src_attributes);
2519 :
2520 : BAIL:
2521 0 : if (src == &src_tmp.base)
2522 0 : _cairo_pattern_fini (&src_tmp.base);
2523 :
2524 0 : return status;
2525 : }
2526 :
2527 : /**
2528 : * _cairo_pattern_get_extents:
2529 : *
2530 : * Return the "target-space" extents of @pattern in @extents.
2531 : *
2532 : * For unbounded patterns, the @extents will be initialized with
2533 : * "infinite" extents, (minimum and maximum fixed-point values).
2534 : *
2535 : * XXX: Currently, bounded gradient patterns will also return
2536 : * "infinite" extents, though it would be possible to optimize these
2537 : * with a little more work.
2538 : **/
2539 : void
2540 0 : _cairo_pattern_get_extents (const cairo_pattern_t *pattern,
2541 : cairo_rectangle_int_t *extents)
2542 : {
2543 : double x1, y1, x2, y2;
2544 : cairo_status_t status;
2545 :
2546 0 : switch (pattern->type) {
2547 : case CAIRO_PATTERN_TYPE_SOLID:
2548 0 : goto UNBOUNDED;
2549 :
2550 : case CAIRO_PATTERN_TYPE_SURFACE:
2551 : {
2552 : cairo_rectangle_int_t surface_extents;
2553 0 : const cairo_surface_pattern_t *surface_pattern =
2554 : (const cairo_surface_pattern_t *) pattern;
2555 0 : cairo_surface_t *surface = surface_pattern->surface;
2556 : double pad;
2557 :
2558 0 : if (! _cairo_surface_get_extents (surface, &surface_extents))
2559 0 : goto UNBOUNDED;
2560 :
2561 0 : if (surface_extents.width == 0 || surface_extents.height == 0)
2562 : goto EMPTY;
2563 :
2564 0 : if (pattern->extend != CAIRO_EXTEND_NONE)
2565 0 : goto UNBOUNDED;
2566 :
2567 : /* The filter can effectively enlarge the extents of the
2568 : * pattern, so extend as necessary.
2569 : */
2570 0 : _cairo_pattern_analyze_filter (&surface_pattern->base, &pad);
2571 0 : x1 = surface_extents.x - pad;
2572 0 : y1 = surface_extents.y - pad;
2573 0 : x2 = surface_extents.x + (int) surface_extents.width + pad;
2574 0 : y2 = surface_extents.y + (int) surface_extents.height + pad;
2575 : }
2576 0 : break;
2577 :
2578 : case CAIRO_PATTERN_TYPE_RADIAL:
2579 : {
2580 0 : const cairo_radial_pattern_t *radial =
2581 : (const cairo_radial_pattern_t *) pattern;
2582 : double cx1, cy1;
2583 : double cx2, cy2;
2584 : double r, D;
2585 :
2586 0 : if (radial->r1 == 0 && radial->r2 == 0)
2587 0 : goto EMPTY;
2588 :
2589 0 : cx1 = _cairo_fixed_to_double (radial->c1.x);
2590 0 : cy1 = _cairo_fixed_to_double (radial->c1.y);
2591 0 : r = _cairo_fixed_to_double (radial->r1);
2592 0 : x1 = cx1 - r; x2 = cx1 + r;
2593 0 : y1 = cy1 - r; y2 = cy1 + r;
2594 :
2595 0 : cx2 = _cairo_fixed_to_double (radial->c2.x);
2596 0 : cy2 = _cairo_fixed_to_double (radial->c2.y);
2597 0 : r = fabs (_cairo_fixed_to_double (radial->r2));
2598 :
2599 0 : if (pattern->extend != CAIRO_EXTEND_NONE)
2600 0 : goto UNBOUNDED;
2601 :
2602 : /* We need to be careful, as if the circles are not
2603 : * self-contained, then the solution is actually unbounded.
2604 : */
2605 0 : D = (cx1-cx2)*(cx1-cx2) + (cy1-cy2)*(cy1-cy2);
2606 0 : if (D > r*r - 1e-5)
2607 0 : goto UNBOUNDED;
2608 :
2609 0 : if (cx2 - r < x1)
2610 0 : x1 = cx2 - r;
2611 0 : if (cx2 + r > x2)
2612 0 : x2 = cx2 + r;
2613 :
2614 0 : if (cy2 - r < y1)
2615 0 : y1 = cy2 - r;
2616 0 : if (cy2 + r > y2)
2617 0 : y2 = cy2 + r;
2618 : }
2619 0 : break;
2620 :
2621 : case CAIRO_PATTERN_TYPE_LINEAR:
2622 : {
2623 0 : const cairo_linear_pattern_t *linear =
2624 : (const cairo_linear_pattern_t *) pattern;
2625 :
2626 0 : if (pattern->extend != CAIRO_EXTEND_NONE)
2627 0 : goto UNBOUNDED;
2628 :
2629 0 : if (linear->p1.x == linear->p2.x && linear->p1.y == linear->p2.y)
2630 0 : goto EMPTY;
2631 :
2632 0 : if (pattern->matrix.xy != 0. || pattern->matrix.yx != 0.)
2633 : goto UNBOUNDED;
2634 :
2635 0 : if (linear->p1.x == linear->p2.x) {
2636 0 : x1 = -HUGE_VAL;
2637 0 : x2 = HUGE_VAL;
2638 0 : y1 = _cairo_fixed_to_double (MIN (linear->p1.y, linear->p2.y));
2639 0 : y2 = _cairo_fixed_to_double (MAX (linear->p1.y, linear->p2.y));
2640 0 : } else if (linear->p1.y == linear->p2.y) {
2641 0 : x1 = _cairo_fixed_to_double (MIN (linear->p1.x, linear->p2.x));
2642 0 : x2 = _cairo_fixed_to_double (MAX (linear->p1.x, linear->p2.x));
2643 0 : y1 = -HUGE_VAL;
2644 0 : y2 = HUGE_VAL;
2645 : } else {
2646 0 : goto UNBOUNDED;
2647 : }
2648 : }
2649 0 : break;
2650 :
2651 : default:
2652 0 : ASSERT_NOT_REACHED;
2653 : }
2654 :
2655 0 : if (_cairo_matrix_is_translation (&pattern->matrix)) {
2656 0 : x1 -= pattern->matrix.x0; x2 -= pattern->matrix.x0;
2657 0 : y1 -= pattern->matrix.y0; y2 -= pattern->matrix.y0;
2658 : } else {
2659 : cairo_matrix_t imatrix;
2660 :
2661 0 : imatrix = pattern->matrix;
2662 0 : status = cairo_matrix_invert (&imatrix);
2663 : /* cairo_pattern_set_matrix ensures the matrix is invertible */
2664 0 : assert (status == CAIRO_STATUS_SUCCESS);
2665 :
2666 0 : _cairo_matrix_transform_bounding_box (&imatrix,
2667 : &x1, &y1, &x2, &y2,
2668 : NULL);
2669 : }
2670 :
2671 0 : x1 = floor (x1);
2672 0 : if (x1 < CAIRO_RECT_INT_MIN)
2673 0 : x1 = CAIRO_RECT_INT_MIN;
2674 0 : y1 = floor (y1);
2675 0 : if (y1 < CAIRO_RECT_INT_MIN)
2676 0 : y1 = CAIRO_RECT_INT_MIN;
2677 :
2678 0 : x2 = ceil (x2);
2679 0 : if (x2 > CAIRO_RECT_INT_MAX)
2680 0 : x2 = CAIRO_RECT_INT_MAX;
2681 0 : y2 = ceil (y2);
2682 0 : if (y2 > CAIRO_RECT_INT_MAX)
2683 0 : y2 = CAIRO_RECT_INT_MAX;
2684 :
2685 0 : extents->x = x1; extents->width = x2 - x1;
2686 0 : extents->y = y1; extents->height = y2 - y1;
2687 0 : return;
2688 :
2689 : UNBOUNDED:
2690 : /* unbounded patterns -> 'infinite' extents */
2691 0 : _cairo_unbounded_rectangle_init (extents);
2692 0 : return;
2693 :
2694 : EMPTY:
2695 0 : extents->x = extents->y = 0;
2696 0 : extents->width = extents->height = 0;
2697 0 : return;
2698 : }
2699 :
2700 :
2701 : static unsigned long
2702 0 : _cairo_solid_pattern_hash (unsigned long hash,
2703 : const cairo_pattern_t *pattern)
2704 : {
2705 0 : const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
2706 :
2707 0 : hash = _cairo_hash_bytes (hash, &solid->color, sizeof (solid->color));
2708 :
2709 0 : return hash;
2710 : }
2711 :
2712 : static unsigned long
2713 0 : _cairo_gradient_color_stops_hash (unsigned long hash,
2714 : const cairo_gradient_pattern_t *gradient)
2715 : {
2716 : unsigned int n;
2717 :
2718 0 : hash = _cairo_hash_bytes (hash,
2719 0 : &gradient->n_stops,
2720 : sizeof (gradient->n_stops));
2721 :
2722 0 : for (n = 0; n < gradient->n_stops; n++) {
2723 0 : hash = _cairo_hash_bytes (hash,
2724 0 : &gradient->stops[n].offset,
2725 : sizeof (double));
2726 0 : hash = _cairo_hash_bytes (hash,
2727 0 : &gradient->stops[n].color,
2728 : sizeof (cairo_color_t));
2729 : }
2730 :
2731 0 : return hash;
2732 : }
2733 :
2734 : unsigned long
2735 0 : _cairo_linear_pattern_hash (unsigned long hash,
2736 : const cairo_linear_pattern_t *linear)
2737 : {
2738 0 : hash = _cairo_hash_bytes (hash, &linear->p1, sizeof (linear->p1));
2739 0 : hash = _cairo_hash_bytes (hash, &linear->p2, sizeof (linear->p2));
2740 :
2741 0 : return _cairo_gradient_color_stops_hash (hash, &linear->base);
2742 : }
2743 :
2744 : unsigned long
2745 0 : _cairo_radial_pattern_hash (unsigned long hash,
2746 : const cairo_radial_pattern_t *radial)
2747 : {
2748 0 : hash = _cairo_hash_bytes (hash, &radial->c1, sizeof (radial->c1));
2749 0 : hash = _cairo_hash_bytes (hash, &radial->r1, sizeof (radial->r1));
2750 0 : hash = _cairo_hash_bytes (hash, &radial->c2, sizeof (radial->c2));
2751 0 : hash = _cairo_hash_bytes (hash, &radial->r2, sizeof (radial->r2));
2752 :
2753 0 : return _cairo_gradient_color_stops_hash (hash, &radial->base);
2754 : }
2755 :
2756 : static unsigned long
2757 0 : _cairo_surface_pattern_hash (unsigned long hash,
2758 : const cairo_pattern_t *pattern)
2759 : {
2760 0 : const cairo_surface_pattern_t *surface = (cairo_surface_pattern_t *) pattern;
2761 :
2762 0 : hash ^= surface->surface->unique_id;
2763 :
2764 0 : return hash;
2765 : }
2766 :
2767 : unsigned long
2768 0 : _cairo_pattern_hash (const cairo_pattern_t *pattern)
2769 : {
2770 0 : unsigned long hash = _CAIRO_HASH_INIT_VALUE;
2771 :
2772 0 : if (pattern->status)
2773 0 : return 0;
2774 :
2775 0 : hash = _cairo_hash_bytes (hash, &pattern->type, sizeof (pattern->type));
2776 0 : if (pattern->type != CAIRO_PATTERN_TYPE_SOLID) {
2777 0 : hash = _cairo_hash_bytes (hash,
2778 0 : &pattern->matrix, sizeof (pattern->matrix));
2779 0 : hash = _cairo_hash_bytes (hash,
2780 0 : &pattern->filter, sizeof (pattern->filter));
2781 0 : hash = _cairo_hash_bytes (hash,
2782 0 : &pattern->extend, sizeof (pattern->extend));
2783 0 : hash = _cairo_hash_bytes (hash,
2784 0 : &pattern->has_component_alpha,
2785 : sizeof (pattern->has_component_alpha));
2786 : }
2787 :
2788 0 : switch (pattern->type) {
2789 : case CAIRO_PATTERN_TYPE_SOLID:
2790 0 : return _cairo_solid_pattern_hash (hash, pattern);
2791 : case CAIRO_PATTERN_TYPE_LINEAR:
2792 0 : return _cairo_linear_pattern_hash (hash, (cairo_linear_pattern_t *) pattern);
2793 : case CAIRO_PATTERN_TYPE_RADIAL:
2794 0 : return _cairo_radial_pattern_hash (hash, (cairo_radial_pattern_t *) pattern);
2795 : case CAIRO_PATTERN_TYPE_SURFACE:
2796 0 : return _cairo_surface_pattern_hash (hash, pattern);
2797 : default:
2798 0 : ASSERT_NOT_REACHED;
2799 0 : return FALSE;
2800 : }
2801 : }
2802 :
2803 : static unsigned long
2804 0 : _cairo_gradient_pattern_color_stops_size (const cairo_pattern_t *pattern)
2805 : {
2806 0 : cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern;
2807 :
2808 0 : return gradient->n_stops * (sizeof (double) + sizeof (cairo_color_t));
2809 : }
2810 :
2811 : unsigned long
2812 0 : _cairo_pattern_size (const cairo_pattern_t *pattern)
2813 : {
2814 0 : if (pattern->status)
2815 0 : return 0;
2816 :
2817 : /* XXX */
2818 0 : switch (pattern->type) {
2819 : case CAIRO_PATTERN_TYPE_SOLID:
2820 0 : return sizeof (cairo_solid_pattern_t);
2821 : break;
2822 : case CAIRO_PATTERN_TYPE_SURFACE:
2823 0 : return sizeof (cairo_surface_pattern_t);
2824 : break;
2825 : case CAIRO_PATTERN_TYPE_LINEAR:
2826 0 : return sizeof (cairo_linear_pattern_t) +
2827 0 : _cairo_gradient_pattern_color_stops_size (pattern);
2828 : break;
2829 : case CAIRO_PATTERN_TYPE_RADIAL:
2830 0 : return sizeof (cairo_radial_pattern_t) +
2831 0 : _cairo_gradient_pattern_color_stops_size (pattern);
2832 : default:
2833 0 : ASSERT_NOT_REACHED;
2834 0 : return 0;
2835 : }
2836 : }
2837 :
2838 :
2839 : static cairo_bool_t
2840 0 : _cairo_solid_pattern_equal (const cairo_pattern_t *A,
2841 : const cairo_pattern_t *B)
2842 : {
2843 0 : const cairo_solid_pattern_t *a = (cairo_solid_pattern_t *) A;
2844 0 : const cairo_solid_pattern_t *b = (cairo_solid_pattern_t *) B;
2845 :
2846 0 : return _cairo_color_equal (&a->color, &b->color);
2847 : }
2848 :
2849 : static cairo_bool_t
2850 0 : _cairo_gradient_color_stops_equal (const cairo_gradient_pattern_t *a,
2851 : const cairo_gradient_pattern_t *b)
2852 : {
2853 : unsigned int n;
2854 :
2855 0 : if (a->n_stops != b->n_stops)
2856 0 : return FALSE;
2857 :
2858 0 : for (n = 0; n < a->n_stops; n++) {
2859 0 : if (a->stops[n].offset != b->stops[n].offset)
2860 0 : return FALSE;
2861 0 : if (! _cairo_color_stop_equal (&a->stops[n].color, &b->stops[n].color))
2862 0 : return FALSE;
2863 : }
2864 :
2865 0 : return TRUE;
2866 : }
2867 :
2868 : cairo_bool_t
2869 0 : _cairo_linear_pattern_equal (const cairo_linear_pattern_t *a,
2870 : const cairo_linear_pattern_t *b)
2871 : {
2872 0 : if (a->p1.x != b->p1.x)
2873 0 : return FALSE;
2874 :
2875 0 : if (a->p1.y != b->p1.y)
2876 0 : return FALSE;
2877 :
2878 0 : if (a->p2.x != b->p2.x)
2879 0 : return FALSE;
2880 :
2881 0 : if (a->p2.y != b->p2.y)
2882 0 : return FALSE;
2883 :
2884 0 : return _cairo_gradient_color_stops_equal (&a->base, &b->base);
2885 : }
2886 :
2887 : cairo_bool_t
2888 0 : _cairo_radial_pattern_equal (const cairo_radial_pattern_t *a,
2889 : const cairo_radial_pattern_t *b)
2890 : {
2891 0 : if (a->c1.x != b->c1.x)
2892 0 : return FALSE;
2893 :
2894 0 : if (a->c1.y != b->c1.y)
2895 0 : return FALSE;
2896 :
2897 0 : if (a->r1 != b->r1)
2898 0 : return FALSE;
2899 :
2900 0 : if (a->c2.x != b->c2.x)
2901 0 : return FALSE;
2902 :
2903 0 : if (a->c2.y != b->c2.y)
2904 0 : return FALSE;
2905 :
2906 0 : if (a->r2 != b->r2)
2907 0 : return FALSE;
2908 :
2909 0 : return _cairo_gradient_color_stops_equal (&a->base, &b->base);
2910 : }
2911 :
2912 : static cairo_bool_t
2913 0 : _cairo_surface_pattern_equal (const cairo_pattern_t *A,
2914 : const cairo_pattern_t *B)
2915 : {
2916 0 : const cairo_surface_pattern_t *a = (cairo_surface_pattern_t *) A;
2917 0 : const cairo_surface_pattern_t *b = (cairo_surface_pattern_t *) B;
2918 :
2919 0 : return a->surface->unique_id == b->surface->unique_id;
2920 : }
2921 :
2922 : cairo_bool_t
2923 0 : _cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b)
2924 : {
2925 0 : if (a->status || b->status)
2926 0 : return FALSE;
2927 :
2928 0 : if (a == b)
2929 0 : return TRUE;
2930 :
2931 0 : if (a->type != b->type)
2932 0 : return FALSE;
2933 :
2934 0 : if (a->has_component_alpha != b->has_component_alpha)
2935 0 : return FALSE;
2936 :
2937 0 : if (a->type != CAIRO_PATTERN_TYPE_SOLID) {
2938 0 : if (memcmp (&a->matrix, &b->matrix, sizeof (cairo_matrix_t)))
2939 0 : return FALSE;
2940 :
2941 0 : if (a->filter != b->filter)
2942 0 : return FALSE;
2943 :
2944 0 : if (a->extend != b->extend)
2945 0 : return FALSE;
2946 : }
2947 :
2948 0 : switch (a->type) {
2949 : case CAIRO_PATTERN_TYPE_SOLID:
2950 0 : return _cairo_solid_pattern_equal (a, b);
2951 : case CAIRO_PATTERN_TYPE_LINEAR:
2952 0 : return _cairo_linear_pattern_equal ((cairo_linear_pattern_t *) a,
2953 : (cairo_linear_pattern_t *) b);
2954 : case CAIRO_PATTERN_TYPE_RADIAL:
2955 0 : return _cairo_radial_pattern_equal ((cairo_radial_pattern_t *) a,
2956 : (cairo_radial_pattern_t *) b);
2957 : case CAIRO_PATTERN_TYPE_SURFACE:
2958 0 : return _cairo_surface_pattern_equal (a, b);
2959 : default:
2960 0 : ASSERT_NOT_REACHED;
2961 0 : return FALSE;
2962 : }
2963 : }
2964 :
2965 : /**
2966 : * cairo_pattern_get_rgba
2967 : * @pattern: a #cairo_pattern_t
2968 : * @red: return value for red component of color, or %NULL
2969 : * @green: return value for green component of color, or %NULL
2970 : * @blue: return value for blue component of color, or %NULL
2971 : * @alpha: return value for alpha component of color, or %NULL
2972 : *
2973 : * Gets the solid color for a solid color pattern.
2974 : *
2975 : * Return value: %CAIRO_STATUS_SUCCESS, or
2976 : * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if the pattern is not a solid
2977 : * color pattern.
2978 : *
2979 : * Since: 1.4
2980 : **/
2981 : cairo_status_t
2982 0 : cairo_pattern_get_rgba (cairo_pattern_t *pattern,
2983 : double *red, double *green,
2984 : double *blue, double *alpha)
2985 : {
2986 0 : cairo_solid_pattern_t *solid = (cairo_solid_pattern_t*) pattern;
2987 : double r0, g0, b0, a0;
2988 :
2989 0 : if (pattern->status)
2990 0 : return pattern->status;
2991 :
2992 0 : if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
2993 0 : return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
2994 :
2995 0 : _cairo_color_get_rgba (&solid->color, &r0, &g0, &b0, &a0);
2996 :
2997 0 : if (red)
2998 0 : *red = r0;
2999 0 : if (green)
3000 0 : *green = g0;
3001 0 : if (blue)
3002 0 : *blue = b0;
3003 0 : if (alpha)
3004 0 : *alpha = a0;
3005 :
3006 0 : return CAIRO_STATUS_SUCCESS;
3007 : }
3008 :
3009 : /**
3010 : * cairo_pattern_get_surface
3011 : * @pattern: a #cairo_pattern_t
3012 : * @surface: return value for surface of pattern, or %NULL
3013 : *
3014 : * Gets the surface of a surface pattern. The reference returned in
3015 : * @surface is owned by the pattern; the caller should call
3016 : * cairo_surface_reference() if the surface is to be retained.
3017 : *
3018 : * Return value: %CAIRO_STATUS_SUCCESS, or
3019 : * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if the pattern is not a surface
3020 : * pattern.
3021 : *
3022 : * Since: 1.4
3023 : **/
3024 : cairo_status_t
3025 0 : cairo_pattern_get_surface (cairo_pattern_t *pattern,
3026 : cairo_surface_t **surface)
3027 : {
3028 0 : cairo_surface_pattern_t *spat = (cairo_surface_pattern_t*) pattern;
3029 :
3030 0 : if (pattern->status)
3031 0 : return pattern->status;
3032 :
3033 0 : if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
3034 0 : return CAIRO_STATUS_PATTERN_TYPE_MISMATCH;
3035 :
3036 0 : if (surface)
3037 0 : *surface = spat->surface;
3038 :
3039 0 : return CAIRO_STATUS_SUCCESS;
3040 : }
3041 :
3042 : /**
3043 : * cairo_pattern_get_color_stop_rgba
3044 : * @pattern: a #cairo_pattern_t
3045 : * @index: index of the stop to return data for
3046 : * @offset: return value for the offset of the stop, or %NULL
3047 : * @red: return value for red component of color, or %NULL
3048 : * @green: return value for green component of color, or %NULL
3049 : * @blue: return value for blue component of color, or %NULL
3050 : * @alpha: return value for alpha component of color, or %NULL
3051 : *
3052 : * Gets the color and offset information at the given @index for a
3053 : * gradient pattern. Values of @index are 0 to 1 less than the number
3054 : * returned by cairo_pattern_get_color_stop_count().
3055 : *
3056 : * Return value: %CAIRO_STATUS_SUCCESS, or %CAIRO_STATUS_INVALID_INDEX
3057 : * if @index is not valid for the given pattern. If the pattern is
3058 : * not a gradient pattern, %CAIRO_STATUS_PATTERN_TYPE_MISMATCH is
3059 : * returned.
3060 : *
3061 : * Since: 1.4
3062 : **/
3063 : cairo_status_t
3064 0 : cairo_pattern_get_color_stop_rgba (cairo_pattern_t *pattern,
3065 : int index, double *offset,
3066 : double *red, double *green,
3067 : double *blue, double *alpha)
3068 : {
3069 0 : cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t*) pattern;
3070 :
3071 0 : if (pattern->status)
3072 0 : return pattern->status;
3073 :
3074 0 : if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR &&
3075 0 : pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
3076 0 : return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
3077 :
3078 0 : if (index < 0 || (unsigned int) index >= gradient->n_stops)
3079 0 : return _cairo_error (CAIRO_STATUS_INVALID_INDEX);
3080 :
3081 0 : if (offset)
3082 0 : *offset = gradient->stops[index].offset;
3083 0 : if (red)
3084 0 : *red = gradient->stops[index].color.red;
3085 0 : if (green)
3086 0 : *green = gradient->stops[index].color.green;
3087 0 : if (blue)
3088 0 : *blue = gradient->stops[index].color.blue;
3089 0 : if (alpha)
3090 0 : *alpha = gradient->stops[index].color.alpha;
3091 :
3092 0 : return CAIRO_STATUS_SUCCESS;
3093 : }
3094 :
3095 : /**
3096 : * cairo_pattern_get_color_stop_count
3097 : * @pattern: a #cairo_pattern_t
3098 : * @count: return value for the number of color stops, or %NULL
3099 : *
3100 : * Gets the number of color stops specified in the given gradient
3101 : * pattern.
3102 : *
3103 : * Return value: %CAIRO_STATUS_SUCCESS, or
3104 : * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a gradient
3105 : * pattern.
3106 : *
3107 : * Since: 1.4
3108 : */
3109 : cairo_status_t
3110 0 : cairo_pattern_get_color_stop_count (cairo_pattern_t *pattern,
3111 : int *count)
3112 : {
3113 0 : cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t*) pattern;
3114 :
3115 0 : if (pattern->status)
3116 0 : return pattern->status;
3117 :
3118 0 : if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR &&
3119 0 : pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
3120 0 : return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
3121 :
3122 0 : if (count)
3123 0 : *count = gradient->n_stops;
3124 :
3125 0 : return CAIRO_STATUS_SUCCESS;
3126 : }
3127 :
3128 : /**
3129 : * cairo_pattern_get_linear_points
3130 : * @pattern: a #cairo_pattern_t
3131 : * @x0: return value for the x coordinate of the first point, or %NULL
3132 : * @y0: return value for the y coordinate of the first point, or %NULL
3133 : * @x1: return value for the x coordinate of the second point, or %NULL
3134 : * @y1: return value for the y coordinate of the second point, or %NULL
3135 : *
3136 : * Gets the gradient endpoints for a linear gradient.
3137 : *
3138 : * Return value: %CAIRO_STATUS_SUCCESS, or
3139 : * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a linear
3140 : * gradient pattern.
3141 : *
3142 : * Since: 1.4
3143 : **/
3144 : cairo_status_t
3145 0 : cairo_pattern_get_linear_points (cairo_pattern_t *pattern,
3146 : double *x0, double *y0,
3147 : double *x1, double *y1)
3148 : {
3149 0 : cairo_linear_pattern_t *linear = (cairo_linear_pattern_t*) pattern;
3150 :
3151 0 : if (pattern->status)
3152 0 : return pattern->status;
3153 :
3154 0 : if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR)
3155 0 : return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
3156 :
3157 0 : if (x0)
3158 0 : *x0 = _cairo_fixed_to_double (linear->p1.x);
3159 0 : if (y0)
3160 0 : *y0 = _cairo_fixed_to_double (linear->p1.y);
3161 0 : if (x1)
3162 0 : *x1 = _cairo_fixed_to_double (linear->p2.x);
3163 0 : if (y1)
3164 0 : *y1 = _cairo_fixed_to_double (linear->p2.y);
3165 :
3166 0 : return CAIRO_STATUS_SUCCESS;
3167 : }
3168 :
3169 : /**
3170 : * cairo_pattern_get_radial_circles
3171 : * @pattern: a #cairo_pattern_t
3172 : * @x0: return value for the x coordinate of the center of the first circle, or %NULL
3173 : * @y0: return value for the y coordinate of the center of the first circle, or %NULL
3174 : * @r0: return value for the radius of the first circle, or %NULL
3175 : * @x1: return value for the x coordinate of the center of the second circle, or %NULL
3176 : * @y1: return value for the y coordinate of the center of the second circle, or %NULL
3177 : * @r1: return value for the radius of the second circle, or %NULL
3178 : *
3179 : * Gets the gradient endpoint circles for a radial gradient, each
3180 : * specified as a center coordinate and a radius.
3181 : *
3182 : * Return value: %CAIRO_STATUS_SUCCESS, or
3183 : * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a radial
3184 : * gradient pattern.
3185 : *
3186 : * Since: 1.4
3187 : **/
3188 : cairo_status_t
3189 0 : cairo_pattern_get_radial_circles (cairo_pattern_t *pattern,
3190 : double *x0, double *y0, double *r0,
3191 : double *x1, double *y1, double *r1)
3192 : {
3193 0 : cairo_radial_pattern_t *radial = (cairo_radial_pattern_t*) pattern;
3194 :
3195 0 : if (pattern->status)
3196 0 : return pattern->status;
3197 :
3198 0 : if (pattern->type != CAIRO_PATTERN_TYPE_RADIAL)
3199 0 : return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH);
3200 :
3201 0 : if (x0)
3202 0 : *x0 = _cairo_fixed_to_double (radial->c1.x);
3203 0 : if (y0)
3204 0 : *y0 = _cairo_fixed_to_double (radial->c1.y);
3205 0 : if (r0)
3206 0 : *r0 = _cairo_fixed_to_double (radial->r1);
3207 0 : if (x1)
3208 0 : *x1 = _cairo_fixed_to_double (radial->c2.x);
3209 0 : if (y1)
3210 0 : *y1 = _cairo_fixed_to_double (radial->c2.y);
3211 0 : if (r1)
3212 0 : *r1 = _cairo_fixed_to_double (radial->r2);
3213 :
3214 0 : return CAIRO_STATUS_SUCCESS;
3215 : }
3216 :
3217 : void
3218 0 : _cairo_pattern_reset_static_data (void)
3219 : {
3220 : #if HAS_FREED_POOL
3221 : int i;
3222 :
3223 0 : for (i = 0; i < ARRAY_LENGTH (freed_pattern_pool); i++)
3224 0 : _freed_pool_reset (&freed_pattern_pool[i]);
3225 : #endif
3226 :
3227 0 : _cairo_pattern_reset_solid_surface_cache ();
3228 0 : }
|