Rev 1892 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1892 | Rev 3959 | ||
---|---|---|---|
Line 27... | Line 27... | ||
27 | * Keith Packard |
27 | * Keith Packard |
28 | * Carl Worth |
28 | * Carl Worth |
29 | */ |
29 | */ |
Line 30... | Line 30... | ||
30 | 30 | ||
- | 31 | #include "cairoint.h" |
|
- | 32 | ||
31 | #include "cairoint.h" |
33 | #include "cairo-array-private.h" |
32 | #include "cairo-error-private.h" |
34 | #include "cairo-error-private.h" |
- | 35 | #include "cairo-freed-pool-private.h" |
|
- | 36 | #include "cairo-image-surface-private.h" |
|
- | 37 | #include "cairo-list-inline.h" |
|
- | 38 | #include "cairo-path-private.h" |
|
- | 39 | #include "cairo-pattern-private.h" |
|
- | 40 | #include "cairo-recording-surface-inline.h" |
|
- | 41 | #include "cairo-surface-snapshot-inline.h" |
|
- | 42 | ||
- | 43 | #include |
|
- | 44 | ||
Line 33... | Line 45... | ||
33 | #include "cairo-freed-pool-private.h" |
45 | #define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */ |
34 | 46 | ||
35 | /** |
47 | /** |
36 | * SECTION:cairo-pattern |
48 | * SECTION:cairo-pattern |
Line 42... | Line 54... | ||
42 | * The primary use of patterns is as the source for all cairo drawing |
54 | * 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 |
55 | * operations, although they can also be used as masks, that is, as the |
44 | * brush too. |
56 | * brush too. |
45 | * |
57 | * |
46 | * A cairo pattern is created by using one of the many constructors, |
58 | * A cairo pattern is created by using one of the many constructors, |
- | 59 | * of the form |
|
47 | * of the form cairo_pattern_create_ |
60 | * |
48 | * or implicitly through |
61 | * or implicitly through |
49 | * cairo_set_source_ |
62 | * |
- | 63 | * functions. |
|
50 | */ |
64 | **/ |
Line 51... | Line -... | ||
51 | - | ||
52 | #if HAS_FREED_POOL |
65 | |
53 | static freed_pool_t freed_pattern_pool[4]; |
- | |
Line 54... | Line 66... | ||
54 | #endif |
66 | static freed_pool_t freed_pattern_pool[5]; |
55 | 67 | ||
56 | static const cairo_solid_pattern_t _cairo_pattern_nil = { |
68 | static const cairo_solid_pattern_t _cairo_pattern_nil = { |
57 | { CAIRO_PATTERN_TYPE_SOLID, /* type */ |
69 | { |
58 | CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ |
70 | CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ |
59 | CAIRO_STATUS_NO_MEMORY, /* status */ |
71 | CAIRO_STATUS_NO_MEMORY, /* status */ |
- | 72 | { 0, 0, 0, NULL }, /* user_data */ |
|
- | 73 | { NULL, NULL }, /* observers */ |
|
60 | { 0, 0, 0, NULL }, /* user_data */ |
74 | |
61 | { 1., 0., 0., 1., 0., 0., }, /* matrix */ |
75 | CAIRO_PATTERN_TYPE_SOLID, /* type */ |
- | 76 | CAIRO_FILTER_DEFAULT, /* filter */ |
|
- | 77 | CAIRO_EXTEND_GRADIENT_DEFAULT, /* extend */ |
|
- | 78 | FALSE, /* has component alpha */ |
|
- | 79 | { 1., 0., 0., 1., 0., 0., }, /* matrix */ |
|
62 | CAIRO_FILTER_DEFAULT, /* filter */ |
80 | 1.0 /* opacity */ |
Line 63... | Line 81... | ||
63 | CAIRO_EXTEND_GRADIENT_DEFAULT }, /* extend */ |
81 | } |
64 | }; |
82 | }; |
65 | 83 | ||
66 | static const cairo_solid_pattern_t _cairo_pattern_nil_null_pointer = { |
84 | static const cairo_solid_pattern_t _cairo_pattern_nil_null_pointer = { |
67 | { CAIRO_PATTERN_TYPE_SOLID, /* type */ |
85 | { |
68 | CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ |
86 | CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ |
- | 87 | CAIRO_STATUS_NULL_POINTER, /* status */ |
|
- | 88 | { 0, 0, 0, NULL }, /* user_data */ |
|
69 | CAIRO_STATUS_NULL_POINTER, /* status */ |
89 | { NULL, NULL }, /* observers */ |
70 | { 0, 0, 0, NULL }, /* user_data */ |
90 | |
- | 91 | CAIRO_PATTERN_TYPE_SOLID, /* type */ |
|
- | 92 | CAIRO_FILTER_DEFAULT, /* filter */ |
|
- | 93 | CAIRO_EXTEND_GRADIENT_DEFAULT, /* extend */ |
|
- | 94 | FALSE, /* has component alpha */ |
|
71 | { 1., 0., 0., 1., 0., 0., }, /* matrix */ |
95 | { 1., 0., 0., 1., 0., 0., }, /* matrix */ |
Line 72... | Line 96... | ||
72 | CAIRO_FILTER_DEFAULT, /* filter */ |
96 | 1.0 /* opacity */ |
73 | CAIRO_EXTEND_GRADIENT_DEFAULT }, /* extend */ |
97 | } |
74 | }; |
98 | }; |
75 | 99 | ||
76 | const cairo_solid_pattern_t _cairo_pattern_black = { |
100 | const cairo_solid_pattern_t _cairo_pattern_black = { |
- | 101 | { |
|
- | 102 | CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ |
|
- | 103 | CAIRO_STATUS_SUCCESS, /* status */ |
|
- | 104 | { 0, 0, 0, NULL }, /* user_data */ |
|
- | 105 | { NULL, NULL }, /* observers */ |
|
- | 106 | ||
77 | { CAIRO_PATTERN_TYPE_SOLID, /* type */ |
107 | CAIRO_PATTERN_TYPE_SOLID, /* type */ |
78 | CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ |
108 | CAIRO_FILTER_NEAREST, /* filter */ |
79 | CAIRO_STATUS_SUCCESS, /* status */ |
109 | CAIRO_EXTEND_REPEAT, /* extend */ |
80 | { 0, 0, 0, NULL }, /* user_data */ |
110 | FALSE, /* has component alpha */ |
81 | { 1., 0., 0., 1., 0., 0., }, /* matrix */ |
111 | { 1., 0., 0., 1., 0., 0., }, /* matrix */ |
Line 82... | Line 112... | ||
82 | CAIRO_FILTER_DEFAULT, /* filter */ |
112 | 1.0 /* opacity */ |
83 | CAIRO_EXTEND_GRADIENT_DEFAULT}, /* extend */ |
113 | }, |
84 | { 0., 0., 0., 1., 0, 0, 0, 0xffff },/* color (double rgba, short rgba) */ |
114 | { 0., 0., 0., 1., 0, 0, 0, 0xffff },/* color (double rgba, short rgba) */ |
85 | }; |
115 | }; |
86 | 116 | ||
- | 117 | const cairo_solid_pattern_t _cairo_pattern_clear = { |
|
- | 118 | { |
|
- | 119 | CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ |
|
- | 120 | CAIRO_STATUS_SUCCESS, /* status */ |
|
- | 121 | { 0, 0, 0, NULL }, /* user_data */ |
|
- | 122 | { NULL, NULL }, /* observers */ |
|
87 | const cairo_solid_pattern_t _cairo_pattern_clear = { |
123 | |
88 | { CAIRO_PATTERN_TYPE_SOLID, /* type */ |
124 | CAIRO_PATTERN_TYPE_SOLID, /* type */ |
89 | CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ |
125 | CAIRO_FILTER_NEAREST, /* filter */ |
90 | CAIRO_STATUS_SUCCESS, /* status */ |
126 | CAIRO_EXTEND_REPEAT, /* extend */ |
91 | { 0, 0, 0, NULL }, /* user_data */ |
127 | FALSE, /* has component alpha */ |
Line 92... | Line 128... | ||
92 | { 1., 0., 0., 1., 0., 0., }, /* matrix */ |
128 | { 1., 0., 0., 1., 0., 0., }, /* matrix */ |
93 | CAIRO_FILTER_DEFAULT, /* filter */ |
129 | 1.0 /* opacity */ |
94 | CAIRO_EXTEND_GRADIENT_DEFAULT}, /* extend */ |
130 | }, |
95 | { 0., 0., 0., 0., 0, 0, 0, 0 },/* color (double rgba, short rgba) */ |
131 | { 0., 0., 0., 0., 0, 0, 0, 0 },/* color (double rgba, short rgba) */ |
96 | }; |
132 | }; |
- | 133 | ||
- | 134 | const cairo_solid_pattern_t _cairo_pattern_white = { |
|
- | 135 | { |
|
- | 136 | CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ |
|
- | 137 | CAIRO_STATUS_SUCCESS, /* status */ |
|
- | 138 | { 0, 0, 0, NULL }, /* user_data */ |
|
97 | 139 | { NULL, NULL }, /* observers */ |
|
98 | const cairo_solid_pattern_t _cairo_pattern_white = { |
140 | |
99 | { CAIRO_PATTERN_TYPE_SOLID, /* type */ |
141 | CAIRO_PATTERN_TYPE_SOLID, /* type */ |
100 | CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ |
142 | CAIRO_FILTER_NEAREST, /* filter */ |
101 | CAIRO_STATUS_SUCCESS, /* status */ |
143 | CAIRO_EXTEND_REPEAT, /* extend */ |
Line -... | Line 144... | ||
- | 144 | FALSE, /* has component alpha */ |
|
- | 145 | { 1., 0., 0., 1., 0., 0., }, /* matrix */ |
|
- | 146 | 1.0 /* opacity */ |
|
- | 147 | }, |
|
- | 148 | { 1., 1., 1., 1., 0xffff, 0xffff, 0xffff, 0xffff },/* color (double rgba, short rgba) */ |
|
- | 149 | }; |
|
- | 150 | ||
- | 151 | static void |
|
- | 152 | _cairo_pattern_notify_observers (cairo_pattern_t *pattern, |
|
- | 153 | unsigned int flags) |
|
102 | { 0, 0, 0, NULL }, /* user_data */ |
154 | { |
103 | { 1., 0., 0., 1., 0., 0., }, /* matrix */ |
155 | cairo_pattern_observer_t *pos; |
104 | CAIRO_FILTER_DEFAULT, /* filter */ |
156 | |
105 | CAIRO_EXTEND_GRADIENT_DEFAULT}, /* extend */ |
157 | cairo_list_foreach_entry (pos, cairo_pattern_observer_t, &pattern->observers, link) |
106 | { 1., 1., 1., 1., 0xffff, 0xffff, 0xffff, 0xffff },/* color (double rgba, short rgba) */ |
158 | pos->notify (pos, pattern, flags); |
Line 135... | Line 187... | ||
135 | _cairo_status_set_error (&pattern->status, status); |
187 | _cairo_status_set_error (&pattern->status, status); |
Line 136... | Line 188... | ||
136 | 188 | ||
137 | return _cairo_error (status); |
189 | return _cairo_error (status); |
Line 138... | Line 190... | ||
138 | } |
190 | } |
139 | 191 | ||
140 | static void |
192 | void |
141 | _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type) |
193 | _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type) |
142 | { |
194 | { |
143 | #if HAVE_VALGRIND |
195 | #if HAVE_VALGRIND |
Line 152... | Line 204... | ||
152 | VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_linear_pattern_t)); |
204 | VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_linear_pattern_t)); |
153 | break; |
205 | break; |
154 | case CAIRO_PATTERN_TYPE_RADIAL: |
206 | case CAIRO_PATTERN_TYPE_RADIAL: |
155 | VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_radial_pattern_t)); |
207 | VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_radial_pattern_t)); |
156 | break; |
208 | break; |
- | 209 | case CAIRO_PATTERN_TYPE_MESH: |
|
- | 210 | VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_mesh_pattern_t)); |
|
- | 211 | break; |
|
- | 212 | case CAIRO_PATTERN_TYPE_RASTER_SOURCE: |
|
- | 213 | break; |
|
157 | } |
214 | } |
158 | #endif |
215 | #endif |
Line 159... | Line 216... | ||
159 | 216 | ||
160 | pattern->type = type; |
217 | pattern->type = type; |
Line 164... | Line 221... | ||
164 | * Callers needs to explicitly increment the count for heap allocations. */ |
221 | * Callers needs to explicitly increment the count for heap allocations. */ |
165 | CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 0); |
222 | CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 0); |
Line 166... | Line 223... | ||
166 | 223 | ||
Line 167... | Line 224... | ||
167 | _cairo_user_data_array_init (&pattern->user_data); |
224 | _cairo_user_data_array_init (&pattern->user_data); |
- | 225 | ||
168 | 226 | if (type == CAIRO_PATTERN_TYPE_SURFACE || |
|
169 | if (type == CAIRO_PATTERN_TYPE_SURFACE) |
227 | type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) |
170 | pattern->extend = CAIRO_EXTEND_SURFACE_DEFAULT; |
228 | pattern->extend = CAIRO_EXTEND_SURFACE_DEFAULT; |
Line 171... | Line 229... | ||
171 | else |
229 | else |
- | 230 | pattern->extend = CAIRO_EXTEND_GRADIENT_DEFAULT; |
|
Line 172... | Line 231... | ||
172 | pattern->extend = CAIRO_EXTEND_GRADIENT_DEFAULT; |
231 | |
Line 173... | Line 232... | ||
173 | 232 | pattern->filter = CAIRO_FILTER_DEFAULT; |
|
- | 233 | pattern->opacity = 1.0; |
|
- | 234 | ||
174 | pattern->filter = CAIRO_FILTER_DEFAULT; |
235 | pattern->has_component_alpha = FALSE; |
Line 175... | Line 236... | ||
175 | 236 | ||
176 | pattern->has_component_alpha = FALSE; |
237 | cairo_matrix_init_identity (&pattern->matrix); |
177 | 238 | ||
Line 217... | Line 278... | ||
217 | } |
278 | } |
Line 218... | Line 279... | ||
218 | 279 | ||
219 | return CAIRO_STATUS_SUCCESS; |
280 | return CAIRO_STATUS_SUCCESS; |
Line -... | Line 281... | ||
- | 281 | } |
|
- | 282 | ||
- | 283 | static cairo_status_t |
|
- | 284 | _cairo_mesh_pattern_init_copy (cairo_mesh_pattern_t *pattern, |
|
- | 285 | const cairo_mesh_pattern_t *other) |
|
- | 286 | { |
|
- | 287 | *pattern = *other; |
|
- | 288 | ||
- | 289 | _cairo_array_init (&pattern->patches, sizeof (cairo_mesh_patch_t)); |
|
- | 290 | return _cairo_array_append_multiple (&pattern->patches, |
|
- | 291 | _cairo_array_index_const (&other->patches, 0), |
|
- | 292 | _cairo_array_num_elements (&other->patches)); |
|
220 | } |
293 | } |
221 | 294 | ||
222 | cairo_status_t |
295 | cairo_status_t |
223 | _cairo_pattern_init_copy (cairo_pattern_t *pattern, |
296 | _cairo_pattern_init_copy (cairo_pattern_t *pattern, |
- | 297 | const cairo_pattern_t *other) |
|
- | 298 | { |
|
224 | const cairo_pattern_t *other) |
299 | cairo_status_t status; |
225 | { |
300 | |
Line 226... | Line 301... | ||
226 | if (other->status) |
301 | if (other->status) |
227 | return _cairo_pattern_set_error (pattern, other->status); |
302 | return _cairo_pattern_set_error (pattern, other->status); |
Line 246... | Line 321... | ||
246 | } break; |
321 | } break; |
247 | case CAIRO_PATTERN_TYPE_LINEAR: |
322 | case CAIRO_PATTERN_TYPE_LINEAR: |
248 | case CAIRO_PATTERN_TYPE_RADIAL: { |
323 | case CAIRO_PATTERN_TYPE_RADIAL: { |
249 | cairo_gradient_pattern_t *dst = (cairo_gradient_pattern_t *) pattern; |
324 | cairo_gradient_pattern_t *dst = (cairo_gradient_pattern_t *) pattern; |
250 | cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) other; |
325 | cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) other; |
251 | cairo_status_t status; |
- | |
Line 252... | Line 326... | ||
252 | 326 | ||
253 | if (other->type == CAIRO_PATTERN_TYPE_LINEAR) { |
327 | if (other->type == CAIRO_PATTERN_TYPE_LINEAR) { |
254 | VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_linear_pattern_t))); |
328 | VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_linear_pattern_t))); |
255 | } else { |
329 | } else { |
Line 259... | Line 333... | ||
259 | status = _cairo_gradient_pattern_init_copy (dst, src); |
333 | status = _cairo_gradient_pattern_init_copy (dst, src); |
260 | if (unlikely (status)) |
334 | if (unlikely (status)) |
261 | return status; |
335 | return status; |
Line 262... | Line 336... | ||
262 | 336 | ||
- | 337 | } break; |
|
- | 338 | case CAIRO_PATTERN_TYPE_MESH: { |
|
- | 339 | cairo_mesh_pattern_t *dst = (cairo_mesh_pattern_t *) pattern; |
|
- | 340 | cairo_mesh_pattern_t *src = (cairo_mesh_pattern_t *) other; |
|
- | 341 | ||
- | 342 | VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_mesh_pattern_t))); |
|
- | 343 | ||
- | 344 | status = _cairo_mesh_pattern_init_copy (dst, src); |
|
- | 345 | if (unlikely (status)) |
|
- | 346 | return status; |
|
- | 347 | ||
- | 348 | } break; |
|
- | 349 | ||
- | 350 | case CAIRO_PATTERN_TYPE_RASTER_SOURCE: { |
|
- | 351 | status = _cairo_raster_source_pattern_init_copy (pattern, other); |
|
- | 352 | if (unlikely (status)) |
|
- | 353 | return status; |
|
263 | } break; |
354 | } break; |
Line 264... | Line 355... | ||
264 | } |
355 | } |
265 | 356 | ||
266 | /* The reference count and user_data array are unique to the copy. */ |
357 | /* The reference count and user_data array are unique to the copy. */ |
Line 291... | Line 382... | ||
291 | size = sizeof (cairo_linear_pattern_t); |
382 | size = sizeof (cairo_linear_pattern_t); |
292 | break; |
383 | break; |
293 | case CAIRO_PATTERN_TYPE_RADIAL: |
384 | case CAIRO_PATTERN_TYPE_RADIAL: |
294 | size = sizeof (cairo_radial_pattern_t); |
385 | size = sizeof (cairo_radial_pattern_t); |
295 | break; |
386 | break; |
- | 387 | case CAIRO_PATTERN_TYPE_MESH: |
|
- | 388 | size = sizeof (cairo_mesh_pattern_t); |
|
- | 389 | break; |
|
- | 390 | case CAIRO_PATTERN_TYPE_RASTER_SOURCE: |
|
- | 391 | size = sizeof (cairo_raster_source_pattern_t); |
|
- | 392 | break; |
|
296 | } |
393 | } |
Line 297... | Line 394... | ||
297 | 394 | ||
Line 298... | Line 395... | ||
298 | memcpy (pattern, other, size); |
395 | memcpy (pattern, other, size); |
Line 322... | Line 419... | ||
322 | 419 | ||
Line 323... | Line 420... | ||
323 | surface_pattern->surface = _cairo_surface_snapshot (surface); |
420 | surface_pattern->surface = _cairo_surface_snapshot (surface); |
Line 324... | Line 421... | ||
324 | 421 | ||
- | 422 | cairo_surface_destroy (surface); |
|
325 | cairo_surface_destroy (surface); |
423 | |
326 | - | ||
Line 327... | Line 424... | ||
327 | if (surface_pattern->surface->status) |
424 | status = surface_pattern->surface->status; |
328 | return surface_pattern->surface->status; |
425 | } else if (pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) |
Line 329... | Line 426... | ||
329 | } |
426 | status = _cairo_raster_source_pattern_snapshot (pattern); |
330 | 427 | ||
331 | return CAIRO_STATUS_SUCCESS; |
428 | return status; |
Line 351... | Line 448... | ||
351 | (cairo_gradient_pattern_t *) pattern; |
448 | (cairo_gradient_pattern_t *) pattern; |
Line 352... | Line 449... | ||
352 | 449 | ||
353 | if (gradient->stops && gradient->stops != gradient->stops_embedded) |
450 | if (gradient->stops && gradient->stops != gradient->stops_embedded) |
354 | free (gradient->stops); |
451 | free (gradient->stops); |
- | 452 | } break; |
|
- | 453 | case CAIRO_PATTERN_TYPE_MESH: { |
|
- | 454 | cairo_mesh_pattern_t *mesh = |
|
- | 455 | (cairo_mesh_pattern_t *) pattern; |
|
- | 456 | ||
- | 457 | _cairo_array_fini (&mesh->patches); |
|
- | 458 | } break; |
|
- | 459 | case CAIRO_PATTERN_TYPE_RASTER_SOURCE: |
|
- | 460 | _cairo_raster_source_pattern_finish (pattern); |
|
355 | } break; |
461 | break; |
Line 356... | Line 462... | ||
356 | } |
462 | } |
357 | 463 | ||
358 | #if HAVE_VALGRIND |
464 | #if HAVE_VALGRIND |
Line 367... | Line 473... | ||
367 | VALGRIND_MAKE_MEM_NOACCESS (pattern, sizeof (cairo_linear_pattern_t)); |
473 | VALGRIND_MAKE_MEM_NOACCESS (pattern, sizeof (cairo_linear_pattern_t)); |
368 | break; |
474 | break; |
369 | case CAIRO_PATTERN_TYPE_RADIAL: |
475 | case CAIRO_PATTERN_TYPE_RADIAL: |
370 | VALGRIND_MAKE_MEM_NOACCESS (pattern, sizeof (cairo_radial_pattern_t)); |
476 | VALGRIND_MAKE_MEM_NOACCESS (pattern, sizeof (cairo_radial_pattern_t)); |
371 | break; |
477 | break; |
- | 478 | case CAIRO_PATTERN_TYPE_MESH: |
|
- | 479 | VALGRIND_MAKE_MEM_NOACCESS (pattern, sizeof (cairo_mesh_pattern_t)); |
|
- | 480 | break; |
|
- | 481 | case CAIRO_PATTERN_TYPE_RASTER_SOURCE: |
|
- | 482 | break; |
|
372 | } |
483 | } |
373 | #endif |
484 | #endif |
374 | } |
485 | } |
Line 375... | Line 486... | ||
375 | 486 | ||
Line 394... | Line 505... | ||
394 | pattern = malloc (sizeof (cairo_linear_pattern_t)); |
505 | pattern = malloc (sizeof (cairo_linear_pattern_t)); |
395 | break; |
506 | break; |
396 | case CAIRO_PATTERN_TYPE_RADIAL: |
507 | case CAIRO_PATTERN_TYPE_RADIAL: |
397 | pattern = malloc (sizeof (cairo_radial_pattern_t)); |
508 | pattern = malloc (sizeof (cairo_radial_pattern_t)); |
398 | break; |
509 | break; |
- | 510 | case CAIRO_PATTERN_TYPE_MESH: |
|
- | 511 | pattern = malloc (sizeof (cairo_mesh_pattern_t)); |
|
- | 512 | break; |
|
- | 513 | case CAIRO_PATTERN_TYPE_RASTER_SOURCE: |
|
- | 514 | pattern = malloc (sizeof (cairo_raster_source_pattern_t)); |
|
- | 515 | break; |
|
399 | default: |
516 | default: |
400 | ASSERT_NOT_REACHED; |
517 | ASSERT_NOT_REACHED; |
401 | return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
518 | return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
402 | } |
519 | } |
403 | if (unlikely (pattern == NULL)) |
520 | if (unlikely (pattern == NULL)) |
Line 412... | Line 529... | ||
412 | CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 1); |
529 | CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 1); |
413 | *pattern_out = pattern; |
530 | *pattern_out = pattern; |
414 | return CAIRO_STATUS_SUCCESS; |
531 | return CAIRO_STATUS_SUCCESS; |
415 | } |
532 | } |
Line 416... | Line -... | ||
416 | - | ||
417 | 533 | ||
418 | void |
534 | void |
419 | _cairo_pattern_init_solid (cairo_solid_pattern_t *pattern, |
535 | _cairo_pattern_init_solid (cairo_solid_pattern_t *pattern, |
420 | const cairo_color_t *color) |
536 | const cairo_color_t *color) |
421 | { |
537 | { |
Line 448... | Line 564... | ||
448 | pattern->n_stops = 0; |
564 | pattern->n_stops = 0; |
449 | pattern->stops_size = 0; |
565 | pattern->stops_size = 0; |
450 | pattern->stops = NULL; |
566 | pattern->stops = NULL; |
451 | } |
567 | } |
Line 452... | Line 568... | ||
452 | 568 | ||
453 | void |
569 | static void |
454 | _cairo_pattern_init_linear (cairo_linear_pattern_t *pattern, |
570 | _cairo_pattern_init_linear (cairo_linear_pattern_t *pattern, |
455 | double x0, double y0, double x1, double y1) |
571 | double x0, double y0, double x1, double y1) |
456 | { |
572 | { |
Line 457... | Line 573... | ||
457 | _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_TYPE_LINEAR); |
573 | _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_TYPE_LINEAR); |
458 | 574 | ||
459 | pattern->p1.x = _cairo_fixed_from_double (x0); |
575 | pattern->pd1.x = x0; |
460 | pattern->p1.y = _cairo_fixed_from_double (y0); |
576 | pattern->pd1.y = y0; |
461 | pattern->p2.x = _cairo_fixed_from_double (x1); |
577 | pattern->pd2.x = x1; |
Line 462... | Line 578... | ||
462 | pattern->p2.y = _cairo_fixed_from_double (y1); |
578 | pattern->pd2.y = y1; |
463 | } |
579 | } |
464 | 580 | ||
465 | void |
581 | static void |
466 | _cairo_pattern_init_radial (cairo_radial_pattern_t *pattern, |
582 | _cairo_pattern_init_radial (cairo_radial_pattern_t *pattern, |
467 | double cx0, double cy0, double radius0, |
583 | double cx0, double cy0, double radius0, |
Line 468... | Line 584... | ||
468 | double cx1, double cy1, double radius1) |
584 | double cx1, double cy1, double radius1) |
469 | { |
585 | { |
470 | _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_TYPE_RADIAL); |
586 | _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_TYPE_RADIAL); |
471 | 587 | ||
472 | pattern->c1.x = _cairo_fixed_from_double (cx0); |
588 | pattern->cd1.center.x = cx0; |
473 | pattern->c1.y = _cairo_fixed_from_double (cy0); |
589 | pattern->cd1.center.y = cy0; |
474 | pattern->r1 = _cairo_fixed_from_double (fabs (radius0)); |
590 | pattern->cd1.radius = fabs (radius0); |
Line 475... | Line 591... | ||
475 | pattern->c2.x = _cairo_fixed_from_double (cx1); |
591 | pattern->cd2.center.x = cx1; |
476 | pattern->c2.y = _cairo_fixed_from_double (cy1); |
592 | pattern->cd2.center.y = cy1; |
477 | pattern->r2 = _cairo_fixed_from_double (fabs (radius1)); |
593 | pattern->cd2.radius = fabs (radius1); |
Line 533... | Line 649... | ||
533 | * finished with it. |
649 | * finished with it. |
534 | * |
650 | * |
535 | * This function will always return a valid pointer, but if an error |
651 | * 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 |
652 | * occurred the pattern status will be set to an error. To inspect |
537 | * the status of a pattern use cairo_pattern_status(). |
653 | * the status of a pattern use cairo_pattern_status(). |
- | 654 | * |
|
- | 655 | * Since: 1.0 |
|
538 | **/ |
656 | **/ |
539 | cairo_pattern_t * |
657 | cairo_pattern_t * |
540 | cairo_pattern_create_rgb (double red, double green, double blue) |
658 | cairo_pattern_create_rgb (double red, double green, double blue) |
541 | { |
659 | { |
542 | cairo_color_t color; |
- | |
543 | - | ||
544 | red = _cairo_restrict_value (red, 0.0, 1.0); |
- | |
545 | green = _cairo_restrict_value (green, 0.0, 1.0); |
- | |
546 | blue = _cairo_restrict_value (blue, 0.0, 1.0); |
- | |
547 | - | ||
548 | _cairo_color_init_rgb (&color, red, green, blue); |
- | |
549 | - | ||
550 | CAIRO_MUTEX_INITIALIZE (); |
- | |
551 | - | ||
552 | return _cairo_pattern_create_solid (&color); |
660 | return cairo_pattern_create_rgba (red, green, blue, 1.0); |
553 | } |
661 | } |
554 | slim_hidden_def (cairo_pattern_create_rgb); |
662 | slim_hidden_def (cairo_pattern_create_rgb); |
Line 555... | Line 663... | ||
555 | 663 | ||
556 | /** |
664 | /** |
Line 571... | Line 679... | ||
571 | * finished with it. |
679 | * finished with it. |
572 | * |
680 | * |
573 | * This function will always return a valid pointer, but if an error |
681 | * 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 |
682 | * occurred the pattern status will be set to an error. To inspect |
575 | * the status of a pattern use cairo_pattern_status(). |
683 | * the status of a pattern use cairo_pattern_status(). |
- | 684 | * |
|
- | 685 | * Since: 1.0 |
|
576 | **/ |
686 | **/ |
577 | cairo_pattern_t * |
687 | cairo_pattern_t * |
578 | cairo_pattern_create_rgba (double red, double green, double blue, |
688 | cairo_pattern_create_rgba (double red, double green, double blue, |
579 | double alpha) |
689 | double alpha) |
580 | { |
690 | { |
Line 605... | Line 715... | ||
605 | * finished with it. |
715 | * finished with it. |
606 | * |
716 | * |
607 | * This function will always return a valid pointer, but if an error |
717 | * 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 |
718 | * occurred the pattern status will be set to an error. To inspect |
609 | * the status of a pattern use cairo_pattern_status(). |
719 | * the status of a pattern use cairo_pattern_status(). |
- | 720 | * |
|
- | 721 | * Since: 1.0 |
|
610 | **/ |
722 | **/ |
611 | cairo_pattern_t * |
723 | cairo_pattern_t * |
612 | cairo_pattern_create_for_surface (cairo_surface_t *surface) |
724 | cairo_pattern_create_for_surface (cairo_surface_t *surface) |
613 | { |
725 | { |
614 | cairo_surface_pattern_t *pattern; |
726 | cairo_surface_pattern_t *pattern; |
Line 663... | Line 775... | ||
663 | * finished with it. |
775 | * finished with it. |
664 | * |
776 | * |
665 | * This function will always return a valid pointer, but if an error |
777 | * 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 |
778 | * occurred the pattern status will be set to an error. To inspect |
667 | * the status of a pattern use cairo_pattern_status(). |
779 | * the status of a pattern use cairo_pattern_status(). |
- | 780 | * |
|
- | 781 | * Since: 1.0 |
|
668 | **/ |
782 | **/ |
669 | cairo_pattern_t * |
783 | cairo_pattern_t * |
670 | cairo_pattern_create_linear (double x0, double y0, double x1, double y1) |
784 | cairo_pattern_create_linear (double x0, double y0, double x1, double y1) |
671 | { |
785 | { |
672 | cairo_linear_pattern_t *pattern; |
786 | cairo_linear_pattern_t *pattern; |
Line 714... | Line 828... | ||
714 | * finished with it. |
828 | * finished with it. |
715 | * |
829 | * |
716 | * This function will always return a valid pointer, but if an error |
830 | * 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 |
831 | * occurred the pattern status will be set to an error. To inspect |
718 | * the status of a pattern use cairo_pattern_status(). |
832 | * the status of a pattern use cairo_pattern_status(). |
- | 833 | * |
|
- | 834 | * Since: 1.0 |
|
719 | **/ |
835 | **/ |
720 | cairo_pattern_t * |
836 | cairo_pattern_t * |
721 | cairo_pattern_create_radial (double cx0, double cy0, double radius0, |
837 | cairo_pattern_create_radial (double cx0, double cy0, double radius0, |
722 | double cx1, double cy1, double radius1) |
838 | double cx1, double cy1, double radius1) |
723 | { |
839 | { |
Line 739... | Line 855... | ||
739 | CAIRO_REFERENCE_COUNT_INIT (&pattern->base.base.ref_count, 1); |
855 | CAIRO_REFERENCE_COUNT_INIT (&pattern->base.base.ref_count, 1); |
Line 740... | Line 856... | ||
740 | 856 | ||
741 | return &pattern->base.base; |
857 | return &pattern->base.base; |
Line -... | Line 858... | ||
- | 858 | } |
|
- | 859 | ||
- | 860 | /* This order is specified in the diagram in the documentation for |
|
- | 861 | * cairo_pattern_create_mesh() */ |
|
- | 862 | static const int mesh_path_point_i[12] = { 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 2, 1 }; |
|
- | 863 | static const int mesh_path_point_j[12] = { 0, 1, 2, 3, 3, 3, 3, 2, 1, 0, 0, 0 }; |
|
- | 864 | static const int mesh_control_point_i[4] = { 1, 1, 2, 2 }; |
|
- | 865 | static const int mesh_control_point_j[4] = { 1, 2, 2, 1 }; |
|
- | 866 | ||
- | 867 | /** |
|
- | 868 | * cairo_pattern_create_mesh: |
|
- | 869 | * |
|
- | 870 | * Create a new mesh pattern. |
|
- | 871 | * |
|
- | 872 | * Mesh patterns are tensor-product patch meshes (type 7 shadings in |
|
- | 873 | * PDF). Mesh patterns may also be used to create other types of |
|
- | 874 | * shadings that are special cases of tensor-product patch meshes such |
|
- | 875 | * as Coons patch meshes (type 6 shading in PDF) and Gouraud-shaded |
|
- | 876 | * triangle meshes (type 4 and 5 shadings in PDF). |
|
- | 877 | * |
|
- | 878 | * Mesh patterns consist of one or more tensor-product patches, which |
|
- | 879 | * should be defined before using the mesh pattern. Using a mesh |
|
- | 880 | * pattern with a partially defined patch as source or mask will put |
|
- | 881 | * the context in an error status with a status of |
|
- | 882 | * %CAIRO_STATUS_INVALID_MESH_CONSTRUCTION. |
|
- | 883 | * |
|
- | 884 | * A tensor-product patch is defined by 4 Bézier curves (side 0, 1, 2, |
|
- | 885 | * 3) and by 4 additional control points (P0, P1, P2, P3) that provide |
|
- | 886 | * further control over the patch and complete the definition of the |
|
- | 887 | * tensor-product patch. The corner C0 is the first point of the |
|
- | 888 | * patch. |
|
- | 889 | * |
|
- | 890 | * Degenerate sides are permitted so straight lines may be used. A |
|
- | 891 | * zero length line on one side may be used to create 3 sided patches. |
|
- | 892 | * |
|
- | 893 | * |
|
- | 894 | * C1 Side 1 C2 |
|
- | 895 | * +---------------+ |
|
- | 896 | * | | |
|
- | 897 | * | P1 P2 | |
|
- | 898 | * | | |
|
- | 899 | * Side 0 | | Side 2 |
|
- | 900 | * | | |
|
- | 901 | * | | |
|
- | 902 | * | P0 P3 | |
|
- | 903 | * | | |
|
- | 904 | * +---------------+ |
|
- | 905 | * C0 Side 3 C3 |
|
- | 906 | * |
|
- | 907 | * |
|
- | 908 | * Each patch is constructed by first calling |
|
- | 909 | * cairo_mesh_pattern_begin_patch(), then cairo_mesh_pattern_move_to() |
|
- | 910 | * to specify the first point in the patch (C0). Then the sides are |
|
- | 911 | * specified with calls to cairo_mesh_pattern_curve_to() and |
|
- | 912 | * cairo_mesh_pattern_line_to(). |
|
- | 913 | * |
|
- | 914 | * The four additional control points (P0, P1, P2, P3) in a patch can |
|
- | 915 | * be specified with cairo_mesh_pattern_set_control_point(). |
|
- | 916 | * |
|
- | 917 | * At each corner of the patch (C0, C1, C2, C3) a color may be |
|
- | 918 | * specified with cairo_mesh_pattern_set_corner_color_rgb() or |
|
- | 919 | * cairo_mesh_pattern_set_corner_color_rgba(). Any corner whose color |
|
- | 920 | * is not explicitly specified defaults to transparent black. |
|
- | 921 | * |
|
- | 922 | * A Coons patch is a special case of the tensor-product patch where |
|
- | 923 | * the control points are implicitly defined by the sides of the |
|
- | 924 | * patch. The default value for any control point not specified is the |
|
- | 925 | * implicit value for a Coons patch, i.e. if no control points are |
|
- | 926 | * specified the patch is a Coons patch. |
|
- | 927 | * |
|
- | 928 | * A triangle is a special case of the tensor-product patch where the |
|
- | 929 | * control points are implicitly defined by the sides of the patch, |
|
- | 930 | * all the sides are lines and one of them has length 0, i.e. if the |
|
- | 931 | * patch is specified using just 3 lines, it is a triangle. If the |
|
- | 932 | * corners connected by the 0-length side have the same color, the |
|
- | 933 | * patch is a Gouraud-shaded triangle. |
|
- | 934 | * |
|
- | 935 | * Patches may be oriented differently to the above diagram. For |
|
- | 936 | * example the first point could be at the top left. The diagram only |
|
- | 937 | * shows the relationship between the sides, corners and control |
|
- | 938 | * points. Regardless of where the first point is located, when |
|
- | 939 | * specifying colors, corner 0 will always be the first point, corner |
|
- | 940 | * 1 the point between side 0 and side 1 etc. |
|
- | 941 | * |
|
- | 942 | * Calling cairo_mesh_pattern_end_patch() completes the current |
|
- | 943 | * patch. If less than 4 sides have been defined, the first missing |
|
- | 944 | * side is defined as a line from the current point to the first point |
|
- | 945 | * of the patch (C0) and the other sides are degenerate lines from C0 |
|
- | 946 | * to C0. The corners between the added sides will all be coincident |
|
- | 947 | * with C0 of the patch and their color will be set to be the same as |
|
- | 948 | * the color of C0. |
|
- | 949 | * |
|
- | 950 | * Additional patches may be added with additional calls to |
|
- | 951 | * cairo_mesh_pattern_begin_patch()/cairo_mesh_pattern_end_patch(). |
|
- | 952 | * |
|
- | 953 | * |
|
- | 954 | * cairo_pattern_t *pattern = cairo_pattern_create_mesh (); |
|
- | 955 | * |
|
- | 956 | * /* Add a Coons patch */ |
|
- | 957 | * cairo_mesh_pattern_begin_patch (pattern); |
|
- | 958 | * cairo_mesh_pattern_move_to (pattern, 0, 0); |
|
- | 959 | * cairo_mesh_pattern_curve_to (pattern, 30, -30, 60, 30, 100, 0); |
|
- | 960 | * cairo_mesh_pattern_curve_to (pattern, 60, 30, 130, 60, 100, 100); |
|
- | 961 | * cairo_mesh_pattern_curve_to (pattern, 60, 70, 30, 130, 0, 100); |
|
- | 962 | * cairo_mesh_pattern_curve_to (pattern, 30, 70, -30, 30, 0, 0); |
|
- | 963 | * cairo_mesh_pattern_set_corner_color_rgb (pattern, 0, 1, 0, 0); |
|
- | 964 | * cairo_mesh_pattern_set_corner_color_rgb (pattern, 1, 0, 1, 0); |
|
- | 965 | * cairo_mesh_pattern_set_corner_color_rgb (pattern, 2, 0, 0, 1); |
|
- | 966 | * cairo_mesh_pattern_set_corner_color_rgb (pattern, 3, 1, 1, 0); |
|
- | 967 | * cairo_mesh_pattern_end_patch (pattern); |
|
- | 968 | * |
|
- | 969 | * /* Add a Gouraud-shaded triangle */ |
|
- | 970 | * cairo_mesh_pattern_begin_patch (pattern) |
|
- | 971 | * cairo_mesh_pattern_move_to (pattern, 100, 100); |
|
- | 972 | * cairo_mesh_pattern_line_to (pattern, 130, 130); |
|
- | 973 | * cairo_mesh_pattern_line_to (pattern, 130, 70); |
|
- | 974 | * cairo_mesh_pattern_set_corner_color_rgb (pattern, 0, 1, 0, 0); |
|
- | 975 | * cairo_mesh_pattern_set_corner_color_rgb (pattern, 1, 0, 1, 0); |
|
- | 976 | * cairo_mesh_pattern_set_corner_color_rgb (pattern, 2, 0, 0, 1); |
|
- | 977 | * cairo_mesh_pattern_end_patch (pattern) |
|
- | 978 | * |
|
- | 979 | * |
|
- | 980 | * When two patches overlap, the last one that has been added is drawn |
|
- | 981 | * over the first one. |
|
- | 982 | * |
|
- | 983 | * When a patch folds over itself, points are sorted depending on |
|
- | 984 | * their parameter coordinates inside the patch. The v coordinate |
|
- | 985 | * ranges from 0 to 1 when moving from side 3 to side 1; the u |
|
- | 986 | * coordinate ranges from 0 to 1 when going from side 0 to side |
|
- | 987 | * 2. Points with higher v coordinate hide points with lower v |
|
- | 988 | * coordinate. When two points have the same v coordinate, the one |
|
- | 989 | * with higher u coordinate is above. This means that points nearer to |
|
- | 990 | * side 1 are above points nearer to side 3; when this is not |
|
- | 991 | * sufficient to decide which point is above (for example when both |
|
- | 992 | * points belong to side 1 or side 3) points nearer to side 2 are |
|
- | 993 | * above points nearer to side 0. |
|
- | 994 | * |
|
- | 995 | * For a complete definition of tensor-product patches, see the PDF |
|
- | 996 | * specification (ISO32000), which describes the parametrization in |
|
- | 997 | * detail. |
|
- | 998 | * |
|
- | 999 | * Note: The coordinates are always in pattern space. For a new |
|
- | 1000 | * pattern, pattern space is identical to user space, but the |
|
- | 1001 | * relationship between the spaces can be changed with |
|
- | 1002 | * cairo_pattern_set_matrix(). |
|
- | 1003 | * |
|
- | 1004 | * Return value: the newly created #cairo_pattern_t if successful, or |
|
- | 1005 | * an error pattern in case of no memory. The caller owns the returned |
|
- | 1006 | * object and should call cairo_pattern_destroy() when finished with |
|
- | 1007 | * it. |
|
- | 1008 | * |
|
- | 1009 | * This function will always return a valid pointer, but if an error |
|
- | 1010 | * occurred the pattern status will be set to an error. To inspect the |
|
- | 1011 | * status of a pattern use cairo_pattern_status(). |
|
- | 1012 | * |
|
- | 1013 | * Since: 1.12 |
|
- | 1014 | **/ |
|
- | 1015 | cairo_pattern_t * |
|
- | 1016 | cairo_pattern_create_mesh (void) |
|
- | 1017 | { |
|
- | 1018 | cairo_mesh_pattern_t *pattern; |
|
- | 1019 | ||
- | 1020 | pattern = |
|
- | 1021 | _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_MESH]); |
|
- | 1022 | if (unlikely (pattern == NULL)) { |
|
- | 1023 | pattern = malloc (sizeof (cairo_mesh_pattern_t)); |
|
- | 1024 | if (unlikely (pattern == NULL)) { |
|
- | 1025 | _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); |
|
- | 1026 | return (cairo_pattern_t *) &_cairo_pattern_nil.base; |
|
- | 1027 | } |
|
- | 1028 | } |
|
- | 1029 | ||
- | 1030 | CAIRO_MUTEX_INITIALIZE (); |
|
- | 1031 | ||
- | 1032 | _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_MESH); |
|
- | 1033 | _cairo_array_init (&pattern->patches, sizeof (cairo_mesh_patch_t)); |
|
- | 1034 | pattern->current_patch = NULL; |
|
- | 1035 | CAIRO_REFERENCE_COUNT_INIT (&pattern->base.ref_count, 1); |
|
- | 1036 | ||
- | 1037 | return &pattern->base; |
|
742 | } |
1038 | } |
743 | 1039 | ||
744 | /** |
1040 | /** |
745 | * cairo_pattern_reference: |
1041 | * cairo_pattern_reference: |
746 | * @pattern: a #cairo_pattern_t |
1042 | * @pattern: a #cairo_pattern_t |
Line 751... | Line 1047... | ||
751 | * |
1047 | * |
752 | * The number of references to a #cairo_pattern_t can be get using |
1048 | * The number of references to a #cairo_pattern_t can be get using |
753 | * cairo_pattern_get_reference_count(). |
1049 | * cairo_pattern_get_reference_count(). |
754 | * |
1050 | * |
755 | * Return value: the referenced #cairo_pattern_t. |
1051 | * Return value: the referenced #cairo_pattern_t. |
- | 1052 | * |
|
- | 1053 | * Since: 1.0 |
|
756 | **/ |
1054 | **/ |
757 | cairo_pattern_t * |
1055 | cairo_pattern_t * |
758 | cairo_pattern_reference (cairo_pattern_t *pattern) |
1056 | cairo_pattern_reference (cairo_pattern_t *pattern) |
759 | { |
1057 | { |
760 | if (pattern == NULL || |
1058 | if (pattern == NULL || |
Line 791... | Line 1089... | ||
791 | * @pattern: a #cairo_pattern_t |
1089 | * @pattern: a #cairo_pattern_t |
792 | * |
1090 | * |
793 | * Checks whether an error has previously occurred for this |
1091 | * Checks whether an error has previously occurred for this |
794 | * pattern. |
1092 | * pattern. |
795 | * |
1093 | * |
796 | * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_STATUS_NO_MEMORY, or |
1094 | * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_STATUS_NO_MEMORY, |
- | 1095 | * %CAIRO_STATUS_INVALID_MATRIX, %CAIRO_STATUS_PATTERN_TYPE_MISMATCH, |
|
797 | * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. |
1096 | * or %CAIRO_STATUS_INVALID_MESH_CONSTRUCTION. |
- | 1097 | * |
|
- | 1098 | * Since: 1.0 |
|
798 | **/ |
1099 | **/ |
799 | cairo_status_t |
1100 | cairo_status_t |
800 | cairo_pattern_status (cairo_pattern_t *pattern) |
1101 | cairo_pattern_status (cairo_pattern_t *pattern) |
801 | { |
1102 | { |
802 | return pattern->status; |
1103 | return pattern->status; |
Line 807... | Line 1108... | ||
807 | * @pattern: a #cairo_pattern_t |
1108 | * @pattern: a #cairo_pattern_t |
808 | * |
1109 | * |
809 | * Decreases the reference count on @pattern by one. If the result is |
1110 | * Decreases the reference count on @pattern by one. If the result is |
810 | * zero, then @pattern and all associated resources are freed. See |
1111 | * zero, then @pattern and all associated resources are freed. See |
811 | * cairo_pattern_reference(). |
1112 | * cairo_pattern_reference(). |
- | 1113 | * |
|
- | 1114 | * Since: 1.0 |
|
812 | **/ |
1115 | **/ |
813 | void |
1116 | void |
814 | cairo_pattern_destroy (cairo_pattern_t *pattern) |
1117 | cairo_pattern_destroy (cairo_pattern_t *pattern) |
815 | { |
1118 | { |
816 | cairo_pattern_type_t type; |
1119 | cairo_pattern_type_t type; |
Line 826... | Line 1129... | ||
826 | 1129 | ||
827 | type = pattern->type; |
1130 | type = pattern->type; |
Line 828... | Line 1131... | ||
828 | _cairo_pattern_fini (pattern); |
1131 | _cairo_pattern_fini (pattern); |
- | 1132 | ||
829 | 1133 | /* maintain a small cache of freed patterns */ |
|
- | 1134 | if (type < ARRAY_LENGTH (freed_pattern_pool)) |
|
- | 1135 | _freed_pool_put (&freed_pattern_pool[type], pattern); |
|
830 | /* maintain a small cache of freed patterns */ |
1136 | else |
831 | _freed_pool_put (&freed_pattern_pool[type], pattern); |
1137 | free (pattern); |
Line 832... | Line 1138... | ||
832 | } |
1138 | } |
833 | slim_hidden_def (cairo_pattern_destroy); |
1139 | slim_hidden_def (cairo_pattern_destroy); |
Line 904... | Line 1210... | ||
904 | 1210 | ||
905 | return _cairo_user_data_array_set_data (&pattern->user_data, |
1211 | return _cairo_user_data_array_set_data (&pattern->user_data, |
906 | key, user_data, destroy); |
1212 | key, user_data, destroy); |
Line -... | Line 1213... | ||
- | 1213 | } |
|
- | 1214 | ||
- | 1215 | /** |
|
- | 1216 | * cairo_mesh_pattern_begin_patch: |
|
- | 1217 | * @pattern: a #cairo_pattern_t |
|
- | 1218 | * |
|
- | 1219 | * Begin a patch in a mesh pattern. |
|
- | 1220 | * |
|
- | 1221 | * After calling this function, the patch shape should be defined with |
|
- | 1222 | * cairo_mesh_pattern_move_to(), cairo_mesh_pattern_line_to() and |
|
- | 1223 | * cairo_mesh_pattern_curve_to(). |
|
- | 1224 | * |
|
- | 1225 | * After defining the patch, cairo_mesh_pattern_end_patch() must be |
|
- | 1226 | * called before using @pattern as a source or mask. |
|
- | 1227 | * |
|
- | 1228 | * Note: If @pattern is not a mesh pattern then @pattern will be put |
|
- | 1229 | * into an error status with a status of |
|
- | 1230 | * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. If @pattern already has a |
|
- | 1231 | * current patch, it will be put into an error status with a status of |
|
- | 1232 | * %CAIRO_STATUS_INVALID_MESH_CONSTRUCTION. |
|
- | 1233 | * |
|
- | 1234 | * Since: 1.12 |
|
- | 1235 | **/ |
|
- | 1236 | void |
|
- | 1237 | cairo_mesh_pattern_begin_patch (cairo_pattern_t *pattern) |
|
- | 1238 | { |
|
- | 1239 | cairo_mesh_pattern_t *mesh; |
|
- | 1240 | cairo_status_t status; |
|
- | 1241 | cairo_mesh_patch_t *current_patch; |
|
- | 1242 | int i; |
|
- | 1243 | ||
- | 1244 | if (unlikely (pattern->status)) |
|
- | 1245 | return; |
|
- | 1246 | ||
- | 1247 | if (unlikely (pattern->type != CAIRO_PATTERN_TYPE_MESH)) { |
|
- | 1248 | _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
|
- | 1249 | return; |
|
- | 1250 | } |
|
- | 1251 | ||
- | 1252 | mesh = (cairo_mesh_pattern_t *) pattern; |
|
- | 1253 | if (unlikely (mesh->current_patch)) { |
|
- | 1254 | _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_MESH_CONSTRUCTION); |
|
- | 1255 | return; |
|
- | 1256 | } |
|
- | 1257 | ||
- | 1258 | status = _cairo_array_allocate (&mesh->patches, 1, (void **) ¤t_patch); |
|
- | 1259 | if (unlikely (status)) { |
|
- | 1260 | _cairo_pattern_set_error (pattern, status); |
|
- | 1261 | return; |
|
- | 1262 | } |
|
- | 1263 | ||
- | 1264 | mesh->current_patch = current_patch; |
|
- | 1265 | mesh->current_side = -2; /* no current point */ |
|
- | 1266 | ||
- | 1267 | for (i = 0; i < 4; i++) |
|
- | 1268 | mesh->has_control_point[i] = FALSE; |
|
- | 1269 | ||
- | 1270 | for (i = 0; i < 4; i++) |
|
- | 1271 | mesh->has_color[i] = FALSE; |
|
- | 1272 | } |
|
- | 1273 | ||
- | 1274 | ||
- | 1275 | static void |
|
- | 1276 | _calc_control_point (cairo_mesh_patch_t *patch, int control_point) |
|
- | 1277 | { |
|
- | 1278 | /* The Coons patch is a special case of the Tensor Product patch |
|
- | 1279 | * where the four control points are: |
|
- | 1280 | * |
|
- | 1281 | * P11 = S(1/3, 1/3) |
|
- | 1282 | * P12 = S(1/3, 2/3) |
|
- | 1283 | * P21 = S(2/3, 1/3) |
|
- | 1284 | * P22 = S(2/3, 2/3) |
|
- | 1285 | * |
|
- | 1286 | * where S is the gradient surface. |
|
- | 1287 | * |
|
- | 1288 | * When one or more control points has not been specified |
|
- | 1289 | * calculated the Coons patch control points are substituted. If |
|
- | 1290 | * no control points are specified the gradient will be a Coons |
|
- | 1291 | * patch. |
|
- | 1292 | * |
|
- | 1293 | * The equations below are defined in the ISO32000 standard. |
|
- | 1294 | */ |
|
- | 1295 | cairo_point_double_t *p[3][3]; |
|
- | 1296 | int cp_i, cp_j, i, j; |
|
- | 1297 | ||
- | 1298 | cp_i = mesh_control_point_i[control_point]; |
|
- | 1299 | cp_j = mesh_control_point_j[control_point]; |
|
- | 1300 | ||
- | 1301 | for (i = 0; i < 3; i++) |
|
- | 1302 | for (j = 0; j < 3; j++) |
|
- | 1303 | p[i][j] = &patch->points[cp_i ^ i][cp_j ^ j]; |
|
- | 1304 | ||
- | 1305 | p[0][0]->x = (- 4 * p[1][1]->x |
|
- | 1306 | + 6 * (p[1][0]->x + p[0][1]->x) |
|
- | 1307 | - 2 * (p[1][2]->x + p[2][1]->x) |
|
- | 1308 | + 3 * (p[2][0]->x + p[0][2]->x) |
|
- | 1309 | - 1 * p[2][2]->x) * (1. / 9); |
|
- | 1310 | ||
- | 1311 | p[0][0]->y = (- 4 * p[1][1]->y |
|
- | 1312 | + 6 * (p[1][0]->y + p[0][1]->y) |
|
- | 1313 | - 2 * (p[1][2]->y + p[2][1]->y) |
|
- | 1314 | + 3 * (p[2][0]->y + p[0][2]->y) |
|
- | 1315 | - 1 * p[2][2]->y) * (1. / 9); |
|
- | 1316 | } |
|
- | 1317 | ||
- | 1318 | /** |
|
- | 1319 | * cairo_mesh_pattern_end_patch: |
|
- | 1320 | * @pattern: a #cairo_pattern_t |
|
- | 1321 | * |
|
- | 1322 | * Indicates the end of the current patch in a mesh pattern. |
|
- | 1323 | * |
|
- | 1324 | * If the current patch has less than 4 sides, it is closed with a |
|
- | 1325 | * straight line from the current point to the first point of the |
|
- | 1326 | * patch as if cairo_mesh_pattern_line_to() was used. |
|
- | 1327 | * |
|
- | 1328 | * Note: If @pattern is not a mesh pattern then @pattern will be put |
|
- | 1329 | * into an error status with a status of |
|
- | 1330 | * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. If @pattern has no current |
|
- | 1331 | * patch or the current patch has no current point, @pattern will be |
|
- | 1332 | * put into an error status with a status of |
|
- | 1333 | * %CAIRO_STATUS_INVALID_MESH_CONSTRUCTION. |
|
- | 1334 | * |
|
- | 1335 | * Since: 1.12 |
|
- | 1336 | **/ |
|
- | 1337 | void |
|
- | 1338 | cairo_mesh_pattern_end_patch (cairo_pattern_t *pattern) |
|
- | 1339 | { |
|
- | 1340 | cairo_mesh_pattern_t *mesh; |
|
- | 1341 | cairo_mesh_patch_t *current_patch; |
|
- | 1342 | int i; |
|
- | 1343 | ||
- | 1344 | if (unlikely (pattern->status)) |
|
- | 1345 | return; |
|
- | 1346 | ||
- | 1347 | if (unlikely (pattern->type != CAIRO_PATTERN_TYPE_MESH)) { |
|
- | 1348 | _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
|
- | 1349 | return; |
|
- | 1350 | } |
|
- | 1351 | ||
- | 1352 | mesh = (cairo_mesh_pattern_t *) pattern; |
|
- | 1353 | current_patch = mesh->current_patch; |
|
- | 1354 | if (unlikely (!current_patch)) { |
|
- | 1355 | _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_MESH_CONSTRUCTION); |
|
- | 1356 | return; |
|
- | 1357 | } |
|
- | 1358 | ||
- | 1359 | if (unlikely (mesh->current_side == -2)) { |
|
- | 1360 | _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_MESH_CONSTRUCTION); |
|
- | 1361 | return; |
|
- | 1362 | } |
|
- | 1363 | ||
- | 1364 | while (mesh->current_side < 3) { |
|
- | 1365 | int corner_num; |
|
- | 1366 | ||
- | 1367 | cairo_mesh_pattern_line_to (pattern, |
|
- | 1368 | current_patch->points[0][0].x, |
|
- | 1369 | current_patch->points[0][0].y); |
|
- | 1370 | ||
- | 1371 | corner_num = mesh->current_side + 1; |
|
- | 1372 | if (corner_num < 4 && ! mesh->has_color[corner_num]) { |
|
- | 1373 | current_patch->colors[corner_num] = current_patch->colors[0]; |
|
- | 1374 | mesh->has_color[corner_num] = TRUE; |
|
- | 1375 | } |
|
- | 1376 | } |
|
- | 1377 | ||
- | 1378 | for (i = 0; i < 4; i++) { |
|
- | 1379 | if (! mesh->has_control_point[i]) |
|
- | 1380 | _calc_control_point (current_patch, i); |
|
- | 1381 | } |
|
- | 1382 | ||
- | 1383 | for (i = 0; i < 4; i++) { |
|
- | 1384 | if (! mesh->has_color[i]) |
|
- | 1385 | current_patch->colors[i] = *CAIRO_COLOR_TRANSPARENT; |
|
- | 1386 | } |
|
- | 1387 | ||
- | 1388 | mesh->current_patch = NULL; |
|
- | 1389 | } |
|
- | 1390 | ||
- | 1391 | /** |
|
- | 1392 | * cairo_mesh_pattern_curve_to: |
|
- | 1393 | * @pattern: a #cairo_pattern_t |
|
- | 1394 | * @x1: the X coordinate of the first control point |
|
- | 1395 | * @y1: the Y coordinate of the first control point |
|
- | 1396 | * @x2: the X coordinate of the second control point |
|
- | 1397 | * @y2: the Y coordinate of the second control point |
|
- | 1398 | * @x3: the X coordinate of the end of the curve |
|
- | 1399 | * @y3: the Y coordinate of the end of the curve |
|
- | 1400 | * |
|
- | 1401 | * Adds a cubic Bézier spline to the current patch from the current |
|
- | 1402 | * point to position (@x3, @y3) in pattern-space coordinates, using |
|
- | 1403 | * (@x1, @y1) and (@x2, @y2) as the control points. |
|
- | 1404 | * |
|
- | 1405 | * If the current patch has no current point before the call to |
|
- | 1406 | * cairo_mesh_pattern_curve_to(), this function will behave as if |
|
- | 1407 | * preceded by a call to cairo_mesh_pattern_move_to(@pattern, @x1, |
|
- | 1408 | * @y1). |
|
- | 1409 | * |
|
- | 1410 | * After this call the current point will be (@x3, @y3). |
|
- | 1411 | * |
|
- | 1412 | * Note: If @pattern is not a mesh pattern then @pattern will be put |
|
- | 1413 | * into an error status with a status of |
|
- | 1414 | * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. If @pattern has no current |
|
- | 1415 | * patch or the current patch already has 4 sides, @pattern will be |
|
- | 1416 | * put into an error status with a status of |
|
- | 1417 | * %CAIRO_STATUS_INVALID_MESH_CONSTRUCTION. |
|
- | 1418 | * |
|
- | 1419 | * Since: 1.12 |
|
- | 1420 | **/ |
|
- | 1421 | void |
|
- | 1422 | cairo_mesh_pattern_curve_to (cairo_pattern_t *pattern, |
|
- | 1423 | double x1, double y1, |
|
- | 1424 | double x2, double y2, |
|
- | 1425 | double x3, double y3) |
|
- | 1426 | { |
|
- | 1427 | cairo_mesh_pattern_t *mesh; |
|
- | 1428 | int current_point, i, j; |
|
- | 1429 | ||
- | 1430 | if (unlikely (pattern->status)) |
|
- | 1431 | return; |
|
- | 1432 | ||
- | 1433 | if (unlikely (pattern->type != CAIRO_PATTERN_TYPE_MESH)) { |
|
- | 1434 | _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
|
- | 1435 | return; |
|
- | 1436 | } |
|
- | 1437 | ||
- | 1438 | mesh = (cairo_mesh_pattern_t *) pattern; |
|
- | 1439 | if (unlikely (!mesh->current_patch)) { |
|
- | 1440 | _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_MESH_CONSTRUCTION); |
|
- | 1441 | return; |
|
- | 1442 | } |
|
- | 1443 | ||
- | 1444 | if (unlikely (mesh->current_side == 3)) { |
|
- | 1445 | _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_MESH_CONSTRUCTION); |
|
- | 1446 | return; |
|
- | 1447 | } |
|
- | 1448 | ||
- | 1449 | if (mesh->current_side == -2) |
|
- | 1450 | cairo_mesh_pattern_move_to (pattern, x1, y1); |
|
- | 1451 | ||
- | 1452 | assert (mesh->current_side >= -1); |
|
- | 1453 | assert (pattern->status == CAIRO_STATUS_SUCCESS); |
|
- | 1454 | ||
- | 1455 | mesh->current_side++; |
|
- | 1456 | ||
- | 1457 | current_point = 3 * mesh->current_side; |
|
- | 1458 | ||
- | 1459 | current_point++; |
|
- | 1460 | i = mesh_path_point_i[current_point]; |
|
- | 1461 | j = mesh_path_point_j[current_point]; |
|
- | 1462 | mesh->current_patch->points[i][j].x = x1; |
|
- | 1463 | mesh->current_patch->points[i][j].y = y1; |
|
- | 1464 | ||
- | 1465 | current_point++; |
|
- | 1466 | i = mesh_path_point_i[current_point]; |
|
- | 1467 | j = mesh_path_point_j[current_point]; |
|
- | 1468 | mesh->current_patch->points[i][j].x = x2; |
|
- | 1469 | mesh->current_patch->points[i][j].y = y2; |
|
- | 1470 | ||
- | 1471 | current_point++; |
|
- | 1472 | if (current_point < 12) { |
|
- | 1473 | i = mesh_path_point_i[current_point]; |
|
- | 1474 | j = mesh_path_point_j[current_point]; |
|
- | 1475 | mesh->current_patch->points[i][j].x = x3; |
|
- | 1476 | mesh->current_patch->points[i][j].y = y3; |
|
- | 1477 | } |
|
- | 1478 | } |
|
- | 1479 | slim_hidden_def (cairo_mesh_pattern_curve_to); |
|
- | 1480 | ||
- | 1481 | /** |
|
- | 1482 | * cairo_mesh_pattern_line_to: |
|
- | 1483 | * @pattern: a #cairo_pattern_t |
|
- | 1484 | * @x: the X coordinate of the end of the new line |
|
- | 1485 | * @y: the Y coordinate of the end of the new line |
|
- | 1486 | * |
|
- | 1487 | * Adds a line to the current patch from the current point to position |
|
- | 1488 | * (@x, @y) in pattern-space coordinates. |
|
- | 1489 | * |
|
- | 1490 | * If there is no current point before the call to |
|
- | 1491 | * cairo_mesh_pattern_line_to() this function will behave as |
|
- | 1492 | * cairo_mesh_pattern_move_to(@pattern, @x, @y). |
|
- | 1493 | * |
|
- | 1494 | * After this call the current point will be (@x, @y). |
|
- | 1495 | * |
|
- | 1496 | * Note: If @pattern is not a mesh pattern then @pattern will be put |
|
- | 1497 | * into an error status with a status of |
|
- | 1498 | * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. If @pattern has no current |
|
- | 1499 | * patch or the current patch already has 4 sides, @pattern will be |
|
- | 1500 | * put into an error status with a status of |
|
- | 1501 | * %CAIRO_STATUS_INVALID_MESH_CONSTRUCTION. |
|
- | 1502 | * |
|
- | 1503 | * Since: 1.12 |
|
- | 1504 | **/ |
|
- | 1505 | void |
|
- | 1506 | cairo_mesh_pattern_line_to (cairo_pattern_t *pattern, |
|
- | 1507 | double x, double y) |
|
- | 1508 | { |
|
- | 1509 | cairo_mesh_pattern_t *mesh; |
|
- | 1510 | cairo_point_double_t last_point; |
|
- | 1511 | int last_point_idx, i, j; |
|
- | 1512 | ||
- | 1513 | if (unlikely (pattern->status)) |
|
- | 1514 | return; |
|
- | 1515 | ||
- | 1516 | if (unlikely (pattern->type != CAIRO_PATTERN_TYPE_MESH)) { |
|
- | 1517 | _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
|
- | 1518 | return; |
|
- | 1519 | } |
|
- | 1520 | ||
- | 1521 | mesh = (cairo_mesh_pattern_t *) pattern; |
|
- | 1522 | if (unlikely (!mesh->current_patch)) { |
|
- | 1523 | _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_MESH_CONSTRUCTION); |
|
- | 1524 | return; |
|
- | 1525 | } |
|
- | 1526 | ||
- | 1527 | if (unlikely (mesh->current_side == 3)) { |
|
- | 1528 | _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_MESH_CONSTRUCTION); |
|
- | 1529 | return; |
|
- | 1530 | } |
|
- | 1531 | ||
- | 1532 | if (mesh->current_side == -2) { |
|
- | 1533 | cairo_mesh_pattern_move_to (pattern, x, y); |
|
- | 1534 | return; |
|
- | 1535 | } |
|
- | 1536 | ||
- | 1537 | last_point_idx = 3 * (mesh->current_side + 1); |
|
- | 1538 | i = mesh_path_point_i[last_point_idx]; |
|
- | 1539 | j = mesh_path_point_j[last_point_idx]; |
|
- | 1540 | ||
- | 1541 | last_point = mesh->current_patch->points[i][j]; |
|
- | 1542 | ||
- | 1543 | cairo_mesh_pattern_curve_to (pattern, |
|
- | 1544 | (2 * last_point.x + x) * (1. / 3), |
|
- | 1545 | (2 * last_point.y + y) * (1. / 3), |
|
- | 1546 | (last_point.x + 2 * x) * (1. / 3), |
|
- | 1547 | (last_point.y + 2 * y) * (1. / 3), |
|
- | 1548 | x, y); |
|
- | 1549 | } |
|
- | 1550 | slim_hidden_def (cairo_mesh_pattern_line_to); |
|
- | 1551 | ||
- | 1552 | /** |
|
- | 1553 | * cairo_mesh_pattern_move_to: |
|
- | 1554 | * @pattern: a #cairo_pattern_t |
|
- | 1555 | * @x: the X coordinate of the new position |
|
- | 1556 | * @y: the Y coordinate of the new position |
|
- | 1557 | * |
|
- | 1558 | * Define the first point of the current patch in a mesh pattern. |
|
- | 1559 | * |
|
- | 1560 | * After this call the current point will be (@x, @y). |
|
- | 1561 | * |
|
- | 1562 | * Note: If @pattern is not a mesh pattern then @pattern will be put |
|
- | 1563 | * into an error status with a status of |
|
- | 1564 | * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. If @pattern has no current |
|
- | 1565 | * patch or the current patch already has at least one side, @pattern |
|
- | 1566 | * will be put into an error status with a status of |
|
- | 1567 | * %CAIRO_STATUS_INVALID_MESH_CONSTRUCTION. |
|
- | 1568 | * |
|
- | 1569 | * Since: 1.12 |
|
- | 1570 | **/ |
|
- | 1571 | void |
|
- | 1572 | cairo_mesh_pattern_move_to (cairo_pattern_t *pattern, |
|
- | 1573 | double x, double y) |
|
- | 1574 | { |
|
- | 1575 | cairo_mesh_pattern_t *mesh; |
|
- | 1576 | ||
- | 1577 | if (unlikely (pattern->status)) |
|
- | 1578 | return; |
|
- | 1579 | ||
- | 1580 | if (unlikely (pattern->type != CAIRO_PATTERN_TYPE_MESH)) { |
|
- | 1581 | _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
|
- | 1582 | return; |
|
- | 1583 | } |
|
- | 1584 | ||
- | 1585 | mesh = (cairo_mesh_pattern_t *) pattern; |
|
- | 1586 | if (unlikely (!mesh->current_patch)) { |
|
- | 1587 | _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_MESH_CONSTRUCTION); |
|
- | 1588 | return; |
|
- | 1589 | } |
|
- | 1590 | ||
- | 1591 | if (unlikely (mesh->current_side >= 0)) { |
|
- | 1592 | _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_MESH_CONSTRUCTION); |
|
- | 1593 | return; |
|
- | 1594 | } |
|
- | 1595 | ||
- | 1596 | mesh->current_side = -1; |
|
- | 1597 | mesh->current_patch->points[0][0].x = x; |
|
- | 1598 | mesh->current_patch->points[0][0].y = y; |
|
- | 1599 | } |
|
- | 1600 | slim_hidden_def (cairo_mesh_pattern_move_to); |
|
- | 1601 | ||
- | 1602 | /** |
|
- | 1603 | * cairo_mesh_pattern_set_control_point: |
|
- | 1604 | * @pattern: a #cairo_pattern_t |
|
- | 1605 | * @point_num: the control point to set the position for |
|
- | 1606 | * @x: the X coordinate of the control point |
|
- | 1607 | * @y: the Y coordinate of the control point |
|
- | 1608 | * |
|
- | 1609 | * Set an internal control point of the current patch. |
|
- | 1610 | * |
|
- | 1611 | * Valid values for @point_num are from 0 to 3 and identify the |
|
- | 1612 | * control points as explained in cairo_pattern_create_mesh(). |
|
- | 1613 | * |
|
- | 1614 | * Note: If @pattern is not a mesh pattern then @pattern will be put |
|
- | 1615 | * into an error status with a status of |
|
- | 1616 | * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. If @point_num is not valid, |
|
- | 1617 | * @pattern will be put into an error status with a status of |
|
- | 1618 | * %CAIRO_STATUS_INVALID_INDEX. If @pattern has no current patch, |
|
- | 1619 | * @pattern will be put into an error status with a status of |
|
- | 1620 | * %CAIRO_STATUS_INVALID_MESH_CONSTRUCTION. |
|
- | 1621 | * |
|
- | 1622 | * Since: 1.12 |
|
- | 1623 | **/ |
|
- | 1624 | void |
|
- | 1625 | cairo_mesh_pattern_set_control_point (cairo_pattern_t *pattern, |
|
- | 1626 | unsigned int point_num, |
|
- | 1627 | double x, |
|
- | 1628 | double y) |
|
- | 1629 | { |
|
- | 1630 | cairo_mesh_pattern_t *mesh; |
|
- | 1631 | int i, j; |
|
- | 1632 | ||
- | 1633 | if (unlikely (pattern->status)) |
|
- | 1634 | return; |
|
- | 1635 | ||
- | 1636 | if (unlikely (pattern->type != CAIRO_PATTERN_TYPE_MESH)) { |
|
- | 1637 | _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
|
- | 1638 | return; |
|
- | 1639 | } |
|
- | 1640 | ||
- | 1641 | if (unlikely (point_num > 3)) { |
|
- | 1642 | _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_INDEX); |
|
- | 1643 | return; |
|
- | 1644 | } |
|
- | 1645 | ||
- | 1646 | mesh = (cairo_mesh_pattern_t *) pattern; |
|
- | 1647 | if (unlikely (!mesh->current_patch)) { |
|
- | 1648 | _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_MESH_CONSTRUCTION); |
|
- | 1649 | return; |
|
- | 1650 | } |
|
- | 1651 | ||
- | 1652 | i = mesh_control_point_i[point_num]; |
|
- | 1653 | j = mesh_control_point_j[point_num]; |
|
- | 1654 | ||
- | 1655 | mesh->current_patch->points[i][j].x = x; |
|
- | 1656 | mesh->current_patch->points[i][j].y = y; |
|
- | 1657 | mesh->has_control_point[point_num] = TRUE; |
|
907 | } |
1658 | } |
908 | 1659 | ||
909 | /* make room for at least one more color stop */ |
1660 | /* make room for at least one more color stop */ |
910 | static cairo_status_t |
1661 | static cairo_status_t |
911 | _cairo_pattern_gradient_grow (cairo_gradient_pattern_t *pattern) |
1662 | _cairo_pattern_gradient_grow (cairo_gradient_pattern_t *pattern) |
Line 946... | Line 1697... | ||
946 | 1697 | ||
947 | return CAIRO_STATUS_SUCCESS; |
1698 | return CAIRO_STATUS_SUCCESS; |
Line 948... | Line 1699... | ||
948 | } |
1699 | } |
- | 1700 | ||
- | 1701 | static void |
|
- | 1702 | _cairo_mesh_pattern_set_corner_color (cairo_mesh_pattern_t *mesh, |
|
- | 1703 | unsigned int corner_num, |
|
- | 1704 | double red, double green, double blue, |
|
- | 1705 | double alpha) |
|
- | 1706 | { |
|
- | 1707 | cairo_color_t *color; |
|
- | 1708 | ||
- | 1709 | assert (mesh->current_patch); |
|
- | 1710 | assert (corner_num <= 3); |
|
- | 1711 | ||
- | 1712 | color = &mesh->current_patch->colors[corner_num]; |
|
- | 1713 | color->red = red; |
|
- | 1714 | color->green = green; |
|
- | 1715 | color->blue = blue; |
|
- | 1716 | color->alpha = alpha; |
|
- | 1717 | ||
- | 1718 | color->red_short = _cairo_color_double_to_short (red); |
|
- | 1719 | color->green_short = _cairo_color_double_to_short (green); |
|
- | 1720 | color->blue_short = _cairo_color_double_to_short (blue); |
|
- | 1721 | color->alpha_short = _cairo_color_double_to_short (alpha); |
|
- | 1722 | ||
- | 1723 | mesh->has_color[corner_num] = TRUE; |
|
- | 1724 | } |
|
- | 1725 | ||
- | 1726 | /** |
|
- | 1727 | * cairo_mesh_pattern_set_corner_color_rgb: |
|
- | 1728 | * @pattern: a #cairo_pattern_t |
|
- | 1729 | * @corner_num: the corner to set the color for |
|
- | 1730 | * @red: red component of color |
|
- | 1731 | * @green: green component of color |
|
- | 1732 | * @blue: blue component of color |
|
- | 1733 | * |
|
- | 1734 | * Sets the color of a corner of the current patch in a mesh pattern. |
|
- | 1735 | * |
|
- | 1736 | * The color is specified in the same way as in cairo_set_source_rgb(). |
|
- | 1737 | * |
|
- | 1738 | * Valid values for @corner_num are from 0 to 3 and identify the |
|
- | 1739 | * corners as explained in cairo_pattern_create_mesh(). |
|
- | 1740 | * |
|
- | 1741 | * Note: If @pattern is not a mesh pattern then @pattern will be put |
|
- | 1742 | * into an error status with a status of |
|
- | 1743 | * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. If @corner_num is not valid, |
|
- | 1744 | * @pattern will be put into an error status with a status of |
|
- | 1745 | * %CAIRO_STATUS_INVALID_INDEX. If @pattern has no current patch, |
|
- | 1746 | * @pattern will be put into an error status with a status of |
|
- | 1747 | * %CAIRO_STATUS_INVALID_MESH_CONSTRUCTION. |
|
- | 1748 | * |
|
- | 1749 | * Since: 1.12 |
|
- | 1750 | **/ |
|
- | 1751 | void |
|
- | 1752 | cairo_mesh_pattern_set_corner_color_rgb (cairo_pattern_t *pattern, |
|
- | 1753 | unsigned int corner_num, |
|
- | 1754 | double red, double green, double blue) |
|
- | 1755 | { |
|
- | 1756 | cairo_mesh_pattern_set_corner_color_rgba (pattern, corner_num, red, green, blue, 1.0); |
|
- | 1757 | } |
|
- | 1758 | ||
- | 1759 | /** |
|
- | 1760 | * cairo_mesh_pattern_set_corner_color_rgba: |
|
- | 1761 | * @pattern: a #cairo_pattern_t |
|
- | 1762 | * @corner_num: the corner to set the color for |
|
- | 1763 | * @red: red component of color |
|
- | 1764 | * @green: green component of color |
|
- | 1765 | * @blue: blue component of color |
|
- | 1766 | * @alpha: alpha component of color |
|
- | 1767 | * |
|
- | 1768 | * Sets the color of a corner of the current patch in a mesh pattern. |
|
- | 1769 | * |
|
- | 1770 | * The color is specified in the same way as in cairo_set_source_rgba(). |
|
- | 1771 | * |
|
- | 1772 | * Valid values for @corner_num are from 0 to 3 and identify the |
|
- | 1773 | * corners as explained in cairo_pattern_create_mesh(). |
|
- | 1774 | * |
|
- | 1775 | * Note: If @pattern is not a mesh pattern then @pattern will be put |
|
- | 1776 | * into an error status with a status of |
|
- | 1777 | * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. If @corner_num is not valid, |
|
- | 1778 | * @pattern will be put into an error status with a status of |
|
- | 1779 | * %CAIRO_STATUS_INVALID_INDEX. If @pattern has no current patch, |
|
- | 1780 | * @pattern will be put into an error status with a status of |
|
- | 1781 | * %CAIRO_STATUS_INVALID_MESH_CONSTRUCTION. |
|
- | 1782 | * |
|
- | 1783 | * Since: 1.12 |
|
- | 1784 | **/ |
|
- | 1785 | void |
|
- | 1786 | cairo_mesh_pattern_set_corner_color_rgba (cairo_pattern_t *pattern, |
|
- | 1787 | unsigned int corner_num, |
|
- | 1788 | double red, double green, double blue, |
|
- | 1789 | double alpha) |
|
- | 1790 | { |
|
- | 1791 | cairo_mesh_pattern_t *mesh; |
|
- | 1792 | ||
- | 1793 | if (unlikely (pattern->status)) |
|
- | 1794 | return; |
|
- | 1795 | ||
- | 1796 | if (unlikely (pattern->type != CAIRO_PATTERN_TYPE_MESH)) { |
|
- | 1797 | _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
|
- | 1798 | return; |
|
- | 1799 | } |
|
- | 1800 | ||
- | 1801 | if (unlikely (corner_num > 3)) { |
|
- | 1802 | _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_INDEX); |
|
- | 1803 | return; |
|
- | 1804 | } |
|
- | 1805 | ||
- | 1806 | mesh = (cairo_mesh_pattern_t *) pattern; |
|
- | 1807 | if (unlikely (!mesh->current_patch)) { |
|
- | 1808 | _cairo_pattern_set_error (pattern, CAIRO_STATUS_INVALID_MESH_CONSTRUCTION); |
|
- | 1809 | return; |
|
- | 1810 | } |
|
- | 1811 | ||
- | 1812 | red = _cairo_restrict_value (red, 0.0, 1.0); |
|
- | 1813 | green = _cairo_restrict_value (green, 0.0, 1.0); |
|
- | 1814 | blue = _cairo_restrict_value (blue, 0.0, 1.0); |
|
- | 1815 | alpha = _cairo_restrict_value (alpha, 0.0, 1.0); |
|
- | 1816 | ||
- | 1817 | _cairo_mesh_pattern_set_corner_color (mesh, corner_num, red, green, blue, alpha); |
|
- | 1818 | } |
|
- | 1819 | slim_hidden_def (cairo_mesh_pattern_set_corner_color_rgba); |
|
949 | 1820 | ||
950 | static void |
1821 | static void |
951 | _cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern, |
1822 | _cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern, |
952 | double offset, |
1823 | double offset, |
953 | double red, |
1824 | double red, |
Line 1018... | Line 1889... | ||
1018 | * |
1889 | * |
1019 | * |
1890 | * |
1020 | * Note: If the pattern is not a gradient pattern, (eg. a linear or |
1891 | * 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 |
1892 | * radial pattern), then the pattern will be put into an error status |
1022 | * with a status of %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. |
1893 | * with a status of %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. |
- | 1894 | * |
|
- | 1895 | * Since: 1.0 |
|
1023 | **/ |
1896 | **/ |
1024 | void |
1897 | void |
1025 | cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern, |
1898 | cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern, |
1026 | double offset, |
1899 | double offset, |
1027 | double red, |
1900 | double red, |
1028 | double green, |
1901 | double green, |
1029 | double blue) |
1902 | double blue) |
1030 | { |
1903 | { |
1031 | if (pattern->status) |
- | |
1032 | return; |
- | |
1033 | - | ||
1034 | if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR && |
- | |
1035 | pattern->type != CAIRO_PATTERN_TYPE_RADIAL) |
- | |
1036 | { |
- | |
1037 | _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
- | |
1038 | return; |
- | |
1039 | } |
- | |
1040 | - | ||
1041 | offset = _cairo_restrict_value (offset, 0.0, 1.0); |
- | |
1042 | red = _cairo_restrict_value (red, 0.0, 1.0); |
- | |
1043 | green = _cairo_restrict_value (green, 0.0, 1.0); |
- | |
1044 | blue = _cairo_restrict_value (blue, 0.0, 1.0); |
- | |
1045 | - | ||
1046 | _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern, |
1904 | cairo_pattern_add_color_stop_rgba (pattern, offset, red, green, blue, 1.0); |
1047 | offset, red, green, blue, 1.0); |
- | |
1048 | } |
1905 | } |
Line 1049... | Line 1906... | ||
1049 | 1906 | ||
1050 | /** |
1907 | /** |
1051 | * cairo_pattern_add_color_stop_rgba: |
1908 | * cairo_pattern_add_color_stop_rgba: |
Line 1071... | Line 1928... | ||
1071 | * transitions instead of the typical blend. |
1928 | * transitions instead of the typical blend. |
1072 | * |
1929 | * |
1073 | * Note: If the pattern is not a gradient pattern, (eg. a linear or |
1930 | * 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 |
1931 | * radial pattern), then the pattern will be put into an error status |
1075 | * with a status of %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. |
1932 | * with a status of %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. |
- | 1933 | * |
|
- | 1934 | * Since: 1.0 |
|
1076 | */ |
1935 | **/ |
1077 | void |
1936 | void |
1078 | cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern, |
1937 | cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern, |
1079 | double offset, |
1938 | double offset, |
1080 | double red, |
1939 | double red, |
1081 | double green, |
1940 | double green, |
Line 1099... | Line 1958... | ||
1099 | alpha = _cairo_restrict_value (alpha, 0.0, 1.0); |
1958 | alpha = _cairo_restrict_value (alpha, 0.0, 1.0); |
Line 1100... | Line 1959... | ||
1100 | 1959 | ||
1101 | _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern, |
1960 | _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern, |
1102 | offset, red, green, blue, alpha); |
1961 | offset, red, green, blue, alpha); |
- | 1962 | } |
|
Line 1103... | Line 1963... | ||
1103 | } |
1963 | slim_hidden_def (cairo_pattern_add_color_stop_rgba); |
1104 | 1964 | ||
1105 | /** |
1965 | /** |
1106 | * cairo_pattern_set_matrix: |
1966 | * cairo_pattern_set_matrix: |
Line 1131... | Line 1991... | ||
1131 | * Meanwhile, using values of 2.0 rather than 0.5 in the code above |
1991 | * 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. |
1992 | * would cause the pattern to appear at half of its default size. |
1133 | * |
1993 | * |
1134 | * Also, please note the discussion of the user-space locking |
1994 | * Also, please note the discussion of the user-space locking |
1135 | * semantics of cairo_set_source(). |
1995 | * semantics of cairo_set_source(). |
- | 1996 | * |
|
- | 1997 | * Since: 1.0 |
|
1136 | **/ |
1998 | **/ |
1137 | void |
1999 | void |
1138 | cairo_pattern_set_matrix (cairo_pattern_t *pattern, |
2000 | cairo_pattern_set_matrix (cairo_pattern_t *pattern, |
1139 | const cairo_matrix_t *matrix) |
2001 | const cairo_matrix_t *matrix) |
1140 | { |
2002 | { |
Line 1146... | Line 2008... | ||
1146 | 2008 | ||
1147 | if (memcmp (&pattern->matrix, matrix, sizeof (cairo_matrix_t)) == 0) |
2009 | if (memcmp (&pattern->matrix, matrix, sizeof (cairo_matrix_t)) == 0) |
Line 1148... | Line 2010... | ||
1148 | return; |
2010 | return; |
- | 2011 | ||
Line 1149... | Line 2012... | ||
1149 | 2012 | pattern->matrix = *matrix; |
|
1150 | pattern->matrix = *matrix; |
2013 | _cairo_pattern_notify_observers (pattern, CAIRO_PATTERN_NOTIFY_MATRIX); |
1151 | 2014 | ||
1152 | inverse = *matrix; |
2015 | inverse = *matrix; |
Line 1160... | Line 2023... | ||
1160 | * cairo_pattern_get_matrix: |
2023 | * cairo_pattern_get_matrix: |
1161 | * @pattern: a #cairo_pattern_t |
2024 | * @pattern: a #cairo_pattern_t |
1162 | * @matrix: return value for the matrix |
2025 | * @matrix: return value for the matrix |
1163 | * |
2026 | * |
1164 | * Stores the pattern's transformation matrix into @matrix. |
2027 | * Stores the pattern's transformation matrix into @matrix. |
- | 2028 | * |
|
- | 2029 | * Since: 1.0 |
|
1165 | **/ |
2030 | **/ |
1166 | void |
2031 | void |
1167 | cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix) |
2032 | cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix) |
1168 | { |
2033 | { |
1169 | *matrix = pattern->matrix; |
2034 | *matrix = pattern->matrix; |
Line 1186... | Line 2051... | ||
1186 | * |
2051 | * |
1187 | * |
2052 | * |
1188 | * cairo_set_source_surface (cr, image, x, y); |
2053 | * cairo_set_source_surface (cr, image, x, y); |
1189 | * cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); |
2054 | * cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); |
1190 | * |
2055 | * |
- | 2056 | * |
|
- | 2057 | * Since: 1.0 |
|
1191 | **/ |
2058 | **/ |
1192 | void |
2059 | void |
1193 | cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter) |
2060 | cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter) |
1194 | { |
2061 | { |
1195 | if (pattern->status) |
2062 | if (pattern->status) |
1196 | return; |
2063 | return; |
Line 1197... | Line 2064... | ||
1197 | 2064 | ||
- | 2065 | pattern->filter = filter; |
|
1198 | pattern->filter = filter; |
2066 | _cairo_pattern_notify_observers (pattern, CAIRO_PATTERN_NOTIFY_FILTER); |
Line 1199... | Line 2067... | ||
1199 | } |
2067 | } |
1200 | 2068 | ||
1201 | /** |
2069 | /** |
1202 | * cairo_pattern_get_filter: |
2070 | * cairo_pattern_get_filter: |
1203 | * @pattern: a #cairo_pattern_t |
2071 | * @pattern: a #cairo_pattern_t |
1204 | * |
2072 | * |
1205 | * Gets the current filter for a pattern. See #cairo_filter_t |
2073 | * Gets the current filter for a pattern. See #cairo_filter_t |
1206 | * for details on each filter. |
2074 | * for details on each filter. |
- | 2075 | * |
|
- | 2076 | * Return value: the current filter used for resizing the pattern. |
|
1207 | * |
2077 | * |
1208 | * Return value: the current filter used for resizing the pattern. |
2078 | * Since: 1.0 |
1209 | **/ |
2079 | **/ |
1210 | cairo_filter_t |
2080 | cairo_filter_t |
1211 | cairo_pattern_get_filter (cairo_pattern_t *pattern) |
2081 | cairo_pattern_get_filter (cairo_pattern_t *pattern) |
Line 1223... | Line 2093... | ||
1223 | * See #cairo_extend_t for details on the semantics of each extend |
2093 | * See #cairo_extend_t for details on the semantics of each extend |
1224 | * strategy. |
2094 | * strategy. |
1225 | * |
2095 | * |
1226 | * The default extend mode is %CAIRO_EXTEND_NONE for surface patterns |
2096 | * The default extend mode is %CAIRO_EXTEND_NONE for surface patterns |
1227 | * and %CAIRO_EXTEND_PAD for gradient patterns. |
2097 | * and %CAIRO_EXTEND_PAD for gradient patterns. |
- | 2098 | * |
|
- | 2099 | * Since: 1.0 |
|
1228 | **/ |
2100 | **/ |
1229 | void |
2101 | void |
1230 | cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend) |
2102 | cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend) |
1231 | { |
2103 | { |
1232 | if (pattern->status) |
2104 | if (pattern->status) |
1233 | return; |
2105 | return; |
Line 1234... | Line 2106... | ||
1234 | 2106 | ||
- | 2107 | pattern->extend = extend; |
|
1235 | pattern->extend = extend; |
2108 | _cairo_pattern_notify_observers (pattern, CAIRO_PATTERN_NOTIFY_EXTEND); |
Line 1236... | Line 2109... | ||
1236 | } |
2109 | } |
1237 | 2110 | ||
1238 | /** |
2111 | /** |
Line 1242... | Line 2115... | ||
1242 | * Gets the current extend mode for a pattern. See #cairo_extend_t |
2115 | * Gets the current extend mode for a pattern. See #cairo_extend_t |
1243 | * for details on the semantics of each extend strategy. |
2116 | * for details on the semantics of each extend strategy. |
1244 | * |
2117 | * |
1245 | * Return value: the current extend strategy used for drawing the |
2118 | * Return value: the current extend strategy used for drawing the |
1246 | * pattern. |
2119 | * pattern. |
- | 2120 | * |
|
- | 2121 | * Since: 1.0 |
|
1247 | **/ |
2122 | **/ |
1248 | cairo_extend_t |
2123 | cairo_extend_t |
1249 | cairo_pattern_get_extend (cairo_pattern_t *pattern) |
2124 | cairo_pattern_get_extend (cairo_pattern_t *pattern) |
1250 | { |
2125 | { |
1251 | return pattern->extend; |
2126 | return pattern->extend; |
Line 1260... | Line 2135... | ||
1260 | return; |
2135 | return; |
Line 1261... | Line 2136... | ||
1261 | 2136 | ||
1262 | cairo_matrix_multiply (&pattern->matrix, ctm_inverse, &pattern->matrix); |
2137 | cairo_matrix_multiply (&pattern->matrix, ctm_inverse, &pattern->matrix); |
Line 1263... | Line 2138... | ||
1263 | } |
2138 | } |
1264 | 2139 | ||
1265 | static void |
- | |
1266 | _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, |
2140 | static cairo_bool_t |
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 | 2141 | _linear_pattern_is_degenerate (const cairo_linear_pattern_t *linear) |
|
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 | point0.x = _cairo_fixed_to_double (pattern->p1.x); |
- | |
1286 | point0.y = _cairo_fixed_to_double (pattern->p1.y); |
- | |
1287 | point1.x = _cairo_fixed_to_double (pattern->p2.x); |
- | |
1288 | point1.y = _cairo_fixed_to_double (pattern->p2.y); |
- | |
1289 | - | ||
1290 | _cairo_matrix_get_affine (&pattern->base.base.matrix, |
- | |
1291 | &a, &b, &c, &d, &tx, &ty); |
- | |
1292 | - | ||
1293 | dx = point1.x - point0.x; |
- | |
1294 | dy = point1.y - point0.y; |
- | |
1295 | scale = dx * dx + dy * dy; |
- | |
1296 | scale = (scale) ? 1.0 / scale : 1.0; |
2142 | { |
1297 | - | ||
1298 | start = dx * point0.x + dy * point0.y; |
- | |
1299 | - | ||
1300 | for (i = 0; i < 3; i++) { |
- | |
1301 | double qx_device = (i % 2) * (width - 1) + offset_x; |
- | |
1302 | double qy_device = (i / 2) * (height - 1) + offset_y; |
- | |
1303 | - | ||
1304 | /* transform fragment into pattern space */ |
- | |
1305 | double qx = a * qx_device + c * qy_device + tx; |
- | |
1306 | double qy = b * qx_device + d * qy_device + ty; |
- | |
1307 | 2143 | return fabs (linear->pd1.x - linear->pd2.x) < DBL_EPSILON && |
|
Line -... | Line 2144... | ||
- | 2144 | fabs (linear->pd1.y - linear->pd2.y) < DBL_EPSILON; |
|
- | 2145 | } |
|
- | 2146 | ||
1308 | factors[i] = _cairo_fixed_from_double (((dx * qx + dy * qy) - start) * scale); |
2147 | static cairo_bool_t |
1309 | } |
2148 | _radial_pattern_is_degenerate (const cairo_radial_pattern_t *radial) |
- | 2149 | { |
|
- | 2150 | /* A radial pattern is considered degenerate if it can be |
|
- | 2151 | * represented as a solid or clear pattern. This corresponds to |
|
- | 2152 | * one of the two cases: |
|
- | 2153 | * |
|
1310 | 2154 | * 1) The radii are both very small: |
|
1311 | /* We consider a pattern to be vertical if the fixed point factor |
2155 | * |dr| < DBL_EPSILON && min (r0, r1) < DBL_EPSILON |
- | 2156 | * |
|
- | 2157 | * 2) The two circles have about the same radius and are very |
|
1312 | * at the two upper corners is the same. We could accept a small |
2158 | * close to each other (approximately a cylinder gradient that |
1313 | * change, but determining what change is acceptable would require |
2159 | * doesn't move with the parameter): |
- | 2160 | * |dr| < DBL_EPSILON && max (|dx|, |dy|) < 2 * DBL_EPSILON |
|
1314 | * sorting the stops in the pattern and looking at the differences. |
2161 | * |
Line -... | Line 2162... | ||
- | 2162 | * These checks are consistent with the assumptions used in |
|
- | 2163 | * _cairo_radial_pattern_box_to_parameter (). |
|
1315 | * |
2164 | */ |
1316 | * Horizontal works the same way with the two left corners. |
2165 | |
1317 | */ |
2166 | return fabs (radial->cd1.radius - radial->cd2.radius) < DBL_EPSILON && |
Line 1318... | Line 2167... | ||
1318 | 2167 | (MIN (radial->cd1.radius, radial->cd2.radius) < DBL_EPSILON || |
|
1319 | *is_vertical = factors[1] == factors[0]; |
2168 | MAX (fabs (radial->cd1.center.x - radial->cd2.center.x), |
1320 | *is_horizontal = factors[2] == factors[0]; |
2169 | fabs (radial->cd1.center.y - radial->cd2.center.y)) < 2 * DBL_EPSILON); |
1321 | } |
2170 | } |
1322 | 2171 | ||
1323 | static cairo_int_status_t |
- | |
1324 | _cairo_pattern_acquire_surface_for_gradient (const cairo_gradient_pattern_t *pattern, |
- | |
1325 | cairo_surface_t *dst, |
- | |
1326 | int x, |
- | |
1327 | int y, |
2172 | static void |
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 | cairo_bool_t repeat = FALSE; |
2173 | _cairo_linear_pattern_box_to_parameter (const cairo_linear_pattern_t *linear, |
1338 | cairo_bool_t opaque = TRUE; |
2174 | double x0, double y0, |
1339 | - | ||
1340 | pixman_gradient_stop_t pixman_stops_static[2]; |
- | |
1341 | pixman_gradient_stop_t *pixman_stops = pixman_stops_static; |
- | |
1342 | unsigned int i; |
- | |
Line 1343... | Line -... | ||
1343 | int clone_offset_x, clone_offset_y; |
- | |
1344 | cairo_matrix_t matrix = pattern->base.matrix; |
- | |
1345 | - | ||
1346 | if (CAIRO_INJECT_FAULT ()) |
- | |
1347 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
2175 | double x1, double y1, |
1348 | - | ||
Line -... | Line 2176... | ||
- | 2176 | double range[2]) |
|
1349 | if (pattern->n_stops > ARRAY_LENGTH(pixman_stops_static)) { |
2177 | { |
1350 | pixman_stops = _cairo_malloc_ab (pattern->n_stops, |
2178 | double t0, tdx, tdy; |
1351 | sizeof(pixman_gradient_stop_t)); |
2179 | double p1x, p1y, pdx, pdy, invsqnorm; |
1352 | if (unlikely (pixman_stops == NULL)) |
2180 | |
- | 2181 | assert (! _linear_pattern_is_degenerate (linear)); |
|
1353 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
2182 | |
- | 2183 | /* |
|
- | 2184 | * Linear gradients are othrogonal to the line passing through |
|
- | 2185 | * their extremes. Because of convexity, the parameter range can |
|
1354 | } |
2186 | * be computed as the convex hull (one the real line) of the |
1355 | 2187 | * parameter values of the 4 corners of the box. |
|
1356 | for (i = 0; i < pattern->n_stops; i++) { |
2188 | * |
1357 | pixman_stops[i].x = _cairo_fixed_16_16_from_double (pattern->stops[i].offset); |
2189 | * The parameter value t for a point (x,y) can be computed as: |
Line 1358... | Line 2190... | ||
1358 | pixman_stops[i].color.red = pattern->stops[i].color.red_short; |
2190 | * |
1359 | pixman_stops[i].color.green = pattern->stops[i].color.green_short; |
2191 | * t = (p2 - p1) . (x,y) / |p2 - p1|^2 |
1360 | pixman_stops[i].color.blue = pattern->stops[i].color.blue_short; |
2192 | * |
1361 | pixman_stops[i].color.alpha = pattern->stops[i].color.alpha_short; |
2193 | * t0 is the t value for the top left corner |
- | 2194 | * tdx is the difference between left and right corners |
|
1362 | if (! CAIRO_ALPHA_SHORT_IS_OPAQUE (pixman_stops[i].color.alpha)) |
2195 | * tdy is the difference between top and bottom corners |
- | 2196 | */ |
|
Line 1363... | Line 2197... | ||
1363 | opaque = FALSE; |
2197 | |
- | 2198 | p1x = linear->pd1.x; |
|
1364 | } |
2199 | p1y = linear->pd1.y; |
Line 1365... | Line 2200... | ||
1365 | 2200 | pdx = linear->pd2.x - p1x; |
|
1366 | if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) |
2201 | pdy = linear->pd2.y - p1y; |
1367 | { |
- | |
1368 | cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) pattern; |
- | |
1369 | pixman_point_fixed_t p1, p2; |
- | |
1370 | cairo_fixed_t xdim, ydim; |
2202 | invsqnorm = 1.0 / (pdx * pdx + pdy * pdy); |
1371 | 2203 | pdx *= invsqnorm; |
|
1372 | xdim = linear->p2.x - linear->p1.x; |
2204 | pdy *= invsqnorm; |
1373 | ydim = linear->p2.y - linear->p1.y; |
2205 | |
1374 | 2206 | t0 = (x0 - p1x) * pdx + (y0 - p1y) * pdy; |
|
1375 | /* |
- | |
1376 | * Transform the matrix to avoid overflow when converting between |
- | |
1377 | * cairo_fixed_t and pixman_fixed_t (without incurring performance |
- | |
1378 | * loss when the transformation is unnecessary). |
- | |
1379 | * |
- | |
Line -... | Line 2207... | ||
- | 2207 | tdx = (x1 - x0) * pdx; |
|
1380 | * XXX: Consider converting out-of-range co-ordinates and transforms. |
2208 | tdy = (y1 - y0) * pdy; |
1381 | * Having a function to compute the required transformation to |
2209 | |
1382 | * "normalize" a given bounding box would be generally useful - |
2210 | /* |
1383 | * cf linear patterns, gradient patterns, surface patterns... |
2211 | * Because of the linearity of the t value, tdx can simply be |
Line 1384... | Line -... | ||
1384 | */ |
- | |
1385 | #define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */ |
- | |
1386 | if (_cairo_fixed_integer_ceil (xdim) > PIXMAN_MAX_INT || |
- | |
1387 | _cairo_fixed_integer_ceil (ydim) > PIXMAN_MAX_INT) |
- | |
1388 | { |
- | |
1389 | double sf; |
2212 | * added the t0 to move along the top edge. After this, range[0] |
1390 | 2213 | * and range[1] represent the parameter range for the top edge, so |
|
1391 | if (xdim > ydim) |
2214 | * extending it to include the whole box simply requires adding |
1392 | sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (xdim); |
- | |
1393 | else |
- | |
1394 | sf = PIXMAN_MAX_INT / _cairo_fixed_to_double (ydim); |
- | |
1395 | - | ||
1396 | p1.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.x) * sf); |
2215 | * tdy to the correct extreme. |
1397 | p1.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p1.y) * sf); |
2216 | */ |
Line 1398... | Line -... | ||
1398 | p2.x = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.x) * sf); |
- | |
1399 | p2.y = _cairo_fixed_16_16_from_double (_cairo_fixed_to_double (linear->p2.y) * sf); |
2217 | |
1400 | 2218 | range[0] = range[1] = t0; |
|
1401 | cairo_matrix_scale (&matrix, sf, sf); |
- | |
1402 | } |
- | |
1403 | else |
2219 | if (tdx < 0) |
1404 | { |
2220 | range[0] += tdx; |
1405 | p1.x = _cairo_fixed_to_16_16 (linear->p1.x); |
2221 | else |
1406 | p1.y = _cairo_fixed_to_16_16 (linear->p1.y); |
2222 | range[1] += tdx; |
1407 | p2.x = _cairo_fixed_to_16_16 (linear->p2.x); |
- | |
1408 | p2.y = _cairo_fixed_to_16_16 (linear->p2.y); |
2223 | |
1409 | } |
2224 | if (tdy < 0) |
1410 | 2225 | range[0] += tdy; |
|
Line 1411... | Line -... | ||
1411 | pixman_image = pixman_image_create_linear_gradient (&p1, &p2, |
- | |
1412 | pixman_stops, |
- | |
1413 | pattern->n_stops); |
- | |
1414 | } |
- | |
1415 | else |
- | |
1416 | { |
- | |
1417 | cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) pattern; |
- | |
1418 | pixman_point_fixed_t c1, c2; |
2226 | else |
1419 | pixman_fixed_t r1, r2; |
2227 | range[1] += tdy; |
Line -... | Line 2228... | ||
- | 2228 | } |
|
1420 | 2229 | ||
1421 | c1.x = _cairo_fixed_to_16_16 (radial->c1.x); |
- | |
1422 | c1.y = _cairo_fixed_to_16_16 (radial->c1.y); |
2230 | static cairo_bool_t |
1423 | r1 = _cairo_fixed_to_16_16 (radial->r1); |
2231 | _extend_range (double range[2], double value, cairo_bool_t valid) |
1424 | 2232 | { |
|
1425 | c2.x = _cairo_fixed_to_16_16 (radial->c2.x); |
- | |
- | 2233 | if (!valid) |
|
1426 | c2.y = _cairo_fixed_to_16_16 (radial->c2.y); |
2234 | range[0] = range[1] = value; |
1427 | r2 = _cairo_fixed_to_16_16 (radial->r2); |
2235 | else if (value < range[0]) |
- | 2236 | range[0] = value; |
|
1428 | 2237 | else if (value > range[1]) |
|
1429 | pixman_image = pixman_image_create_radial_gradient (&c1, &c2, |
2238 | range[1] = value; |
1430 | r1, r2, |
2239 | |
- | 2240 | return TRUE; |
|
- | 2241 | } |
|
1431 | pixman_stops, |
2242 | |
- | 2243 | /* |
|
1432 | pattern->n_stops); |
2244 | * _cairo_radial_pattern_focus_is_inside: |
1433 | } |
- | |
1434 | 2245 | * |
|
1435 | if (pixman_stops != pixman_stops_static) |
- | |
1436 | free (pixman_stops); |
- | |
1437 | - | ||
1438 | if (unlikely (pixman_image == NULL)) |
- | |
1439 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
- | |
1440 | - | ||
1441 | if (_cairo_surface_is_image (dst)) |
- | |
Line -... | Line 2246... | ||
- | 2246 | * Returns %TRUE if and only if the focus point exists and is |
|
- | 2247 | * contained in one of the two extreme circles. This condition is |
|
1442 | { |
2248 | * equivalent to one of the two extreme circles being completely |
- | 2249 | * contained in the other one. |
|
- | 2250 | * |
|
- | 2251 | * Note: if the focus is on the border of one of the two circles (in |
|
Line 1443... | Line 2252... | ||
1443 | image = (cairo_image_surface_t *) |
2252 | * which case the circles are tangent in the focus point), it is not |
1444 | _cairo_image_surface_create_for_pixman_image (pixman_image, |
2253 | * considered as contained in the circle, hence this function returns |
Line -... | Line 2254... | ||
- | 2254 | * %FALSE. |
|
1445 | PIXMAN_a8r8g8b8); |
2255 | * |
- | 2256 | */ |
|
- | 2257 | cairo_bool_t |
|
1446 | if (image->base.status) |
2258 | _cairo_radial_pattern_focus_is_inside (const cairo_radial_pattern_t *radial) |
- | 2259 | { |
|
- | 2260 | double cx, cy, cr, dx, dy, dr; |
|
- | 2261 | ||
- | 2262 | cx = radial->cd1.center.x; |
|
- | 2263 | cy = radial->cd1.center.y; |
|
1447 | { |
2264 | cr = radial->cd1.radius; |
1448 | pixman_image_unref (pixman_image); |
2265 | dx = radial->cd2.center.x - cx; |
1449 | return image->base.status; |
2266 | dy = radial->cd2.center.y - cy; |
1450 | } |
2267 | dr = radial->cd2.radius - cr; |
1451 | 2268 | ||
- | 2269 | return dx*dx + dy*dy < dr*dr; |
|
1452 | attr->x_offset = attr->y_offset = 0; |
2270 | } |
- | 2271 | ||
1453 | attr->matrix = matrix; |
2272 | static void |
1454 | attr->extend = pattern->base.extend; |
2273 | _cairo_radial_pattern_box_to_parameter (const cairo_radial_pattern_t *radial, |
1455 | attr->filter = CAIRO_FILTER_NEAREST; |
2274 | double x0, double y0, |
1456 | attr->has_component_alpha = pattern->base.has_component_alpha; |
2275 | double x1, double y1, |
- | 2276 | double tolerance, |
|
- | 2277 | double range[2]) |
|
- | 2278 | { |
|
- | 2279 | double cx, cy, cr, dx, dy, dr; |
|
- | 2280 | double a, x_focus, y_focus; |
|
1457 | 2281 | double mindr, minx, miny, maxx, maxy; |
|
1458 | *out = &image->base; |
2282 | cairo_bool_t valid; |
- | 2283 | ||
1459 | 2284 | assert (! _radial_pattern_is_degenerate (radial)); |
|
- | 2285 | assert (x0 < x1); |
|
- | 2286 | assert (y0 < y1); |
|
- | 2287 | ||
- | 2288 | tolerance = MAX (tolerance, DBL_EPSILON); |
|
- | 2289 | ||
1460 | return CAIRO_STATUS_SUCCESS; |
2290 | range[0] = range[1] = 0; |
- | 2291 | valid = FALSE; |
|
- | 2292 | ||
- | 2293 | x_focus = y_focus = 0; /* silence gcc */ |
|
- | 2294 | ||
1461 | } |
2295 | cx = radial->cd1.center.x; |
1462 | 2296 | cy = radial->cd1.center.y; |
|
- | 2297 | cr = radial->cd1.radius; |
|
- | 2298 | dx = radial->cd2.center.x - cx; |
|
1463 | if (pattern->base.type == CAIRO_PATTERN_TYPE_LINEAR) { |
2299 | dy = radial->cd2.center.y - cy; |
1464 | cairo_bool_t is_horizontal; |
2300 | dr = radial->cd2.radius - cr; |
- | 2301 | ||
1465 | cairo_bool_t is_vertical; |
2302 | /* translate by -(cx, cy) to simplify computations */ |
1466 | 2303 | x0 -= cx; |
|
- | 2304 | y0 -= cy; |
|
- | 2305 | x1 -= cx; |
|
1467 | _cairo_linear_pattern_classify ((cairo_linear_pattern_t *)pattern, |
2306 | y1 -= cy; |
Line -... | Line 2307... | ||
- | 2307 | ||
- | 2308 | /* enlarge boundaries slightly to avoid rounding problems in the |
|
1468 | x, y, width, height, |
2309 | * parameter range computation */ |
- | 2310 | x0 -= DBL_EPSILON; |
|
1469 | &is_horizontal, &is_vertical); |
2311 | y0 -= DBL_EPSILON; |
1470 | if (is_horizontal) { |
2312 | x1 += DBL_EPSILON; |
1471 | height = 1; |
2313 | y1 += DBL_EPSILON; |
- | 2314 | ||
1472 | repeat = TRUE; |
2315 | /* enlarge boundaries even more to avoid rounding problems when |
1473 | } |
2316 | * testing if a point belongs to the box */ |
Line -... | Line 2317... | ||
- | 2317 | minx = x0 - DBL_EPSILON; |
|
1474 | /* width-1 repeating patterns are quite slow with scan-line based |
2318 | miny = y0 - DBL_EPSILON; |
- | 2319 | maxx = x1 + DBL_EPSILON; |
|
1475 | * compositing code, so we use a wider strip and spend some extra |
2320 | maxy = y1 + DBL_EPSILON; |
1476 | * expense in computing the gradient. It's possible that for narrow |
2321 | |
- | 2322 | /* we dont' allow negative radiuses, so we will be checking that |
|
1477 | * gradients we'd be better off using a 2 or 4 pixel strip; the |
2323 | * t*dr >= mindr to consider t valid */ |
1478 | * wider the gradient, the more it's worth spending extra time |
2324 | mindr = -(cr + DBL_EPSILON); |
1479 | * computing a sample. |
2325 | |
- | 2326 | /* |
|
- | 2327 | * After the previous transformations, the start circle is |
|
Line 1480... | Line 2328... | ||
1480 | */ |
2328 | * centered in the origin and has radius cr. A 1-unit change in |
1481 | if (is_vertical && width > 8) { |
2329 | * the t parameter corresponds to dx,dy,dr changes in the x,y,r of |
1482 | width = 8; |
2330 | * the circle (center coordinates, radius). |
1483 | repeat = TRUE; |
2331 | * |
1484 | } |
2332 | * To compute the minimum range needed to correctly draw the |
- | 2333 | * pattern, we start with an empty range and extend it to include |
|
1485 | } |
2334 | * the circles touching the bounding box or within it. |
1486 | 2335 | */ |
|
1487 | if (! pixman_image_set_filter (pixman_image, PIXMAN_FILTER_BILINEAR, |
- | |
1488 | NULL, 0)) |
- | |
1489 | { |
- | |
1490 | pixman_image_unref (pixman_image); |
- | |
1491 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
- | |
1492 | } |
- | |
1493 | - | ||
1494 | image = (cairo_image_surface_t *) |
- | |
1495 | cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height); |
- | |
1496 | if (image->base.status) { |
- | |
1497 | pixman_image_unref (pixman_image); |
- | |
1498 | return image->base.status; |
- | |
1499 | } |
- | |
1500 | - | ||
1501 | _cairo_matrix_to_pixman_matrix (&matrix, &pixman_transform, |
2336 | |
Line -... | Line 2337... | ||
- | 2337 | /* |
|
- | 2338 | * Focus, the point where the circle has radius == 0. |
|
- | 2339 | * |
|
1502 | width/2., height/2.); |
2340 | * r = cr + t * dr = 0 |
- | 2341 | * t = -cr / dr |
|
- | 2342 | * |
|
- | 2343 | * If the radius is constant (dr == 0) there is no focus (the |
|
- | 2344 | * gradient represents a cylinder instead of a cone). |
|
- | 2345 | */ |
|
1503 | if (!pixman_image_set_transform (pixman_image, &pixman_transform)) { |
2346 | if (fabs (dr) >= DBL_EPSILON) { |
1504 | cairo_surface_destroy (&image->base); |
2347 | double t_focus; |
1505 | pixman_image_unref (pixman_image); |
2348 | |
- | 2349 | t_focus = -cr / dr; |
|
- | 2350 | x_focus = t_focus * dx; |
|
- | 2351 | y_focus = t_focus * dy; |
|
- | 2352 | if (minx <= x_focus && x_focus <= maxx && |
|
- | 2353 | miny <= y_focus && y_focus <= maxy) |
|
- | 2354 | { |
|
- | 2355 | valid = _extend_range (range, t_focus, valid); |
|
- | 2356 | } |
|
1506 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
2357 | } |
1507 | } |
2358 | |
- | 2359 | /* |
|
- | 2360 | * Circles externally tangent to box edges. |
|
- | 2361 | * |
|
- | 2362 | * All circles have center in (dx, dy) * t |
|
1508 | 2363 | * |
|
- | 2364 | * If the circle is tangent to the line defined by the edge of the |
|
- | 2365 | * box, then at least one of the following holds true: |
|
- | 2366 | * |
|
- | 2367 | * (dx*t) + (cr + dr*t) == x0 (left edge) |
|
- | 2368 | * (dx*t) - (cr + dr*t) == x1 (right edge) |
|
1509 | switch (pattern->base.extend) { |
2369 | * (dy*t) + (cr + dr*t) == y0 (top edge) |
- | 2370 | * (dy*t) - (cr + dr*t) == y1 (bottom edge) |
|
- | 2371 | * |
|
- | 2372 | * The solution is only valid if the tangent point is actually on |
|
- | 2373 | * the edge, i.e. if its y coordinate is in [y0,y1] for left/right |
|
- | 2374 | * edges and if its x coordinate is in [x0,x1] for top/bottom |
|
- | 2375 | * edges. |
|
- | 2376 | * |
|
- | 2377 | * For the first equation: |
|
- | 2378 | * |
|
- | 2379 | * (dx + dr) * t = x0 - cr |
|
1510 | case CAIRO_EXTEND_NONE: |
2380 | * t = (x0 - cr) / (dx + dr) |
- | 2381 | * y = dy * t |
|
- | 2382 | * |
|
- | 2383 | * in the code this becomes: |
|
- | 2384 | * |
|
1511 | pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_NONE); |
2385 | * t_edge = (num) / (den) |
Line 1512... | Line 2386... | ||
1512 | break; |
2386 | * v = (delta) * t_edge |
Line -... | Line 2387... | ||
- | 2387 | * |
|
- | 2388 | * If the denominator in t is 0, the pattern is tangent to a line |
|
- | 2389 | * parallel to the edge under examination. The corner-case where |
|
1513 | case CAIRO_EXTEND_REPEAT: |
2390 | * the boundary line is the same as the edge is handled by the |
- | 2391 | * focus point case and/or by the a==0 case. |
|
- | 2392 | */ |
|
- | 2393 | #define T_EDGE(num,den,delta,lower,upper) \ |
|
1514 | pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_NORMAL); |
2394 | if (fabs (den) >= DBL_EPSILON) { \ |
- | 2395 | double t_edge, v; \ |
|
- | 2396 | \ |
|
- | 2397 | t_edge = (num) / (den); \ |
|
1515 | break; |
2398 | v = t_edge * (delta); \ |
- | 2399 | if (t_edge * dr >= mindr && (lower) <= v && v <= (upper)) \ |
|
- | 2400 | valid = _extend_range (range, t_edge, valid); \ |
|
- | 2401 | } |
|
- | 2402 | ||
- | 2403 | /* circles tangent (externally) to left/right/top/bottom edge */ |
|
- | 2404 | T_EDGE (x0 - cr, dx + dr, dy, miny, maxy); |
|
- | 2405 | T_EDGE (x1 + cr, dx - dr, dy, miny, maxy); |
|
- | 2406 | T_EDGE (y0 - cr, dy + dr, dx, minx, maxx); |
|
- | 2407 | T_EDGE (y1 + cr, dy - dr, dx, minx, maxx); |
|
- | 2408 | ||
- | 2409 | #undef T_EDGE |
|
- | 2410 | ||
1516 | case CAIRO_EXTEND_REFLECT: |
2411 | /* |
- | 2412 | * Circles passing through a corner. |
|
- | 2413 | * |
|
- | 2414 | * A circle passing through the point (x,y) satisfies: |
|
1517 | pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_REFLECT); |
2415 | * |
- | 2416 | * (x-t*dx)^2 + (y-t*dy)^2 == (cr + t*dr)^2 |
|
- | 2417 | * |
|
- | 2418 | * If we set: |
|
- | 2419 | * a = dx^2 + dy^2 - dr^2 |
|
- | 2420 | * b = x*dx + y*dy + cr*dr |
|
- | 2421 | * c = x^2 + y^2 - cr^2 |
|
- | 2422 | * we have: |
|
- | 2423 | * a*t^2 - 2*b*t + c == 0 |
|
- | 2424 | */ |
|
- | 2425 | a = dx * dx + dy * dy - dr * dr; |
|
- | 2426 | if (fabs (a) < DBL_EPSILON * DBL_EPSILON) { |
|
- | 2427 | double b, maxd2; |
|
- | 2428 | ||
- | 2429 | /* Ensure that gradients with both a and dr small are |
|
- | 2430 | * considered degenerate. |
|
- | 2431 | * The floating point version of the degeneracy test implemented |
|
- | 2432 | * in _radial_pattern_is_degenerate() is: |
|
- | 2433 | * |
|
- | 2434 | * 1) The circles are practically the same size: |
|
- | 2435 | * |dr| < DBL_EPSILON |
|
- | 2436 | * AND |
|
- | 2437 | * 2a) The circles are both very small: |
|
Line -... | Line 2438... | ||
- | 2438 | * min (r0, r1) < DBL_EPSILON |
|
- | 2439 | * OR |
|
- | 2440 | * 2b) The circles are very close to each other: |
|
- | 2441 | * max (|dx|, |dy|) < 2 * DBL_EPSILON |
|
- | 2442 | * |
|
- | 2443 | * Assuming that the gradient is not degenerate, we want to |
|
- | 2444 | * show that |a| < DBL_EPSILON^2 implies |dr| >= DBL_EPSILON. |
|
- | 2445 | * |
|
- | 2446 | * If the gradient is not degenerate yet it has |dr| < |
|
- | 2447 | * DBL_EPSILON, (2b) is false, thus: |
|
- | 2448 | * |
|
- | 2449 | * max (|dx|, |dy|) >= 2*DBL_EPSILON |
|
- | 2450 | * which implies: |
|
- | 2451 | * 4*DBL_EPSILON^2 <= max (|dx|, |dy|)^2 <= dx^2 + dy^2 |
|
- | 2452 | * |
|
- | 2453 | * From the definition of a, we get: |
|
- | 2454 | * a = dx^2 + dy^2 - dr^2 < DBL_EPSILON^2 |
|
- | 2455 | * dx^2 + dy^2 - DBL_EPSILON^2 < dr^2 |
|
1518 | break; |
2456 | * 3*DBL_EPSILON^2 < dr^2 |
- | 2457 | * |
|
- | 2458 | * which is inconsistent with the hypotheses, thus |dr| < |
|
- | 2459 | * DBL_EPSILON is false or the gradient is degenerate. |
|
- | 2460 | */ |
|
- | 2461 | assert (fabs (dr) >= DBL_EPSILON); |
|
- | 2462 | ||
- | 2463 | /* |
|
- | 2464 | * If a == 0, all the circles are tangent to a line in the |
|
- | 2465 | * focus point. If this line is within the box extents, we |
|
- | 2466 | * should add the circle with infinite radius, but this would |
|
- | 2467 | * make the range unbounded, so we add the smallest circle whose |
|
- | 2468 | * distance to the desired (degenerate) circle within the |
|
- | 2469 | * bounding box does not exceed tolerance. |
|
- | 2470 | * |
|
- | 2471 | * The equation of the line is b==0, i.e.: |
|
- | 2472 | * x*dx + y*dy + cr*dr == 0 |
|
- | 2473 | * |
|
- | 2474 | * We compute the intersection of the line with the box and |
|
- | 2475 | * keep the intersection with maximum square distance (maxd2) |
|
- | 2476 | * from the focus point. |
|
- | 2477 | * |
|
- | 2478 | * In the code the intersection is represented in another |
|
- | 2479 | * coordinate system, whose origin is the focus point and |
|
- | 2480 | * which has a u,v axes, which are respectively orthogonal and |
|
- | 2481 | * parallel to the edge being intersected. |
|
- | 2482 | * |
|
- | 2483 | * The intersection is valid only if it belongs to the box, |
|
- | 2484 | * otherwise it is ignored. |
|
- | 2485 | * |
|
- | 2486 | * For example: |
|
- | 2487 | * |
|
- | 2488 | * y = y0 |
|
- | 2489 | * x*dx + y0*dy + cr*dr == 0 |
|
- | 2490 | * x = -(y0*dy + cr*dr) / dx |
|
- | 2491 | * |
|
- | 2492 | * which in (u,v) is: |
|
- | 2493 | * u = y0 - y_focus |
|
- | 2494 | * v = -(y0*dy + cr*dr) / dx - x_focus |
|
- | 2495 | * |
|
- | 2496 | * In the code: |
|
- | 2497 | * u = (edge) - (u_origin) |
|
Line 1519... | Line -... | ||
1519 | case CAIRO_EXTEND_PAD: |
- | |
1520 | pixman_image_set_repeat (pixman_image, PIXMAN_REPEAT_PAD); |
2498 | * v = -((edge) * (delta) + cr*dr) / (den) - v_focus |
1521 | break; |
- | |
1522 | } |
- | |
1523 | - | ||
1524 | pixman_image_composite32 (PIXMAN_OP_SRC, |
- | |
Line -... | Line 2499... | ||
- | 2499 | */ |
|
- | 2500 | #define T_EDGE(edge,delta,den,lower,upper,u_origin,v_origin) \ |
|
- | 2501 | if (fabs (den) >= DBL_EPSILON) { \ |
|
- | 2502 | double v; \ |
|
- | 2503 | \ |
|
- | 2504 | v = -((edge) * (delta) + cr * dr) / (den); \ |
|
- | 2505 | if ((lower) <= v && v <= (upper)) { \ |
|
- | 2506 | double u, d2; \ |
|
- | 2507 | \ |
|
- | 2508 | u = (edge) - (u_origin); \ |
|
- | 2509 | v -= (v_origin); \ |
|
1525 | pixman_image, |
2510 | d2 = u*u + v*v; \ |
- | 2511 | if (maxd2 < d2) \ |
|
- | 2512 | maxd2 = d2; \ |
|
- | 2513 | } \ |
|
- | 2514 | } |
|
- | 2515 | ||
- | 2516 | maxd2 = 0; |
|
1526 | NULL, |
2517 | |
Line -... | Line 2518... | ||
- | 2518 | /* degenerate circles (lines) passing through each edge */ |
|
1527 | image->pixman_image, |
2519 | T_EDGE (y0, dy, dx, minx, maxx, y_focus, x_focus); |
- | 2520 | T_EDGE (y1, dy, dx, minx, maxx, y_focus, x_focus); |
|
- | 2521 | T_EDGE (x0, dx, dy, miny, maxy, x_focus, y_focus); |
|
- | 2522 | T_EDGE (x1, dx, dy, miny, maxy, x_focus, y_focus); |
|
- | 2523 | ||
- | 2524 | #undef T_EDGE |
|
1528 | x, y, |
2525 | |
- | 2526 | /* |
|
- | 2527 | * The limit circle can be transformed rigidly to the y=0 line |
|
1529 | 0, 0, |
2528 | * and the circles tangent to it in (0,0) are: |
- | 2529 | * |
|
- | 2530 | * x^2 + (y-r)^2 = r^2 <=> x^2 + y^2 - 2*y*r = 0 |
|
1530 | 0, 0, |
2531 | * |
1531 | width, height); |
2532 | * y is the distance from the line, in our case tolerance; |
1532 | 2533 | * x is the distance along the line, i.e. sqrt(maxd2), |
|
1533 | pixman_image_unref (pixman_image); |
2534 | * so: |
1534 | 2535 | * |
|
1535 | _cairo_debug_check_image_surface_is_defined (&image->base); |
2536 | * r = cr + dr * t = (maxd2 + tolerance^2) / (2*tolerance) |
- | 2537 | * t = (r - cr) / dr = |
|
- | 2538 | * (maxd2 + tolerance^2 - 2*tolerance*cr) / (2*tolerance*dr) |
|
- | 2539 | */ |
|
- | 2540 | if (maxd2 > 0) { |
|
- | 2541 | double t_limit = maxd2 + tolerance*tolerance - 2*tolerance*cr; |
|
1536 | 2542 | t_limit /= 2 * tolerance * dr; |
|
- | 2543 | valid = _extend_range (range, t_limit, valid); |
|
- | 2544 | } |
|
- | 2545 | ||
- | 2546 | /* |
|
Line 1537... | Line 2547... | ||
1537 | status = _cairo_surface_clone_similar (dst, &image->base, |
2547 | * Nondegenerate, nonlimit circles passing through the corners. |
1538 | 0, 0, width, height, |
- | |
1539 | &clone_offset_x, |
- | |
1540 | &clone_offset_y, |
- | |
1541 | out); |
2548 | * |
1542 | - | ||
1543 | cairo_surface_destroy (&image->base); |
- | |
1544 | 2549 | * a == 0 && a*t^2 - 2*b*t + c == 0 |
|
Line 1545... | Line -... | ||
1545 | attr->x_offset = -x; |
- | |
1546 | attr->y_offset = -y; |
2550 | * |
Line -... | Line 2551... | ||
- | 2551 | * t = c / (2*b) |
|
- | 2552 | * |
|
- | 2553 | * The b == 0 case has just been handled, so we only have to |
|
- | 2554 | * compute this if b != 0. |
|
- | 2555 | */ |
|
- | 2556 | #define T_CORNER(x,y) \ |
|
- | 2557 | b = (x) * dx + (y) * dy + cr * dr; \ |
|
1547 | cairo_matrix_init_identity (&attr->matrix); |
2558 | if (fabs (b) >= DBL_EPSILON) { \ |
- | 2559 | double t_corner; \ |
|
- | 2560 | double x2 = (x) * (x); \ |
|
- | 2561 | double y2 = (y) * (y); \ |
|
- | 2562 | double cr2 = (cr) * (cr); \ |
|
- | 2563 | double c = x2 + y2 - cr2; \ |
|
- | 2564 | \ |
|
- | 2565 | t_corner = 0.5 * c / b; \ |
|
- | 2566 | if (t_corner * dr >= mindr) \ |
|
- | 2567 | valid = _extend_range (range, t_corner, valid); \ |
|
- | 2568 | } |
|
- | 2569 | ||
- | 2570 | /* circles touching each corner */ |
|
- | 2571 | T_CORNER (x0, y0); |
|
- | 2572 | T_CORNER (x0, y1); |
|
- | 2573 | T_CORNER (x1, y0); |
|
- | 2574 | T_CORNER (x1, y1); |
|
- | 2575 | ||
- | 2576 | #undef T_CORNER |
|
- | 2577 | } else { |
|
- | 2578 | double inva, b, c, d; |
|
- | 2579 | ||
- | 2580 | inva = 1 / a; |
|
1548 | attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE; |
2581 | |
Line 1549... | Line 2582... | ||
1549 | attr->filter = CAIRO_FILTER_NEAREST; |
2582 | /* |
1550 | attr->has_component_alpha = pattern->base.has_component_alpha; |
2583 | * Nondegenerate, nonlimit circles passing through the corners. |
1551 | - | ||
1552 | return status; |
- | |
1553 | } |
- | |
1554 | - | ||
1555 | /* We maintain a small cache here, because we don't want to constantly |
- | |
1556 | * recreate surfaces for simple solid colors. */ |
- | |
1557 | #define MAX_SURFACE_CACHE_SIZE 16 |
- | |
1558 | static struct { |
- | |
1559 | struct _cairo_pattern_solid_surface_cache{ |
- | |
1560 | cairo_color_t color; |
- | |
1561 | cairo_surface_t *surface; |
- | |
1562 | } cache[MAX_SURFACE_CACHE_SIZE]; |
2584 | * |
Line -... | Line 2585... | ||
- | 2585 | * a != 0 && a*t^2 - 2*b*t + c == 0 |
|
1563 | int size; |
2586 | * |
- | 2587 | * t = (b +- sqrt (b*b - a*c)) / a |
|
1564 | } solid_surface_cache; |
2588 | * |
1565 | 2589 | * If the argument of sqrt() is negative, then no circle |
|
1566 | static cairo_bool_t |
- | |
1567 | _cairo_pattern_solid_surface_matches ( |
- | |
1568 | const struct _cairo_pattern_solid_surface_cache *cache, |
2590 | * passes through the corner. |
- | 2591 | */ |
|
1569 | const cairo_solid_pattern_t *pattern, |
2592 | #define T_CORNER(x,y) \ |
1570 | cairo_surface_t *dst) |
2593 | b = (x) * dx + (y) * dy + cr * dr; \ |
1571 | { |
2594 | c = (x) * (x) + (y) * (y) - cr * cr; \ |
1572 | if (cairo_surface_get_content (cache->surface) != _cairo_color_get_content (&pattern->color)) |
2595 | d = b * b - a * c; \ |
1573 | return FALSE; |
2596 | if (d >= 0) { \ |
1574 | 2597 | double t_corner; \ |
|
1575 | if (CAIRO_REFERENCE_COUNT_GET_VALUE (&cache->surface->ref_count) != 1) |
- | |
1576 | return FALSE; |
- | |
1577 | 2598 | \ |
|
1578 | if (! _cairo_surface_is_similar (cache->surface, dst)) |
2599 | d = sqrt (d); \ |
1579 | return FALSE; |
- | |
1580 | 2600 | t_corner = (b + d) * inva; \ |
|
1581 | return TRUE; |
2601 | if (t_corner * dr >= mindr) \ |
1582 | } |
- | |
1583 | 2602 | valid = _extend_range (range, t_corner, valid); \ |
|
1584 | static cairo_bool_t |
2603 | t_corner = (b - d) * inva; \ |
1585 | _cairo_pattern_solid_surface_matches_color ( |
2604 | if (t_corner * dr >= mindr) \ |
- | 2605 | valid = _extend_range (range, t_corner, valid); \ |
|
1586 | const struct _cairo_pattern_solid_surface_cache *cache, |
2606 | } |
1587 | const cairo_solid_pattern_t *pattern, |
- | |
Line 1588... | Line 2607... | ||
1588 | cairo_surface_t *dst) |
2607 | |
1589 | { |
2608 | /* circles touching each corner */ |
1590 | if (! _cairo_color_equal (&cache->color, &pattern->color)) |
2609 | T_CORNER (x0, y0); |
1591 | return FALSE; |
2610 | T_CORNER (x0, y1); |
1592 | - | ||
- | 2611 | T_CORNER (x1, y0); |
|
1593 | return _cairo_pattern_solid_surface_matches (cache, pattern, dst); |
2612 | T_CORNER (x1, y1); |
1594 | } |
2613 | |
1595 | 2614 | #undef T_CORNER |
|
Line -... | Line 2615... | ||
- | 2615 | } |
|
1596 | static cairo_int_status_t |
2616 | } |
1597 | _cairo_pattern_acquire_surface_for_solid (const cairo_solid_pattern_t *pattern, |
2617 | |
1598 | cairo_surface_t *dst, |
2618 | /** |
1599 | int x, |
2619 | * _cairo_gradient_pattern_box_to_parameter: |
1600 | int y, |
2620 | * |
- | 2621 | * Compute a interpolation range sufficient to draw (within the given |
|
1601 | unsigned int width, |
2622 | * tolerance) the gradient in the given box getting the same result as |
1602 | unsigned int height, |
2623 | * using the (-inf, +inf) range. |
1603 | cairo_surface_t **out, |
2624 | * |
1604 | cairo_surface_attributes_t *attribs) |
2625 | * Assumes that the pattern is not degenerate. This can be guaranteed |
1605 | { |
2626 | * by simplifying it to a solid clear if _cairo_pattern_is_clear or to |
1606 | static int i; |
2627 | * a solid color if _cairo_gradient_pattern_is_solid. |
1607 | 2628 | * |
|
1608 | cairo_surface_t *surface, *to_destroy = NULL; |
- | |
1609 | cairo_status_t status; |
- | |
Line 1610... | Line 2629... | ||
1610 | 2629 | * The range isn't guaranteed to be minimal, but it tries to. |
|
1611 | CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock); |
- | |
1612 | - | ||
1613 | /* Check cache first */ |
- | |
1614 | if (i < solid_surface_cache.size && |
- | |
1615 | _cairo_pattern_solid_surface_matches_color (&solid_surface_cache.cache[i], |
- | |
1616 | pattern, |
- | |
1617 | dst)) |
- | |
Line 1618... | Line 2630... | ||
1618 | { |
2630 | **/ |
1619 | goto DONE; |
2631 | void |
1620 | } |
2632 | _cairo_gradient_pattern_box_to_parameter (const cairo_gradient_pattern_t *gradient, |
1621 | 2633 | double x0, double y0, |
|
1622 | for (i = 0 ; i < solid_surface_cache.size; i++) { |
2634 | double x1, double y1, |
1623 | if (_cairo_pattern_solid_surface_matches_color (&solid_surface_cache.cache[i], |
2635 | double tolerance, |
1624 | pattern, |
- | |
1625 | dst)) |
2636 | double out_range[2]) |
- | 2637 | { |
|
1626 | { |
2638 | assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR || |
1627 | goto DONE; |
2639 | gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL); |
1628 | } |
2640 | |
Line 1629... | Line -... | ||
1629 | } |
- | |
1630 | - | ||
1631 | /* Choose a surface to repaint/evict */ |
- | |
1632 | surface = NULL; |
- | |
1633 | if (solid_surface_cache.size == MAX_SURFACE_CACHE_SIZE) { |
2641 | if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) { |
1634 | i = rand () % MAX_SURFACE_CACHE_SIZE; |
- | |
1635 | surface = solid_surface_cache.cache[i].surface; |
- | |
1636 | 2642 | _cairo_linear_pattern_box_to_parameter ((cairo_linear_pattern_t *) gradient, |
|
1637 | if (_cairo_pattern_solid_surface_matches (&solid_surface_cache.cache[i], |
- | |
1638 | pattern, |
- | |
1639 | dst)) |
- | |
1640 | { |
- | |
1641 | /* Reuse the surface instead of evicting */ |
- | |
1642 | status = _cairo_surface_repaint_solid_pattern_surface (dst, surface, pattern); |
- | |
1643 | if (unlikely (status)) |
- | |
1644 | goto EVICT; |
- | |
1645 | - | ||
1646 | cairo_surface_reference (surface); |
- | |
1647 | } |
- | |
Line 1648... | Line -... | ||
1648 | else |
- | |
1649 | { |
- | |
1650 | EVICT: |
- | |
1651 | surface = NULL; |
- | |
1652 | } |
- | |
1653 | } |
- | |
Line 1654... | Line -... | ||
1654 | - | ||
1655 | if (surface == NULL) { |
2643 | x0, y0, x1, y1, out_range); |
1656 | /* Not cached, need to create new */ |
- | |
1657 | surface = _cairo_surface_create_solid_pattern_surface (dst, pattern); |
2644 | } else { |
1658 | if (surface == NULL) { |
2645 | _cairo_radial_pattern_box_to_parameter ((cairo_radial_pattern_t *) gradient, |
1659 | status = CAIRO_INT_STATUS_UNSUPPORTED; |
2646 | x0, y0, x1, y1, tolerance, out_range); |
- | 2647 | } |
|
1660 | goto UNLOCK; |
2648 | } |
1661 | } |
2649 | |
- | 2650 | /** |
|
1662 | if (unlikely (surface->status)) { |
2651 | * _cairo_gradient_pattern_interpolate: |
1663 | status = surface->status; |
2652 | * |
1664 | goto UNLOCK; |
2653 | * Interpolate between the start and end objects of linear or radial |
1665 | } |
2654 | * gradients. The interpolated object is stored in out_circle, with |
1666 | 2655 | * the radius being zero in the linear gradient case. |
|
- | 2656 | **/ |
|
- | 2657 | void |
|
- | 2658 | _cairo_gradient_pattern_interpolate (const cairo_gradient_pattern_t *gradient, |
|
1667 | if (unlikely (! _cairo_surface_is_similar (surface, dst))) |
2659 | double t, |
1668 | { |
- | |
1669 | /* In the rare event of a substitute surface being returned, |
- | |
1670 | * don't cache the fallback. |
- | |
1671 | */ |
- | |
1672 | *out = surface; |
- | |
1673 | goto NOCACHE; |
- | |
1674 | } |
- | |
1675 | } |
- | |
1676 | - | ||
1677 | if (i == solid_surface_cache.size) |
- | |
1678 | solid_surface_cache.size++; |
- | |
1679 | - | ||
1680 | to_destroy = solid_surface_cache.cache[i].surface; |
- | |
1681 | solid_surface_cache.cache[i].surface = surface; |
- | |
1682 | solid_surface_cache.cache[i].color = pattern->color; |
- | |
1683 | - | ||
1684 | DONE: |
2660 | cairo_circle_double_t *out_circle) |
1685 | *out = cairo_surface_reference (solid_surface_cache.cache[i].surface); |
- | |
1686 | - | ||
1687 | NOCACHE: |
- | |
Line 1688... | Line -... | ||
1688 | attribs->x_offset = attribs->y_offset = 0; |
- | |
1689 | cairo_matrix_init_identity (&attribs->matrix); |
2661 | { |
1690 | attribs->extend = CAIRO_EXTEND_REPEAT; |
2662 | assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR || |
1691 | attribs->filter = CAIRO_FILTER_NEAREST; |
- | |
1692 | attribs->has_component_alpha = pattern->base.has_component_alpha; |
- | |
1693 | - | ||
1694 | status = CAIRO_STATUS_SUCCESS; |
- | |
Line 1695... | Line -... | ||
1695 | - | ||
1696 | UNLOCK: |
- | |
1697 | CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock); |
2663 | gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL); |
1698 | 2664 | ||
1699 | if (to_destroy) |
- | |
1700 | cairo_surface_destroy (to_destroy); |
- | |
1701 | - | ||
Line -... | Line 2665... | ||
- | 2665 | #define lerp(a,b) (a)*(1-t) + (b)*t |
|
- | 2666 | ||
- | 2667 | if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) { |
|
- | 2668 | cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient; |
|
- | 2669 | out_circle->center.x = lerp (linear->pd1.x, linear->pd2.x); |
|
- | 2670 | out_circle->center.y = lerp (linear->pd1.y, linear->pd2.y); |
|
1702 | return status; |
2671 | out_circle->radius = 0; |
1703 | } |
2672 | } else { |
1704 | 2673 | cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) gradient; |
|
- | 2674 | out_circle->center.x = lerp (radial->cd1.center.x, radial->cd2.center.x); |
|
- | 2675 | out_circle->center.y = lerp (radial->cd1.center.y, radial->cd2.center.y); |
|
- | 2676 | out_circle->radius = lerp (radial->cd1.radius , radial->cd2.radius); |
|
- | 2677 | } |
|
Line 1705... | Line 2678... | ||
1705 | static void |
2678 | |
1706 | _cairo_pattern_reset_solid_surface_cache (void) |
- | |
1707 | { |
- | |
1708 | CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock); |
- | |
1709 | 2679 | #undef lerp |
|
Line 1710... | Line 2680... | ||
1710 | /* remove surfaces starting from the end so that solid_surface_cache.cache |
2680 | } |
1711 | * is always in a consistent state when we release the mutex. */ |
2681 | |
- | 2682 | ||
- | 2683 | /** |
|
- | 2684 | * _cairo_gradient_pattern_fit_to_range: |
|
- | 2685 | * |
|
- | 2686 | * Scale the extremes of a gradient to guarantee that the coordinates |
|
- | 2687 | * and their deltas are within the range (-max_value, max_value). The |
|
- | 2688 | * new extremes are stored in out_circle. |
|
1712 | while (solid_surface_cache.size) { |
2689 | * |
- | 2690 | * The pattern matrix is scaled to guarantee that the aspect of the |
|
- | 2691 | * gradient is the same and the result is stored in out_matrix. |
|
- | 2692 | * |
|
- | 2693 | **/ |
|
1713 | cairo_surface_t *surface; |
2694 | void |
1714 | 2695 | _cairo_gradient_pattern_fit_to_range (const cairo_gradient_pattern_t *gradient, |
|
- | 2696 | double max_value, |
|
- | 2697 | cairo_matrix_t *out_matrix, |
|
- | 2698 | cairo_circle_double_t out_circle[2]) |
|
- | 2699 | { |
|
- | 2700 | double dim; |
|
- | 2701 | ||
Line 1715... | Line 2702... | ||
1715 | solid_surface_cache.size--; |
2702 | assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR || |
1716 | surface = solid_surface_cache.cache[solid_surface_cache.size].surface; |
2703 | gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL); |
1717 | solid_surface_cache.cache[solid_surface_cache.size].surface = NULL; |
2704 | |
1718 | 2705 | if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) { |
|
1719 | /* release the lock to avoid the possibility of a recursive |
2706 | cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient; |
1720 | * deadlock when the surface destroy closure gets called */ |
- | |
1721 | CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock); |
- | |
1722 | cairo_surface_destroy (surface); |
- | |
1723 | CAIRO_MUTEX_LOCK (_cairo_pattern_solid_surface_cache_lock); |
- | |
1724 | } |
- | |
1725 | - | ||
1726 | CAIRO_MUTEX_UNLOCK (_cairo_pattern_solid_surface_cache_lock); |
- | |
1727 | } |
2707 | |
Line 1728... | Line 2708... | ||
1728 | 2708 | out_circle[0].center = linear->pd1; |
|
1729 | static void |
2709 | out_circle[0].radius = 0; |
1730 | _extents_to_linear_parameter (const cairo_linear_pattern_t *linear, |
2710 | out_circle[1].center = linear->pd2; |
Line 1784... | Line 2764... | ||
1784 | if (gradient->n_stops == 0 || |
2764 | if (gradient->n_stops == 0 || |
1785 | (gradient->base.extend == CAIRO_EXTEND_NONE && |
2765 | (gradient->base.extend == CAIRO_EXTEND_NONE && |
1786 | gradient->stops[0].offset == gradient->stops[gradient->n_stops - 1].offset)) |
2766 | gradient->stops[0].offset == gradient->stops[gradient->n_stops - 1].offset)) |
1787 | return TRUE; |
2767 | return TRUE; |
Line 1788... | Line -... | ||
1788 | - | ||
1789 | /* Check if the extents intersect the drawn part of the pattern. */ |
2768 | |
1790 | if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) { |
2769 | if (gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL) { |
1791 | if (gradient->base.extend == CAIRO_EXTEND_NONE) { |
2770 | /* degenerate radial gradients are clear */ |
- | 2771 | if (_radial_pattern_is_degenerate ((cairo_radial_pattern_t *) gradient)) |
|
- | 2772 | return TRUE; |
|
1792 | cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient; |
2773 | } else if (gradient->base.extend == CAIRO_EXTEND_NONE) { |
1793 | /* EXTEND_NONE degenerate linear gradients are clear */ |
2774 | /* EXTEND_NONE degenerate linear gradients are clear */ |
1794 | if (_linear_pattern_is_degenerate (linear)) |
2775 | if (_linear_pattern_is_degenerate ((cairo_linear_pattern_t *) gradient)) |
- | 2776 | return TRUE; |
|
Line -... | Line 2777... | ||
- | 2777 | } |
|
1795 | return TRUE; |
2778 | |
- | 2779 | /* Check if the extents intersect the drawn part of the pattern. */ |
|
- | 2780 | if (extents != NULL && |
|
- | 2781 | (gradient->base.extend == CAIRO_EXTEND_NONE || |
|
1796 | 2782 | gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL)) |
|
- | 2783 | { |
|
1797 | if (extents != NULL) { |
2784 | double t[2]; |
- | 2785 | ||
- | 2786 | _cairo_gradient_pattern_box_to_parameter (gradient, |
|
- | 2787 | extents->x, |
|
- | 2788 | extents->y, |
|
- | 2789 | extents->x + extents->width, |
|
- | 2790 | extents->y + extents->height, |
|
- | 2791 | DBL_EPSILON, |
|
- | 2792 | t); |
|
1798 | double t[2]; |
2793 | |
- | 2794 | if (gradient->base.extend == CAIRO_EXTEND_NONE && |
|
- | 2795 | (t[0] >= gradient->stops[gradient->n_stops - 1].offset || |
|
1799 | _extents_to_linear_parameter (linear, extents, t); |
2796 | t[1] <= gradient->stops[0].offset)) |
1800 | if ((t[0] <= 0.0 && t[1] <= 0.0) || (t[0] >= 1.0 && t[1] >= 1.0)) |
2797 | { |
1801 | return TRUE; |
2798 | return TRUE; |
1802 | } |
2799 | } |
1803 | } |
- | |
1804 | } else { |
- | |
1805 | cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) gradient; |
- | |
1806 | /* degenerate radial gradients are clear */ |
2800 | |
1807 | if (_radial_pattern_is_degenerate (radial)) |
- | |
1808 | return TRUE; |
2801 | if (t[0] == t[1]) |
Line 1809... | Line 2802... | ||
1809 | /* TODO: check actual intersection */ |
2802 | return TRUE; |
1810 | } |
2803 | } |
1811 | 2804 | ||
Line 1925... | Line 2918... | ||
1925 | 2918 | ||
1926 | _cairo_color_init_rgba (color, r * .5, g * .5, b * .5, a * .5); |
2919 | _cairo_color_init_rgba (color, r * .5, g * .5, b * .5, a * .5); |
Line 1927... | Line 2920... | ||
1927 | } |
2920 | } |
- | 2921 | ||
- | 2922 | /** |
|
- | 2923 | * _cairo_pattern_alpha_range: |
|
- | 2924 | * |
|
- | 2925 | * Convenience function to determine the minimum and maximum alpha in |
|
- | 2926 | * the drawn part of a pattern (i.e. ignoring clear parts caused by |
|
- | 2927 | * extend modes and/or pattern shape). |
|
- | 2928 | * |
|
- | 2929 | * If not NULL, out_min and out_max will be set respectively to the |
|
- | 2930 | * minimum and maximum alpha value of the pattern. |
|
- | 2931 | **/ |
|
- | 2932 | void |
|
- | 2933 | _cairo_pattern_alpha_range (const cairo_pattern_t *pattern, |
|
- | 2934 | double *out_min, |
|
- | 2935 | double *out_max) |
|
- | 2936 | { |
|
- | 2937 | double alpha_min, alpha_max; |
|
- | 2938 | ||
- | 2939 | switch (pattern->type) { |
|
- | 2940 | case CAIRO_PATTERN_TYPE_SOLID: { |
|
- | 2941 | const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern; |
|
- | 2942 | alpha_min = alpha_max = solid->color.alpha; |
|
- | 2943 | break; |
|
- | 2944 | } |
|
- | 2945 | ||
- | 2946 | case CAIRO_PATTERN_TYPE_LINEAR: |
|
- | 2947 | case CAIRO_PATTERN_TYPE_RADIAL: { |
|
- | 2948 | const cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern; |
|
- | 2949 | unsigned int i; |
|
- | 2950 | ||
- | 2951 | assert (gradient->n_stops >= 1); |
|
- | 2952 | ||
- | 2953 | alpha_min = alpha_max = gradient->stops[0].color.alpha; |
|
- | 2954 | for (i = 1; i < gradient->n_stops; i++) { |
|
- | 2955 | if (alpha_min > gradient->stops[i].color.alpha) |
|
- | 2956 | alpha_min = gradient->stops[i].color.alpha; |
|
- | 2957 | else if (alpha_max < gradient->stops[i].color.alpha) |
|
- | 2958 | alpha_max = gradient->stops[i].color.alpha; |
|
- | 2959 | } |
|
- | 2960 | ||
- | 2961 | break; |
|
- | 2962 | } |
|
- | 2963 | ||
- | 2964 | case CAIRO_PATTERN_TYPE_MESH: { |
|
- | 2965 | const cairo_mesh_pattern_t *mesh = (const cairo_mesh_pattern_t *) pattern; |
|
- | 2966 | const cairo_mesh_patch_t *patch = _cairo_array_index_const (&mesh->patches, 0); |
|
- | 2967 | unsigned int i, j, n = _cairo_array_num_elements (&mesh->patches); |
|
- | 2968 | ||
- | 2969 | assert (n >= 1); |
|
- | 2970 | ||
- | 2971 | alpha_min = alpha_max = patch[0].colors[0].alpha; |
|
- | 2972 | for (i = 0; i < n; i++) { |
|
- | 2973 | for (j = 0; j < 4; j++) { |
|
- | 2974 | if (patch[i].colors[j].alpha < alpha_min) |
|
- | 2975 | alpha_min = patch[i].colors[j].alpha; |
|
- | 2976 | else if (patch[i].colors[j].alpha > alpha_max) |
|
- | 2977 | alpha_max = patch[i].colors[j].alpha; |
|
- | 2978 | } |
|
- | 2979 | } |
|
- | 2980 | ||
- | 2981 | break; |
|
- | 2982 | } |
|
- | 2983 | ||
- | 2984 | default: |
|
- | 2985 | ASSERT_NOT_REACHED; |
|
- | 2986 | /* fall through */ |
|
- | 2987 | ||
- | 2988 | case CAIRO_PATTERN_TYPE_SURFACE: |
|
- | 2989 | case CAIRO_PATTERN_TYPE_RASTER_SOURCE: |
|
- | 2990 | alpha_min = 0; |
|
- | 2991 | alpha_max = 1; |
|
- | 2992 | break; |
|
- | 2993 | } |
|
- | 2994 | ||
- | 2995 | if (out_min) |
|
- | 2996 | *out_min = alpha_min; |
|
- | 2997 | if (out_max) |
|
- | 2998 | *out_max = alpha_max; |
|
- | 2999 | } |
|
- | 3000 | ||
- | 3001 | /** |
|
- | 3002 | * _cairo_mesh_pattern_coord_box: |
|
- | 3003 | * |
|
- | 3004 | * Convenience function to determine the range of the coordinates of |
|
- | 3005 | * the points used to define the patches of the mesh. |
|
- | 3006 | * |
|
- | 3007 | * This is guaranteed to contain the pattern extents, but might not be |
|
- | 3008 | * tight, just like a Bezier curve is always inside the convex hull of |
|
- | 3009 | * the control points. |
|
- | 3010 | * |
|
- | 3011 | * This function cannot be used while the mesh is being constructed. |
|
- | 3012 | * |
|
- | 3013 | * The function returns TRUE and sets the output parametes to define |
|
- | 3014 | * the coodrinate range if the mesh pattern contains at least one |
|
- | 3015 | * patch, otherwise it returns FALSE. |
|
- | 3016 | **/ |
|
- | 3017 | cairo_bool_t |
|
- | 3018 | _cairo_mesh_pattern_coord_box (const cairo_mesh_pattern_t *mesh, |
|
- | 3019 | double *out_xmin, |
|
- | 3020 | double *out_ymin, |
|
- | 3021 | double *out_xmax, |
|
- | 3022 | double *out_ymax) |
|
- | 3023 | { |
|
- | 3024 | const cairo_mesh_patch_t *patch; |
|
- | 3025 | unsigned int num_patches, i, j, k; |
|
- | 3026 | double x0, y0, x1, y1; |
|
- | 3027 | ||
- | 3028 | assert (mesh->current_patch == NULL); |
|
- | 3029 | ||
- | 3030 | num_patches = _cairo_array_num_elements (&mesh->patches); |
|
- | 3031 | ||
- | 3032 | if (num_patches == 0) |
|
- | 3033 | return FALSE; |
|
- | 3034 | ||
- | 3035 | patch = _cairo_array_index_const (&mesh->patches, 0); |
|
- | 3036 | x0 = x1 = patch->points[0][0].x; |
|
- | 3037 | y0 = y1 = patch->points[0][0].y; |
|
- | 3038 | ||
- | 3039 | for (i = 0; i < num_patches; i++) { |
|
- | 3040 | for (j = 0; j < 4; j++) { |
|
- | 3041 | for (k = 0; k < 4; k++) { |
|
- | 3042 | x0 = MIN (x0, patch[i].points[j][k].x); |
|
- | 3043 | y0 = MIN (y0, patch[i].points[j][k].y); |
|
- | 3044 | x1 = MAX (x1, patch[i].points[j][k].x); |
|
- | 3045 | y1 = MAX (y1, patch[i].points[j][k].y); |
|
- | 3046 | } |
|
- | 3047 | } |
|
- | 3048 | } |
|
- | 3049 | ||
- | 3050 | *out_xmin = x0; |
|
- | 3051 | *out_ymin = y0; |
|
- | 3052 | *out_xmax = x1; |
|
- | 3053 | *out_ymax = y1; |
|
- | 3054 | ||
- | 3055 | return TRUE; |
|
- | 3056 | } |
|
1928 | 3057 | ||
1929 | /** |
3058 | /** |
1930 | * _cairo_gradient_pattern_is_solid |
3059 | * _cairo_gradient_pattern_is_solid: |
1931 | * |
3060 | * |
1932 | * Convenience function to determine whether a gradient pattern is |
3061 | * Convenience function to determine whether a gradient pattern is |
1933 | * a solid color within the given extents. In this case the color |
3062 | * a solid color within the given extents. In this case the color |
Line 1964... | Line 3093... | ||
1964 | */ |
3093 | */ |
Line 1965... | Line 3094... | ||
1965 | 3094 | ||
1966 | if (extents == NULL) |
3095 | if (extents == NULL) |
Line 1967... | Line 3096... | ||
1967 | return FALSE; |
3096 | return FALSE; |
- | 3097 | ||
- | 3098 | _cairo_linear_pattern_box_to_parameter (linear, |
|
- | 3099 | extents->x, |
|
- | 3100 | extents->y, |
|
- | 3101 | extents->x + extents->width, |
|
- | 3102 | extents->y + extents->height, |
|
1968 | 3103 | t); |
|
1969 | _extents_to_linear_parameter (linear, extents, t); |
3104 | |
1970 | if (t[0] < 0.0 || t[1] > 1.0) |
3105 | if (t[0] < 0.0 || t[1] > 1.0) |
1971 | return FALSE; |
3106 | return FALSE; |
1972 | } |
3107 | } |
Line 1985... | Line 3120... | ||
1985 | gradient->stops[0].color.alpha); |
3120 | gradient->stops[0].color.alpha); |
Line 1986... | Line 3121... | ||
1986 | 3121 | ||
1987 | return TRUE; |
3122 | return TRUE; |
Line -... | Line 3123... | ||
- | 3123 | } |
|
- | 3124 | ||
- | 3125 | static cairo_bool_t |
|
- | 3126 | _mesh_is_clear (const cairo_mesh_pattern_t *mesh) |
|
- | 3127 | { |
|
- | 3128 | double x1, y1, x2, y2; |
|
- | 3129 | cairo_bool_t is_valid; |
|
- | 3130 | ||
- | 3131 | is_valid = _cairo_mesh_pattern_coord_box (mesh, &x1, &y1, &x2, &y2); |
|
- | 3132 | if (!is_valid) |
|
- | 3133 | return TRUE; |
|
- | 3134 | ||
- | 3135 | if (x2 - x1 < DBL_EPSILON || y2 - y1 < DBL_EPSILON) |
|
- | 3136 | return TRUE; |
|
- | 3137 | ||
- | 3138 | return FALSE; |
|
1988 | } |
3139 | } |
1989 | 3140 | ||
1990 | /** |
3141 | /** |
1991 | * _cairo_pattern_is_opaque_solid |
3142 | * _cairo_pattern_is_opaque_solid: |
1992 | * |
3143 | * |
1993 | * Convenience function to determine whether a pattern is an opaque |
3144 | * Convenience function to determine whether a pattern is an opaque |
1994 | * (alpha==1.0) solid color pattern. This is done by testing whether |
3145 | * (alpha==1.0) solid color pattern. This is done by testing whether |
Line 2011... | Line 3162... | ||
2011 | return CAIRO_COLOR_IS_OPAQUE (&solid->color); |
3162 | return CAIRO_COLOR_IS_OPAQUE (&solid->color); |
2012 | } |
3163 | } |
Line 2013... | Line 3164... | ||
2013 | 3164 | ||
2014 | static cairo_bool_t |
3165 | static cairo_bool_t |
2015 | _surface_is_opaque (const cairo_surface_pattern_t *pattern, |
3166 | _surface_is_opaque (const cairo_surface_pattern_t *pattern, |
2016 | const cairo_rectangle_int_t *r) |
3167 | const cairo_rectangle_int_t *sample) |
- | 3168 | { |
|
- | 3169 | cairo_rectangle_int_t extents; |
|
2017 | { |
3170 | |
2018 | if (pattern->surface->content & CAIRO_CONTENT_ALPHA) |
3171 | if (pattern->surface->content & CAIRO_CONTENT_ALPHA) |
Line 2019... | Line 3172... | ||
2019 | return FALSE; |
3172 | return FALSE; |
2020 | 3173 | ||
Line 2021... | Line -... | ||
2021 | if (pattern->base.extend != CAIRO_EXTEND_NONE) |
- | |
2022 | return TRUE; |
- | |
2023 | - | ||
2024 | if (r != NULL) { |
3174 | if (pattern->base.extend != CAIRO_EXTEND_NONE) |
2025 | cairo_rectangle_int_t extents; |
3175 | return TRUE; |
Line 2026... | Line 3176... | ||
2026 | 3176 | ||
2027 | if (! _cairo_surface_get_extents (pattern->surface, &extents)) |
3177 | if (! _cairo_surface_get_extents (pattern->surface, &extents)) |
- | 3178 | return TRUE; |
|
2028 | return TRUE; |
3179 | |
- | 3180 | if (sample == NULL) |
|
- | 3181 | return FALSE; |
|
- | 3182 | ||
- | 3183 | return _cairo_rectangle_contains_rectangle (&extents, sample); |
|
2029 | 3184 | } |
|
2030 | if (r->x >= extents.x && |
3185 | |
- | 3186 | static cairo_bool_t |
|
- | 3187 | _raster_source_is_opaque (const cairo_raster_source_pattern_t *pattern, |
|
- | 3188 | const cairo_rectangle_int_t *sample) |
|
- | 3189 | { |
|
2031 | r->y >= extents.y && |
3190 | if (pattern->content & CAIRO_CONTENT_ALPHA) |
2032 | r->x + r->width <= extents.x + extents.width && |
- | |
2033 | r->y + r->height <= extents.y + extents.height) |
- | |
Line -... | Line 3191... | ||
- | 3191 | return FALSE; |
|
2034 | { |
3192 | |
- | 3193 | if (pattern->base.extend != CAIRO_EXTEND_NONE) |
|
- | 3194 | return TRUE; |
|
2035 | return TRUE; |
3195 | |
Line 2036... | Line 3196... | ||
2036 | } |
3196 | if (sample == NULL) |
2037 | } |
3197 | return FALSE; |
2038 | 3198 | ||
Line 2051... | Line 3211... | ||
2051 | return pattern->surface->is_clear && |
3211 | return pattern->surface->is_clear && |
2052 | pattern->surface->content & CAIRO_CONTENT_ALPHA; |
3212 | pattern->surface->content & CAIRO_CONTENT_ALPHA; |
2053 | } |
3213 | } |
Line 2054... | Line 3214... | ||
2054 | 3214 | ||
- | 3215 | static cairo_bool_t |
|
- | 3216 | _raster_source_is_clear (const cairo_raster_source_pattern_t *pattern) |
|
- | 3217 | { |
|
- | 3218 | return pattern->extents.width == 0 || pattern->extents.height == 0; |
|
- | 3219 | } |
|
- | 3220 | ||
2055 | static cairo_bool_t |
3221 | static cairo_bool_t |
2056 | _gradient_is_opaque (const cairo_gradient_pattern_t *gradient, |
3222 | _gradient_is_opaque (const cairo_gradient_pattern_t *gradient, |
2057 | const cairo_rectangle_int_t *extents) |
3223 | const cairo_rectangle_int_t *sample) |
2058 | { |
3224 | { |
Line 2059... | Line 3225... | ||
2059 | unsigned int i; |
3225 | unsigned int i; |
2060 | 3226 | ||
Line 2073... | Line 3239... | ||
2073 | 3239 | ||
2074 | /* EXTEND_NONE degenerate radial gradients are clear */ |
3240 | /* EXTEND_NONE degenerate radial gradients are clear */ |
2075 | if (_linear_pattern_is_degenerate (linear)) |
3241 | if (_linear_pattern_is_degenerate (linear)) |
Line 2076... | Line 3242... | ||
2076 | return FALSE; |
3242 | return FALSE; |
2077 | 3243 | ||
Line 2078... | Line 3244... | ||
2078 | if (extents == NULL) |
3244 | if (sample == NULL) |
- | 3245 | return FALSE; |
|
- | 3246 | ||
- | 3247 | _cairo_linear_pattern_box_to_parameter (linear, |
|
- | 3248 | sample->x, |
|
- | 3249 | sample->y, |
|
- | 3250 | sample->x + sample->width, |
|
2079 | return FALSE; |
3251 | sample->y + sample->height, |
2080 | 3252 | t); |
|
2081 | _extents_to_linear_parameter (linear, extents, t); |
3253 | |
2082 | if (t[0] < 0.0 || t[1] > 1.0) |
3254 | if (t[0] < 0.0 || t[1] > 1.0) |
2083 | return FALSE; |
3255 | return FALSE; |
Line 2091... | Line 3263... | ||
2091 | 3263 | ||
2092 | return TRUE; |
3264 | return TRUE; |
Line 2093... | Line 3265... | ||
2093 | } |
3265 | } |
2094 | 3266 | ||
2095 | /** |
3267 | /** |
2096 | * _cairo_pattern_is_opaque |
3268 | * _cairo_pattern_is_opaque: |
2097 | * |
3269 | * |
2098 | * Convenience function to determine whether a pattern is an opaque |
3270 | * Convenience function to determine whether a pattern is an opaque |
2099 | * pattern (of any type). The same caveats that apply to |
3271 | * pattern (of any type). The same caveats that apply to |
2100 | * _cairo_pattern_is_opaque_solid apply here as well. |
3272 | * _cairo_pattern_is_opaque_solid apply here as well. |
2101 | * |
3273 | * |
2102 | * Return value: %TRUE if the pattern is a opaque. |
3274 | * Return value: %TRUE if the pattern is a opaque. |
2103 | **/ |
3275 | **/ |
2104 | cairo_bool_t |
3276 | cairo_bool_t |
2105 | _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern, |
3277 | _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern, |
2106 | const cairo_rectangle_int_t *extents) |
3278 | const cairo_rectangle_int_t *sample) |
Line 2107... | Line 3279... | ||
2107 | { |
3279 | { |
2108 | const cairo_pattern_union_t *pattern; |
3280 | const cairo_pattern_union_t *pattern; |
Line 2113... | Line 3285... | ||
2113 | pattern = (cairo_pattern_union_t *) abstract_pattern; |
3285 | pattern = (cairo_pattern_union_t *) abstract_pattern; |
2114 | switch (pattern->base.type) { |
3286 | switch (pattern->base.type) { |
2115 | case CAIRO_PATTERN_TYPE_SOLID: |
3287 | case CAIRO_PATTERN_TYPE_SOLID: |
2116 | return _cairo_pattern_is_opaque_solid (abstract_pattern); |
3288 | return _cairo_pattern_is_opaque_solid (abstract_pattern); |
2117 | case CAIRO_PATTERN_TYPE_SURFACE: |
3289 | case CAIRO_PATTERN_TYPE_SURFACE: |
2118 | return _surface_is_opaque (&pattern->surface, extents); |
3290 | return _surface_is_opaque (&pattern->surface, sample); |
- | 3291 | case CAIRO_PATTERN_TYPE_RASTER_SOURCE: |
|
- | 3292 | return _raster_source_is_opaque (&pattern->raster_source, sample); |
|
2119 | case CAIRO_PATTERN_TYPE_LINEAR: |
3293 | case CAIRO_PATTERN_TYPE_LINEAR: |
2120 | case CAIRO_PATTERN_TYPE_RADIAL: |
3294 | case CAIRO_PATTERN_TYPE_RADIAL: |
2121 | return _gradient_is_opaque (&pattern->gradient.base, extents); |
3295 | return _gradient_is_opaque (&pattern->gradient.base, sample); |
- | 3296 | case CAIRO_PATTERN_TYPE_MESH: |
|
- | 3297 | return FALSE; |
|
2122 | } |
3298 | } |
Line 2123... | Line 3299... | ||
2123 | 3299 | ||
2124 | ASSERT_NOT_REACHED; |
3300 | ASSERT_NOT_REACHED; |
2125 | return FALSE; |
3301 | return FALSE; |
Line 2132... | Line 3308... | ||
2132 | 3308 | ||
2133 | if (abstract_pattern->has_component_alpha) |
3309 | if (abstract_pattern->has_component_alpha) |
Line 2134... | Line 3310... | ||
2134 | return FALSE; |
3310 | return FALSE; |
2135 | 3311 | ||
2136 | pattern = (cairo_pattern_union_t *) abstract_pattern; |
3312 | pattern = (cairo_pattern_union_t *) abstract_pattern; |
2137 | switch (pattern->type) { |
3313 | switch (abstract_pattern->type) { |
2138 | case CAIRO_PATTERN_TYPE_SOLID: |
3314 | case CAIRO_PATTERN_TYPE_SOLID: |
2139 | return CAIRO_COLOR_IS_CLEAR (&pattern->solid.color); |
3315 | return CAIRO_COLOR_IS_CLEAR (&pattern->solid.color); |
- | 3316 | case CAIRO_PATTERN_TYPE_SURFACE: |
|
- | 3317 | return _surface_is_clear (&pattern->surface); |
|
2140 | case CAIRO_PATTERN_TYPE_SURFACE: |
3318 | case CAIRO_PATTERN_TYPE_RASTER_SOURCE: |
2141 | return _surface_is_clear (&pattern->surface); |
3319 | return _raster_source_is_clear (&pattern->raster_source); |
2142 | case CAIRO_PATTERN_TYPE_LINEAR: |
3320 | case CAIRO_PATTERN_TYPE_LINEAR: |
- | 3321 | case CAIRO_PATTERN_TYPE_RADIAL: |
|
- | 3322 | return _gradient_is_clear (&pattern->gradient.base, NULL); |
|
2143 | case CAIRO_PATTERN_TYPE_RADIAL: |
3323 | case CAIRO_PATTERN_TYPE_MESH: |
Line 2144... | Line 3324... | ||
2144 | return _gradient_is_clear (&pattern->gradient.base, NULL); |
3324 | return _mesh_is_clear (&pattern->mesh); |
2145 | } |
3325 | } |
2146 | 3326 | ||
Line 2159... | Line 3339... | ||
2159 | * we can optimize the filter to a simpler value. |
3339 | * we can optimize the filter to a simpler value. |
2160 | * |
3340 | * |
2161 | * XXX: We don't actually have any way of querying the backend for |
3341 | * XXX: We don't actually have any way of querying the backend for |
2162 | * the filter radius, so we just guess base on what we know that |
3342 | * the filter radius, so we just guess base on what we know that |
2163 | * backends do currently (see bug #10508) |
3343 | * backends do currently (see bug #10508) |
2164 | */ |
3344 | **/ |
2165 | cairo_filter_t |
3345 | cairo_filter_t |
2166 | _cairo_pattern_analyze_filter (const cairo_pattern_t *pattern, |
3346 | _cairo_pattern_analyze_filter (const cairo_pattern_t *pattern, |
2167 | double *pad_out) |
3347 | double *pad_out) |
2168 | { |
3348 | { |
2169 | double pad; |
3349 | double pad; |
Line 2204... | Line 3384... | ||
2204 | *pad_out = pad; |
3384 | *pad_out = pad; |
Line 2205... | Line 3385... | ||
2205 | 3385 | ||
2206 | return optimized_filter; |
3386 | return optimized_filter; |
Line 2207... | Line -... | ||
2207 | } |
- | |
2208 | - | ||
2209 | - | ||
2210 | static double |
- | |
2211 | _pixman_nearest_sample (double d) |
- | |
2212 | { |
- | |
2213 | return ceil (d - .5); |
- | |
2214 | } |
3387 | } |
2215 | 3388 | ||
2216 | static cairo_int_status_t |
3389 | cairo_filter_t |
2217 | _cairo_pattern_acquire_surface_for_surface (const cairo_surface_pattern_t *pattern, |
- | |
2218 | cairo_surface_t *dst, |
- | |
2219 | int x, |
- | |
2220 | int y, |
- | |
2221 | unsigned int width, |
- | |
2222 | unsigned int height, |
- | |
2223 | unsigned int flags, |
3390 | _cairo_pattern_sampled_area (const cairo_pattern_t *pattern, |
2224 | cairo_surface_t **out, |
3391 | const cairo_rectangle_int_t *extents, |
2225 | cairo_surface_attributes_t *attr) |
3392 | cairo_rectangle_int_t *sample) |
2226 | { |
- | |
2227 | cairo_surface_t *surface; |
- | |
2228 | cairo_rectangle_int_t extents; |
3393 | { |
2229 | cairo_rectangle_int_t sampled_area; |
- | |
2230 | double x1, y1, x2, y2; |
3394 | cairo_filter_t filter; |
2231 | int tx, ty; |
- | |
2232 | double pad; |
- | |
2233 | cairo_bool_t is_identity; |
- | |
2234 | cairo_bool_t is_empty; |
- | |
2235 | cairo_bool_t is_bounded; |
- | |
2236 | cairo_int_status_t status; |
- | |
2237 | - | ||
2238 | surface = cairo_surface_reference (pattern->surface); |
- | |
2239 | - | ||
2240 | is_identity = FALSE; |
- | |
2241 | attr->matrix = pattern->base.matrix; |
- | |
2242 | attr->extend = pattern->base.extend; |
- | |
2243 | attr->filter = _cairo_pattern_analyze_filter (&pattern->base, &pad); |
- | |
2244 | attr->has_component_alpha = pattern->base.has_component_alpha; |
- | |
2245 | - | ||
2246 | attr->x_offset = attr->y_offset = tx = ty = 0; |
- | |
2247 | if (_cairo_matrix_is_integer_translation (&attr->matrix, &tx, &ty)) { |
- | |
2248 | cairo_matrix_init_identity (&attr->matrix); |
- | |
2249 | attr->x_offset = tx; |
- | |
2250 | attr->y_offset = ty; |
- | |
2251 | is_identity = TRUE; |
- | |
2252 | } else if (attr->filter == CAIRO_FILTER_NEAREST) { |
- | |
2253 | /* |
- | |
2254 | * For NEAREST, we can remove the fractional translation component |
- | |
2255 | * from the transformation - this ensures that the pattern will always |
- | |
2256 | * hit fast-paths in the backends for simple transformations that |
- | |
2257 | * become (almost) identity, without loss of quality. |
- | |
2258 | */ |
- | |
2259 | attr->matrix.x0 = 0; |
- | |
2260 | attr->matrix.y0 = 0; |
- | |
2261 | if (_cairo_matrix_is_pixel_exact (&attr->matrix)) { |
- | |
2262 | /* The rounding here is rather peculiar as it needs to match the |
- | |
2263 | * rounding performed on the sample coordinate used by pixman. |
- | |
2264 | */ |
- | |
2265 | attr->matrix.x0 = _pixman_nearest_sample (pattern->base.matrix.x0); |
- | |
2266 | attr->matrix.y0 = _pixman_nearest_sample (pattern->base.matrix.y0); |
- | |
2267 | } else { |
- | |
2268 | attr->matrix.x0 = pattern->base.matrix.x0; |
- | |
2269 | attr->matrix.y0 = pattern->base.matrix.y0; |
- | |
2270 | } |
- | |
2271 | - | ||
2272 | if (_cairo_matrix_is_integer_translation (&attr->matrix, &tx, &ty)) { |
- | |
2273 | cairo_matrix_init_identity (&attr->matrix); |
- | |
2274 | attr->x_offset = tx; |
- | |
2275 | attr->y_offset = ty; |
- | |
2276 | is_identity = TRUE; |
- | |
2277 | } |
- | |
2278 | } |
- | |
2279 | - | ||
2280 | /* XXX: Hack: |
- | |
2281 | * |
- | |
2282 | * The way we currently support CAIRO_EXTEND_REFLECT is to create |
- | |
2283 | * an image twice bigger on each side, and create a pattern of four |
- | |
2284 | * images such that the new image, when repeated, has the same effect |
- | |
2285 | * of reflecting the original pattern. |
- | |
2286 | */ |
- | |
2287 | if (flags & CAIRO_PATTERN_ACQUIRE_NO_REFLECT && |
- | |
2288 | attr->extend == CAIRO_EXTEND_REFLECT) |
- | |
2289 | { |
- | |
2290 | cairo_t *cr; |
- | |
2291 | cairo_surface_t *src; |
- | |
2292 | int w, h; |
- | |
2293 | - | ||
2294 | is_bounded = _cairo_surface_get_extents (surface, &extents); |
- | |
2295 | assert (is_bounded); |
- | |
2296 | - | ||
2297 | status = _cairo_surface_clone_similar (dst, surface, |
- | |
2298 | extents.x, extents.y, |
- | |
2299 | extents.width, extents.height, |
- | |
2300 | &extents.x, &extents.y, &src); |
- | |
2301 | if (unlikely (status)) |
- | |
2302 | goto BAIL; |
- | |
2303 | - | ||
Line 2304... | Line -... | ||
2304 | w = 2 * extents.width; |
- | |
2305 | h = 2 * extents.height; |
3395 | double x1, x2, y1, y2; |
2306 | - | ||
2307 | if (is_identity) { |
- | |
2308 | attr->x_offset = -x; |
- | |
2309 | x += tx; |
- | |
2310 | while (x <= -w) |
- | |
2311 | x += w; |
- | |
2312 | while (x >= w) |
- | |
2313 | x -= w; |
- | |
2314 | extents.x += x; |
3396 | double pad; |
2315 | tx = x = 0; |
- | |
2316 | - | ||
2317 | attr->y_offset = -y; |
- | |
2318 | y += ty; |
- | |
2319 | while (y <= -h) |
- | |
2320 | y += h; |
3397 | |
2321 | while (y >= h) |
3398 | filter = _cairo_pattern_analyze_filter (pattern, &pad); |
2322 | y -= h; |
3399 | if (pad == 0.0 && _cairo_matrix_is_identity (&pattern->matrix)) { |
Line 2323... | Line -... | ||
2323 | extents.y += y; |
- | |
2324 | ty = y = 0; |
- | |
2325 | } |
- | |
2326 | - | ||
2327 | cairo_surface_destroy (surface); |
3400 | *sample = *extents; |
2328 | surface = _cairo_surface_create_similar_solid (dst, |
- | |
2329 | dst->content, w, h, |
- | |
2330 | CAIRO_COLOR_TRANSPARENT, |
- | |
2331 | FALSE); |
- | |
2332 | if (surface == NULL) |
3401 | return filter; |
2333 | return CAIRO_INT_STATUS_UNSUPPORTED; |
- | |
2334 | if (unlikely (surface->status)) { |
- | |
2335 | cairo_surface_destroy (src); |
- | |
2336 | return surface->status; |
- | |
2337 | } |
- | |
2338 | - | ||
2339 | surface->device_transform = pattern->surface->device_transform; |
- | |
2340 | surface->device_transform_inverse = pattern->surface->device_transform_inverse; |
- | |
2341 | - | ||
2342 | cr = cairo_create (surface); |
- | |
2343 | - | ||
2344 | cairo_set_source_surface (cr, src, -extents.x, -extents.y); |
- | |
2345 | cairo_paint (cr); |
- | |
2346 | 3402 | } |
|
2347 | cairo_scale (cr, -1, +1); |
- | |
2348 | cairo_set_source_surface (cr, src, extents.x-w, -extents.y); |
- | |
2349 | cairo_paint (cr); |
- | |
2350 | cairo_set_source_surface (cr, src, extents.x, -extents.y); |
- | |
2351 | cairo_paint (cr); |
- | |
2352 | - | ||
2353 | cairo_scale (cr, +1, -1); |
- | |
2354 | cairo_set_source_surface (cr, src, extents.x-w, extents.y-h); |
- | |
2355 | cairo_paint (cr); |
- | |
2356 | cairo_set_source_surface (cr, src, extents.x, extents.y-h); |
3403 | |
2357 | cairo_paint (cr); |
- | |
2358 | cairo_set_source_surface (cr, src, extents.x-w, extents.y); |
- | |
2359 | cairo_paint (cr); |
- | |
2360 | cairo_set_source_surface (cr, src, extents.x, extents.y); |
- | |
2361 | cairo_paint (cr); |
- | |
2362 | - | ||
2363 | cairo_scale (cr, -1, +1); |
- | |
2364 | cairo_set_source_surface (cr, src, -extents.x, extents.y-h); |
- | |
2365 | cairo_paint (cr); |
- | |
2366 | cairo_set_source_surface (cr, src, -extents.x, extents.y); |
- | |
2367 | cairo_paint (cr); |
- | |
2368 | - | ||
2369 | status = cairo_status (cr); |
- | |
2370 | cairo_destroy (cr); |
- | |
2371 | - | ||
2372 | cairo_surface_destroy (src); |
- | |
2373 | - | ||
2374 | if (unlikely (status)) |
- | |
Line 2375... | Line -... | ||
2375 | goto BAIL; |
- | |
2376 | - | ||
2377 | attr->extend = CAIRO_EXTEND_REPEAT; |
- | |
2378 | } |
- | |
2379 | - | ||
2380 | /* We first transform the rectangle to the coordinate space of the |
- | |
2381 | * source surface so that we only need to clone that portion of the |
- | |
2382 | * surface that will be read. |
- | |
2383 | */ |
- | |
2384 | x1 = x; |
3404 | x1 = extents->x; |
2385 | y1 = y; |
3405 | y1 = extents->y; |
2386 | x2 = x + (int) width; |
3406 | x2 = extents->x + (int) extents->width; |
2387 | y2 = y + (int) height; |
- | |
2388 | if (! is_identity) { |
- | |
2389 | _cairo_matrix_transform_bounding_box (&attr->matrix, |
3407 | y2 = extents->y + (int) extents->height; |
2390 | &x1, &y1, &x2, &y2, |
3408 | |
2391 | NULL); |
- | |
2392 | } |
- | |
2393 | - | ||
2394 | sampled_area.x = floor (x1 - pad); |
- | |
2395 | sampled_area.y = floor (y1 - pad); |
- | |
2396 | sampled_area.width = ceil (x2 + pad) - sampled_area.x; |
- | |
2397 | sampled_area.height = ceil (y2 + pad) - sampled_area.y; |
- | |
2398 | - | ||
2399 | sampled_area.x += tx; |
- | |
2400 | sampled_area.y += ty; |
- | |
2401 | 3409 | _cairo_matrix_transform_bounding_box (&pattern->matrix, |
|
2402 | if ( _cairo_surface_get_extents (surface, &extents)) { |
- | |
2403 | if (attr->extend == CAIRO_EXTEND_NONE) { |
- | |
2404 | /* Never acquire a larger area than the source itself */ |
- | |
2405 | is_empty = _cairo_rectangle_intersect (&extents, &sampled_area); |
- | |
2406 | } else { |
- | |
2407 | int trim = 0; |
- | |
2408 | - | ||
2409 | if (sampled_area.x >= extents.x && |
- | |
2410 | sampled_area.x + (int) sampled_area.width <= extents.x + (int) extents.width) |
- | |
2411 | { |
- | |
2412 | /* source is horizontally contained within extents, trim */ |
- | |
2413 | extents.x = sampled_area.x; |
- | |
2414 | extents.width = sampled_area.width; |
- | |
2415 | trim |= 0x1; |
- | |
2416 | } |
- | |
2417 | - | ||
2418 | if (sampled_area.y >= extents.y && |
- | |
2419 | sampled_area.y + (int) sampled_area.height <= extents.y + (int) extents.height) |
- | |
2420 | { |
- | |
2421 | /* source is vertically contained within extents, trim */ |
- | |
2422 | extents.y = sampled_area.y; |
- | |
2423 | extents.height = sampled_area.height; |
- | |
2424 | trim |= 0x2; |
3410 | &x1, &y1, &x2, &y2, |
2425 | } |
- | |
2426 | - | ||
2427 | if (trim == 0x3) { |
- | |
2428 | /* source is wholly contained within extents, drop the REPEAT */ |
- | |
2429 | attr->extend = CAIRO_EXTEND_NONE; |
- | |
2430 | } |
- | |
2431 | - | ||
2432 | is_empty = extents.width == 0 || extents.height == 0; |
- | |
2433 | } |
- | |
2434 | } |
- | |
2435 | - | ||
2436 | /* XXX can we use is_empty? */ |
- | |
2437 | - | ||
2438 | status = _cairo_surface_clone_similar (dst, surface, |
- | |
2439 | extents.x, extents.y, |
- | |
2440 | extents.width, extents.height, |
- | |
2441 | &x, &y, out); |
- | |
2442 | if (unlikely (status)) |
- | |
2443 | goto BAIL; |
- | |
2444 | - | ||
2445 | if (x != 0 || y != 0) { |
- | |
2446 | if (is_identity) { |
- | |
2447 | attr->x_offset -= x; |
- | |
2448 | attr->y_offset -= y; |
- | |
2449 | } else { |
- | |
2450 | cairo_matrix_t m; |
- | |
2451 | - | ||
2452 | x -= attr->x_offset; |
- | |
2453 | y -= attr->y_offset; |
- | |
2454 | attr->x_offset = 0; |
- | |
2455 | attr->y_offset = 0; |
- | |
2456 | - | ||
2457 | cairo_matrix_init_translate (&m, -x, -y); |
- | |
2458 | cairo_matrix_multiply (&attr->matrix, &attr->matrix, &m); |
- | |
2459 | } |
- | |
2460 | } |
- | |
2461 | - | ||
2462 | /* reduce likelihood of range overflow with large downscaling */ |
- | |
2463 | if (! is_identity) { |
- | |
2464 | cairo_matrix_t m; |
- | |
2465 | cairo_status_t invert_status; |
- | |
2466 | - | ||
2467 | m = attr->matrix; |
- | |
2468 | invert_status = cairo_matrix_invert (&m); |
- | |
2469 | assert (invert_status == CAIRO_STATUS_SUCCESS); |
- | |
2470 | - | ||
2471 | if (m.x0 != 0. || m.y0 != 0.) { |
- | |
2472 | /* pixman also limits the [xy]_offset to 16 bits so evenly |
- | |
2473 | * spread the bits between the two. |
- | |
2474 | */ |
- | |
2475 | x = floor (m.x0 / 2); |
- | |
2476 | y = floor (m.y0 / 2); |
- | |
2477 | attr->x_offset -= x; |
- | |
2478 | attr->y_offset -= y; |
- | |
2479 | cairo_matrix_init_translate (&m, x, y); |
- | |
2480 | cairo_matrix_multiply (&attr->matrix, &m, &attr->matrix); |
- | |
2481 | } |
- | |
2482 | } |
- | |
2483 | - | ||
2484 | BAIL: |
- | |
2485 | cairo_surface_destroy (surface); |
- | |
2486 | return status; |
- | |
2487 | } |
- | |
2488 | - | ||
2489 | /** |
- | |
2490 | * _cairo_pattern_acquire_surface: |
- | |
2491 | * @pattern: a #cairo_pattern_t |
- | |
2492 | * @dst: destination surface |
- | |
2493 | * @x: X coordinate in source corresponding to left side of destination area |
- | |
2494 | * @y: Y coordinate in source corresponding to top side of destination area |
- | |
2495 | * @width: width of destination area |
- | |
2496 | * @height: height of destination area |
- | |
2497 | * @surface_out: location to store a pointer to a surface |
- | |
2498 | * @attributes: surface attributes that destination backend should apply to |
- | |
2499 | * the returned surface |
- | |
2500 | * |
- | |
2501 | * A convenience function to obtain a surface to use as the source for |
- | |
2502 | * drawing on @dst. |
- | |
2503 | * |
- | |
2504 | * Note that this function is only suitable for use when the destination |
- | |
2505 | * surface is pixel based and 1 device unit maps to one pixel. |
- | |
2506 | * |
- | |
2507 | * Return value: %CAIRO_STATUS_SUCCESS if a surface was stored in @surface_out. |
- | |
2508 | **/ |
- | |
2509 | cairo_int_status_t |
- | |
2510 | _cairo_pattern_acquire_surface (const cairo_pattern_t *pattern, |
- | |
2511 | cairo_surface_t *dst, |
- | |
2512 | int x, |
- | |
2513 | int y, |
- | |
2514 | unsigned int width, |
- | |
2515 | unsigned int height, |
- | |
2516 | unsigned int flags, |
- | |
2517 | cairo_surface_t **surface_out, |
- | |
2518 | cairo_surface_attributes_t *attributes) |
- | |
2519 | { |
- | |
2520 | if (unlikely (pattern->status)) { |
- | |
2521 | *surface_out = NULL; |
- | |
2522 | return pattern->status; |
- | |
2523 | } |
- | |
2524 | - | ||
2525 | switch (pattern->type) { |
- | |
2526 | case CAIRO_PATTERN_TYPE_SOLID: |
- | |
2527 | return _cairo_pattern_acquire_surface_for_solid ((cairo_solid_pattern_t *) pattern, |
- | |
2528 | dst, x, y, width, height, |
- | |
2529 | surface_out, |
- | |
2530 | attributes); |
- | |
2531 | - | ||
2532 | case CAIRO_PATTERN_TYPE_LINEAR: |
- | |
2533 | case CAIRO_PATTERN_TYPE_RADIAL: |
- | |
2534 | return _cairo_pattern_acquire_surface_for_gradient ((cairo_gradient_pattern_t *) pattern, |
- | |
2535 | dst, x, y, width, height, |
- | |
2536 | surface_out, |
- | |
2537 | attributes); |
- | |
2538 | - | ||
2539 | case CAIRO_PATTERN_TYPE_SURFACE: |
- | |
2540 | return _cairo_pattern_acquire_surface_for_surface ((cairo_surface_pattern_t *) pattern, |
- | |
2541 | dst, x, y, width, height, |
- | |
2542 | flags, |
- | |
2543 | surface_out, |
- | |
2544 | attributes); |
- | |
2545 | - | ||
2546 | default: |
- | |
2547 | ASSERT_NOT_REACHED; |
- | |
2548 | return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
- | |
2549 | } |
- | |
2550 | } |
- | |
2551 | - | ||
2552 | /** |
- | |
2553 | * _cairo_pattern_release_surface: |
- | |
2554 | * @pattern: a #cairo_pattern_t |
- | |
2555 | * @surface: a surface obtained by _cairo_pattern_acquire_surface |
- | |
2556 | * @attributes: attributes obtained by _cairo_pattern_acquire_surface |
- | |
2557 | * |
- | |
2558 | * Releases resources obtained by _cairo_pattern_acquire_surface. |
- | |
2559 | **/ |
- | |
2560 | void |
- | |
2561 | _cairo_pattern_release_surface (const cairo_pattern_t *pattern, |
- | |
Line 2562... | Line -... | ||
2562 | cairo_surface_t *surface, |
- | |
2563 | cairo_surface_attributes_t *attributes) |
- | |
2564 | { |
- | |
2565 | cairo_surface_destroy (surface); |
- | |
2566 | } |
- | |
2567 | - | ||
2568 | cairo_int_status_t |
- | |
2569 | _cairo_pattern_acquire_surfaces (const cairo_pattern_t *src, |
- | |
2570 | const cairo_pattern_t *mask, |
- | |
2571 | cairo_surface_t *dst, |
- | |
2572 | int src_x, |
- | |
2573 | int src_y, |
- | |
2574 | int mask_x, |
- | |
2575 | int mask_y, |
- | |
2576 | unsigned int width, |
- | |
2577 | unsigned int height, |
- | |
2578 | unsigned int flags, |
- | |
2579 | cairo_surface_t **src_out, |
- | |
2580 | cairo_surface_t **mask_out, |
- | |
2581 | cairo_surface_attributes_t *src_attributes, |
- | |
2582 | cairo_surface_attributes_t *mask_attributes) |
- | |
2583 | { |
- | |
2584 | cairo_int_status_t status; |
- | |
2585 | cairo_pattern_union_t src_tmp; |
- | |
2586 | - | ||
2587 | if (unlikely (src->status)) |
- | |
2588 | return src->status; |
- | |
2589 | if (unlikely (mask != NULL && mask->status)) |
3411 | NULL); |
2590 | return mask->status; |
- | |
2591 | 3412 | if (x1 > CAIRO_RECT_INT_MIN) |
|
2592 | /* If src and mask are both solid, then the mask alpha can be |
- | |
2593 | * combined into src and mask can be ignored. */ |
3413 | sample->x = floor (x1 - pad); |
2594 | - | ||
2595 | if (src->type == CAIRO_PATTERN_TYPE_SOLID && |
- | |
2596 | mask && |
- | |
2597 | ! mask->has_component_alpha && |
- | |
2598 | mask->type == CAIRO_PATTERN_TYPE_SOLID) |
3414 | else |
2599 | { |
- | |
2600 | cairo_color_t combined; |
- | |
2601 | cairo_solid_pattern_t *src_solid = (cairo_solid_pattern_t *) src; |
- | |
2602 | cairo_solid_pattern_t *mask_solid = (cairo_solid_pattern_t *) mask; |
- | |
2603 | - | ||
2604 | combined = src_solid->color; |
- | |
2605 | _cairo_color_multiply_alpha (&combined, mask_solid->color.alpha); |
- | |
2606 | - | ||
2607 | _cairo_pattern_init_solid (&src_tmp.solid, &combined); |
- | |
2608 | - | ||
2609 | src = &src_tmp.base; |
- | |
2610 | mask = NULL; |
- | |
2611 | } |
- | |
2612 | - | ||
2613 | status = _cairo_pattern_acquire_surface (src, dst, |
- | |
Line 2614... | Line 3415... | ||
2614 | src_x, src_y, |
3415 | sample->x = CAIRO_RECT_INT_MIN; |
2615 | width, height, |
3416 | |
2616 | flags, |
- | |
2617 | src_out, src_attributes); |
3417 | if (y1 > CAIRO_RECT_INT_MIN) |
- | 3418 | sample->y = floor (y1 - pad); |
|
Line 2618... | Line -... | ||
2618 | if (unlikely (status)) |
- | |
2619 | goto BAIL; |
3419 | else |
2620 | 3420 | sample->y = CAIRO_RECT_INT_MIN; |
|
2621 | if (mask == NULL) { |
3421 | |
2622 | *mask_out = NULL; |
3422 | if (x2 < CAIRO_RECT_INT_MAX) |
2623 | goto BAIL; |
- | |
2624 | } |
- | |
Line 2625... | Line -... | ||
2625 | - | ||
2626 | status = _cairo_pattern_acquire_surface (mask, dst, |
3423 | sample->width = ceil (x2 + pad); |
2627 | mask_x, mask_y, |
3424 | else |
Line 2628... | Line 3425... | ||
2628 | width, height, |
3425 | sample->width = CAIRO_RECT_INT_MAX; |
2629 | flags, |
3426 | |
Line 2630... | Line 3427... | ||
2630 | mask_out, mask_attributes); |
3427 | if (y2 < CAIRO_RECT_INT_MAX) |
2631 | if (unlikely (status)) |
3428 | sample->height = ceil (y2 + pad); |
2632 | _cairo_pattern_release_surface (src, *src_out, src_attributes); |
3429 | else |
Line 2687... | Line 3484... | ||
2687 | x2 = surface_extents.x + (int) surface_extents.width + pad; |
3484 | x2 = surface_extents.x + (int) surface_extents.width + pad; |
2688 | y2 = surface_extents.y + (int) surface_extents.height + pad; |
3485 | y2 = surface_extents.y + (int) surface_extents.height + pad; |
2689 | } |
3486 | } |
2690 | break; |
3487 | break; |
Line -... | Line 3488... | ||
- | 3488 | ||
- | 3489 | case CAIRO_PATTERN_TYPE_RASTER_SOURCE: |
|
- | 3490 | { |
|
- | 3491 | const cairo_raster_source_pattern_t *raster = |
|
- | 3492 | (const cairo_raster_source_pattern_t *) pattern; |
|
- | 3493 | double pad; |
|
- | 3494 | ||
- | 3495 | if (raster->extents.width == 0 || raster->extents.height == 0) |
|
- | 3496 | goto EMPTY; |
|
- | 3497 | ||
- | 3498 | if (pattern->extend != CAIRO_EXTEND_NONE) |
|
- | 3499 | goto UNBOUNDED; |
|
- | 3500 | ||
- | 3501 | /* The filter can effectively enlarge the extents of the |
|
- | 3502 | * pattern, so extend as necessary. |
|
- | 3503 | */ |
|
- | 3504 | _cairo_pattern_analyze_filter (pattern, &pad); |
|
- | 3505 | x1 = raster->extents.x - pad; |
|
- | 3506 | y1 = raster->extents.y - pad; |
|
- | 3507 | x2 = raster->extents.x + (int) raster->extents.width + pad; |
|
- | 3508 | y2 = raster->extents.y + (int) raster->extents.height + pad; |
|
- | 3509 | } |
|
- | 3510 | break; |
|
2691 | 3511 | ||
2692 | case CAIRO_PATTERN_TYPE_RADIAL: |
3512 | case CAIRO_PATTERN_TYPE_RADIAL: |
2693 | { |
3513 | { |
2694 | const cairo_radial_pattern_t *radial = |
3514 | const cairo_radial_pattern_t *radial = |
2695 | (const cairo_radial_pattern_t *) pattern; |
3515 | (const cairo_radial_pattern_t *) pattern; |
2696 | double cx1, cy1; |
3516 | double cx1, cy1; |
2697 | double cx2, cy2; |
3517 | double cx2, cy2; |
Line 2698... | Line 3518... | ||
2698 | double r, D; |
3518 | double r1, r2; |
- | 3519 | ||
- | 3520 | if (_radial_pattern_is_degenerate (radial)) { |
|
- | 3521 | /* cairo-gstate should have optimised degenerate |
|
2699 | 3522 | * patterns to solid clear patterns, so we can ignore |
|
- | 3523 | * them here. */ |
|
Line 2700... | Line -... | ||
2700 | if (radial->r1 == 0 && radial->r2 == 0) |
- | |
2701 | goto EMPTY; |
3524 | goto EMPTY; |
2702 | - | ||
2703 | cx1 = _cairo_fixed_to_double (radial->c1.x); |
3525 | } |
2704 | cy1 = _cairo_fixed_to_double (radial->c1.y); |
- | |
2705 | r = _cairo_fixed_to_double (radial->r1); |
- | |
2706 | x1 = cx1 - r; x2 = cx1 + r; |
- | |
2707 | y1 = cy1 - r; y2 = cy1 + r; |
- | |
2708 | - | ||
2709 | cx2 = _cairo_fixed_to_double (radial->c2.x); |
- | |
2710 | cy2 = _cairo_fixed_to_double (radial->c2.y); |
3526 | |
2711 | r = fabs (_cairo_fixed_to_double (radial->r2)); |
3527 | /* TODO: in some cases (focus outside/on the circle) it is |
Line 2712... | Line 3528... | ||
2712 | 3528 | * half-bounded. */ |
|
2713 | if (pattern->extend != CAIRO_EXTEND_NONE) |
- | |
2714 | goto UNBOUNDED; |
- | |
2715 | 3529 | if (pattern->extend != CAIRO_EXTEND_NONE) |
|
2716 | /* We need to be careful, as if the circles are not |
3530 | goto UNBOUNDED; |
2717 | * self-contained, then the solution is actually unbounded. |
- | |
2718 | */ |
3531 | |
2719 | D = (cx1-cx2)*(cx1-cx2) + (cy1-cy2)*(cy1-cy2); |
3532 | cx1 = radial->cd1.center.x; |
2720 | if (D > r*r - 1e-5) |
- | |
2721 | goto UNBOUNDED; |
3533 | cy1 = radial->cd1.center.y; |
2722 | 3534 | r1 = radial->cd1.radius; |
|
2723 | if (cx2 - r < x1) |
3535 | |
2724 | x1 = cx2 - r; |
3536 | cx2 = radial->cd2.center.x; |
2725 | if (cx2 + r > x2) |
3537 | cy2 = radial->cd2.center.y; |
2726 | x2 = cx2 + r; |
3538 | r2 = radial->cd2.radius; |
2727 | 3539 | ||
2728 | if (cy2 - r < y1) |
3540 | x1 = MIN (cx1 - r1, cx2 - r2); |
2729 | y1 = cy2 - r; |
3541 | y1 = MIN (cy1 - r1, cy2 - r2); |
Line 2730... | Line 3542... | ||
2730 | if (cy2 + r > y2) |
3542 | x2 = MAX (cx1 + r1, cx2 + r2); |
2731 | y2 = cy2 + r; |
3543 | y2 = MAX (cy1 + r1, cy2 + r2); |
Line 2738... | Line 3550... | ||
2738 | (const cairo_linear_pattern_t *) pattern; |
3550 | (const cairo_linear_pattern_t *) pattern; |
Line 2739... | Line 3551... | ||
2739 | 3551 | ||
2740 | if (pattern->extend != CAIRO_EXTEND_NONE) |
3552 | if (pattern->extend != CAIRO_EXTEND_NONE) |
Line 2741... | Line 3553... | ||
2741 | goto UNBOUNDED; |
3553 | goto UNBOUNDED; |
- | 3554 | ||
- | 3555 | if (_linear_pattern_is_degenerate (linear)) { |
|
- | 3556 | /* cairo-gstate should have optimised degenerate |
|
2742 | 3557 | * patterns to solid ones, so we can again ignore |
|
- | 3558 | * them here. */ |
|
Line -... | Line 3559... | ||
- | 3559 | goto EMPTY; |
|
- | 3560 | } |
|
2743 | if (linear->p1.x == linear->p2.x && linear->p1.y == linear->p2.y) |
3561 | |
2744 | goto EMPTY; |
3562 | /* TODO: to get tight extents, use the matrix to transform |
Line 2745... | Line 3563... | ||
2745 | 3563 | * the pattern instead of transforming the extents later. */ |
|
2746 | if (pattern->matrix.xy != 0. || pattern->matrix.yx != 0.) |
3564 | if (pattern->matrix.xy != 0. || pattern->matrix.yx != 0.) |
2747 | goto UNBOUNDED; |
3565 | goto UNBOUNDED; |
2748 | 3566 | ||
2749 | if (linear->p1.x == linear->p2.x) { |
3567 | if (linear->pd1.x == linear->pd2.x) { |
2750 | x1 = -HUGE_VAL; |
3568 | x1 = -HUGE_VAL; |
2751 | x2 = HUGE_VAL; |
3569 | x2 = HUGE_VAL; |
2752 | y1 = _cairo_fixed_to_double (MIN (linear->p1.y, linear->p2.y)); |
3570 | y1 = MIN (linear->pd1.y, linear->pd2.y); |
2753 | y2 = _cairo_fixed_to_double (MAX (linear->p1.y, linear->p2.y)); |
3571 | y2 = MAX (linear->pd1.y, linear->pd2.y); |
2754 | } else if (linear->p1.y == linear->p2.y) { |
3572 | } else if (linear->pd1.y == linear->pd2.y) { |
2755 | x1 = _cairo_fixed_to_double (MIN (linear->p1.x, linear->p2.x)); |
3573 | x1 = MIN (linear->pd1.x, linear->pd2.x); |
2756 | x2 = _cairo_fixed_to_double (MAX (linear->p1.x, linear->p2.x)); |
3574 | x2 = MAX (linear->pd1.x, linear->pd2.x); |
2757 | y1 = -HUGE_VAL; |
3575 | y1 = -HUGE_VAL; |
2758 | y2 = HUGE_VAL; |
3576 | y2 = HUGE_VAL; |
2759 | } else { |
3577 | } else { |
Line -... | Line 3578... | ||
- | 3578 | goto UNBOUNDED; |
|
- | 3579 | } |
|
- | 3580 | } |
|
- | 3581 | break; |
|
- | 3582 | ||
- | 3583 | case CAIRO_PATTERN_TYPE_MESH: |
|
- | 3584 | { |
|
- | 3585 | const cairo_mesh_pattern_t *mesh = |
|
- | 3586 | (const cairo_mesh_pattern_t *) pattern; |
|
- | 3587 | double padx, pady; |
|
- | 3588 | cairo_bool_t is_valid; |
|
- | 3589 | ||
- | 3590 | is_valid = _cairo_mesh_pattern_coord_box (mesh, &x1, &y1, &x2, &y2); |
|
- | 3591 | if (!is_valid) |
|
- | 3592 | goto EMPTY; |
|
- | 3593 | ||
- | 3594 | padx = pady = 1.; |
|
- | 3595 | cairo_matrix_transform_distance (&pattern->matrix, &padx, &pady); |
|
- | 3596 | padx = fabs (padx); |
|
- | 3597 | pady = fabs (pady); |
|
- | 3598 | ||
- | 3599 | x1 -= padx; |
|
- | 3600 | y1 -= pady; |
|
2760 | goto UNBOUNDED; |
3601 | x2 += padx; |
2761 | } |
3602 | y2 += pady; |
2762 | } |
3603 | } |
Line 2763... | Line 3604... | ||
2763 | break; |
3604 | break; |
Line 2809... | Line 3650... | ||
2809 | extents->x = extents->y = 0; |
3650 | extents->x = extents->y = 0; |
2810 | extents->width = extents->height = 0; |
3651 | extents->width = extents->height = 0; |
2811 | return; |
3652 | return; |
2812 | } |
3653 | } |
Line -... | Line 3654... | ||
- | 3654 | ||
- | 3655 | /** |
|
- | 3656 | * _cairo_pattern_get_ink_extents: |
|
- | 3657 | * |
|
- | 3658 | * Return the "target-space" inked extents of @pattern in @extents. |
|
- | 3659 | **/ |
|
- | 3660 | cairo_int_status_t |
|
- | 3661 | _cairo_pattern_get_ink_extents (const cairo_pattern_t *pattern, |
|
- | 3662 | cairo_rectangle_int_t *extents) |
|
- | 3663 | { |
|
- | 3664 | if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE && |
|
- | 3665 | pattern->extend == CAIRO_EXTEND_NONE) |
|
- | 3666 | { |
|
- | 3667 | const cairo_surface_pattern_t *surface_pattern = |
|
- | 3668 | (const cairo_surface_pattern_t *) pattern; |
|
- | 3669 | cairo_surface_t *surface = surface_pattern->surface; |
|
- | 3670 | ||
- | 3671 | surface = _cairo_surface_get_source (surface, NULL); |
|
- | 3672 | if (_cairo_surface_is_recording (surface)) { |
|
- | 3673 | cairo_matrix_t imatrix; |
|
- | 3674 | cairo_box_t box; |
|
- | 3675 | cairo_status_t status; |
|
- | 3676 | ||
- | 3677 | imatrix = pattern->matrix; |
|
- | 3678 | status = cairo_matrix_invert (&imatrix); |
|
- | 3679 | /* cairo_pattern_set_matrix ensures the matrix is invertible */ |
|
- | 3680 | assert (status == CAIRO_STATUS_SUCCESS); |
|
- | 3681 | ||
- | 3682 | status = _cairo_recording_surface_get_ink_bbox ((cairo_recording_surface_t *)surface, |
|
- | 3683 | &box, &imatrix); |
|
- | 3684 | if (unlikely (status)) |
|
- | 3685 | return status; |
|
- | 3686 | ||
- | 3687 | _cairo_box_round_to_rectangle (&box, extents); |
|
- | 3688 | return CAIRO_STATUS_SUCCESS; |
|
- | 3689 | } |
|
- | 3690 | } |
|
- | 3691 | ||
- | 3692 | _cairo_pattern_get_extents (pattern, extents); |
|
- | 3693 | return CAIRO_STATUS_SUCCESS; |
|
Line 2813... | Line 3694... | ||
2813 | 3694 | } |
|
2814 | 3695 | ||
2815 | static unsigned long |
3696 | static unsigned long |
2816 | _cairo_solid_pattern_hash (unsigned long hash, |
3697 | _cairo_solid_pattern_hash (unsigned long hash, |
2817 | const cairo_pattern_t *pattern) |
- | |
2818 | { |
- | |
2819 | const cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern; |
3698 | const cairo_solid_pattern_t *solid) |
Line 2820... | Line 3699... | ||
2820 | 3699 | { |
|
2821 | hash = _cairo_hash_bytes (hash, &solid->color, sizeof (solid->color)); |
3700 | hash = _cairo_hash_bytes (hash, &solid->color, sizeof (solid->color)); |
Line 2837... | Line 3716... | ||
2837 | hash = _cairo_hash_bytes (hash, |
3716 | hash = _cairo_hash_bytes (hash, |
2838 | &gradient->stops[n].offset, |
3717 | &gradient->stops[n].offset, |
2839 | sizeof (double)); |
3718 | sizeof (double)); |
2840 | hash = _cairo_hash_bytes (hash, |
3719 | hash = _cairo_hash_bytes (hash, |
2841 | &gradient->stops[n].color, |
3720 | &gradient->stops[n].color, |
2842 | sizeof (cairo_color_t)); |
3721 | sizeof (cairo_color_stop_t)); |
2843 | } |
3722 | } |
Line 2844... | Line 3723... | ||
2844 | 3723 | ||
2845 | return hash; |
3724 | return hash; |
Line 2846... | Line 3725... | ||
2846 | } |
3725 | } |
2847 | 3726 | ||
2848 | unsigned long |
3727 | unsigned long |
2849 | _cairo_linear_pattern_hash (unsigned long hash, |
3728 | _cairo_linear_pattern_hash (unsigned long hash, |
2850 | const cairo_linear_pattern_t *linear) |
3729 | const cairo_linear_pattern_t *linear) |
2851 | { |
3730 | { |
Line 2852... | Line 3731... | ||
2852 | hash = _cairo_hash_bytes (hash, &linear->p1, sizeof (linear->p1)); |
3731 | hash = _cairo_hash_bytes (hash, &linear->pd1, sizeof (linear->pd1)); |
2853 | hash = _cairo_hash_bytes (hash, &linear->p2, sizeof (linear->p2)); |
3732 | hash = _cairo_hash_bytes (hash, &linear->pd2, sizeof (linear->pd2)); |
Line 2854... | Line 3733... | ||
2854 | 3733 | ||
2855 | return _cairo_gradient_color_stops_hash (hash, &linear->base); |
3734 | return _cairo_gradient_color_stops_hash (hash, &linear->base); |
2856 | } |
3735 | } |
2857 | 3736 | ||
2858 | unsigned long |
3737 | unsigned long |
2859 | _cairo_radial_pattern_hash (unsigned long hash, |
3738 | _cairo_radial_pattern_hash (unsigned long hash, |
2860 | const cairo_radial_pattern_t *radial) |
3739 | const cairo_radial_pattern_t *radial) |
2861 | { |
3740 | { |
Line 2862... | Line 3741... | ||
2862 | hash = _cairo_hash_bytes (hash, &radial->c1, sizeof (radial->c1)); |
3741 | hash = _cairo_hash_bytes (hash, &radial->cd1.center, sizeof (radial->cd1.center)); |
2863 | hash = _cairo_hash_bytes (hash, &radial->r1, sizeof (radial->r1)); |
3742 | hash = _cairo_hash_bytes (hash, &radial->cd1.radius, sizeof (radial->cd1.radius)); |
Line 2864... | Line 3743... | ||
2864 | hash = _cairo_hash_bytes (hash, &radial->c2, sizeof (radial->c2)); |
3743 | hash = _cairo_hash_bytes (hash, &radial->cd2.center, sizeof (radial->cd2.center)); |
2865 | hash = _cairo_hash_bytes (hash, &radial->r2, sizeof (radial->r2)); |
3744 | hash = _cairo_hash_bytes (hash, &radial->cd2.radius, sizeof (radial->cd2.radius)); |
2866 | - | ||
2867 | return _cairo_gradient_color_stops_hash (hash, &radial->base); |
3745 | |
2868 | } |
3746 | return _cairo_gradient_color_stops_hash (hash, &radial->base); |
- | 3747 | } |
|
Line -... | Line 3748... | ||
- | 3748 | ||
- | 3749 | static unsigned long |
|
- | 3750 | _cairo_mesh_pattern_hash (unsigned long hash, const cairo_mesh_pattern_t *mesh) |
|
- | 3751 | { |
|
- | 3752 | const cairo_mesh_patch_t *patch = _cairo_array_index_const (&mesh->patches, 0); |
|
- | 3753 | unsigned int i, n = _cairo_array_num_elements (&mesh->patches); |
|
- | 3754 | ||
- | 3755 | for (i = 0; i < n; i++) |
|
- | 3756 | hash = _cairo_hash_bytes (hash, patch + i, sizeof (cairo_mesh_patch_t)); |
|
- | 3757 | ||
2869 | 3758 | return hash; |
|
Line 2870... | Line 3759... | ||
2870 | static unsigned long |
3759 | } |
2871 | _cairo_surface_pattern_hash (unsigned long hash, |
3760 | |
Line -... | Line 3761... | ||
- | 3761 | static unsigned long |
|
- | 3762 | _cairo_surface_pattern_hash (unsigned long hash, |
|
- | 3763 | const cairo_surface_pattern_t *surface) |
|
- | 3764 | { |
|
- | 3765 | hash ^= surface->surface->unique_id; |
|
- | 3766 | ||
- | 3767 | return hash; |
|
- | 3768 | } |
|
- | 3769 | ||
2872 | const cairo_pattern_t *pattern) |
3770 | static unsigned long |
2873 | { |
3771 | _cairo_raster_source_pattern_hash (unsigned long hash, |
2874 | const cairo_surface_pattern_t *surface = (cairo_surface_pattern_t *) pattern; |
3772 | const cairo_raster_source_pattern_t *raster) |
2875 | 3773 | { |
|
Line 2899... | Line 3797... | ||
2899 | sizeof (pattern->has_component_alpha)); |
3797 | sizeof (pattern->has_component_alpha)); |
2900 | } |
3798 | } |
Line 2901... | Line 3799... | ||
2901 | 3799 | ||
2902 | switch (pattern->type) { |
3800 | switch (pattern->type) { |
2903 | case CAIRO_PATTERN_TYPE_SOLID: |
3801 | case CAIRO_PATTERN_TYPE_SOLID: |
2904 | return _cairo_solid_pattern_hash (hash, pattern); |
3802 | return _cairo_solid_pattern_hash (hash, (cairo_solid_pattern_t *) pattern); |
2905 | case CAIRO_PATTERN_TYPE_LINEAR: |
3803 | case CAIRO_PATTERN_TYPE_LINEAR: |
2906 | return _cairo_linear_pattern_hash (hash, (cairo_linear_pattern_t *) pattern); |
3804 | return _cairo_linear_pattern_hash (hash, (cairo_linear_pattern_t *) pattern); |
2907 | case CAIRO_PATTERN_TYPE_RADIAL: |
3805 | case CAIRO_PATTERN_TYPE_RADIAL: |
- | 3806 | return _cairo_radial_pattern_hash (hash, (cairo_radial_pattern_t *) pattern); |
|
- | 3807 | case CAIRO_PATTERN_TYPE_MESH: |
|
2908 | return _cairo_radial_pattern_hash (hash, (cairo_radial_pattern_t *) pattern); |
3808 | return _cairo_mesh_pattern_hash (hash, (cairo_mesh_pattern_t *) pattern); |
2909 | case CAIRO_PATTERN_TYPE_SURFACE: |
3809 | case CAIRO_PATTERN_TYPE_SURFACE: |
- | 3810 | return _cairo_surface_pattern_hash (hash, (cairo_surface_pattern_t *) pattern); |
|
- | 3811 | case CAIRO_PATTERN_TYPE_RASTER_SOURCE: |
|
2910 | return _cairo_surface_pattern_hash (hash, pattern); |
3812 | return _cairo_raster_source_pattern_hash (hash, (cairo_raster_source_pattern_t *) pattern); |
2911 | default: |
3813 | default: |
2912 | ASSERT_NOT_REACHED; |
3814 | ASSERT_NOT_REACHED; |
2913 | return FALSE; |
3815 | return FALSE; |
2914 | } |
3816 | } |
Line 2915... | Line -... | ||
2915 | } |
- | |
2916 | - | ||
2917 | static unsigned long |
- | |
2918 | _cairo_gradient_pattern_color_stops_size (const cairo_pattern_t *pattern) |
- | |
2919 | { |
- | |
2920 | cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern; |
- | |
2921 | - | ||
2922 | return gradient->n_stops * (sizeof (double) + sizeof (cairo_color_t)); |
- | |
2923 | } |
- | |
2924 | - | ||
2925 | unsigned long |
- | |
2926 | _cairo_pattern_size (const cairo_pattern_t *pattern) |
- | |
2927 | { |
- | |
2928 | if (pattern->status) |
- | |
2929 | return 0; |
- | |
2930 | - | ||
2931 | /* XXX */ |
- | |
2932 | switch (pattern->type) { |
- | |
2933 | case CAIRO_PATTERN_TYPE_SOLID: |
- | |
2934 | return sizeof (cairo_solid_pattern_t); |
- | |
2935 | break; |
- | |
2936 | case CAIRO_PATTERN_TYPE_SURFACE: |
- | |
2937 | return sizeof (cairo_surface_pattern_t); |
- | |
2938 | break; |
- | |
2939 | case CAIRO_PATTERN_TYPE_LINEAR: |
- | |
2940 | return sizeof (cairo_linear_pattern_t) + |
- | |
2941 | _cairo_gradient_pattern_color_stops_size (pattern); |
- | |
2942 | break; |
- | |
2943 | case CAIRO_PATTERN_TYPE_RADIAL: |
- | |
2944 | return sizeof (cairo_radial_pattern_t) + |
- | |
2945 | _cairo_gradient_pattern_color_stops_size (pattern); |
- | |
2946 | default: |
- | |
2947 | ASSERT_NOT_REACHED; |
- | |
2948 | return 0; |
- | |
2949 | } |
- | |
2950 | } |
- | |
2951 | 3817 | } |
|
2952 | 3818 | ||
2953 | static cairo_bool_t |
3819 | static cairo_bool_t |
2954 | _cairo_solid_pattern_equal (const cairo_pattern_t *A, |
3820 | _cairo_solid_pattern_equal (const cairo_solid_pattern_t *a, |
2955 | const cairo_pattern_t *B) |
- | |
2956 | { |
- | |
2957 | const cairo_solid_pattern_t *a = (cairo_solid_pattern_t *) A; |
- | |
2958 | const cairo_solid_pattern_t *b = (cairo_solid_pattern_t *) B; |
3821 | const cairo_solid_pattern_t *b) |
2959 | 3822 | { |
|
Line 2960... | Line 3823... | ||
2960 | return _cairo_color_equal (&a->color, &b->color); |
3823 | return _cairo_color_equal (&a->color, &b->color); |
2961 | } |
3824 | } |
Line 2981... | Line 3844... | ||
2981 | 3844 | ||
2982 | cairo_bool_t |
3845 | cairo_bool_t |
2983 | _cairo_linear_pattern_equal (const cairo_linear_pattern_t *a, |
3846 | _cairo_linear_pattern_equal (const cairo_linear_pattern_t *a, |
2984 | const cairo_linear_pattern_t *b) |
3847 | const cairo_linear_pattern_t *b) |
2985 | { |
3848 | { |
2986 | if (a->p1.x != b->p1.x) |
3849 | if (a->pd1.x != b->pd1.x) |
Line 2987... | Line 3850... | ||
2987 | return FALSE; |
3850 | return FALSE; |
2988 | 3851 | ||
Line 2989... | Line 3852... | ||
2989 | if (a->p1.y != b->p1.y) |
3852 | if (a->pd1.y != b->pd1.y) |
2990 | return FALSE; |
3853 | return FALSE; |
Line 2991... | Line 3854... | ||
2991 | 3854 | ||
2992 | if (a->p2.x != b->p2.x) |
3855 | if (a->pd2.x != b->pd2.x) |
Line 2993... | Line 3856... | ||
2993 | return FALSE; |
3856 | return FALSE; |
2994 | 3857 | ||
Line 2995... | Line 3858... | ||
2995 | if (a->p2.y != b->p2.y) |
3858 | if (a->pd2.y != b->pd2.y) |
2996 | return FALSE; |
3859 | return FALSE; |
2997 | 3860 | ||
2998 | return _cairo_gradient_color_stops_equal (&a->base, &b->base); |
3861 | return _cairo_gradient_color_stops_equal (&a->base, &b->base); |
2999 | } |
3862 | } |
3000 | 3863 | ||
Line 3001... | Line 3864... | ||
3001 | cairo_bool_t |
3864 | cairo_bool_t |
3002 | _cairo_radial_pattern_equal (const cairo_radial_pattern_t *a, |
3865 | _cairo_radial_pattern_equal (const cairo_radial_pattern_t *a, |
Line 3003... | Line 3866... | ||
3003 | const cairo_radial_pattern_t *b) |
3866 | const cairo_radial_pattern_t *b) |
3004 | { |
3867 | { |
Line 3005... | Line 3868... | ||
3005 | if (a->c1.x != b->c1.x) |
3868 | if (a->cd1.center.x != b->cd1.center.x) |
3006 | return FALSE; |
3869 | return FALSE; |
Line 3007... | Line 3870... | ||
3007 | 3870 | ||
3008 | if (a->c1.y != b->c1.y) |
3871 | if (a->cd1.center.y != b->cd1.center.y) |
Line 3009... | Line 3872... | ||
3009 | return FALSE; |
3872 | return FALSE; |
3010 | 3873 | ||
Line 3011... | Line 3874... | ||
3011 | if (a->r1 != b->r1) |
3874 | if (a->cd1.radius != b->cd1.radius) |
3012 | return FALSE; |
3875 | return FALSE; |
Line 3013... | Line 3876... | ||
3013 | 3876 | ||
3014 | if (a->c2.x != b->c2.x) |
3877 | if (a->cd2.center.x != b->cd2.center.x) |
3015 | return FALSE; |
3878 | return FALSE; |
3016 | 3879 | ||
3017 | if (a->c2.y != b->c2.y) |
3880 | if (a->cd2.center.y != b->cd2.center.y) |
- | 3881 | return FALSE; |
|
- | 3882 | ||
- | 3883 | if (a->cd2.radius != b->cd2.radius) |
|
3018 | return FALSE; |
3884 | return FALSE; |
Line -... | Line 3885... | ||
- | 3885 | ||
- | 3886 | return _cairo_gradient_color_stops_equal (&a->base, &b->base); |
|
- | 3887 | } |
|
- | 3888 | ||
- | 3889 | static cairo_bool_t |
|
- | 3890 | _cairo_mesh_pattern_equal (const cairo_mesh_pattern_t *a, |
|
- | 3891 | const cairo_mesh_pattern_t *b) |
|
- | 3892 | { |
|
- | 3893 | const cairo_mesh_patch_t *patch_a, *patch_b; |
|
- | 3894 | unsigned int i, num_patches_a, num_patches_b; |
|
- | 3895 | ||
- | 3896 | num_patches_a = _cairo_array_num_elements (&a->patches); |
|
- | 3897 | num_patches_b = _cairo_array_num_elements (&b->patches); |
|
- | 3898 | ||
- | 3899 | if (num_patches_a != num_patches_b) |
|
- | 3900 | return FALSE; |
|
- | 3901 | ||
3019 | 3902 | for (i = 0; i < num_patches_a; i++) { |
|
3020 | if (a->r2 != b->r2) |
3903 | patch_a = _cairo_array_index_const (&a->patches, i); |
Line -... | Line 3904... | ||
- | 3904 | patch_b = _cairo_array_index_const (&a->patches, i); |
|
- | 3905 | if (memcmp (patch_a, patch_b, sizeof(cairo_mesh_patch_t)) != 0) |
|
- | 3906 | return FALSE; |
|
- | 3907 | } |
|
- | 3908 | ||
- | 3909 | return TRUE; |
|
- | 3910 | } |
|
3021 | return FALSE; |
3911 | |
3022 | 3912 | static cairo_bool_t |
|
3023 | return _cairo_gradient_color_stops_equal (&a->base, &b->base); |
3913 | _cairo_surface_pattern_equal (const cairo_surface_pattern_t *a, |
3024 | } |
3914 | const cairo_surface_pattern_t *b) |
3025 | 3915 | { |
|
Line 3059... | Line 3949... | ||
3059 | return FALSE; |
3949 | return FALSE; |
3060 | } |
3950 | } |
Line 3061... | Line 3951... | ||
3061 | 3951 | ||
3062 | switch (a->type) { |
3952 | switch (a->type) { |
- | 3953 | case CAIRO_PATTERN_TYPE_SOLID: |
|
3063 | case CAIRO_PATTERN_TYPE_SOLID: |
3954 | return _cairo_solid_pattern_equal ((cairo_solid_pattern_t *) a, |
3064 | return _cairo_solid_pattern_equal (a, b); |
3955 | (cairo_solid_pattern_t *) b); |
3065 | case CAIRO_PATTERN_TYPE_LINEAR: |
3956 | case CAIRO_PATTERN_TYPE_LINEAR: |
3066 | return _cairo_linear_pattern_equal ((cairo_linear_pattern_t *) a, |
3957 | return _cairo_linear_pattern_equal ((cairo_linear_pattern_t *) a, |
3067 | (cairo_linear_pattern_t *) b); |
3958 | (cairo_linear_pattern_t *) b); |
3068 | case CAIRO_PATTERN_TYPE_RADIAL: |
3959 | case CAIRO_PATTERN_TYPE_RADIAL: |
3069 | return _cairo_radial_pattern_equal ((cairo_radial_pattern_t *) a, |
3960 | return _cairo_radial_pattern_equal ((cairo_radial_pattern_t *) a, |
- | 3961 | (cairo_radial_pattern_t *) b); |
|
- | 3962 | case CAIRO_PATTERN_TYPE_MESH: |
|
- | 3963 | return _cairo_mesh_pattern_equal ((cairo_mesh_pattern_t *) a, |
|
3070 | (cairo_radial_pattern_t *) b); |
3964 | (cairo_mesh_pattern_t *) b); |
- | 3965 | case CAIRO_PATTERN_TYPE_SURFACE: |
|
3071 | case CAIRO_PATTERN_TYPE_SURFACE: |
3966 | return _cairo_surface_pattern_equal ((cairo_surface_pattern_t *) a, |
- | 3967 | (cairo_surface_pattern_t *) b); |
|
- | 3968 | case CAIRO_PATTERN_TYPE_RASTER_SOURCE: |
|
- | 3969 | return _cairo_raster_source_pattern_equal ((cairo_raster_source_pattern_t *) a, |
|
3072 | return _cairo_surface_pattern_equal (a, b); |
3970 | (cairo_raster_source_pattern_t *) b); |
3073 | default: |
3971 | default: |
3074 | ASSERT_NOT_REACHED; |
3972 | ASSERT_NOT_REACHED; |
3075 | return FALSE; |
3973 | return FALSE; |
3076 | } |
3974 | } |
Line 3077... | Line 3975... | ||
3077 | } |
3975 | } |
3078 | 3976 | ||
3079 | /** |
3977 | /** |
3080 | * cairo_pattern_get_rgba |
3978 | * cairo_pattern_get_rgba: |
3081 | * @pattern: a #cairo_pattern_t |
3979 | * @pattern: a #cairo_pattern_t |
3082 | * @red: return value for red component of color, or %NULL |
3980 | * @red: return value for red component of color, or %NULL |
3083 | * @green: return value for green component of color, or %NULL |
3981 | * @green: return value for green component of color, or %NULL |
Line 3119... | Line 4017... | ||
3119 | 4017 | ||
3120 | return CAIRO_STATUS_SUCCESS; |
4018 | return CAIRO_STATUS_SUCCESS; |
Line 3121... | Line 4019... | ||
3121 | } |
4019 | } |
3122 | 4020 | ||
3123 | /** |
4021 | /** |
3124 | * cairo_pattern_get_surface |
4022 | * cairo_pattern_get_surface: |
3125 | * @pattern: a #cairo_pattern_t |
4023 | * @pattern: a #cairo_pattern_t |
3126 | * @surface: return value for surface of pattern, or %NULL |
4024 | * @surface: return value for surface of pattern, or %NULL |
3127 | * |
4025 | * |
Line 3152... | Line 4050... | ||
3152 | 4050 | ||
3153 | return CAIRO_STATUS_SUCCESS; |
4051 | return CAIRO_STATUS_SUCCESS; |
Line 3154... | Line 4052... | ||
3154 | } |
4052 | } |
3155 | 4053 | ||
3156 | /** |
4054 | /** |
3157 | * cairo_pattern_get_color_stop_rgba |
4055 | * cairo_pattern_get_color_stop_rgba: |
3158 | * @pattern: a #cairo_pattern_t |
4056 | * @pattern: a #cairo_pattern_t |
3159 | * @index: index of the stop to return data for |
4057 | * @index: index of the stop to return data for |
3160 | * @offset: return value for the offset of the stop, or %NULL |
4058 | * @offset: return value for the offset of the stop, or %NULL |
Line 3205... | Line 4103... | ||
3205 | 4103 | ||
3206 | return CAIRO_STATUS_SUCCESS; |
4104 | return CAIRO_STATUS_SUCCESS; |
Line 3207... | Line 4105... | ||
3207 | } |
4105 | } |
3208 | 4106 | ||
3209 | /** |
4107 | /** |
3210 | * cairo_pattern_get_color_stop_count |
4108 | * cairo_pattern_get_color_stop_count: |
3211 | * @pattern: a #cairo_pattern_t |
4109 | * @pattern: a #cairo_pattern_t |
3212 | * @count: return value for the number of color stops, or %NULL |
4110 | * @count: return value for the number of color stops, or %NULL |
3213 | * |
4111 | * |
Line 3217... | Line 4115... | ||
3217 | * Return value: %CAIRO_STATUS_SUCCESS, or |
4115 | * Return value: %CAIRO_STATUS_SUCCESS, or |
3218 | * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a gradient |
4116 | * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a gradient |
3219 | * pattern. |
4117 | * pattern. |
3220 | * |
4118 | * |
3221 | * Since: 1.4 |
4119 | * Since: 1.4 |
3222 | */ |
4120 | **/ |
3223 | cairo_status_t |
4121 | cairo_status_t |
3224 | cairo_pattern_get_color_stop_count (cairo_pattern_t *pattern, |
4122 | cairo_pattern_get_color_stop_count (cairo_pattern_t *pattern, |
3225 | int *count) |
4123 | int *count) |
3226 | { |
4124 | { |
3227 | cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t*) pattern; |
4125 | cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t*) pattern; |
Line 3238... | Line 4136... | ||
3238 | 4136 | ||
3239 | return CAIRO_STATUS_SUCCESS; |
4137 | return CAIRO_STATUS_SUCCESS; |
Line 3240... | Line 4138... | ||
3240 | } |
4138 | } |
3241 | 4139 | ||
3242 | /** |
4140 | /** |
3243 | * cairo_pattern_get_linear_points |
4141 | * cairo_pattern_get_linear_points: |
3244 | * @pattern: a #cairo_pattern_t |
4142 | * @pattern: a #cairo_pattern_t |
3245 | * @x0: return value for the x coordinate of the first point, or %NULL |
4143 | * @x0: return value for the x coordinate of the first point, or %NULL |
3246 | * @y0: return value for the y coordinate of the first point, or %NULL |
4144 | * @y0: return value for the y coordinate of the first point, or %NULL |
Line 3267... | Line 4165... | ||
3267 | 4165 | ||
3268 | if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR) |
4166 | if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR) |
Line 3269... | Line 4167... | ||
3269 | return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
4167 | return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
3270 | 4168 | ||
3271 | if (x0) |
4169 | if (x0) |
3272 | *x0 = _cairo_fixed_to_double (linear->p1.x); |
4170 | *x0 = linear->pd1.x; |
3273 | if (y0) |
4171 | if (y0) |
3274 | *y0 = _cairo_fixed_to_double (linear->p1.y); |
4172 | *y0 = linear->pd1.y; |
3275 | if (x1) |
4173 | if (x1) |
3276 | *x1 = _cairo_fixed_to_double (linear->p2.x); |
4174 | *x1 = linear->pd2.x; |
Line 3277... | Line 4175... | ||
3277 | if (y1) |
4175 | if (y1) |
3278 | *y1 = _cairo_fixed_to_double (linear->p2.y); |
4176 | *y1 = linear->pd2.y; |
Line 3279... | Line 4177... | ||
3279 | 4177 | ||
3280 | return CAIRO_STATUS_SUCCESS; |
4178 | return CAIRO_STATUS_SUCCESS; |
3281 | } |
4179 | } |
3282 | 4180 | ||
3283 | /** |
4181 | /** |
3284 | * cairo_pattern_get_radial_circles |
4182 | * cairo_pattern_get_radial_circles: |
3285 | * @pattern: a #cairo_pattern_t |
4183 | * @pattern: a #cairo_pattern_t |
Line 3311... | Line 4209... | ||
3311 | 4209 | ||
3312 | if (pattern->type != CAIRO_PATTERN_TYPE_RADIAL) |
4210 | if (pattern->type != CAIRO_PATTERN_TYPE_RADIAL) |
Line 3313... | Line 4211... | ||
3313 | return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
4211 | return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
3314 | 4212 | ||
3315 | if (x0) |
4213 | if (x0) |
3316 | *x0 = _cairo_fixed_to_double (radial->c1.x); |
4214 | *x0 = radial->cd1.center.x; |
3317 | if (y0) |
4215 | if (y0) |
3318 | *y0 = _cairo_fixed_to_double (radial->c1.y); |
4216 | *y0 = radial->cd1.center.y; |
3319 | if (r0) |
4217 | if (r0) |
3320 | *r0 = _cairo_fixed_to_double (radial->r1); |
4218 | *r0 = radial->cd1.radius; |
3321 | if (x1) |
4219 | if (x1) |
3322 | *x1 = _cairo_fixed_to_double (radial->c2.x); |
4220 | *x1 = radial->cd2.center.x; |
3323 | if (y1) |
4221 | if (y1) |
- | 4222 | *y1 = radial->cd2.center.y; |
|
- | 4223 | if (r1) |
|
- | 4224 | *r1 = radial->cd2.radius; |
|
- | 4225 | ||
- | 4226 | return CAIRO_STATUS_SUCCESS; |
|
- | 4227 | } |
|
- | 4228 | ||
- | 4229 | /** |
|
- | 4230 | * cairo_mesh_pattern_get_patch_count: |
|
- | 4231 | * @pattern: a #cairo_pattern_t |
|
- | 4232 | * @count: return value for the number patches, or %NULL |
|
- | 4233 | * |
|
- | 4234 | * Gets the number of patches specified in the given mesh pattern. |
|
- | 4235 | * |
|
- | 4236 | * The number only includes patches which have been finished by |
|
- | 4237 | * calling cairo_mesh_pattern_end_patch(). For example it will be 0 |
|
- | 4238 | * during the definition of the first patch. |
|
- | 4239 | * |
|
- | 4240 | * Return value: %CAIRO_STATUS_SUCCESS, or |
|
- | 4241 | * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a mesh |
|
- | 4242 | * pattern. |
|
- | 4243 | * |
|
- | 4244 | * Since: 1.12 |
|
- | 4245 | **/ |
|
- | 4246 | cairo_status_t |
|
- | 4247 | cairo_mesh_pattern_get_patch_count (cairo_pattern_t *pattern, |
|
- | 4248 | unsigned int *count) |
|
- | 4249 | { |
|
- | 4250 | cairo_mesh_pattern_t *mesh = (cairo_mesh_pattern_t *) pattern; |
|
- | 4251 | ||
- | 4252 | if (unlikely (pattern->status)) |
|
- | 4253 | return pattern->status; |
|
- | 4254 | ||
- | 4255 | if (unlikely (pattern->type != CAIRO_PATTERN_TYPE_MESH)) |
|
- | 4256 | return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
|
3324 | *y1 = _cairo_fixed_to_double (radial->c2.y); |
4257 | |
- | 4258 | if (count) { |
|
- | 4259 | *count = _cairo_array_num_elements (&mesh->patches); |
|
- | 4260 | if (mesh->current_patch) |
|
- | 4261 | *count -= 1; |
|
- | 4262 | } |
|
- | 4263 | ||
- | 4264 | return CAIRO_STATUS_SUCCESS; |
|
- | 4265 | } |
|
- | 4266 | slim_hidden_def (cairo_mesh_pattern_get_patch_count); |
|
- | 4267 | ||
- | 4268 | /** |
|
- | 4269 | * cairo_mesh_pattern_get_path: |
|
- | 4270 | * @pattern: a #cairo_pattern_t |
|
- | 4271 | * @patch_num: the patch number to return data for |
|
- | 4272 | * |
|
- | 4273 | * Gets path defining the patch @patch_num for a mesh |
|
- | 4274 | * pattern. |
|
- | 4275 | * |
|
- | 4276 | * @patch_num can range 0 to 1 less than the number returned by |
|
- | 4277 | * cairo_mesh_pattern_get_patch_count(). |
|
- | 4278 | * |
|
- | 4279 | * Return value: the path defining the patch, or a path with status |
|
- | 4280 | * %CAIRO_STATUS_INVALID_INDEX if @patch_num or @point_num is not |
|
- | 4281 | * valid for @pattern. If @pattern is not a mesh pattern, a path with |
|
- | 4282 | * status %CAIRO_STATUS_PATTERN_TYPE_MISMATCH is returned. |
|
- | 4283 | * |
|
- | 4284 | * Since: 1.12 |
|
- | 4285 | **/ |
|
- | 4286 | cairo_path_t * |
|
- | 4287 | cairo_mesh_pattern_get_path (cairo_pattern_t *pattern, |
|
- | 4288 | unsigned int patch_num) |
|
- | 4289 | { |
|
- | 4290 | cairo_mesh_pattern_t *mesh = (cairo_mesh_pattern_t *) pattern; |
|
- | 4291 | const cairo_mesh_patch_t *patch; |
|
- | 4292 | cairo_path_t *path; |
|
- | 4293 | cairo_path_data_t *data; |
|
- | 4294 | unsigned int patch_count; |
|
- | 4295 | int l, current_point; |
|
- | 4296 | ||
- | 4297 | if (unlikely (pattern->status)) |
|
- | 4298 | return _cairo_path_create_in_error (pattern->status); |
|
- | 4299 | ||
- | 4300 | if (unlikely (pattern->type != CAIRO_PATTERN_TYPE_MESH)) |
|
- | 4301 | return _cairo_path_create_in_error (_cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH)); |
|
- | 4302 | ||
- | 4303 | patch_count = _cairo_array_num_elements (&mesh->patches); |
|
- | 4304 | if (mesh->current_patch) |
|
- | 4305 | patch_count--; |
|
- | 4306 | ||
- | 4307 | if (unlikely (patch_num >= patch_count)) |
|
- | 4308 | return _cairo_path_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_INDEX)); |
|
- | 4309 | ||
- | 4310 | patch = _cairo_array_index_const (&mesh->patches, patch_num); |
|
- | 4311 | ||
- | 4312 | path = malloc (sizeof (cairo_path_t)); |
|
- | 4313 | if (path == NULL) |
|
- | 4314 | return _cairo_path_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); |
|
- | 4315 | ||
- | 4316 | path->num_data = 18; |
|
- | 4317 | path->data = _cairo_malloc_ab (path->num_data, |
|
- | 4318 | sizeof (cairo_path_data_t)); |
|
- | 4319 | if (path->data == NULL) { |
|
- | 4320 | free (path); |
|
- | 4321 | return _cairo_path_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); |
|
- | 4322 | } |
|
- | 4323 | ||
- | 4324 | data = path->data; |
|
- | 4325 | data[0].header.type = CAIRO_PATH_MOVE_TO; |
|
- | 4326 | data[0].header.length = 2; |
|
- | 4327 | data[1].point.x = patch->points[0][0].x; |
|
- | 4328 | data[1].point.y = patch->points[0][0].y; |
|
- | 4329 | data += data[0].header.length; |
|
- | 4330 | ||
- | 4331 | current_point = 0; |
|
- | 4332 | ||
- | 4333 | for (l = 0; l < 4; l++) { |
|
- | 4334 | int i, j, k; |
|
- | 4335 | ||
- | 4336 | data[0].header.type = CAIRO_PATH_CURVE_TO; |
|
- | 4337 | data[0].header.length = 4; |
|
- | 4338 | ||
- | 4339 | for (k = 1; k < 4; k++) { |
|
- | 4340 | current_point = (current_point + 1) % 12; |
|
- | 4341 | i = mesh_path_point_i[current_point]; |
|
- | 4342 | j = mesh_path_point_j[current_point]; |
|
- | 4343 | data[k].point.x = patch->points[i][j].x; |
|
- | 4344 | data[k].point.y = patch->points[i][j].y; |
|
- | 4345 | } |
|
- | 4346 | ||
- | 4347 | data += data[0].header.length; |
|
- | 4348 | } |
|
- | 4349 | ||
- | 4350 | path->status = CAIRO_STATUS_SUCCESS; |
|
- | 4351 | ||
- | 4352 | return path; |
|
- | 4353 | } |
|
- | 4354 | slim_hidden_def (cairo_mesh_pattern_get_path); |
|
- | 4355 | ||
- | 4356 | /** |
|
- | 4357 | * cairo_mesh_pattern_get_corner_color_rgba: |
|
- | 4358 | * @pattern: a #cairo_pattern_t |
|
- | 4359 | * @patch_num: the patch number to return data for |
|
- | 4360 | * @corner_num: the corner number to return data for |
|
- | 4361 | * @red: return value for red component of color, or %NULL |
|
- | 4362 | * @green: return value for green component of color, or %NULL |
|
- | 4363 | * @blue: return value for blue component of color, or %NULL |
|
- | 4364 | * @alpha: return value for alpha component of color, or %NULL |
|
- | 4365 | * |
|
- | 4366 | * Gets the color information in corner @corner_num of patch |
|
- | 4367 | * @patch_num for a mesh pattern. |
|
- | 4368 | * |
|
- | 4369 | * @patch_num can range 0 to 1 less than the number returned by |
|
- | 4370 | * cairo_mesh_pattern_get_patch_count(). |
|
- | 4371 | * |
|
- | 4372 | * Valid values for @corner_num are from 0 to 3 and identify the |
|
- | 4373 | * corners as explained in cairo_pattern_create_mesh(). |
|
- | 4374 | * |
|
- | 4375 | * Return value: %CAIRO_STATUS_SUCCESS, or %CAIRO_STATUS_INVALID_INDEX |
|
- | 4376 | * if @patch_num or @corner_num is not valid for @pattern. If |
|
- | 4377 | * @pattern is not a mesh pattern, %CAIRO_STATUS_PATTERN_TYPE_MISMATCH |
|
- | 4378 | * is returned. |
|
- | 4379 | * |
|
- | 4380 | * Since: 1.12 |
|
- | 4381 | **/ |
|
- | 4382 | cairo_status_t |
|
- | 4383 | cairo_mesh_pattern_get_corner_color_rgba (cairo_pattern_t *pattern, |
|
- | 4384 | unsigned int patch_num, |
|
- | 4385 | unsigned int corner_num, |
|
- | 4386 | double *red, double *green, |
|
- | 4387 | double *blue, double *alpha) |
|
- | 4388 | { |
|
- | 4389 | cairo_mesh_pattern_t *mesh = (cairo_mesh_pattern_t *) pattern; |
|
- | 4390 | unsigned int patch_count; |
|
- | 4391 | const cairo_mesh_patch_t *patch; |
|
- | 4392 | ||
- | 4393 | if (unlikely (pattern->status)) |
|
- | 4394 | return pattern->status; |
|
- | 4395 | ||
- | 4396 | if (unlikely (pattern->type != CAIRO_PATTERN_TYPE_MESH)) |
|
- | 4397 | return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
|
- | 4398 | ||
- | 4399 | if (unlikely (corner_num > 3)) |
|
- | 4400 | return _cairo_error (CAIRO_STATUS_INVALID_INDEX); |
|
- | 4401 | ||
- | 4402 | patch_count = _cairo_array_num_elements (&mesh->patches); |
|
- | 4403 | if (mesh->current_patch) |
|
- | 4404 | patch_count--; |
|
- | 4405 | ||
- | 4406 | if (unlikely (patch_num >= patch_count)) |
|
- | 4407 | return _cairo_error (CAIRO_STATUS_INVALID_INDEX); |
|
- | 4408 | ||
- | 4409 | patch = _cairo_array_index_const (&mesh->patches, patch_num); |
|
- | 4410 | ||
- | 4411 | if (red) |
|
- | 4412 | *red = patch->colors[corner_num].red; |
|
- | 4413 | if (green) |
|
- | 4414 | *green = patch->colors[corner_num].green; |
|
- | 4415 | if (blue) |
|
- | 4416 | *blue = patch->colors[corner_num].blue; |
|
- | 4417 | if (alpha) |
|
- | 4418 | *alpha = patch->colors[corner_num].alpha; |
|
- | 4419 | ||
- | 4420 | return CAIRO_STATUS_SUCCESS; |
|
- | 4421 | } |
|
- | 4422 | slim_hidden_def (cairo_mesh_pattern_get_corner_color_rgba); |
|
- | 4423 | ||
- | 4424 | /** |
|
- | 4425 | * cairo_mesh_pattern_get_control_point: |
|
- | 4426 | * @pattern: a #cairo_pattern_t |
|
- | 4427 | * @patch_num: the patch number to return data for |
|
- | 4428 | * @point_num: the control point number to return data for |
|
- | 4429 | * @x: return value for the x coordinate of the control point, or %NULL |
|
- | 4430 | * @y: return value for the y coordinate of the control point, or %NULL |
|
- | 4431 | * |
|
- | 4432 | * Gets the control point @point_num of patch @patch_num for a mesh |
|
- | 4433 | * pattern. |
|
- | 4434 | * |
|
- | 4435 | * @patch_num can range 0 to 1 less than the number returned by |
|
- | 4436 | * cairo_mesh_pattern_get_patch_count(). |
|
- | 4437 | * |
|
- | 4438 | * Valid values for @point_num are from 0 to 3 and identify the |
|
- | 4439 | * control points as explained in cairo_pattern_create_mesh(). |
|
- | 4440 | * |
|
- | 4441 | * Return value: %CAIRO_STATUS_SUCCESS, or %CAIRO_STATUS_INVALID_INDEX |
|
- | 4442 | * if @patch_num or @point_num is not valid for @pattern. If @pattern |
|
- | 4443 | * is not a mesh pattern, %CAIRO_STATUS_PATTERN_TYPE_MISMATCH is |
|
- | 4444 | * returned. |
|
- | 4445 | * |
|
- | 4446 | * Since: 1.12 |
|
- | 4447 | **/ |
|
- | 4448 | cairo_status_t |
|
- | 4449 | cairo_mesh_pattern_get_control_point (cairo_pattern_t *pattern, |
|
- | 4450 | unsigned int patch_num, |
|
- | 4451 | unsigned int point_num, |
|
- | 4452 | double *x, double *y) |
|
- | 4453 | { |
|
- | 4454 | cairo_mesh_pattern_t *mesh = (cairo_mesh_pattern_t *) pattern; |
|
- | 4455 | const cairo_mesh_patch_t *patch; |
|
- | 4456 | unsigned int patch_count; |
|
- | 4457 | int i, j; |
|
- | 4458 | ||
- | 4459 | if (pattern->status) |
|
- | 4460 | return pattern->status; |
|
- | 4461 | ||
- | 4462 | if (pattern->type != CAIRO_PATTERN_TYPE_MESH) |
|
- | 4463 | return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
|
- | 4464 | ||
- | 4465 | if (point_num > 3) |
|
- | 4466 | return _cairo_error (CAIRO_STATUS_INVALID_INDEX); |
|
- | 4467 | ||
- | 4468 | patch_count = _cairo_array_num_elements (&mesh->patches); |
|
- | 4469 | if (mesh->current_patch) |
|
- | 4470 | patch_count--; |
|
- | 4471 | ||
- | 4472 | if (unlikely (patch_num >= patch_count)) |
|
- | 4473 | return _cairo_error (CAIRO_STATUS_INVALID_INDEX); |
|
- | 4474 | ||
- | 4475 | patch = _cairo_array_index_const (&mesh->patches, patch_num); |
|
- | 4476 | ||
- | 4477 | i = mesh_control_point_i[point_num]; |
|
- | 4478 | j = mesh_control_point_j[point_num]; |
|
- | 4479 | ||
- | 4480 | if (x) |
|
- | 4481 | *x = patch->points[i][j].x; |
|
Line 3325... | Line 4482... | ||
3325 | if (r1) |
4482 | if (y) |
3326 | *r1 = _cairo_fixed_to_double (radial->r2); |
4483 | *y = patch->points[i][j].y; |
- | 4484 | ||
Line 3327... | Line 4485... | ||
3327 | 4485 | return CAIRO_STATUS_SUCCESS; |
|
3328 | return CAIRO_STATUS_SUCCESS; |
4486 | } |
3329 | } |
4487 | slim_hidden_def (cairo_mesh_pattern_get_control_point); |
3330 | - | ||
3331 | void |
4488 | |
Line 3332... | Line 4489... | ||
3332 | _cairo_pattern_reset_static_data (void) |
4489 | void |
3333 | { |
4490 | _cairo_pattern_reset_static_data (void) |
3334 | #if HAS_FREED_POOL |
4491 | { |
Line -... | Line 4492... | ||
- | 4492 | int i; |
|
- | 4493 | ||
- | 4494 | for (i = 0; i < ARRAY_LENGTH (freed_pattern_pool); i++) |
|
- | 4495 | _freed_pool_reset (&freed_pattern_pool[i]); |
|
- | 4496 | } |
|
- | 4497 | ||
- | 4498 | static void |
|
- | 4499 | _cairo_debug_print_surface_pattern (FILE *file, |
|
- | 4500 | const cairo_surface_pattern_t *pattern) |
|
3335 | int i; |
4501 | { |
- | 4502 | printf (" surface type: %d\n", pattern->surface->type); |
|
- | 4503 | } |
|
- | 4504 | ||
- | 4505 | static void |
|
- | 4506 | _cairo_debug_print_raster_source_pattern (FILE *file, |
|
- | 4507 | const cairo_raster_source_pattern_t *raster) |
|
- | 4508 | { |
|
- | 4509 | printf (" content: %x, size %dx%d\n", raster->content, raster->extents.width, raster->extents.height); |
|
- | 4510 | } |
|
- | 4511 | ||
- | 4512 | static void |
|
- | 4513 | _cairo_debug_print_linear_pattern (FILE *file, |
|
- | 4514 | const cairo_linear_pattern_t *pattern) |
|
- | 4515 | { |
|
- | 4516 | } |
|
- | 4517 | ||
- | 4518 | static void |
|
- | 4519 | _cairo_debug_print_radial_pattern (FILE *file, |
|
- | 4520 | const cairo_radial_pattern_t *pattern) |
|
- | 4521 | { |
|
- | 4522 | } |
|
- | 4523 | ||
- | 4524 | static void |
|
- | 4525 | _cairo_debug_print_mesh_pattern (FILE *file, |
|
- | 4526 | const cairo_mesh_pattern_t *pattern) |
|
- | 4527 | { |
|
- | 4528 | } |
|
- | 4529 | ||
- | 4530 | void |
|
- | 4531 | _cairo_debug_print_pattern (FILE *file, const cairo_pattern_t *pattern) |
|
- | 4532 | { |
|
- | 4533 | const char *s; |
|
- | 4534 | switch (pattern->type) { |
|
- | 4535 | case CAIRO_PATTERN_TYPE_SOLID: s = "solid"; break; |
|
- | 4536 | case CAIRO_PATTERN_TYPE_SURFACE: s = "surface"; break; |
|
- | 4537 | case CAIRO_PATTERN_TYPE_LINEAR: s = "linear"; break; |
|
- | 4538 | case CAIRO_PATTERN_TYPE_RADIAL: s = "radial"; break; |
|
- | 4539 | case CAIRO_PATTERN_TYPE_MESH: s = "mesh"; break; |
|
- | 4540 | case CAIRO_PATTERN_TYPE_RASTER_SOURCE: s = "raster"; break; |
|
- | 4541 | default: s = "invalid"; ASSERT_NOT_REACHED; break; |
|
- | 4542 | } |
|
- | 4543 | ||
- | 4544 | fprintf (file, "pattern: %s\n", s); |
|
- | 4545 | if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) |
|
- | 4546 | return; |
|
- | 4547 | ||
- | 4548 | switch (pattern->extend) { |
|
- | 4549 | case CAIRO_EXTEND_NONE: s = "none"; break; |
|
- | 4550 | case CAIRO_EXTEND_REPEAT: s = "repeat"; break; |
|
- | 4551 | case CAIRO_EXTEND_REFLECT: s = "reflect"; break; |
|
- | 4552 | case CAIRO_EXTEND_PAD: s = "pad"; break; |
|
- | 4553 | default: s = "invalid"; ASSERT_NOT_REACHED; break; |
|
- | 4554 | } |
|
- | 4555 | fprintf (file, " extend: %s\n", s); |
|
- | 4556 | ||
- | 4557 | switch (pattern->filter) { |
|
- | 4558 | case CAIRO_FILTER_FAST: s = "fast"; break; |
|
- | 4559 | case CAIRO_FILTER_GOOD: s = "good"; break; |
|
- | 4560 | case CAIRO_FILTER_BEST: s = "best"; break; |
|
- | 4561 | case CAIRO_FILTER_NEAREST: s = "nearest"; break; |
|
- | 4562 | case CAIRO_FILTER_BILINEAR: s = "bilinear"; break; |
|
- | 4563 | case CAIRO_FILTER_GAUSSIAN: s = "guassian"; break; |
|
- | 4564 | default: s = "invalid"; ASSERT_NOT_REACHED; break; |
|
- | 4565 | } |
|
- | 4566 | fprintf (file, " filter: %s\n", s); |
|
- | 4567 | fprintf (file, " matrix: [%g %g %g %g %g %g]\n", |
|
- | 4568 | pattern->matrix.xx, pattern->matrix.yx, |
|
- | 4569 | pattern->matrix.xy, pattern->matrix.yy, |
|
- | 4570 | pattern->matrix.x0, pattern->matrix.y0); |
|
- | 4571 | switch (pattern->type) { |
|
- | 4572 | default: |
|
- | 4573 | case CAIRO_PATTERN_TYPE_SOLID: |
|
- | 4574 | break; |
|
- | 4575 | case CAIRO_PATTERN_TYPE_RASTER_SOURCE: |
|
- | 4576 | _cairo_debug_print_raster_source_pattern (file, (cairo_raster_source_pattern_t *)pattern); |
|
- | 4577 | break; |
|
- | 4578 | case CAIRO_PATTERN_TYPE_SURFACE: |
|
- | 4579 | _cairo_debug_print_surface_pattern (file, (cairo_surface_pattern_t *)pattern); |
|
- | 4580 | break; |
|
- | 4581 | case CAIRO_PATTERN_TYPE_LINEAR: |
|
- | 4582 | _cairo_debug_print_linear_pattern (file, (cairo_linear_pattern_t *)pattern); |
|
- | 4583 | break; |
|
- | 4584 | case CAIRO_PATTERN_TYPE_RADIAL: |
|
3336 | 4585 | _cairo_debug_print_radial_pattern (file, (cairo_radial_pattern_t *)pattern); |