Rev 1892 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1892 | serge | 1 | /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ |
2 | /* cairo - a vector graphics library with display and print output |
||
3 | * |
||
4 | * Copyright © 2004 David Reveman |
||
5 | * Copyright © 2005 Red Hat, Inc. |
||
6 | * |
||
7 | * Permission to use, copy, modify, distribute, and sell this software |
||
8 | * and its documentation for any purpose is hereby granted without |
||
9 | * fee, provided that the above copyright notice appear in all copies |
||
10 | * and that both that copyright notice and this permission notice |
||
11 | * appear in supporting documentation, and that the name of David |
||
12 | * Reveman not be used in advertising or publicity pertaining to |
||
13 | * distribution of the software without specific, written prior |
||
14 | * permission. David Reveman makes no representations about the |
||
15 | * suitability of this software for any purpose. It is provided "as |
||
16 | * is" without express or implied warranty. |
||
17 | * |
||
18 | * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS |
||
19 | * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND |
||
20 | * FITNESS, IN NO EVENT SHALL DAVID REVEMAN BE LIABLE FOR ANY SPECIAL, |
||
21 | * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER |
||
22 | * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
||
23 | * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR |
||
24 | * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
||
25 | * |
||
26 | * Authors: David Reveman |
||
27 | * Keith Packard |
||
28 | * Carl Worth |
||
29 | */ |
||
30 | |||
31 | #include "cairoint.h" |
||
3959 | Serge | 32 | |
33 | #include "cairo-array-private.h" |
||
1892 | serge | 34 | #include "cairo-error-private.h" |
35 | #include "cairo-freed-pool-private.h" |
||
3959 | Serge | 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" |
||
1892 | serge | 42 | |
3959 | Serge | 43 | #include |
44 | |||
45 | #define PIXMAN_MAX_INT ((pixman_fixed_1 >> 1) - pixman_fixed_e) /* need to ensure deltas also fit */ |
||
46 | |||
1892 | serge | 47 | /** |
48 | * SECTION:cairo-pattern |
||
49 | * @Title: cairo_pattern_t |
||
50 | * @Short_Description: Sources for drawing |
||
51 | * @See_Also: #cairo_t, #cairo_surface_t |
||
52 | * |
||
53 | * #cairo_pattern_t is the paint with which cairo draws. |
||
54 | * The primary use of patterns is as the source for all cairo drawing |
||
55 | * operations, although they can also be used as masks, that is, as the |
||
56 | * brush too. |
||
57 | * |
||
58 | * A cairo pattern is created by using one of the many constructors, |
||
3959 | Serge | 59 | * of the form |
60 | * |
||
1892 | serge | 61 | * or implicitly through |
3959 | Serge | 62 | * |
63 | * functions. |
||
64 | **/ |
||
1892 | serge | 65 | |
3959 | Serge | 66 | static freed_pool_t freed_pattern_pool[5]; |
1892 | serge | 67 | |
68 | static const cairo_solid_pattern_t _cairo_pattern_nil = { |
||
3959 | Serge | 69 | { |
1892 | serge | 70 | CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ |
71 | CAIRO_STATUS_NO_MEMORY, /* status */ |
||
72 | { 0, 0, 0, NULL }, /* user_data */ |
||
3959 | Serge | 73 | { NULL, NULL }, /* observers */ |
74 | |||
75 | CAIRO_PATTERN_TYPE_SOLID, /* type */ |
||
76 | CAIRO_FILTER_DEFAULT, /* filter */ |
||
77 | CAIRO_EXTEND_GRADIENT_DEFAULT, /* extend */ |
||
78 | FALSE, /* has component alpha */ |
||
1892 | serge | 79 | { 1., 0., 0., 1., 0., 0., }, /* matrix */ |
3959 | Serge | 80 | 1.0 /* opacity */ |
81 | } |
||
1892 | serge | 82 | }; |
83 | |||
84 | static const cairo_solid_pattern_t _cairo_pattern_nil_null_pointer = { |
||
3959 | Serge | 85 | { |
1892 | serge | 86 | CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ |
87 | CAIRO_STATUS_NULL_POINTER, /* status */ |
||
88 | { 0, 0, 0, NULL }, /* user_data */ |
||
3959 | Serge | 89 | { NULL, NULL }, /* observers */ |
90 | |||
91 | CAIRO_PATTERN_TYPE_SOLID, /* type */ |
||
92 | CAIRO_FILTER_DEFAULT, /* filter */ |
||
93 | CAIRO_EXTEND_GRADIENT_DEFAULT, /* extend */ |
||
94 | FALSE, /* has component alpha */ |
||
1892 | serge | 95 | { 1., 0., 0., 1., 0., 0., }, /* matrix */ |
3959 | Serge | 96 | 1.0 /* opacity */ |
97 | } |
||
1892 | serge | 98 | }; |
99 | |||
100 | const cairo_solid_pattern_t _cairo_pattern_black = { |
||
3959 | Serge | 101 | { |
1892 | serge | 102 | CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ |
103 | CAIRO_STATUS_SUCCESS, /* status */ |
||
104 | { 0, 0, 0, NULL }, /* user_data */ |
||
3959 | Serge | 105 | { NULL, NULL }, /* observers */ |
106 | |||
107 | CAIRO_PATTERN_TYPE_SOLID, /* type */ |
||
108 | CAIRO_FILTER_NEAREST, /* filter */ |
||
109 | CAIRO_EXTEND_REPEAT, /* extend */ |
||
110 | FALSE, /* has component alpha */ |
||
1892 | serge | 111 | { 1., 0., 0., 1., 0., 0., }, /* matrix */ |
3959 | Serge | 112 | 1.0 /* opacity */ |
113 | }, |
||
1892 | serge | 114 | { 0., 0., 0., 1., 0, 0, 0, 0xffff },/* color (double rgba, short rgba) */ |
115 | }; |
||
116 | |||
117 | const cairo_solid_pattern_t _cairo_pattern_clear = { |
||
3959 | Serge | 118 | { |
1892 | serge | 119 | CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ |
120 | CAIRO_STATUS_SUCCESS, /* status */ |
||
121 | { 0, 0, 0, NULL }, /* user_data */ |
||
3959 | Serge | 122 | { NULL, NULL }, /* observers */ |
123 | |||
124 | CAIRO_PATTERN_TYPE_SOLID, /* type */ |
||
125 | CAIRO_FILTER_NEAREST, /* filter */ |
||
126 | CAIRO_EXTEND_REPEAT, /* extend */ |
||
127 | FALSE, /* has component alpha */ |
||
1892 | serge | 128 | { 1., 0., 0., 1., 0., 0., }, /* matrix */ |
3959 | Serge | 129 | 1.0 /* opacity */ |
130 | }, |
||
1892 | serge | 131 | { 0., 0., 0., 0., 0, 0, 0, 0 },/* color (double rgba, short rgba) */ |
132 | }; |
||
133 | |||
134 | const cairo_solid_pattern_t _cairo_pattern_white = { |
||
3959 | Serge | 135 | { |
1892 | serge | 136 | CAIRO_REFERENCE_COUNT_INVALID, /* ref_count */ |
137 | CAIRO_STATUS_SUCCESS, /* status */ |
||
138 | { 0, 0, 0, NULL }, /* user_data */ |
||
3959 | Serge | 139 | { NULL, NULL }, /* observers */ |
140 | |||
141 | CAIRO_PATTERN_TYPE_SOLID, /* type */ |
||
142 | CAIRO_FILTER_NEAREST, /* filter */ |
||
143 | CAIRO_EXTEND_REPEAT, /* extend */ |
||
144 | FALSE, /* has component alpha */ |
||
1892 | serge | 145 | { 1., 0., 0., 1., 0., 0., }, /* matrix */ |
3959 | Serge | 146 | 1.0 /* opacity */ |
147 | }, |
||
1892 | serge | 148 | { 1., 1., 1., 1., 0xffff, 0xffff, 0xffff, 0xffff },/* color (double rgba, short rgba) */ |
149 | }; |
||
150 | |||
3959 | Serge | 151 | static void |
152 | _cairo_pattern_notify_observers (cairo_pattern_t *pattern, |
||
153 | unsigned int flags) |
||
154 | { |
||
155 | cairo_pattern_observer_t *pos; |
||
156 | |||
157 | cairo_list_foreach_entry (pos, cairo_pattern_observer_t, &pattern->observers, link) |
||
158 | pos->notify (pos, pattern, flags); |
||
159 | } |
||
160 | |||
1892 | serge | 161 | /** |
162 | * _cairo_pattern_set_error: |
||
163 | * @pattern: a pattern |
||
164 | * @status: a status value indicating an error |
||
165 | * |
||
166 | * Atomically sets pattern->status to @status and calls _cairo_error; |
||
167 | * Does nothing if status is %CAIRO_STATUS_SUCCESS. |
||
168 | * |
||
169 | * All assignments of an error status to pattern->status should happen |
||
170 | * through _cairo_pattern_set_error(). Note that due to the nature of |
||
171 | * the atomic operation, it is not safe to call this function on the nil |
||
172 | * objects. |
||
173 | * |
||
174 | * The purpose of this function is to allow the user to set a |
||
175 | * breakpoint in _cairo_error() to generate a stack trace for when the |
||
176 | * user causes cairo to detect an error. |
||
177 | **/ |
||
178 | static cairo_status_t |
||
179 | _cairo_pattern_set_error (cairo_pattern_t *pattern, |
||
180 | cairo_status_t status) |
||
181 | { |
||
182 | if (status == CAIRO_STATUS_SUCCESS) |
||
183 | return status; |
||
184 | |||
185 | /* Don't overwrite an existing error. This preserves the first |
||
186 | * error, which is the most significant. */ |
||
187 | _cairo_status_set_error (&pattern->status, status); |
||
188 | |||
189 | return _cairo_error (status); |
||
190 | } |
||
191 | |||
3959 | Serge | 192 | void |
1892 | serge | 193 | _cairo_pattern_init (cairo_pattern_t *pattern, cairo_pattern_type_t type) |
194 | { |
||
195 | #if HAVE_VALGRIND |
||
196 | switch (type) { |
||
197 | case CAIRO_PATTERN_TYPE_SOLID: |
||
198 | VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_solid_pattern_t)); |
||
199 | break; |
||
200 | case CAIRO_PATTERN_TYPE_SURFACE: |
||
201 | VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_surface_pattern_t)); |
||
202 | break; |
||
203 | case CAIRO_PATTERN_TYPE_LINEAR: |
||
204 | VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_linear_pattern_t)); |
||
205 | break; |
||
206 | case CAIRO_PATTERN_TYPE_RADIAL: |
||
207 | VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_radial_pattern_t)); |
||
208 | break; |
||
3959 | Serge | 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; |
||
1892 | serge | 214 | } |
215 | #endif |
||
216 | |||
217 | pattern->type = type; |
||
218 | pattern->status = CAIRO_STATUS_SUCCESS; |
||
219 | |||
220 | /* Set the reference count to zero for on-stack patterns. |
||
221 | * Callers needs to explicitly increment the count for heap allocations. */ |
||
222 | CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 0); |
||
223 | |||
224 | _cairo_user_data_array_init (&pattern->user_data); |
||
225 | |||
3959 | Serge | 226 | if (type == CAIRO_PATTERN_TYPE_SURFACE || |
227 | type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) |
||
1892 | serge | 228 | pattern->extend = CAIRO_EXTEND_SURFACE_DEFAULT; |
229 | else |
||
230 | pattern->extend = CAIRO_EXTEND_GRADIENT_DEFAULT; |
||
231 | |||
232 | pattern->filter = CAIRO_FILTER_DEFAULT; |
||
3959 | Serge | 233 | pattern->opacity = 1.0; |
1892 | serge | 234 | |
235 | pattern->has_component_alpha = FALSE; |
||
236 | |||
237 | cairo_matrix_init_identity (&pattern->matrix); |
||
3959 | Serge | 238 | |
239 | cairo_list_init (&pattern->observers); |
||
1892 | serge | 240 | } |
241 | |||
242 | static cairo_status_t |
||
243 | _cairo_gradient_pattern_init_copy (cairo_gradient_pattern_t *pattern, |
||
244 | const cairo_gradient_pattern_t *other) |
||
245 | { |
||
246 | if (CAIRO_INJECT_FAULT ()) |
||
247 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
||
248 | |||
249 | if (other->base.type == CAIRO_PATTERN_TYPE_LINEAR) |
||
250 | { |
||
251 | cairo_linear_pattern_t *dst = (cairo_linear_pattern_t *) pattern; |
||
252 | cairo_linear_pattern_t *src = (cairo_linear_pattern_t *) other; |
||
253 | |||
254 | *dst = *src; |
||
255 | } |
||
256 | else |
||
257 | { |
||
258 | cairo_radial_pattern_t *dst = (cairo_radial_pattern_t *) pattern; |
||
259 | cairo_radial_pattern_t *src = (cairo_radial_pattern_t *) other; |
||
260 | |||
261 | *dst = *src; |
||
262 | } |
||
263 | |||
264 | if (other->stops == other->stops_embedded) |
||
265 | pattern->stops = pattern->stops_embedded; |
||
266 | else if (other->stops) |
||
267 | { |
||
268 | pattern->stops = _cairo_malloc_ab (other->stops_size, |
||
269 | sizeof (cairo_gradient_stop_t)); |
||
270 | if (unlikely (pattern->stops == NULL)) { |
||
271 | pattern->stops_size = 0; |
||
272 | pattern->n_stops = 0; |
||
273 | return _cairo_pattern_set_error (&pattern->base, CAIRO_STATUS_NO_MEMORY); |
||
274 | } |
||
275 | |||
276 | memcpy (pattern->stops, other->stops, |
||
277 | other->n_stops * sizeof (cairo_gradient_stop_t)); |
||
278 | } |
||
279 | |||
280 | return CAIRO_STATUS_SUCCESS; |
||
281 | } |
||
282 | |||
3959 | Serge | 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)); |
||
293 | } |
||
294 | |||
1892 | serge | 295 | cairo_status_t |
296 | _cairo_pattern_init_copy (cairo_pattern_t *pattern, |
||
297 | const cairo_pattern_t *other) |
||
298 | { |
||
3959 | Serge | 299 | cairo_status_t status; |
300 | |||
1892 | serge | 301 | if (other->status) |
302 | return _cairo_pattern_set_error (pattern, other->status); |
||
303 | |||
304 | switch (other->type) { |
||
305 | case CAIRO_PATTERN_TYPE_SOLID: { |
||
306 | cairo_solid_pattern_t *dst = (cairo_solid_pattern_t *) pattern; |
||
307 | cairo_solid_pattern_t *src = (cairo_solid_pattern_t *) other; |
||
308 | |||
309 | VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_solid_pattern_t))); |
||
310 | |||
311 | *dst = *src; |
||
312 | } break; |
||
313 | case CAIRO_PATTERN_TYPE_SURFACE: { |
||
314 | cairo_surface_pattern_t *dst = (cairo_surface_pattern_t *) pattern; |
||
315 | cairo_surface_pattern_t *src = (cairo_surface_pattern_t *) other; |
||
316 | |||
317 | VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_surface_pattern_t))); |
||
318 | |||
319 | *dst = *src; |
||
320 | cairo_surface_reference (dst->surface); |
||
321 | } break; |
||
322 | case CAIRO_PATTERN_TYPE_LINEAR: |
||
323 | case CAIRO_PATTERN_TYPE_RADIAL: { |
||
324 | cairo_gradient_pattern_t *dst = (cairo_gradient_pattern_t *) pattern; |
||
325 | cairo_gradient_pattern_t *src = (cairo_gradient_pattern_t *) other; |
||
326 | |||
327 | if (other->type == CAIRO_PATTERN_TYPE_LINEAR) { |
||
328 | VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_linear_pattern_t))); |
||
329 | } else { |
||
330 | VG (VALGRIND_MAKE_MEM_UNDEFINED (pattern, sizeof (cairo_radial_pattern_t))); |
||
331 | } |
||
332 | |||
333 | status = _cairo_gradient_pattern_init_copy (dst, src); |
||
334 | if (unlikely (status)) |
||
335 | return status; |
||
336 | |||
337 | } break; |
||
3959 | Serge | 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; |
||
354 | } break; |
||
1892 | serge | 355 | } |
356 | |||
357 | /* The reference count and user_data array are unique to the copy. */ |
||
358 | CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 0); |
||
359 | _cairo_user_data_array_init (&pattern->user_data); |
||
360 | |||
361 | return CAIRO_STATUS_SUCCESS; |
||
362 | } |
||
363 | |||
364 | void |
||
365 | _cairo_pattern_init_static_copy (cairo_pattern_t *pattern, |
||
366 | const cairo_pattern_t *other) |
||
367 | { |
||
368 | int size; |
||
369 | |||
370 | assert (other->status == CAIRO_STATUS_SUCCESS); |
||
371 | |||
372 | switch (other->type) { |
||
373 | default: |
||
374 | ASSERT_NOT_REACHED; |
||
375 | case CAIRO_PATTERN_TYPE_SOLID: |
||
376 | size = sizeof (cairo_solid_pattern_t); |
||
377 | break; |
||
378 | case CAIRO_PATTERN_TYPE_SURFACE: |
||
379 | size = sizeof (cairo_surface_pattern_t); |
||
380 | break; |
||
381 | case CAIRO_PATTERN_TYPE_LINEAR: |
||
382 | size = sizeof (cairo_linear_pattern_t); |
||
383 | break; |
||
384 | case CAIRO_PATTERN_TYPE_RADIAL: |
||
385 | size = sizeof (cairo_radial_pattern_t); |
||
386 | break; |
||
3959 | Serge | 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; |
||
1892 | serge | 393 | } |
394 | |||
395 | memcpy (pattern, other, size); |
||
396 | |||
397 | CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 0); |
||
398 | _cairo_user_data_array_init (&pattern->user_data); |
||
399 | } |
||
400 | |||
401 | cairo_status_t |
||
402 | _cairo_pattern_init_snapshot (cairo_pattern_t *pattern, |
||
403 | const cairo_pattern_t *other) |
||
404 | { |
||
405 | cairo_status_t status; |
||
406 | |||
407 | /* We don't bother doing any fancy copy-on-write implementation |
||
408 | * for the pattern's data. It's generally quite tiny. */ |
||
409 | status = _cairo_pattern_init_copy (pattern, other); |
||
410 | if (unlikely (status)) |
||
411 | return status; |
||
412 | |||
413 | /* But we do let the surface snapshot stuff be as fancy as it |
||
414 | * would like to be. */ |
||
415 | if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { |
||
416 | cairo_surface_pattern_t *surface_pattern = |
||
417 | (cairo_surface_pattern_t *) pattern; |
||
418 | cairo_surface_t *surface = surface_pattern->surface; |
||
419 | |||
420 | surface_pattern->surface = _cairo_surface_snapshot (surface); |
||
421 | |||
422 | cairo_surface_destroy (surface); |
||
423 | |||
3959 | Serge | 424 | status = surface_pattern->surface->status; |
425 | } else if (pattern->type == CAIRO_PATTERN_TYPE_RASTER_SOURCE) |
||
426 | status = _cairo_raster_source_pattern_snapshot (pattern); |
||
1892 | serge | 427 | |
3959 | Serge | 428 | return status; |
1892 | serge | 429 | } |
430 | |||
431 | void |
||
432 | _cairo_pattern_fini (cairo_pattern_t *pattern) |
||
433 | { |
||
434 | _cairo_user_data_array_fini (&pattern->user_data); |
||
435 | |||
436 | switch (pattern->type) { |
||
437 | case CAIRO_PATTERN_TYPE_SOLID: |
||
438 | break; |
||
439 | case CAIRO_PATTERN_TYPE_SURFACE: { |
||
440 | cairo_surface_pattern_t *surface_pattern = |
||
441 | (cairo_surface_pattern_t *) pattern; |
||
442 | |||
443 | cairo_surface_destroy (surface_pattern->surface); |
||
444 | } break; |
||
445 | case CAIRO_PATTERN_TYPE_LINEAR: |
||
446 | case CAIRO_PATTERN_TYPE_RADIAL: { |
||
447 | cairo_gradient_pattern_t *gradient = |
||
448 | (cairo_gradient_pattern_t *) pattern; |
||
449 | |||
450 | if (gradient->stops && gradient->stops != gradient->stops_embedded) |
||
451 | free (gradient->stops); |
||
452 | } break; |
||
3959 | Serge | 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); |
||
461 | break; |
||
1892 | serge | 462 | } |
463 | |||
464 | #if HAVE_VALGRIND |
||
465 | switch (pattern->type) { |
||
466 | case CAIRO_PATTERN_TYPE_SOLID: |
||
467 | VALGRIND_MAKE_MEM_NOACCESS (pattern, sizeof (cairo_solid_pattern_t)); |
||
468 | break; |
||
469 | case CAIRO_PATTERN_TYPE_SURFACE: |
||
470 | VALGRIND_MAKE_MEM_NOACCESS (pattern, sizeof (cairo_surface_pattern_t)); |
||
471 | break; |
||
472 | case CAIRO_PATTERN_TYPE_LINEAR: |
||
473 | VALGRIND_MAKE_MEM_NOACCESS (pattern, sizeof (cairo_linear_pattern_t)); |
||
474 | break; |
||
475 | case CAIRO_PATTERN_TYPE_RADIAL: |
||
476 | VALGRIND_MAKE_MEM_NOACCESS (pattern, sizeof (cairo_radial_pattern_t)); |
||
477 | break; |
||
3959 | Serge | 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; |
||
1892 | serge | 483 | } |
484 | #endif |
||
485 | } |
||
486 | |||
487 | cairo_status_t |
||
488 | _cairo_pattern_create_copy (cairo_pattern_t **pattern_out, |
||
489 | const cairo_pattern_t *other) |
||
490 | { |
||
491 | cairo_pattern_t *pattern; |
||
492 | cairo_status_t status; |
||
493 | |||
494 | if (other->status) |
||
495 | return other->status; |
||
496 | |||
497 | switch (other->type) { |
||
498 | case CAIRO_PATTERN_TYPE_SOLID: |
||
499 | pattern = malloc (sizeof (cairo_solid_pattern_t)); |
||
500 | break; |
||
501 | case CAIRO_PATTERN_TYPE_SURFACE: |
||
502 | pattern = malloc (sizeof (cairo_surface_pattern_t)); |
||
503 | break; |
||
504 | case CAIRO_PATTERN_TYPE_LINEAR: |
||
505 | pattern = malloc (sizeof (cairo_linear_pattern_t)); |
||
506 | break; |
||
507 | case CAIRO_PATTERN_TYPE_RADIAL: |
||
508 | pattern = malloc (sizeof (cairo_radial_pattern_t)); |
||
509 | break; |
||
3959 | Serge | 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; |
||
1892 | serge | 516 | default: |
517 | ASSERT_NOT_REACHED; |
||
518 | return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
||
519 | } |
||
520 | if (unlikely (pattern == NULL)) |
||
521 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
||
522 | |||
523 | status = _cairo_pattern_init_copy (pattern, other); |
||
524 | if (unlikely (status)) { |
||
525 | free (pattern); |
||
526 | return status; |
||
527 | } |
||
528 | |||
529 | CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 1); |
||
530 | *pattern_out = pattern; |
||
531 | return CAIRO_STATUS_SUCCESS; |
||
532 | } |
||
533 | |||
534 | void |
||
535 | _cairo_pattern_init_solid (cairo_solid_pattern_t *pattern, |
||
536 | const cairo_color_t *color) |
||
537 | { |
||
538 | _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SOLID); |
||
539 | pattern->color = *color; |
||
540 | } |
||
541 | |||
542 | void |
||
543 | _cairo_pattern_init_for_surface (cairo_surface_pattern_t *pattern, |
||
544 | cairo_surface_t *surface) |
||
545 | { |
||
546 | if (surface->status) { |
||
547 | /* Force to solid to simplify the pattern_fini process. */ |
||
548 | _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SOLID); |
||
549 | _cairo_pattern_set_error (&pattern->base, surface->status); |
||
550 | return; |
||
551 | } |
||
552 | |||
553 | _cairo_pattern_init (&pattern->base, CAIRO_PATTERN_TYPE_SURFACE); |
||
554 | |||
555 | pattern->surface = cairo_surface_reference (surface); |
||
556 | } |
||
557 | |||
558 | static void |
||
559 | _cairo_pattern_init_gradient (cairo_gradient_pattern_t *pattern, |
||
560 | cairo_pattern_type_t type) |
||
561 | { |
||
562 | _cairo_pattern_init (&pattern->base, type); |
||
563 | |||
564 | pattern->n_stops = 0; |
||
565 | pattern->stops_size = 0; |
||
566 | pattern->stops = NULL; |
||
567 | } |
||
568 | |||
3959 | Serge | 569 | static void |
1892 | serge | 570 | _cairo_pattern_init_linear (cairo_linear_pattern_t *pattern, |
571 | double x0, double y0, double x1, double y1) |
||
572 | { |
||
573 | _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_TYPE_LINEAR); |
||
574 | |||
3959 | Serge | 575 | pattern->pd1.x = x0; |
576 | pattern->pd1.y = y0; |
||
577 | pattern->pd2.x = x1; |
||
578 | pattern->pd2.y = y1; |
||
1892 | serge | 579 | } |
580 | |||
3959 | Serge | 581 | static void |
1892 | serge | 582 | _cairo_pattern_init_radial (cairo_radial_pattern_t *pattern, |
583 | double cx0, double cy0, double radius0, |
||
584 | double cx1, double cy1, double radius1) |
||
585 | { |
||
586 | _cairo_pattern_init_gradient (&pattern->base, CAIRO_PATTERN_TYPE_RADIAL); |
||
587 | |||
3959 | Serge | 588 | pattern->cd1.center.x = cx0; |
589 | pattern->cd1.center.y = cy0; |
||
590 | pattern->cd1.radius = fabs (radius0); |
||
591 | pattern->cd2.center.x = cx1; |
||
592 | pattern->cd2.center.y = cy1; |
||
593 | pattern->cd2.radius = fabs (radius1); |
||
1892 | serge | 594 | } |
595 | |||
596 | cairo_pattern_t * |
||
597 | _cairo_pattern_create_solid (const cairo_color_t *color) |
||
598 | { |
||
599 | cairo_solid_pattern_t *pattern; |
||
600 | |||
601 | pattern = |
||
602 | _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SOLID]); |
||
603 | if (unlikely (pattern == NULL)) { |
||
604 | /* None cached, need to create a new pattern. */ |
||
605 | pattern = malloc (sizeof (cairo_solid_pattern_t)); |
||
606 | if (unlikely (pattern == NULL)) { |
||
607 | _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); |
||
608 | return (cairo_pattern_t *) &_cairo_pattern_nil; |
||
609 | } |
||
610 | } |
||
611 | |||
612 | _cairo_pattern_init_solid (pattern, color); |
||
613 | CAIRO_REFERENCE_COUNT_INIT (&pattern->base.ref_count, 1); |
||
614 | |||
615 | return &pattern->base; |
||
616 | } |
||
617 | |||
618 | cairo_pattern_t * |
||
619 | _cairo_pattern_create_in_error (cairo_status_t status) |
||
620 | { |
||
621 | cairo_pattern_t *pattern; |
||
622 | |||
623 | if (status == CAIRO_STATUS_NO_MEMORY) |
||
624 | return (cairo_pattern_t *)&_cairo_pattern_nil.base; |
||
625 | |||
626 | CAIRO_MUTEX_INITIALIZE (); |
||
627 | |||
628 | pattern = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK); |
||
629 | if (pattern->status == CAIRO_STATUS_SUCCESS) |
||
630 | status = _cairo_pattern_set_error (pattern, status); |
||
631 | |||
632 | return pattern; |
||
633 | } |
||
634 | |||
635 | /** |
||
636 | * cairo_pattern_create_rgb: |
||
637 | * @red: red component of the color |
||
638 | * @green: green component of the color |
||
639 | * @blue: blue component of the color |
||
640 | * |
||
641 | * Creates a new #cairo_pattern_t corresponding to an opaque color. The |
||
642 | * color components are floating point numbers in the range 0 to 1. |
||
643 | * If the values passed in are outside that range, they will be |
||
644 | * clamped. |
||
645 | * |
||
646 | * Return value: the newly created #cairo_pattern_t if successful, or |
||
647 | * an error pattern in case of no memory. The caller owns the |
||
648 | * returned object and should call cairo_pattern_destroy() when |
||
649 | * finished with it. |
||
650 | * |
||
651 | * This function will always return a valid pointer, but if an error |
||
652 | * occurred the pattern status will be set to an error. To inspect |
||
653 | * the status of a pattern use cairo_pattern_status(). |
||
3959 | Serge | 654 | * |
655 | * Since: 1.0 |
||
1892 | serge | 656 | **/ |
657 | cairo_pattern_t * |
||
658 | cairo_pattern_create_rgb (double red, double green, double blue) |
||
659 | { |
||
3959 | Serge | 660 | return cairo_pattern_create_rgba (red, green, blue, 1.0); |
1892 | serge | 661 | } |
662 | slim_hidden_def (cairo_pattern_create_rgb); |
||
663 | |||
664 | /** |
||
665 | * cairo_pattern_create_rgba: |
||
666 | * @red: red component of the color |
||
667 | * @green: green component of the color |
||
668 | * @blue: blue component of the color |
||
669 | * @alpha: alpha component of the color |
||
670 | * |
||
671 | * Creates a new #cairo_pattern_t corresponding to a translucent color. |
||
672 | * The color components are floating point numbers in the range 0 to |
||
673 | * 1. If the values passed in are outside that range, they will be |
||
674 | * clamped. |
||
675 | * |
||
676 | * Return value: the newly created #cairo_pattern_t if successful, or |
||
677 | * an error pattern in case of no memory. The caller owns the |
||
678 | * returned object and should call cairo_pattern_destroy() when |
||
679 | * finished with it. |
||
680 | * |
||
681 | * This function will always return a valid pointer, but if an error |
||
682 | * occurred the pattern status will be set to an error. To inspect |
||
683 | * the status of a pattern use cairo_pattern_status(). |
||
3959 | Serge | 684 | * |
685 | * Since: 1.0 |
||
1892 | serge | 686 | **/ |
687 | cairo_pattern_t * |
||
688 | cairo_pattern_create_rgba (double red, double green, double blue, |
||
689 | double alpha) |
||
690 | { |
||
691 | cairo_color_t color; |
||
692 | |||
693 | red = _cairo_restrict_value (red, 0.0, 1.0); |
||
694 | green = _cairo_restrict_value (green, 0.0, 1.0); |
||
695 | blue = _cairo_restrict_value (blue, 0.0, 1.0); |
||
696 | alpha = _cairo_restrict_value (alpha, 0.0, 1.0); |
||
697 | |||
698 | _cairo_color_init_rgba (&color, red, green, blue, alpha); |
||
699 | |||
700 | CAIRO_MUTEX_INITIALIZE (); |
||
701 | |||
702 | return _cairo_pattern_create_solid (&color); |
||
703 | } |
||
704 | slim_hidden_def (cairo_pattern_create_rgba); |
||
705 | |||
706 | /** |
||
707 | * cairo_pattern_create_for_surface: |
||
708 | * @surface: the surface |
||
709 | * |
||
710 | * Create a new #cairo_pattern_t for the given surface. |
||
711 | * |
||
712 | * Return value: the newly created #cairo_pattern_t if successful, or |
||
713 | * an error pattern in case of no memory. The caller owns the |
||
714 | * returned object and should call cairo_pattern_destroy() when |
||
715 | * finished with it. |
||
716 | * |
||
717 | * This function will always return a valid pointer, but if an error |
||
718 | * occurred the pattern status will be set to an error. To inspect |
||
719 | * the status of a pattern use cairo_pattern_status(). |
||
3959 | Serge | 720 | * |
721 | * Since: 1.0 |
||
1892 | serge | 722 | **/ |
723 | cairo_pattern_t * |
||
724 | cairo_pattern_create_for_surface (cairo_surface_t *surface) |
||
725 | { |
||
726 | cairo_surface_pattern_t *pattern; |
||
727 | |||
728 | if (surface == NULL) { |
||
729 | _cairo_error_throw (CAIRO_STATUS_NULL_POINTER); |
||
730 | return (cairo_pattern_t*) &_cairo_pattern_nil_null_pointer; |
||
731 | } |
||
732 | |||
733 | if (surface->status) |
||
734 | return _cairo_pattern_create_in_error (surface->status); |
||
735 | |||
736 | pattern = |
||
737 | _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_SURFACE]); |
||
738 | if (unlikely (pattern == NULL)) { |
||
739 | pattern = malloc (sizeof (cairo_surface_pattern_t)); |
||
740 | if (unlikely (pattern == NULL)) { |
||
741 | _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); |
||
742 | return (cairo_pattern_t *)&_cairo_pattern_nil.base; |
||
743 | } |
||
744 | } |
||
745 | |||
746 | CAIRO_MUTEX_INITIALIZE (); |
||
747 | |||
748 | _cairo_pattern_init_for_surface (pattern, surface); |
||
749 | CAIRO_REFERENCE_COUNT_INIT (&pattern->base.ref_count, 1); |
||
750 | |||
751 | return &pattern->base; |
||
752 | } |
||
753 | slim_hidden_def (cairo_pattern_create_for_surface); |
||
754 | |||
755 | /** |
||
756 | * cairo_pattern_create_linear: |
||
757 | * @x0: x coordinate of the start point |
||
758 | * @y0: y coordinate of the start point |
||
759 | * @x1: x coordinate of the end point |
||
760 | * @y1: y coordinate of the end point |
||
761 | * |
||
762 | * Create a new linear gradient #cairo_pattern_t along the line defined |
||
763 | * by (x0, y0) and (x1, y1). Before using the gradient pattern, a |
||
764 | * number of color stops should be defined using |
||
765 | * cairo_pattern_add_color_stop_rgb() or |
||
766 | * cairo_pattern_add_color_stop_rgba(). |
||
767 | * |
||
768 | * Note: The coordinates here are in pattern space. For a new pattern, |
||
769 | * pattern space is identical to user space, but the relationship |
||
770 | * between the spaces can be changed with cairo_pattern_set_matrix(). |
||
771 | * |
||
772 | * Return value: the newly created #cairo_pattern_t if successful, or |
||
773 | * an error pattern in case of no memory. The caller owns the |
||
774 | * returned object and should call cairo_pattern_destroy() when |
||
775 | * finished with it. |
||
776 | * |
||
777 | * This function will always return a valid pointer, but if an error |
||
778 | * occurred the pattern status will be set to an error. To inspect |
||
779 | * the status of a pattern use cairo_pattern_status(). |
||
3959 | Serge | 780 | * |
781 | * Since: 1.0 |
||
1892 | serge | 782 | **/ |
783 | cairo_pattern_t * |
||
784 | cairo_pattern_create_linear (double x0, double y0, double x1, double y1) |
||
785 | { |
||
786 | cairo_linear_pattern_t *pattern; |
||
787 | |||
788 | pattern = |
||
789 | _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_LINEAR]); |
||
790 | if (unlikely (pattern == NULL)) { |
||
791 | pattern = malloc (sizeof (cairo_linear_pattern_t)); |
||
792 | if (unlikely (pattern == NULL)) { |
||
793 | _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); |
||
794 | return (cairo_pattern_t *) &_cairo_pattern_nil.base; |
||
795 | } |
||
796 | } |
||
797 | |||
798 | CAIRO_MUTEX_INITIALIZE (); |
||
799 | |||
800 | _cairo_pattern_init_linear (pattern, x0, y0, x1, y1); |
||
801 | CAIRO_REFERENCE_COUNT_INIT (&pattern->base.base.ref_count, 1); |
||
802 | |||
803 | return &pattern->base.base; |
||
804 | } |
||
805 | |||
806 | /** |
||
807 | * cairo_pattern_create_radial: |
||
808 | * @cx0: x coordinate for the center of the start circle |
||
809 | * @cy0: y coordinate for the center of the start circle |
||
810 | * @radius0: radius of the start circle |
||
811 | * @cx1: x coordinate for the center of the end circle |
||
812 | * @cy1: y coordinate for the center of the end circle |
||
813 | * @radius1: radius of the end circle |
||
814 | * |
||
815 | * Creates a new radial gradient #cairo_pattern_t between the two |
||
816 | * circles defined by (cx0, cy0, radius0) and (cx1, cy1, radius1). Before using the |
||
817 | * gradient pattern, a number of color stops should be defined using |
||
818 | * cairo_pattern_add_color_stop_rgb() or |
||
819 | * cairo_pattern_add_color_stop_rgba(). |
||
820 | * |
||
821 | * Note: The coordinates here are in pattern space. For a new pattern, |
||
822 | * pattern space is identical to user space, but the relationship |
||
823 | * between the spaces can be changed with cairo_pattern_set_matrix(). |
||
824 | * |
||
825 | * Return value: the newly created #cairo_pattern_t if successful, or |
||
826 | * an error pattern in case of no memory. The caller owns the |
||
827 | * returned object and should call cairo_pattern_destroy() when |
||
828 | * finished with it. |
||
829 | * |
||
830 | * This function will always return a valid pointer, but if an error |
||
831 | * occurred the pattern status will be set to an error. To inspect |
||
832 | * the status of a pattern use cairo_pattern_status(). |
||
3959 | Serge | 833 | * |
834 | * Since: 1.0 |
||
1892 | serge | 835 | **/ |
836 | cairo_pattern_t * |
||
837 | cairo_pattern_create_radial (double cx0, double cy0, double radius0, |
||
838 | double cx1, double cy1, double radius1) |
||
839 | { |
||
840 | cairo_radial_pattern_t *pattern; |
||
841 | |||
842 | pattern = |
||
843 | _freed_pool_get (&freed_pattern_pool[CAIRO_PATTERN_TYPE_RADIAL]); |
||
844 | if (unlikely (pattern == NULL)) { |
||
845 | pattern = malloc (sizeof (cairo_radial_pattern_t)); |
||
846 | if (unlikely (pattern == NULL)) { |
||
847 | _cairo_error_throw (CAIRO_STATUS_NO_MEMORY); |
||
848 | return (cairo_pattern_t *) &_cairo_pattern_nil.base; |
||
849 | } |
||
850 | } |
||
851 | |||
852 | CAIRO_MUTEX_INITIALIZE (); |
||
853 | |||
854 | _cairo_pattern_init_radial (pattern, cx0, cy0, radius0, cx1, cy1, radius1); |
||
855 | CAIRO_REFERENCE_COUNT_INIT (&pattern->base.base.ref_count, 1); |
||
856 | |||
857 | return &pattern->base.base; |
||
858 | } |
||
859 | |||
3959 | Serge | 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 | |||
1892 | serge | 867 | /** |
3959 | Serge | 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; |
||
1038 | } |
||
1039 | |||
1040 | /** |
||
1892 | serge | 1041 | * cairo_pattern_reference: |
1042 | * @pattern: a #cairo_pattern_t |
||
1043 | * |
||
1044 | * Increases the reference count on @pattern by one. This prevents |
||
1045 | * @pattern from being destroyed until a matching call to |
||
1046 | * cairo_pattern_destroy() is made. |
||
1047 | * |
||
1048 | * The number of references to a #cairo_pattern_t can be get using |
||
1049 | * cairo_pattern_get_reference_count(). |
||
1050 | * |
||
1051 | * Return value: the referenced #cairo_pattern_t. |
||
3959 | Serge | 1052 | * |
1053 | * Since: 1.0 |
||
1892 | serge | 1054 | **/ |
1055 | cairo_pattern_t * |
||
1056 | cairo_pattern_reference (cairo_pattern_t *pattern) |
||
1057 | { |
||
1058 | if (pattern == NULL || |
||
1059 | CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count)) |
||
1060 | return pattern; |
||
1061 | |||
1062 | assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&pattern->ref_count)); |
||
1063 | |||
1064 | _cairo_reference_count_inc (&pattern->ref_count); |
||
1065 | |||
1066 | return pattern; |
||
1067 | } |
||
1068 | slim_hidden_def (cairo_pattern_reference); |
||
1069 | |||
1070 | /** |
||
1071 | * cairo_pattern_get_type: |
||
1072 | * @pattern: a #cairo_pattern_t |
||
1073 | * |
||
1074 | * This function returns the type a pattern. |
||
1075 | * See #cairo_pattern_type_t for available types. |
||
1076 | * |
||
1077 | * Return value: The type of @pattern. |
||
1078 | * |
||
1079 | * Since: 1.2 |
||
1080 | **/ |
||
1081 | cairo_pattern_type_t |
||
1082 | cairo_pattern_get_type (cairo_pattern_t *pattern) |
||
1083 | { |
||
1084 | return pattern->type; |
||
1085 | } |
||
1086 | |||
1087 | /** |
||
1088 | * cairo_pattern_status: |
||
1089 | * @pattern: a #cairo_pattern_t |
||
1090 | * |
||
1091 | * Checks whether an error has previously occurred for this |
||
1092 | * pattern. |
||
1093 | * |
||
3959 | Serge | 1094 | * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_STATUS_NO_MEMORY, |
1095 | * %CAIRO_STATUS_INVALID_MATRIX, %CAIRO_STATUS_PATTERN_TYPE_MISMATCH, |
||
1096 | * or %CAIRO_STATUS_INVALID_MESH_CONSTRUCTION. |
||
1097 | * |
||
1098 | * Since: 1.0 |
||
1892 | serge | 1099 | **/ |
1100 | cairo_status_t |
||
1101 | cairo_pattern_status (cairo_pattern_t *pattern) |
||
1102 | { |
||
1103 | return pattern->status; |
||
1104 | } |
||
1105 | |||
1106 | /** |
||
1107 | * cairo_pattern_destroy: |
||
1108 | * @pattern: a #cairo_pattern_t |
||
1109 | * |
||
1110 | * Decreases the reference count on @pattern by one. If the result is |
||
1111 | * zero, then @pattern and all associated resources are freed. See |
||
1112 | * cairo_pattern_reference(). |
||
3959 | Serge | 1113 | * |
1114 | * Since: 1.0 |
||
1892 | serge | 1115 | **/ |
1116 | void |
||
1117 | cairo_pattern_destroy (cairo_pattern_t *pattern) |
||
1118 | { |
||
1119 | cairo_pattern_type_t type; |
||
1120 | |||
1121 | if (pattern == NULL || |
||
1122 | CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count)) |
||
1123 | return; |
||
1124 | |||
1125 | assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&pattern->ref_count)); |
||
1126 | |||
1127 | if (! _cairo_reference_count_dec_and_test (&pattern->ref_count)) |
||
1128 | return; |
||
1129 | |||
1130 | type = pattern->type; |
||
1131 | _cairo_pattern_fini (pattern); |
||
1132 | |||
1133 | /* maintain a small cache of freed patterns */ |
||
3959 | Serge | 1134 | if (type < ARRAY_LENGTH (freed_pattern_pool)) |
1135 | _freed_pool_put (&freed_pattern_pool[type], pattern); |
||
1136 | else |
||
1137 | free (pattern); |
||
1892 | serge | 1138 | } |
1139 | slim_hidden_def (cairo_pattern_destroy); |
||
1140 | |||
1141 | /** |
||
1142 | * cairo_pattern_get_reference_count: |
||
1143 | * @pattern: a #cairo_pattern_t |
||
1144 | * |
||
1145 | * Returns the current reference count of @pattern. |
||
1146 | * |
||
1147 | * Return value: the current reference count of @pattern. If the |
||
1148 | * object is a nil object, 0 will be returned. |
||
1149 | * |
||
1150 | * Since: 1.4 |
||
1151 | **/ |
||
1152 | unsigned int |
||
1153 | cairo_pattern_get_reference_count (cairo_pattern_t *pattern) |
||
1154 | { |
||
1155 | if (pattern == NULL || |
||
1156 | CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count)) |
||
1157 | return 0; |
||
1158 | |||
1159 | return CAIRO_REFERENCE_COUNT_GET_VALUE (&pattern->ref_count); |
||
1160 | } |
||
1161 | |||
1162 | /** |
||
1163 | * cairo_pattern_get_user_data: |
||
1164 | * @pattern: a #cairo_pattern_t |
||
1165 | * @key: the address of the #cairo_user_data_key_t the user data was |
||
1166 | * attached to |
||
1167 | * |
||
1168 | * Return user data previously attached to @pattern using the |
||
1169 | * specified key. If no user data has been attached with the given |
||
1170 | * key this function returns %NULL. |
||
1171 | * |
||
1172 | * Return value: the user data previously attached or %NULL. |
||
1173 | * |
||
1174 | * Since: 1.4 |
||
1175 | **/ |
||
1176 | void * |
||
1177 | cairo_pattern_get_user_data (cairo_pattern_t *pattern, |
||
1178 | const cairo_user_data_key_t *key) |
||
1179 | { |
||
1180 | return _cairo_user_data_array_get_data (&pattern->user_data, |
||
1181 | key); |
||
1182 | } |
||
1183 | |||
1184 | /** |
||
1185 | * cairo_pattern_set_user_data: |
||
1186 | * @pattern: a #cairo_pattern_t |
||
1187 | * @key: the address of a #cairo_user_data_key_t to attach the user data to |
||
1188 | * @user_data: the user data to attach to the #cairo_pattern_t |
||
1189 | * @destroy: a #cairo_destroy_func_t which will be called when the |
||
1190 | * #cairo_t is destroyed or when new user data is attached using the |
||
1191 | * same key. |
||
1192 | * |
||
1193 | * Attach user data to @pattern. To remove user data from a surface, |
||
1194 | * call this function with the key that was used to set it and %NULL |
||
1195 | * for @data. |
||
1196 | * |
||
1197 | * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a |
||
1198 | * slot could not be allocated for the user data. |
||
1199 | * |
||
1200 | * Since: 1.4 |
||
1201 | **/ |
||
1202 | cairo_status_t |
||
1203 | cairo_pattern_set_user_data (cairo_pattern_t *pattern, |
||
1204 | const cairo_user_data_key_t *key, |
||
1205 | void *user_data, |
||
1206 | cairo_destroy_func_t destroy) |
||
1207 | { |
||
1208 | if (CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count)) |
||
1209 | return pattern->status; |
||
1210 | |||
1211 | return _cairo_user_data_array_set_data (&pattern->user_data, |
||
1212 | key, user_data, destroy); |
||
1213 | } |
||
1214 | |||
3959 | Serge | 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; |
||
1658 | } |
||
1659 | |||
1892 | serge | 1660 | /* make room for at least one more color stop */ |
1661 | static cairo_status_t |
||
1662 | _cairo_pattern_gradient_grow (cairo_gradient_pattern_t *pattern) |
||
1663 | { |
||
1664 | cairo_gradient_stop_t *new_stops; |
||
1665 | int old_size = pattern->stops_size; |
||
1666 | int embedded_size = ARRAY_LENGTH (pattern->stops_embedded); |
||
1667 | int new_size = 2 * MAX (old_size, 4); |
||
1668 | |||
1669 | /* we have a local buffer at pattern->stops_embedded. try to fulfill the request |
||
1670 | * from there. */ |
||
1671 | if (old_size < embedded_size) { |
||
1672 | pattern->stops = pattern->stops_embedded; |
||
1673 | pattern->stops_size = embedded_size; |
||
1674 | return CAIRO_STATUS_SUCCESS; |
||
1675 | } |
||
1676 | |||
1677 | if (CAIRO_INJECT_FAULT ()) |
||
1678 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
||
1679 | |||
1680 | assert (pattern->n_stops <= pattern->stops_size); |
||
1681 | |||
1682 | if (pattern->stops == pattern->stops_embedded) { |
||
1683 | new_stops = _cairo_malloc_ab (new_size, sizeof (cairo_gradient_stop_t)); |
||
1684 | if (new_stops) |
||
1685 | memcpy (new_stops, pattern->stops, old_size * sizeof (cairo_gradient_stop_t)); |
||
1686 | } else { |
||
1687 | new_stops = _cairo_realloc_ab (pattern->stops, |
||
1688 | new_size, |
||
1689 | sizeof (cairo_gradient_stop_t)); |
||
1690 | } |
||
1691 | |||
1692 | if (unlikely (new_stops == NULL)) |
||
1693 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
||
1694 | |||
1695 | pattern->stops = new_stops; |
||
1696 | pattern->stops_size = new_size; |
||
1697 | |||
1698 | return CAIRO_STATUS_SUCCESS; |
||
1699 | } |
||
1700 | |||
1701 | static void |
||
3959 | Serge | 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); |
||
1820 | |||
1821 | static void |
||
1822 | _cairo_pattern_add_color_stop (cairo_gradient_pattern_t *pattern, |
||
1892 | serge | 1823 | double offset, |
1824 | double red, |
||
1825 | double green, |
||
1826 | double blue, |
||
1827 | double alpha) |
||
1828 | { |
||
1829 | cairo_gradient_stop_t *stops; |
||
1830 | unsigned int i; |
||
1831 | |||
1832 | if (pattern->n_stops >= pattern->stops_size) { |
||
1833 | cairo_status_t status = _cairo_pattern_gradient_grow (pattern); |
||
1834 | if (unlikely (status)) { |
||
1835 | status = _cairo_pattern_set_error (&pattern->base, status); |
||
1836 | return; |
||
1837 | } |
||
1838 | } |
||
1839 | |||
1840 | stops = pattern->stops; |
||
1841 | |||
1842 | for (i = 0; i < pattern->n_stops; i++) |
||
1843 | { |
||
1844 | if (offset < stops[i].offset) |
||
1845 | { |
||
1846 | memmove (&stops[i + 1], &stops[i], |
||
1847 | sizeof (cairo_gradient_stop_t) * (pattern->n_stops - i)); |
||
1848 | |||
1849 | break; |
||
1850 | } |
||
1851 | } |
||
1852 | |||
1853 | stops[i].offset = offset; |
||
1854 | |||
1855 | stops[i].color.red = red; |
||
1856 | stops[i].color.green = green; |
||
1857 | stops[i].color.blue = blue; |
||
1858 | stops[i].color.alpha = alpha; |
||
1859 | |||
1860 | stops[i].color.red_short = _cairo_color_double_to_short (red); |
||
1861 | stops[i].color.green_short = _cairo_color_double_to_short (green); |
||
1862 | stops[i].color.blue_short = _cairo_color_double_to_short (blue); |
||
1863 | stops[i].color.alpha_short = _cairo_color_double_to_short (alpha); |
||
1864 | |||
1865 | pattern->n_stops++; |
||
1866 | } |
||
1867 | |||
1868 | /** |
||
1869 | * cairo_pattern_add_color_stop_rgb: |
||
1870 | * @pattern: a #cairo_pattern_t |
||
1871 | * @offset: an offset in the range [0.0 .. 1.0] |
||
1872 | * @red: red component of color |
||
1873 | * @green: green component of color |
||
1874 | * @blue: blue component of color |
||
1875 | * |
||
1876 | * Adds an opaque color stop to a gradient pattern. The offset |
||
1877 | * specifies the location along the gradient's control vector. For |
||
1878 | * example, a linear gradient's control vector is from (x0,y0) to |
||
1879 | * (x1,y1) while a radial gradient's control vector is from any point |
||
1880 | * on the start circle to the corresponding point on the end circle. |
||
1881 | * |
||
1882 | * The color is specified in the same way as in cairo_set_source_rgb(). |
||
1883 | * |
||
1884 | * If two (or more) stops are specified with identical offset values, |
||
1885 | * they will be sorted according to the order in which the stops are |
||
1886 | * added, (stops added earlier will compare less than stops added |
||
1887 | * later). This can be useful for reliably making sharp color |
||
1888 | * transitions instead of the typical blend. |
||
1889 | * |
||
1890 | * |
||
1891 | * Note: If the pattern is not a gradient pattern, (eg. a linear or |
||
1892 | * radial pattern), then the pattern will be put into an error status |
||
1893 | * with a status of %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. |
||
3959 | Serge | 1894 | * |
1895 | * Since: 1.0 |
||
1892 | serge | 1896 | **/ |
1897 | void |
||
1898 | cairo_pattern_add_color_stop_rgb (cairo_pattern_t *pattern, |
||
1899 | double offset, |
||
1900 | double red, |
||
1901 | double green, |
||
1902 | double blue) |
||
1903 | { |
||
3959 | Serge | 1904 | cairo_pattern_add_color_stop_rgba (pattern, offset, red, green, blue, 1.0); |
1892 | serge | 1905 | } |
1906 | |||
1907 | /** |
||
1908 | * cairo_pattern_add_color_stop_rgba: |
||
1909 | * @pattern: a #cairo_pattern_t |
||
1910 | * @offset: an offset in the range [0.0 .. 1.0] |
||
1911 | * @red: red component of color |
||
1912 | * @green: green component of color |
||
1913 | * @blue: blue component of color |
||
1914 | * @alpha: alpha component of color |
||
1915 | * |
||
1916 | * Adds a translucent color stop to a gradient pattern. The offset |
||
1917 | * specifies the location along the gradient's control vector. For |
||
1918 | * example, a linear gradient's control vector is from (x0,y0) to |
||
1919 | * (x1,y1) while a radial gradient's control vector is from any point |
||
1920 | * on the start circle to the corresponding point on the end circle. |
||
1921 | * |
||
1922 | * The color is specified in the same way as in cairo_set_source_rgba(). |
||
1923 | * |
||
1924 | * If two (or more) stops are specified with identical offset values, |
||
1925 | * they will be sorted according to the order in which the stops are |
||
1926 | * added, (stops added earlier will compare less than stops added |
||
1927 | * later). This can be useful for reliably making sharp color |
||
1928 | * transitions instead of the typical blend. |
||
1929 | * |
||
1930 | * Note: If the pattern is not a gradient pattern, (eg. a linear or |
||
1931 | * radial pattern), then the pattern will be put into an error status |
||
1932 | * with a status of %CAIRO_STATUS_PATTERN_TYPE_MISMATCH. |
||
3959 | Serge | 1933 | * |
1934 | * Since: 1.0 |
||
1935 | **/ |
||
1892 | serge | 1936 | void |
1937 | cairo_pattern_add_color_stop_rgba (cairo_pattern_t *pattern, |
||
1938 | double offset, |
||
1939 | double red, |
||
1940 | double green, |
||
1941 | double blue, |
||
1942 | double alpha) |
||
1943 | { |
||
1944 | if (pattern->status) |
||
1945 | return; |
||
1946 | |||
1947 | if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR && |
||
1948 | pattern->type != CAIRO_PATTERN_TYPE_RADIAL) |
||
1949 | { |
||
1950 | _cairo_pattern_set_error (pattern, CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
||
1951 | return; |
||
1952 | } |
||
1953 | |||
1954 | offset = _cairo_restrict_value (offset, 0.0, 1.0); |
||
1955 | red = _cairo_restrict_value (red, 0.0, 1.0); |
||
1956 | green = _cairo_restrict_value (green, 0.0, 1.0); |
||
1957 | blue = _cairo_restrict_value (blue, 0.0, 1.0); |
||
1958 | alpha = _cairo_restrict_value (alpha, 0.0, 1.0); |
||
1959 | |||
1960 | _cairo_pattern_add_color_stop ((cairo_gradient_pattern_t *) pattern, |
||
1961 | offset, red, green, blue, alpha); |
||
1962 | } |
||
3959 | Serge | 1963 | slim_hidden_def (cairo_pattern_add_color_stop_rgba); |
1892 | serge | 1964 | |
1965 | /** |
||
1966 | * cairo_pattern_set_matrix: |
||
1967 | * @pattern: a #cairo_pattern_t |
||
1968 | * @matrix: a #cairo_matrix_t |
||
1969 | * |
||
1970 | * Sets the pattern's transformation matrix to @matrix. This matrix is |
||
1971 | * a transformation from user space to pattern space. |
||
1972 | * |
||
1973 | * When a pattern is first created it always has the identity matrix |
||
1974 | * for its transformation matrix, which means that pattern space is |
||
1975 | * initially identical to user space. |
||
1976 | * |
||
1977 | * Important: Please note that the direction of this transformation |
||
1978 | * matrix is from user space to pattern space. This means that if you |
||
1979 | * imagine the flow from a pattern to user space (and on to device |
||
1980 | * space), then coordinates in that flow will be transformed by the |
||
1981 | * inverse of the pattern matrix. |
||
1982 | * |
||
1983 | * For example, if you want to make a pattern appear twice as large as |
||
1984 | * it does by default the correct code to use is: |
||
1985 | * |
||
1986 | * |
||
1987 | * cairo_matrix_init_scale (&matrix, 0.5, 0.5); |
||
1988 | * cairo_pattern_set_matrix (pattern, &matrix); |
||
1989 | * |
||
1990 | * |
||
1991 | * Meanwhile, using values of 2.0 rather than 0.5 in the code above |
||
1992 | * would cause the pattern to appear at half of its default size. |
||
1993 | * |
||
1994 | * Also, please note the discussion of the user-space locking |
||
1995 | * semantics of cairo_set_source(). |
||
3959 | Serge | 1996 | * |
1997 | * Since: 1.0 |
||
1892 | serge | 1998 | **/ |
1999 | void |
||
2000 | cairo_pattern_set_matrix (cairo_pattern_t *pattern, |
||
2001 | const cairo_matrix_t *matrix) |
||
2002 | { |
||
2003 | cairo_matrix_t inverse; |
||
2004 | cairo_status_t status; |
||
2005 | |||
2006 | if (pattern->status) |
||
2007 | return; |
||
2008 | |||
2009 | if (memcmp (&pattern->matrix, matrix, sizeof (cairo_matrix_t)) == 0) |
||
2010 | return; |
||
2011 | |||
2012 | pattern->matrix = *matrix; |
||
3959 | Serge | 2013 | _cairo_pattern_notify_observers (pattern, CAIRO_PATTERN_NOTIFY_MATRIX); |
1892 | serge | 2014 | |
2015 | inverse = *matrix; |
||
2016 | status = cairo_matrix_invert (&inverse); |
||
2017 | if (unlikely (status)) |
||
2018 | status = _cairo_pattern_set_error (pattern, status); |
||
2019 | } |
||
2020 | slim_hidden_def (cairo_pattern_set_matrix); |
||
2021 | |||
2022 | /** |
||
2023 | * cairo_pattern_get_matrix: |
||
2024 | * @pattern: a #cairo_pattern_t |
||
2025 | * @matrix: return value for the matrix |
||
2026 | * |
||
2027 | * Stores the pattern's transformation matrix into @matrix. |
||
3959 | Serge | 2028 | * |
2029 | * Since: 1.0 |
||
1892 | serge | 2030 | **/ |
2031 | void |
||
2032 | cairo_pattern_get_matrix (cairo_pattern_t *pattern, cairo_matrix_t *matrix) |
||
2033 | { |
||
2034 | *matrix = pattern->matrix; |
||
2035 | } |
||
2036 | |||
2037 | /** |
||
2038 | * cairo_pattern_set_filter: |
||
2039 | * @pattern: a #cairo_pattern_t |
||
2040 | * @filter: a #cairo_filter_t describing the filter to use for resizing |
||
2041 | * the pattern |
||
2042 | * |
||
2043 | * Sets the filter to be used for resizing when using this pattern. |
||
2044 | * See #cairo_filter_t for details on each filter. |
||
2045 | * |
||
2046 | * * Note that you might want to control filtering even when you do not |
||
2047 | * have an explicit #cairo_pattern_t object, (for example when using |
||
2048 | * cairo_set_source_surface()). In these cases, it is convenient to |
||
2049 | * use cairo_get_source() to get access to the pattern that cairo |
||
2050 | * creates implicitly. For example: |
||
2051 | * |
||
2052 | * |
||
2053 | * cairo_set_source_surface (cr, image, x, y); |
||
2054 | * cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_NEAREST); |
||
2055 | * |
||
3959 | Serge | 2056 | * |
2057 | * Since: 1.0 |
||
1892 | serge | 2058 | **/ |
2059 | void |
||
2060 | cairo_pattern_set_filter (cairo_pattern_t *pattern, cairo_filter_t filter) |
||
2061 | { |
||
2062 | if (pattern->status) |
||
2063 | return; |
||
2064 | |||
2065 | pattern->filter = filter; |
||
3959 | Serge | 2066 | _cairo_pattern_notify_observers (pattern, CAIRO_PATTERN_NOTIFY_FILTER); |
1892 | serge | 2067 | } |
2068 | |||
2069 | /** |
||
2070 | * cairo_pattern_get_filter: |
||
2071 | * @pattern: a #cairo_pattern_t |
||
2072 | * |
||
2073 | * Gets the current filter for a pattern. See #cairo_filter_t |
||
2074 | * for details on each filter. |
||
2075 | * |
||
2076 | * Return value: the current filter used for resizing the pattern. |
||
3959 | Serge | 2077 | * |
2078 | * Since: 1.0 |
||
1892 | serge | 2079 | **/ |
2080 | cairo_filter_t |
||
2081 | cairo_pattern_get_filter (cairo_pattern_t *pattern) |
||
2082 | { |
||
2083 | return pattern->filter; |
||
2084 | } |
||
2085 | |||
2086 | /** |
||
2087 | * cairo_pattern_set_extend: |
||
2088 | * @pattern: a #cairo_pattern_t |
||
2089 | * @extend: a #cairo_extend_t describing how the area outside of the |
||
2090 | * pattern will be drawn |
||
2091 | * |
||
2092 | * Sets the mode to be used for drawing outside the area of a pattern. |
||
2093 | * See #cairo_extend_t for details on the semantics of each extend |
||
2094 | * strategy. |
||
2095 | * |
||
2096 | * The default extend mode is %CAIRO_EXTEND_NONE for surface patterns |
||
2097 | * and %CAIRO_EXTEND_PAD for gradient patterns. |
||
3959 | Serge | 2098 | * |
2099 | * Since: 1.0 |
||
1892 | serge | 2100 | **/ |
2101 | void |
||
2102 | cairo_pattern_set_extend (cairo_pattern_t *pattern, cairo_extend_t extend) |
||
2103 | { |
||
2104 | if (pattern->status) |
||
2105 | return; |
||
2106 | |||
2107 | pattern->extend = extend; |
||
3959 | Serge | 2108 | _cairo_pattern_notify_observers (pattern, CAIRO_PATTERN_NOTIFY_EXTEND); |
1892 | serge | 2109 | } |
2110 | |||
2111 | /** |
||
2112 | * cairo_pattern_get_extend: |
||
2113 | * @pattern: a #cairo_pattern_t |
||
2114 | * |
||
2115 | * Gets the current extend mode for a pattern. See #cairo_extend_t |
||
2116 | * for details on the semantics of each extend strategy. |
||
2117 | * |
||
2118 | * Return value: the current extend strategy used for drawing the |
||
2119 | * pattern. |
||
3959 | Serge | 2120 | * |
2121 | * Since: 1.0 |
||
1892 | serge | 2122 | **/ |
2123 | cairo_extend_t |
||
2124 | cairo_pattern_get_extend (cairo_pattern_t *pattern) |
||
2125 | { |
||
2126 | return pattern->extend; |
||
2127 | } |
||
2128 | slim_hidden_def (cairo_pattern_get_extend); |
||
2129 | |||
2130 | void |
||
2131 | _cairo_pattern_transform (cairo_pattern_t *pattern, |
||
2132 | const cairo_matrix_t *ctm_inverse) |
||
2133 | { |
||
2134 | if (pattern->status) |
||
2135 | return; |
||
2136 | |||
2137 | cairo_matrix_multiply (&pattern->matrix, ctm_inverse, &pattern->matrix); |
||
2138 | } |
||
2139 | |||
3959 | Serge | 2140 | static cairo_bool_t |
2141 | _linear_pattern_is_degenerate (const cairo_linear_pattern_t *linear) |
||
1892 | serge | 2142 | { |
3959 | Serge | 2143 | return fabs (linear->pd1.x - linear->pd2.x) < DBL_EPSILON && |
2144 | fabs (linear->pd1.y - linear->pd2.y) < DBL_EPSILON; |
||
2145 | } |
||
1892 | serge | 2146 | |
3959 | Serge | 2147 | static cairo_bool_t |
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 | * |
||
2154 | * 1) The radii are both very small: |
||
2155 | * |dr| < DBL_EPSILON && min (r0, r1) < DBL_EPSILON |
||
2156 | * |
||
2157 | * 2) The two circles have about the same radius and are very |
||
2158 | * close to each other (approximately a cylinder gradient that |
||
2159 | * doesn't move with the parameter): |
||
2160 | * |dr| < DBL_EPSILON && max (|dx|, |dy|) < 2 * DBL_EPSILON |
||
2161 | * |
||
2162 | * These checks are consistent with the assumptions used in |
||
2163 | * _cairo_radial_pattern_box_to_parameter (). |
||
1892 | serge | 2164 | */ |
2165 | |||
3959 | Serge | 2166 | return fabs (radial->cd1.radius - radial->cd2.radius) < DBL_EPSILON && |
2167 | (MIN (radial->cd1.radius, radial->cd2.radius) < DBL_EPSILON || |
||
2168 | MAX (fabs (radial->cd1.center.x - radial->cd2.center.x), |
||
2169 | fabs (radial->cd1.center.y - radial->cd2.center.y)) < 2 * DBL_EPSILON); |
||
2170 | } |
||
1892 | serge | 2171 | |
3959 | Serge | 2172 | static void |
2173 | _cairo_linear_pattern_box_to_parameter (const cairo_linear_pattern_t *linear, |
||
2174 | double x0, double y0, |
||
2175 | double x1, double y1, |
||
2176 | double range[2]) |
||
2177 | { |
||
2178 | double t0, tdx, tdy; |
||
2179 | double p1x, p1y, pdx, pdy, invsqnorm; |
||
1892 | serge | 2180 | |
3959 | Serge | 2181 | assert (! _linear_pattern_is_degenerate (linear)); |
1892 | serge | 2182 | |
3959 | Serge | 2183 | /* |
2184 | * Linear gradients are othrogonal to the line passing through |
||
2185 | * their extremes. Because of convexity, the parameter range can |
||
2186 | * be computed as the convex hull (one the real line) of the |
||
2187 | * parameter values of the 4 corners of the box. |
||
2188 | * |
||
2189 | * The parameter value t for a point (x,y) can be computed as: |
||
2190 | * |
||
2191 | * t = (p2 - p1) . (x,y) / |p2 - p1|^2 |
||
2192 | * |
||
2193 | * t0 is the t value for the top left corner |
||
2194 | * tdx is the difference between left and right corners |
||
2195 | * tdy is the difference between top and bottom corners |
||
2196 | */ |
||
1892 | serge | 2197 | |
3959 | Serge | 2198 | p1x = linear->pd1.x; |
2199 | p1y = linear->pd1.y; |
||
2200 | pdx = linear->pd2.x - p1x; |
||
2201 | pdy = linear->pd2.y - p1y; |
||
2202 | invsqnorm = 1.0 / (pdx * pdx + pdy * pdy); |
||
2203 | pdx *= invsqnorm; |
||
2204 | pdy *= invsqnorm; |
||
1892 | serge | 2205 | |
3959 | Serge | 2206 | t0 = (x0 - p1x) * pdx + (y0 - p1y) * pdy; |
2207 | tdx = (x1 - x0) * pdx; |
||
2208 | tdy = (y1 - y0) * pdy; |
||
1892 | serge | 2209 | |
3959 | Serge | 2210 | /* |
2211 | * Because of the linearity of the t value, tdx can simply be |
||
2212 | * added the t0 to move along the top edge. After this, range[0] |
||
2213 | * and range[1] represent the parameter range for the top edge, so |
||
2214 | * extending it to include the whole box simply requires adding |
||
2215 | * tdy to the correct extreme. |
||
1892 | serge | 2216 | */ |
2217 | |||
3959 | Serge | 2218 | range[0] = range[1] = t0; |
2219 | if (tdx < 0) |
||
2220 | range[0] += tdx; |
||
2221 | else |
||
2222 | range[1] += tdx; |
||
2223 | |||
2224 | if (tdy < 0) |
||
2225 | range[0] += tdy; |
||
2226 | else |
||
2227 | range[1] += tdy; |
||
1892 | serge | 2228 | } |
2229 | |||
3959 | Serge | 2230 | static cairo_bool_t |
2231 | _extend_range (double range[2], double value, cairo_bool_t valid) |
||
1892 | serge | 2232 | { |
3959 | Serge | 2233 | if (!valid) |
2234 | range[0] = range[1] = value; |
||
2235 | else if (value < range[0]) |
||
2236 | range[0] = value; |
||
2237 | else if (value > range[1]) |
||
2238 | range[1] = value; |
||
1892 | serge | 2239 | |
3959 | Serge | 2240 | return TRUE; |
2241 | } |
||
1892 | serge | 2242 | |
3959 | Serge | 2243 | /* |
2244 | * _cairo_radial_pattern_focus_is_inside: |
||
2245 | * |
||
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 |
||
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 |
||
2252 | * which case the circles are tangent in the focus point), it is not |
||
2253 | * considered as contained in the circle, hence this function returns |
||
2254 | * %FALSE. |
||
2255 | * |
||
2256 | */ |
||
2257 | cairo_bool_t |
||
2258 | _cairo_radial_pattern_focus_is_inside (const cairo_radial_pattern_t *radial) |
||
2259 | { |
||
2260 | double cx, cy, cr, dx, dy, dr; |
||
1892 | serge | 2261 | |
3959 | Serge | 2262 | cx = radial->cd1.center.x; |
2263 | cy = radial->cd1.center.y; |
||
2264 | cr = radial->cd1.radius; |
||
2265 | dx = radial->cd2.center.x - cx; |
||
2266 | dy = radial->cd2.center.y - cy; |
||
2267 | dr = radial->cd2.radius - cr; |
||
1892 | serge | 2268 | |
3959 | Serge | 2269 | return dx*dx + dy*dy < dr*dr; |
2270 | } |
||
1892 | serge | 2271 | |
3959 | Serge | 2272 | static void |
2273 | _cairo_radial_pattern_box_to_parameter (const cairo_radial_pattern_t *radial, |
||
2274 | double x0, double y0, |
||
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; |
||
2281 | double mindr, minx, miny, maxx, maxy; |
||
2282 | cairo_bool_t valid; |
||
1892 | serge | 2283 | |
3959 | Serge | 2284 | assert (! _radial_pattern_is_degenerate (radial)); |
2285 | assert (x0 < x1); |
||
2286 | assert (y0 < y1); |
||
1892 | serge | 2287 | |
3959 | Serge | 2288 | tolerance = MAX (tolerance, DBL_EPSILON); |
1892 | serge | 2289 | |
3959 | Serge | 2290 | range[0] = range[1] = 0; |
2291 | valid = FALSE; |
||
1892 | serge | 2292 | |
3959 | Serge | 2293 | x_focus = y_focus = 0; /* silence gcc */ |
1892 | serge | 2294 | |
3959 | Serge | 2295 | cx = radial->cd1.center.x; |
2296 | cy = radial->cd1.center.y; |
||
2297 | cr = radial->cd1.radius; |
||
2298 | dx = radial->cd2.center.x - cx; |
||
2299 | dy = radial->cd2.center.y - cy; |
||
2300 | dr = radial->cd2.radius - cr; |
||
1892 | serge | 2301 | |
3959 | Serge | 2302 | /* translate by -(cx, cy) to simplify computations */ |
2303 | x0 -= cx; |
||
2304 | y0 -= cy; |
||
2305 | x1 -= cx; |
||
2306 | y1 -= cy; |
||
1892 | serge | 2307 | |
3959 | Serge | 2308 | /* enlarge boundaries slightly to avoid rounding problems in the |
2309 | * parameter range computation */ |
||
2310 | x0 -= DBL_EPSILON; |
||
2311 | y0 -= DBL_EPSILON; |
||
2312 | x1 += DBL_EPSILON; |
||
2313 | y1 += DBL_EPSILON; |
||
1892 | serge | 2314 | |
3959 | Serge | 2315 | /* enlarge boundaries even more to avoid rounding problems when |
2316 | * testing if a point belongs to the box */ |
||
2317 | minx = x0 - DBL_EPSILON; |
||
2318 | miny = y0 - DBL_EPSILON; |
||
2319 | maxx = x1 + DBL_EPSILON; |
||
2320 | maxy = y1 + DBL_EPSILON; |
||
1892 | serge | 2321 | |
3959 | Serge | 2322 | /* we dont' allow negative radiuses, so we will be checking that |
2323 | * t*dr >= mindr to consider t valid */ |
||
2324 | mindr = -(cr + DBL_EPSILON); |
||
1892 | serge | 2325 | |
3959 | Serge | 2326 | /* |
2327 | * After the previous transformations, the start circle is |
||
2328 | * centered in the origin and has radius cr. A 1-unit change in |
||
2329 | * the t parameter corresponds to dx,dy,dr changes in the x,y,r of |
||
2330 | * the circle (center coordinates, radius). |
||
2331 | * |
||
2332 | * To compute the minimum range needed to correctly draw the |
||
2333 | * pattern, we start with an empty range and extend it to include |
||
2334 | * the circles touching the bounding box or within it. |
||
2335 | */ |
||
1892 | serge | 2336 | |
3959 | Serge | 2337 | /* |
2338 | * Focus, the point where the circle has radius == 0. |
||
2339 | * |
||
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 | */ |
||
2346 | if (fabs (dr) >= DBL_EPSILON) { |
||
2347 | double t_focus; |
||
1892 | serge | 2348 | |
3959 | Serge | 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) |
||
1892 | serge | 2354 | { |
3959 | Serge | 2355 | valid = _extend_range (range, t_focus, valid); |
1892 | serge | 2356 | } |
2357 | } |
||
2358 | |||
3959 | Serge | 2359 | /* |
2360 | * Circles externally tangent to box edges. |
||
2361 | * |
||
2362 | * All circles have center in (dx, dy) * t |
||
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) |
||
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 |
||
2380 | * t = (x0 - cr) / (dx + dr) |
||
2381 | * y = dy * t |
||
2382 | * |
||
2383 | * in the code this becomes: |
||
2384 | * |
||
2385 | * t_edge = (num) / (den) |
||
2386 | * v = (delta) * t_edge |
||
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 |
||
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) \ |
||
2394 | if (fabs (den) >= DBL_EPSILON) { \ |
||
2395 | double t_edge, v; \ |
||
2396 | \ |
||
2397 | t_edge = (num) / (den); \ |
||
2398 | v = t_edge * (delta); \ |
||
2399 | if (t_edge * dr >= mindr && (lower) <= v && v <= (upper)) \ |
||
2400 | valid = _extend_range (range, t_edge, valid); \ |
||
1892 | serge | 2401 | } |
2402 | |||
3959 | Serge | 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); |
||
1892 | serge | 2408 | |
3959 | Serge | 2409 | #undef T_EDGE |
1892 | serge | 2410 | |
3959 | Serge | 2411 | /* |
2412 | * Circles passing through a corner. |
||
2413 | * |
||
2414 | * A circle passing through the point (x,y) satisfies: |
||
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; |
||
1892 | serge | 2428 | |
3959 | Serge | 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: |
||
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 |
||
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); |
||
1892 | serge | 2462 | |
3959 | Serge | 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) |
||
2498 | * v = -((edge) * (delta) + cr*dr) / (den) - v_focus |
||
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); \ |
||
2510 | d2 = u*u + v*v; \ |
||
2511 | if (maxd2 < d2) \ |
||
2512 | maxd2 = d2; \ |
||
2513 | } \ |
||
2514 | } |
||
1892 | serge | 2515 | |
3959 | Serge | 2516 | maxd2 = 0; |
1892 | serge | 2517 | |
3959 | Serge | 2518 | /* degenerate circles (lines) passing through each edge */ |
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); |
||
1892 | serge | 2523 | |
3959 | Serge | 2524 | #undef T_EDGE |
1892 | serge | 2525 | |
3959 | Serge | 2526 | /* |
2527 | * The limit circle can be transformed rigidly to the y=0 line |
||
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 |
||
2531 | * |
||
2532 | * y is the distance from the line, in our case tolerance; |
||
2533 | * x is the distance along the line, i.e. sqrt(maxd2), |
||
2534 | * so: |
||
2535 | * |
||
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; |
||
2542 | t_limit /= 2 * tolerance * dr; |
||
2543 | valid = _extend_range (range, t_limit, valid); |
||
2544 | } |
||
1892 | serge | 2545 | |
3959 | Serge | 2546 | /* |
2547 | * Nondegenerate, nonlimit circles passing through the corners. |
||
2548 | * |
||
2549 | * a == 0 && a*t^2 - 2*b*t + c == 0 |
||
2550 | * |
||
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; \ |
||
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 | } |
||
1892 | serge | 2569 | |
3959 | Serge | 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); |
||
1892 | serge | 2575 | |
3959 | Serge | 2576 | #undef T_CORNER |
2577 | } else { |
||
2578 | double inva, b, c, d; |
||
1892 | serge | 2579 | |
3959 | Serge | 2580 | inva = 1 / a; |
1892 | serge | 2581 | |
3959 | Serge | 2582 | /* |
2583 | * Nondegenerate, nonlimit circles passing through the corners. |
||
2584 | * |
||
2585 | * a != 0 && a*t^2 - 2*b*t + c == 0 |
||
2586 | * |
||
2587 | * t = (b +- sqrt (b*b - a*c)) / a |
||
2588 | * |
||
2589 | * If the argument of sqrt() is negative, then no circle |
||
2590 | * passes through the corner. |
||
2591 | */ |
||
2592 | #define T_CORNER(x,y) \ |
||
2593 | b = (x) * dx + (y) * dy + cr * dr; \ |
||
2594 | c = (x) * (x) + (y) * (y) - cr * cr; \ |
||
2595 | d = b * b - a * c; \ |
||
2596 | if (d >= 0) { \ |
||
2597 | double t_corner; \ |
||
2598 | \ |
||
2599 | d = sqrt (d); \ |
||
2600 | t_corner = (b + d) * inva; \ |
||
2601 | if (t_corner * dr >= mindr) \ |
||
2602 | valid = _extend_range (range, t_corner, valid); \ |
||
2603 | t_corner = (b - d) * inva; \ |
||
2604 | if (t_corner * dr >= mindr) \ |
||
2605 | valid = _extend_range (range, t_corner, valid); \ |
||
2606 | } |
||
1892 | serge | 2607 | |
3959 | Serge | 2608 | /* circles touching each corner */ |
2609 | T_CORNER (x0, y0); |
||
2610 | T_CORNER (x0, y1); |
||
2611 | T_CORNER (x1, y0); |
||
2612 | T_CORNER (x1, y1); |
||
1892 | serge | 2613 | |
3959 | Serge | 2614 | #undef T_CORNER |
2615 | } |
||
1892 | serge | 2616 | } |
2617 | |||
3959 | Serge | 2618 | /** |
2619 | * _cairo_gradient_pattern_box_to_parameter: |
||
2620 | * |
||
2621 | * Compute a interpolation range sufficient to draw (within the given |
||
2622 | * tolerance) the gradient in the given box getting the same result as |
||
2623 | * using the (-inf, +inf) range. |
||
2624 | * |
||
2625 | * Assumes that the pattern is not degenerate. This can be guaranteed |
||
2626 | * by simplifying it to a solid clear if _cairo_pattern_is_clear or to |
||
2627 | * a solid color if _cairo_gradient_pattern_is_solid. |
||
2628 | * |
||
2629 | * The range isn't guaranteed to be minimal, but it tries to. |
||
2630 | **/ |
||
2631 | void |
||
2632 | _cairo_gradient_pattern_box_to_parameter (const cairo_gradient_pattern_t *gradient, |
||
2633 | double x0, double y0, |
||
2634 | double x1, double y1, |
||
2635 | double tolerance, |
||
2636 | double out_range[2]) |
||
1892 | serge | 2637 | { |
3959 | Serge | 2638 | assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR || |
2639 | gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL); |
||
1892 | serge | 2640 | |
3959 | Serge | 2641 | if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) { |
2642 | _cairo_linear_pattern_box_to_parameter ((cairo_linear_pattern_t *) gradient, |
||
2643 | x0, y0, x1, y1, out_range); |
||
2644 | } else { |
||
2645 | _cairo_radial_pattern_box_to_parameter ((cairo_radial_pattern_t *) gradient, |
||
2646 | x0, y0, x1, y1, tolerance, out_range); |
||
2647 | } |
||
1892 | serge | 2648 | } |
2649 | |||
3959 | Serge | 2650 | /** |
2651 | * _cairo_gradient_pattern_interpolate: |
||
2652 | * |
||
2653 | * Interpolate between the start and end objects of linear or radial |
||
2654 | * gradients. The interpolated object is stored in out_circle, with |
||
2655 | * the radius being zero in the linear gradient case. |
||
2656 | **/ |
||
2657 | void |
||
2658 | _cairo_gradient_pattern_interpolate (const cairo_gradient_pattern_t *gradient, |
||
2659 | double t, |
||
2660 | cairo_circle_double_t *out_circle) |
||
1892 | serge | 2661 | { |
3959 | Serge | 2662 | assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR || |
2663 | gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL); |
||
1892 | serge | 2664 | |
3959 | Serge | 2665 | #define lerp(a,b) (a)*(1-t) + (b)*t |
1892 | serge | 2666 | |
3959 | Serge | 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); |
||
2671 | out_circle->radius = 0; |
||
2672 | } else { |
||
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); |
||
1892 | serge | 2677 | } |
2678 | |||
3959 | Serge | 2679 | #undef lerp |
2680 | } |
||
1892 | serge | 2681 | |
2682 | |||
3959 | Serge | 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. |
||
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 | **/ |
||
2694 | void |
||
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; |
||
1892 | serge | 2701 | |
3959 | Serge | 2702 | assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR || |
2703 | gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL); |
||
1892 | serge | 2704 | |
3959 | Serge | 2705 | if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) { |
2706 | cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient; |
||
1892 | serge | 2707 | |
3959 | Serge | 2708 | out_circle[0].center = linear->pd1; |
2709 | out_circle[0].radius = 0; |
||
2710 | out_circle[1].center = linear->pd2; |
||
2711 | out_circle[1].radius = 0; |
||
1892 | serge | 2712 | |
3959 | Serge | 2713 | dim = fabs (linear->pd1.x); |
2714 | dim = MAX (dim, fabs (linear->pd1.y)); |
||
2715 | dim = MAX (dim, fabs (linear->pd2.x)); |
||
2716 | dim = MAX (dim, fabs (linear->pd2.y)); |
||
2717 | dim = MAX (dim, fabs (linear->pd1.x - linear->pd2.x)); |
||
2718 | dim = MAX (dim, fabs (linear->pd1.y - linear->pd2.y)); |
||
2719 | } else { |
||
2720 | cairo_radial_pattern_t *radial = (cairo_radial_pattern_t *) gradient; |
||
1892 | serge | 2721 | |
3959 | Serge | 2722 | out_circle[0] = radial->cd1; |
2723 | out_circle[1] = radial->cd2; |
||
1892 | serge | 2724 | |
3959 | Serge | 2725 | dim = fabs (radial->cd1.center.x); |
2726 | dim = MAX (dim, fabs (radial->cd1.center.y)); |
||
2727 | dim = MAX (dim, fabs (radial->cd1.radius)); |
||
2728 | dim = MAX (dim, fabs (radial->cd2.center.x)); |
||
2729 | dim = MAX (dim, fabs (radial->cd2.center.y)); |
||
2730 | dim = MAX (dim, fabs (radial->cd2.radius)); |
||
2731 | dim = MAX (dim, fabs (radial->cd1.center.x - radial->cd2.center.x)); |
||
2732 | dim = MAX (dim, fabs (radial->cd1.center.y - radial->cd2.center.y)); |
||
2733 | dim = MAX (dim, fabs (radial->cd1.radius - radial->cd2.radius)); |
||
2734 | } |
||
1892 | serge | 2735 | |
3959 | Serge | 2736 | if (unlikely (dim > max_value)) { |
2737 | cairo_matrix_t scale; |
||
1892 | serge | 2738 | |
3959 | Serge | 2739 | dim = max_value / dim; |
1892 | serge | 2740 | |
3959 | Serge | 2741 | out_circle[0].center.x *= dim; |
2742 | out_circle[0].center.y *= dim; |
||
2743 | out_circle[0].radius *= dim; |
||
2744 | out_circle[1].center.x *= dim; |
||
2745 | out_circle[1].center.y *= dim; |
||
2746 | out_circle[1].radius *= dim; |
||
1892 | serge | 2747 | |
3959 | Serge | 2748 | cairo_matrix_init_scale (&scale, dim, dim); |
2749 | cairo_matrix_multiply (out_matrix, &gradient->base.matrix, &scale); |
||
2750 | } else { |
||
2751 | *out_matrix = gradient->base.matrix; |
||
1892 | serge | 2752 | } |
2753 | } |
||
2754 | |||
2755 | static cairo_bool_t |
||
2756 | _gradient_is_clear (const cairo_gradient_pattern_t *gradient, |
||
2757 | const cairo_rectangle_int_t *extents) |
||
2758 | { |
||
2759 | unsigned int i; |
||
2760 | |||
2761 | assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR || |
||
2762 | gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL); |
||
2763 | |||
2764 | if (gradient->n_stops == 0 || |
||
2765 | (gradient->base.extend == CAIRO_EXTEND_NONE && |
||
2766 | gradient->stops[0].offset == gradient->stops[gradient->n_stops - 1].offset)) |
||
2767 | return TRUE; |
||
2768 | |||
3959 | Serge | 2769 | if (gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL) { |
2770 | /* degenerate radial gradients are clear */ |
||
2771 | if (_radial_pattern_is_degenerate ((cairo_radial_pattern_t *) gradient)) |
||
2772 | return TRUE; |
||
2773 | } else if (gradient->base.extend == CAIRO_EXTEND_NONE) { |
||
2774 | /* EXTEND_NONE degenerate linear gradients are clear */ |
||
2775 | if (_linear_pattern_is_degenerate ((cairo_linear_pattern_t *) gradient)) |
||
2776 | return TRUE; |
||
2777 | } |
||
2778 | |||
1892 | serge | 2779 | /* Check if the extents intersect the drawn part of the pattern. */ |
3959 | Serge | 2780 | if (extents != NULL && |
2781 | (gradient->base.extend == CAIRO_EXTEND_NONE || |
||
2782 | gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL)) |
||
2783 | { |
||
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); |
||
2793 | |||
2794 | if (gradient->base.extend == CAIRO_EXTEND_NONE && |
||
2795 | (t[0] >= gradient->stops[gradient->n_stops - 1].offset || |
||
2796 | t[1] <= gradient->stops[0].offset)) |
||
2797 | { |
||
1892 | serge | 2798 | return TRUE; |
3959 | Serge | 2799 | } |
1892 | serge | 2800 | |
3959 | Serge | 2801 | if (t[0] == t[1]) |
1892 | serge | 2802 | return TRUE; |
2803 | } |
||
2804 | |||
2805 | for (i = 0; i < gradient->n_stops; i++) |
||
2806 | if (! CAIRO_COLOR_IS_CLEAR (&gradient->stops[i].color)) |
||
2807 | return FALSE; |
||
2808 | |||
2809 | return TRUE; |
||
2810 | } |
||
2811 | |||
2812 | static void |
||
2813 | _gradient_color_average (const cairo_gradient_pattern_t *gradient, |
||
2814 | cairo_color_t *color) |
||
2815 | { |
||
2816 | double delta0, delta1; |
||
2817 | double r, g, b, a; |
||
2818 | unsigned int i, start = 1, end; |
||
2819 | |||
2820 | assert (gradient->n_stops > 0); |
||
2821 | assert (gradient->base.extend != CAIRO_EXTEND_NONE); |
||
2822 | |||
2823 | if (gradient->n_stops == 1) { |
||
2824 | _cairo_color_init_rgba (color, |
||
2825 | gradient->stops[0].color.red, |
||
2826 | gradient->stops[0].color.green, |
||
2827 | gradient->stops[0].color.blue, |
||
2828 | gradient->stops[0].color.alpha); |
||
2829 | return; |
||
2830 | } |
||
2831 | |||
2832 | end = gradient->n_stops - 1; |
||
2833 | |||
2834 | switch (gradient->base.extend) { |
||
2835 | case CAIRO_EXTEND_REPEAT: |
||
2836 | /* |
||
2837 | * Sa, Sb and Sy, Sz are the first two and last two stops respectively. |
||
2838 | * The weight of the first and last stop can be computed as the area of |
||
2839 | * the following triangles (taken with height 1, since the whole [0-1] |
||
2840 | * will have total weight 1 this way): b*h/2 |
||
2841 | * |
||
2842 | * + + |
||
2843 | * / |\ / | \ |
||
2844 | * / | \ / | \ |
||
2845 | * / | \ / | \ |
||
2846 | * ~~~~~+---+---+---+~~~~~~~+-------+---+---+~~~~~ |
||
2847 | * -1+Sz 0 Sa Sb Sy Sz 1 1+Sa |
||
2848 | * |
||
2849 | * For the first stop: (Sb-(-1+Sz)/2 = (1+Sb-Sz)/2 |
||
2850 | * For the last stop: ((1+Sa)-Sy)/2 = (1+Sa-Sy)/2 |
||
2851 | * Halving the result is done after summing up all the areas. |
||
2852 | */ |
||
2853 | delta0 = 1.0 + gradient->stops[1].offset - gradient->stops[end].offset; |
||
2854 | delta1 = 1.0 + gradient->stops[0].offset - gradient->stops[end-1].offset; |
||
2855 | break; |
||
2856 | |||
2857 | case CAIRO_EXTEND_REFLECT: |
||
2858 | /* |
||
2859 | * Sa, Sb and Sy, Sz are the first two and last two stops respectively. |
||
2860 | * The weight of the first and last stop can be computed as the area of |
||
2861 | * the following trapezoids (taken with height 1, since the whole [0-1] |
||
2862 | * will have total weight 1 this way): (b+B)*h/2 |
||
2863 | * |
||
2864 | * +-------+ +---+ |
||
2865 | * | |\ / | | |
||
2866 | * | | \ / | | |
||
2867 | * | | \ / | | |
||
2868 | * +-------+---+~~~~~~~+-------+---+ |
||
2869 | * 0 Sa Sb Sy Sz 1 |
||
2870 | * |
||
2871 | * For the first stop: (Sa+Sb)/2 |
||
2872 | * For the last stop: ((1-Sz) + (1-Sy))/2 = (2-Sy-Sz)/2 |
||
2873 | * Halving the result is done after summing up all the areas. |
||
2874 | */ |
||
2875 | delta0 = gradient->stops[0].offset + gradient->stops[1].offset; |
||
2876 | delta1 = 2.0 - gradient->stops[end-1].offset - gradient->stops[end].offset; |
||
2877 | break; |
||
2878 | |||
2879 | case CAIRO_EXTEND_PAD: |
||
2880 | /* PAD is computed as the average of the first and last stop: |
||
2881 | * - take both of them with weight 1 (they will be halved |
||
2882 | * after the whole sum has been computed). |
||
2883 | * - avoid summing any of the inner stops. |
||
2884 | */ |
||
2885 | delta0 = delta1 = 1.0; |
||
2886 | start = end; |
||
2887 | break; |
||
2888 | |||
2889 | case CAIRO_EXTEND_NONE: |
||
2890 | default: |
||
2891 | ASSERT_NOT_REACHED; |
||
2892 | _cairo_color_init_rgba (color, 0, 0, 0, 0); |
||
2893 | return; |
||
2894 | } |
||
2895 | |||
2896 | r = delta0 * gradient->stops[0].color.red; |
||
2897 | g = delta0 * gradient->stops[0].color.green; |
||
2898 | b = delta0 * gradient->stops[0].color.blue; |
||
2899 | a = delta0 * gradient->stops[0].color.alpha; |
||
2900 | |||
2901 | for (i = start; i < end; ++i) { |
||
2902 | /* Inner stops weight is the same as the area of the triangle they influence |
||
2903 | * (which goes from the stop before to the stop after), again with height 1 |
||
2904 | * since the whole must sum up to 1: b*h/2 |
||
2905 | * Halving is done after the whole sum has been computed. |
||
2906 | */ |
||
2907 | double delta = gradient->stops[i+1].offset - gradient->stops[i-1].offset; |
||
2908 | r += delta * gradient->stops[i].color.red; |
||
2909 | g += delta * gradient->stops[i].color.green; |
||
2910 | b += delta * gradient->stops[i].color.blue; |
||
2911 | a += delta * gradient->stops[i].color.alpha; |
||
2912 | } |
||
2913 | |||
2914 | r += delta1 * gradient->stops[end].color.red; |
||
2915 | g += delta1 * gradient->stops[end].color.green; |
||
2916 | b += delta1 * gradient->stops[end].color.blue; |
||
2917 | a += delta1 * gradient->stops[end].color.alpha; |
||
2918 | |||
2919 | _cairo_color_init_rgba (color, r * .5, g * .5, b * .5, a * .5); |
||
2920 | } |
||
2921 | |||
2922 | /** |
||
3959 | Serge | 2923 | * _cairo_pattern_alpha_range: |
1892 | serge | 2924 | * |
3959 | Serge | 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 | } |
||
3057 | |||
3058 | /** |
||
3059 | * _cairo_gradient_pattern_is_solid: |
||
3060 | * |
||
1892 | serge | 3061 | * Convenience function to determine whether a gradient pattern is |
3062 | * a solid color within the given extents. In this case the color |
||
3063 | * argument is initialized to the color the pattern represents. |
||
3064 | * This functions doesn't handle completely transparent gradients, |
||
3065 | * thus it should be called only after _cairo_pattern_is_clear has |
||
3066 | * returned FALSE. |
||
3067 | * |
||
3068 | * Return value: %TRUE if the pattern is a solid color. |
||
3069 | **/ |
||
3070 | cairo_bool_t |
||
3071 | _cairo_gradient_pattern_is_solid (const cairo_gradient_pattern_t *gradient, |
||
3072 | const cairo_rectangle_int_t *extents, |
||
3073 | cairo_color_t *color) |
||
3074 | { |
||
3075 | unsigned int i; |
||
3076 | |||
3077 | assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR || |
||
3078 | gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL); |
||
3079 | |||
3080 | /* TODO: radial */ |
||
3081 | if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) { |
||
3082 | cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient; |
||
3083 | if (_linear_pattern_is_degenerate (linear)) { |
||
3084 | _gradient_color_average (gradient, color); |
||
3085 | return TRUE; |
||
3086 | } |
||
3087 | |||
3088 | if (gradient->base.extend == CAIRO_EXTEND_NONE) { |
||
3089 | double t[2]; |
||
3090 | |||
3091 | /* We already know that the pattern is not clear, thus if some |
||
3092 | * part of it is clear, the whole is not solid. |
||
3093 | */ |
||
3094 | |||
3095 | if (extents == NULL) |
||
3096 | return FALSE; |
||
3097 | |||
3959 | Serge | 3098 | _cairo_linear_pattern_box_to_parameter (linear, |
3099 | extents->x, |
||
3100 | extents->y, |
||
3101 | extents->x + extents->width, |
||
3102 | extents->y + extents->height, |
||
3103 | t); |
||
3104 | |||
1892 | serge | 3105 | if (t[0] < 0.0 || t[1] > 1.0) |
3106 | return FALSE; |
||
3107 | } |
||
3108 | } else |
||
3109 | return FALSE; |
||
3110 | |||
3111 | for (i = 1; i < gradient->n_stops; i++) |
||
3112 | if (! _cairo_color_stop_equal (&gradient->stops[0].color, |
||
3113 | &gradient->stops[i].color)) |
||
3114 | return FALSE; |
||
3115 | |||
3116 | _cairo_color_init_rgba (color, |
||
3117 | gradient->stops[0].color.red, |
||
3118 | gradient->stops[0].color.green, |
||
3119 | gradient->stops[0].color.blue, |
||
3120 | gradient->stops[0].color.alpha); |
||
3121 | |||
3122 | return TRUE; |
||
3123 | } |
||
3124 | |||
3959 | Serge | 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; |
||
3139 | } |
||
3140 | |||
1892 | serge | 3141 | /** |
3959 | Serge | 3142 | * _cairo_pattern_is_opaque_solid: |
1892 | serge | 3143 | * |
3144 | * Convenience function to determine whether a pattern is an opaque |
||
3145 | * (alpha==1.0) solid color pattern. This is done by testing whether |
||
3146 | * the pattern's alpha value when converted to a byte is 255, so if a |
||
3147 | * backend actually supported deep alpha channels this function might |
||
3148 | * not do the right thing. |
||
3149 | * |
||
3150 | * Return value: %TRUE if the pattern is an opaque, solid color. |
||
3151 | **/ |
||
3152 | cairo_bool_t |
||
3153 | _cairo_pattern_is_opaque_solid (const cairo_pattern_t *pattern) |
||
3154 | { |
||
3155 | cairo_solid_pattern_t *solid; |
||
3156 | |||
3157 | if (pattern->type != CAIRO_PATTERN_TYPE_SOLID) |
||
3158 | return FALSE; |
||
3159 | |||
3160 | solid = (cairo_solid_pattern_t *) pattern; |
||
3161 | |||
3162 | return CAIRO_COLOR_IS_OPAQUE (&solid->color); |
||
3163 | } |
||
3164 | |||
3165 | static cairo_bool_t |
||
3166 | _surface_is_opaque (const cairo_surface_pattern_t *pattern, |
||
3959 | Serge | 3167 | const cairo_rectangle_int_t *sample) |
1892 | serge | 3168 | { |
3959 | Serge | 3169 | cairo_rectangle_int_t extents; |
3170 | |||
1892 | serge | 3171 | if (pattern->surface->content & CAIRO_CONTENT_ALPHA) |
3172 | return FALSE; |
||
3173 | |||
3174 | if (pattern->base.extend != CAIRO_EXTEND_NONE) |
||
3175 | return TRUE; |
||
3176 | |||
3959 | Serge | 3177 | if (! _cairo_surface_get_extents (pattern->surface, &extents)) |
3178 | return TRUE; |
||
1892 | serge | 3179 | |
3959 | Serge | 3180 | if (sample == NULL) |
3181 | return FALSE; |
||
1892 | serge | 3182 | |
3959 | Serge | 3183 | return _cairo_rectangle_contains_rectangle (&extents, sample); |
3184 | } |
||
1892 | serge | 3185 | |
3959 | Serge | 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 | { |
||
3190 | if (pattern->content & CAIRO_CONTENT_ALPHA) |
||
3191 | return FALSE; |
||
3192 | |||
3193 | if (pattern->base.extend != CAIRO_EXTEND_NONE) |
||
3194 | return TRUE; |
||
3195 | |||
3196 | if (sample == NULL) |
||
3197 | return FALSE; |
||
3198 | |||
3199 | return _cairo_rectangle_contains_rectangle (&pattern->extents, sample); |
||
1892 | serge | 3200 | } |
3201 | |||
3202 | static cairo_bool_t |
||
3203 | _surface_is_clear (const cairo_surface_pattern_t *pattern) |
||
3204 | { |
||
3205 | cairo_rectangle_int_t extents; |
||
3206 | |||
3207 | if (_cairo_surface_get_extents (pattern->surface, &extents) && |
||
3208 | (extents.width == 0 || extents.height == 0)) |
||
3209 | return TRUE; |
||
3210 | |||
3211 | return pattern->surface->is_clear && |
||
3212 | pattern->surface->content & CAIRO_CONTENT_ALPHA; |
||
3213 | } |
||
3214 | |||
3215 | static cairo_bool_t |
||
3959 | Serge | 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 | |||
3221 | static cairo_bool_t |
||
1892 | serge | 3222 | _gradient_is_opaque (const cairo_gradient_pattern_t *gradient, |
3959 | Serge | 3223 | const cairo_rectangle_int_t *sample) |
1892 | serge | 3224 | { |
3225 | unsigned int i; |
||
3226 | |||
3227 | assert (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR || |
||
3228 | gradient->base.type == CAIRO_PATTERN_TYPE_RADIAL); |
||
3229 | |||
3230 | if (gradient->n_stops == 0 || |
||
3231 | (gradient->base.extend == CAIRO_EXTEND_NONE && |
||
3232 | gradient->stops[0].offset == gradient->stops[gradient->n_stops - 1].offset)) |
||
3233 | return FALSE; |
||
3234 | |||
3235 | if (gradient->base.type == CAIRO_PATTERN_TYPE_LINEAR) { |
||
3236 | if (gradient->base.extend == CAIRO_EXTEND_NONE) { |
||
3237 | double t[2]; |
||
3238 | cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient; |
||
3239 | |||
3240 | /* EXTEND_NONE degenerate radial gradients are clear */ |
||
3241 | if (_linear_pattern_is_degenerate (linear)) |
||
3242 | return FALSE; |
||
3243 | |||
3959 | Serge | 3244 | if (sample == NULL) |
1892 | serge | 3245 | return FALSE; |
3246 | |||
3959 | Serge | 3247 | _cairo_linear_pattern_box_to_parameter (linear, |
3248 | sample->x, |
||
3249 | sample->y, |
||
3250 | sample->x + sample->width, |
||
3251 | sample->y + sample->height, |
||
3252 | t); |
||
3253 | |||
1892 | serge | 3254 | if (t[0] < 0.0 || t[1] > 1.0) |
3255 | return FALSE; |
||
3256 | } |
||
3257 | } else |
||
3258 | return FALSE; /* TODO: check actual intersection */ |
||
3259 | |||
3260 | for (i = 0; i < gradient->n_stops; i++) |
||
3261 | if (! CAIRO_COLOR_IS_OPAQUE (&gradient->stops[i].color)) |
||
3262 | return FALSE; |
||
3263 | |||
3264 | return TRUE; |
||
3265 | } |
||
3266 | |||
3267 | /** |
||
3959 | Serge | 3268 | * _cairo_pattern_is_opaque: |
1892 | serge | 3269 | * |
3270 | * Convenience function to determine whether a pattern is an opaque |
||
3271 | * pattern (of any type). The same caveats that apply to |
||
3272 | * _cairo_pattern_is_opaque_solid apply here as well. |
||
3273 | * |
||
3274 | * Return value: %TRUE if the pattern is a opaque. |
||
3275 | **/ |
||
3276 | cairo_bool_t |
||
3277 | _cairo_pattern_is_opaque (const cairo_pattern_t *abstract_pattern, |
||
3959 | Serge | 3278 | const cairo_rectangle_int_t *sample) |
1892 | serge | 3279 | { |
3280 | const cairo_pattern_union_t *pattern; |
||
3281 | |||
3282 | if (abstract_pattern->has_component_alpha) |
||
3283 | return FALSE; |
||
3284 | |||
3285 | pattern = (cairo_pattern_union_t *) abstract_pattern; |
||
3286 | switch (pattern->base.type) { |
||
3287 | case CAIRO_PATTERN_TYPE_SOLID: |
||
3288 | return _cairo_pattern_is_opaque_solid (abstract_pattern); |
||
3289 | case CAIRO_PATTERN_TYPE_SURFACE: |
||
3959 | Serge | 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); |
||
1892 | serge | 3293 | case CAIRO_PATTERN_TYPE_LINEAR: |
3294 | case CAIRO_PATTERN_TYPE_RADIAL: |
||
3959 | Serge | 3295 | return _gradient_is_opaque (&pattern->gradient.base, sample); |
3296 | case CAIRO_PATTERN_TYPE_MESH: |
||
3297 | return FALSE; |
||
1892 | serge | 3298 | } |
3299 | |||
3300 | ASSERT_NOT_REACHED; |
||
3301 | return FALSE; |
||
3302 | } |
||
3303 | |||
3304 | cairo_bool_t |
||
3305 | _cairo_pattern_is_clear (const cairo_pattern_t *abstract_pattern) |
||
3306 | { |
||
3307 | const cairo_pattern_union_t *pattern; |
||
3308 | |||
3309 | if (abstract_pattern->has_component_alpha) |
||
3310 | return FALSE; |
||
3311 | |||
3312 | pattern = (cairo_pattern_union_t *) abstract_pattern; |
||
3959 | Serge | 3313 | switch (abstract_pattern->type) { |
1892 | serge | 3314 | case CAIRO_PATTERN_TYPE_SOLID: |
3315 | return CAIRO_COLOR_IS_CLEAR (&pattern->solid.color); |
||
3316 | case CAIRO_PATTERN_TYPE_SURFACE: |
||
3317 | return _surface_is_clear (&pattern->surface); |
||
3959 | Serge | 3318 | case CAIRO_PATTERN_TYPE_RASTER_SOURCE: |
3319 | return _raster_source_is_clear (&pattern->raster_source); |
||
1892 | serge | 3320 | case CAIRO_PATTERN_TYPE_LINEAR: |
3321 | case CAIRO_PATTERN_TYPE_RADIAL: |
||
3322 | return _gradient_is_clear (&pattern->gradient.base, NULL); |
||
3959 | Serge | 3323 | case CAIRO_PATTERN_TYPE_MESH: |
3324 | return _mesh_is_clear (&pattern->mesh); |
||
1892 | serge | 3325 | } |
3326 | |||
3327 | ASSERT_NOT_REACHED; |
||
3328 | return FALSE; |
||
3329 | } |
||
3330 | |||
3331 | /** |
||
3332 | * _cairo_pattern_analyze_filter: |
||
3333 | * @pattern: surface pattern |
||
3334 | * @pad_out: location to store necessary padding in the source image, or %NULL |
||
3335 | * Returns: the optimized #cairo_filter_t to use with @pattern. |
||
3336 | * |
||
3337 | * Analyze the filter to determine how much extra needs to be sampled |
||
3338 | * from the source image to account for the filter radius and whether |
||
3339 | * we can optimize the filter to a simpler value. |
||
3340 | * |
||
3341 | * XXX: We don't actually have any way of querying the backend for |
||
3342 | * the filter radius, so we just guess base on what we know that |
||
3343 | * backends do currently (see bug #10508) |
||
3959 | Serge | 3344 | **/ |
1892 | serge | 3345 | cairo_filter_t |
3346 | _cairo_pattern_analyze_filter (const cairo_pattern_t *pattern, |
||
3347 | double *pad_out) |
||
3348 | { |
||
3349 | double pad; |
||
3350 | cairo_filter_t optimized_filter; |
||
3351 | |||
3352 | switch (pattern->filter) { |
||
3353 | case CAIRO_FILTER_GOOD: |
||
3354 | case CAIRO_FILTER_BEST: |
||
3355 | case CAIRO_FILTER_BILINEAR: |
||
3356 | /* If source pixels map 1:1 onto destination pixels, we do |
||
3357 | * not need to filter (and do not want to filter, since it |
||
3358 | * will cause blurriness) |
||
3359 | */ |
||
3360 | if (_cairo_matrix_is_pixel_exact (&pattern->matrix)) { |
||
3361 | pad = 0.; |
||
3362 | optimized_filter = CAIRO_FILTER_NEAREST; |
||
3363 | } else { |
||
3364 | /* 0.5 is enough for a bilinear filter. It's possible we |
||
3365 | * should defensively use more for CAIRO_FILTER_BEST, but |
||
3366 | * without a single example, it's hard to know how much |
||
3367 | * more would be defensive... |
||
3368 | */ |
||
3369 | pad = 0.5; |
||
3370 | optimized_filter = pattern->filter; |
||
3371 | } |
||
3372 | break; |
||
3373 | |||
3374 | case CAIRO_FILTER_FAST: |
||
3375 | case CAIRO_FILTER_NEAREST: |
||
3376 | case CAIRO_FILTER_GAUSSIAN: |
||
3377 | default: |
||
3378 | pad = 0.; |
||
3379 | optimized_filter = pattern->filter; |
||
3380 | break; |
||
3381 | } |
||
3382 | |||
3383 | if (pad_out) |
||
3384 | *pad_out = pad; |
||
3385 | |||
3386 | return optimized_filter; |
||
3387 | } |
||
3388 | |||
3959 | Serge | 3389 | cairo_filter_t |
3390 | _cairo_pattern_sampled_area (const cairo_pattern_t *pattern, |
||
3391 | const cairo_rectangle_int_t *extents, |
||
3392 | cairo_rectangle_int_t *sample) |
||
1892 | serge | 3393 | { |
3959 | Serge | 3394 | cairo_filter_t filter; |
3395 | double x1, x2, y1, y2; |
||
1892 | serge | 3396 | double pad; |
3397 | |||
3959 | Serge | 3398 | filter = _cairo_pattern_analyze_filter (pattern, &pad); |
3399 | if (pad == 0.0 && _cairo_matrix_is_identity (&pattern->matrix)) { |
||
3400 | *sample = *extents; |
||
3401 | return filter; |
||
1892 | serge | 3402 | } |
3403 | |||
3959 | Serge | 3404 | x1 = extents->x; |
3405 | y1 = extents->y; |
||
3406 | x2 = extents->x + (int) extents->width; |
||
3407 | y2 = extents->y + (int) extents->height; |
||
1892 | serge | 3408 | |
3959 | Serge | 3409 | _cairo_matrix_transform_bounding_box (&pattern->matrix, |
3410 | &x1, &y1, &x2, &y2, |
||
3411 | NULL); |
||
3412 | if (x1 > CAIRO_RECT_INT_MIN) |
||
3413 | sample->x = floor (x1 - pad); |
||
3414 | else |
||
3415 | sample->x = CAIRO_RECT_INT_MIN; |
||
1892 | serge | 3416 | |
3959 | Serge | 3417 | if (y1 > CAIRO_RECT_INT_MIN) |
3418 | sample->y = floor (y1 - pad); |
||
3419 | else |
||
3420 | sample->y = CAIRO_RECT_INT_MIN; |
||
1892 | serge | 3421 | |
3959 | Serge | 3422 | if (x2 < CAIRO_RECT_INT_MAX) |
3423 | sample->width = ceil (x2 + pad); |
||
3424 | else |
||
3425 | sample->width = CAIRO_RECT_INT_MAX; |
||
1892 | serge | 3426 | |
3959 | Serge | 3427 | if (y2 < CAIRO_RECT_INT_MAX) |
3428 | sample->height = ceil (y2 + pad); |
||
3429 | else |
||
3430 | sample->height = CAIRO_RECT_INT_MAX; |
||
1892 | serge | 3431 | |
3959 | Serge | 3432 | sample->width -= sample->x; |
3433 | sample->height -= sample->y; |
||
1892 | serge | 3434 | |
3959 | Serge | 3435 | return filter; |
1892 | serge | 3436 | } |
3437 | |||
3438 | /** |
||
3439 | * _cairo_pattern_get_extents: |
||
3440 | * |
||
3441 | * Return the "target-space" extents of @pattern in @extents. |
||
3442 | * |
||
3443 | * For unbounded patterns, the @extents will be initialized with |
||
3444 | * "infinite" extents, (minimum and maximum fixed-point values). |
||
3445 | * |
||
3446 | * XXX: Currently, bounded gradient patterns will also return |
||
3447 | * "infinite" extents, though it would be possible to optimize these |
||
3448 | * with a little more work. |
||
3449 | **/ |
||
3450 | void |
||
3451 | _cairo_pattern_get_extents (const cairo_pattern_t *pattern, |
||
3452 | cairo_rectangle_int_t *extents) |
||
3453 | { |
||
3454 | double x1, y1, x2, y2; |
||
3455 | cairo_status_t status; |
||
3456 | |||
3457 | switch (pattern->type) { |
||
3458 | case CAIRO_PATTERN_TYPE_SOLID: |
||
3459 | goto UNBOUNDED; |
||
3460 | |||
3461 | case CAIRO_PATTERN_TYPE_SURFACE: |
||
3462 | { |
||
3463 | cairo_rectangle_int_t surface_extents; |
||
3464 | const cairo_surface_pattern_t *surface_pattern = |
||
3465 | (const cairo_surface_pattern_t *) pattern; |
||
3466 | cairo_surface_t *surface = surface_pattern->surface; |
||
3467 | double pad; |
||
3468 | |||
3469 | if (! _cairo_surface_get_extents (surface, &surface_extents)) |
||
3470 | goto UNBOUNDED; |
||
3471 | |||
3472 | if (surface_extents.width == 0 || surface_extents.height == 0) |
||
3473 | goto EMPTY; |
||
3474 | |||
3475 | if (pattern->extend != CAIRO_EXTEND_NONE) |
||
3476 | goto UNBOUNDED; |
||
3477 | |||
3478 | /* The filter can effectively enlarge the extents of the |
||
3479 | * pattern, so extend as necessary. |
||
3480 | */ |
||
3481 | _cairo_pattern_analyze_filter (&surface_pattern->base, &pad); |
||
3482 | x1 = surface_extents.x - pad; |
||
3483 | y1 = surface_extents.y - pad; |
||
3484 | x2 = surface_extents.x + (int) surface_extents.width + pad; |
||
3485 | y2 = surface_extents.y + (int) surface_extents.height + pad; |
||
3486 | } |
||
3487 | break; |
||
3488 | |||
3959 | Serge | 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; |
||
3511 | |||
1892 | serge | 3512 | case CAIRO_PATTERN_TYPE_RADIAL: |
3513 | { |
||
3514 | const cairo_radial_pattern_t *radial = |
||
3515 | (const cairo_radial_pattern_t *) pattern; |
||
3516 | double cx1, cy1; |
||
3517 | double cx2, cy2; |
||
3959 | Serge | 3518 | double r1, r2; |
1892 | serge | 3519 | |
3959 | Serge | 3520 | if (_radial_pattern_is_degenerate (radial)) { |
3521 | /* cairo-gstate should have optimised degenerate |
||
3522 | * patterns to solid clear patterns, so we can ignore |
||
3523 | * them here. */ |
||
1892 | serge | 3524 | goto EMPTY; |
3959 | Serge | 3525 | } |
1892 | serge | 3526 | |
3959 | Serge | 3527 | /* TODO: in some cases (focus outside/on the circle) it is |
3528 | * half-bounded. */ |
||
1892 | serge | 3529 | if (pattern->extend != CAIRO_EXTEND_NONE) |
3530 | goto UNBOUNDED; |
||
3531 | |||
3959 | Serge | 3532 | cx1 = radial->cd1.center.x; |
3533 | cy1 = radial->cd1.center.y; |
||
3534 | r1 = radial->cd1.radius; |
||
1892 | serge | 3535 | |
3959 | Serge | 3536 | cx2 = radial->cd2.center.x; |
3537 | cy2 = radial->cd2.center.y; |
||
3538 | r2 = radial->cd2.radius; |
||
1892 | serge | 3539 | |
3959 | Serge | 3540 | x1 = MIN (cx1 - r1, cx2 - r2); |
3541 | y1 = MIN (cy1 - r1, cy2 - r2); |
||
3542 | x2 = MAX (cx1 + r1, cx2 + r2); |
||
3543 | y2 = MAX (cy1 + r1, cy2 + r2); |
||
1892 | serge | 3544 | } |
3545 | break; |
||
3546 | |||
3547 | case CAIRO_PATTERN_TYPE_LINEAR: |
||
3548 | { |
||
3549 | const cairo_linear_pattern_t *linear = |
||
3550 | (const cairo_linear_pattern_t *) pattern; |
||
3551 | |||
3552 | if (pattern->extend != CAIRO_EXTEND_NONE) |
||
3553 | goto UNBOUNDED; |
||
3554 | |||
3959 | Serge | 3555 | if (_linear_pattern_is_degenerate (linear)) { |
3556 | /* cairo-gstate should have optimised degenerate |
||
3557 | * patterns to solid ones, so we can again ignore |
||
3558 | * them here. */ |
||
1892 | serge | 3559 | goto EMPTY; |
3959 | Serge | 3560 | } |
1892 | serge | 3561 | |
3959 | Serge | 3562 | /* TODO: to get tight extents, use the matrix to transform |
3563 | * the pattern instead of transforming the extents later. */ |
||
1892 | serge | 3564 | if (pattern->matrix.xy != 0. || pattern->matrix.yx != 0.) |
3565 | goto UNBOUNDED; |
||
3566 | |||
3959 | Serge | 3567 | if (linear->pd1.x == linear->pd2.x) { |
1892 | serge | 3568 | x1 = -HUGE_VAL; |
3569 | x2 = HUGE_VAL; |
||
3959 | Serge | 3570 | y1 = MIN (linear->pd1.y, linear->pd2.y); |
3571 | y2 = MAX (linear->pd1.y, linear->pd2.y); |
||
3572 | } else if (linear->pd1.y == linear->pd2.y) { |
||
3573 | x1 = MIN (linear->pd1.x, linear->pd2.x); |
||
3574 | x2 = MAX (linear->pd1.x, linear->pd2.x); |
||
1892 | serge | 3575 | y1 = -HUGE_VAL; |
3576 | y2 = HUGE_VAL; |
||
3577 | } else { |
||
3578 | goto UNBOUNDED; |
||
3579 | } |
||
3580 | } |
||
3581 | break; |
||
3582 | |||
3959 | Serge | 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; |
||
3601 | x2 += padx; |
||
3602 | y2 += pady; |
||
3603 | } |
||
3604 | break; |
||
3605 | |||
1892 | serge | 3606 | default: |
3607 | ASSERT_NOT_REACHED; |
||
3608 | } |
||
3609 | |||
3610 | if (_cairo_matrix_is_translation (&pattern->matrix)) { |
||
3611 | x1 -= pattern->matrix.x0; x2 -= pattern->matrix.x0; |
||
3612 | y1 -= pattern->matrix.y0; y2 -= pattern->matrix.y0; |
||
3613 | } else { |
||
3614 | cairo_matrix_t imatrix; |
||
3615 | |||
3616 | imatrix = pattern->matrix; |
||
3617 | status = cairo_matrix_invert (&imatrix); |
||
3618 | /* cairo_pattern_set_matrix ensures the matrix is invertible */ |
||
3619 | assert (status == CAIRO_STATUS_SUCCESS); |
||
3620 | |||
3621 | _cairo_matrix_transform_bounding_box (&imatrix, |
||
3622 | &x1, &y1, &x2, &y2, |
||
3623 | NULL); |
||
3624 | } |
||
3625 | |||
3626 | x1 = floor (x1); |
||
3627 | if (x1 < CAIRO_RECT_INT_MIN) |
||
3628 | x1 = CAIRO_RECT_INT_MIN; |
||
3629 | y1 = floor (y1); |
||
3630 | if (y1 < CAIRO_RECT_INT_MIN) |
||
3631 | y1 = CAIRO_RECT_INT_MIN; |
||
3632 | |||
3633 | x2 = ceil (x2); |
||
3634 | if (x2 > CAIRO_RECT_INT_MAX) |
||
3635 | x2 = CAIRO_RECT_INT_MAX; |
||
3636 | y2 = ceil (y2); |
||
3637 | if (y2 > CAIRO_RECT_INT_MAX) |
||
3638 | y2 = CAIRO_RECT_INT_MAX; |
||
3639 | |||
3640 | extents->x = x1; extents->width = x2 - x1; |
||
3641 | extents->y = y1; extents->height = y2 - y1; |
||
3642 | return; |
||
3643 | |||
3644 | UNBOUNDED: |
||
3645 | /* unbounded patterns -> 'infinite' extents */ |
||
3646 | _cairo_unbounded_rectangle_init (extents); |
||
3647 | return; |
||
3648 | |||
3649 | EMPTY: |
||
3650 | extents->x = extents->y = 0; |
||
3651 | extents->width = extents->height = 0; |
||
3652 | return; |
||
3653 | } |
||
3654 | |||
3959 | Serge | 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; |
||
1892 | serge | 3670 | |
3959 | Serge | 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; |
||
3694 | } |
||
3695 | |||
1892 | serge | 3696 | static unsigned long |
3697 | _cairo_solid_pattern_hash (unsigned long hash, |
||
3959 | Serge | 3698 | const cairo_solid_pattern_t *solid) |
1892 | serge | 3699 | { |
3700 | hash = _cairo_hash_bytes (hash, &solid->color, sizeof (solid->color)); |
||
3701 | |||
3702 | return hash; |
||
3703 | } |
||
3704 | |||
3705 | static unsigned long |
||
3706 | _cairo_gradient_color_stops_hash (unsigned long hash, |
||
3707 | const cairo_gradient_pattern_t *gradient) |
||
3708 | { |
||
3709 | unsigned int n; |
||
3710 | |||
3711 | hash = _cairo_hash_bytes (hash, |
||
3712 | &gradient->n_stops, |
||
3713 | sizeof (gradient->n_stops)); |
||
3714 | |||
3715 | for (n = 0; n < gradient->n_stops; n++) { |
||
3716 | hash = _cairo_hash_bytes (hash, |
||
3717 | &gradient->stops[n].offset, |
||
3718 | sizeof (double)); |
||
3719 | hash = _cairo_hash_bytes (hash, |
||
3720 | &gradient->stops[n].color, |
||
3959 | Serge | 3721 | sizeof (cairo_color_stop_t)); |
1892 | serge | 3722 | } |
3723 | |||
3724 | return hash; |
||
3725 | } |
||
3726 | |||
3727 | unsigned long |
||
3728 | _cairo_linear_pattern_hash (unsigned long hash, |
||
3729 | const cairo_linear_pattern_t *linear) |
||
3730 | { |
||
3959 | Serge | 3731 | hash = _cairo_hash_bytes (hash, &linear->pd1, sizeof (linear->pd1)); |
3732 | hash = _cairo_hash_bytes (hash, &linear->pd2, sizeof (linear->pd2)); |
||
1892 | serge | 3733 | |
3734 | return _cairo_gradient_color_stops_hash (hash, &linear->base); |
||
3735 | } |
||
3736 | |||
3737 | unsigned long |
||
3738 | _cairo_radial_pattern_hash (unsigned long hash, |
||
3739 | const cairo_radial_pattern_t *radial) |
||
3740 | { |
||
3959 | Serge | 3741 | hash = _cairo_hash_bytes (hash, &radial->cd1.center, sizeof (radial->cd1.center)); |
3742 | hash = _cairo_hash_bytes (hash, &radial->cd1.radius, sizeof (radial->cd1.radius)); |
||
3743 | hash = _cairo_hash_bytes (hash, &radial->cd2.center, sizeof (radial->cd2.center)); |
||
3744 | hash = _cairo_hash_bytes (hash, &radial->cd2.radius, sizeof (radial->cd2.radius)); |
||
1892 | serge | 3745 | |
3746 | return _cairo_gradient_color_stops_hash (hash, &radial->base); |
||
3747 | } |
||
3748 | |||
3749 | static unsigned long |
||
3959 | Serge | 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 | |||
3758 | return hash; |
||
3759 | } |
||
3760 | |||
3761 | static unsigned long |
||
1892 | serge | 3762 | _cairo_surface_pattern_hash (unsigned long hash, |
3959 | Serge | 3763 | const cairo_surface_pattern_t *surface) |
1892 | serge | 3764 | { |
3765 | hash ^= surface->surface->unique_id; |
||
3766 | |||
3767 | return hash; |
||
3768 | } |
||
3769 | |||
3959 | Serge | 3770 | static unsigned long |
3771 | _cairo_raster_source_pattern_hash (unsigned long hash, |
||
3772 | const cairo_raster_source_pattern_t *raster) |
||
3773 | { |
||
3774 | hash ^= (uintptr_t)raster->user_data; |
||
3775 | |||
3776 | return hash; |
||
3777 | } |
||
3778 | |||
1892 | serge | 3779 | unsigned long |
3780 | _cairo_pattern_hash (const cairo_pattern_t *pattern) |
||
3781 | { |
||
3782 | unsigned long hash = _CAIRO_HASH_INIT_VALUE; |
||
3783 | |||
3784 | if (pattern->status) |
||
3785 | return 0; |
||
3786 | |||
3787 | hash = _cairo_hash_bytes (hash, &pattern->type, sizeof (pattern->type)); |
||
3788 | if (pattern->type != CAIRO_PATTERN_TYPE_SOLID) { |
||
3789 | hash = _cairo_hash_bytes (hash, |
||
3790 | &pattern->matrix, sizeof (pattern->matrix)); |
||
3791 | hash = _cairo_hash_bytes (hash, |
||
3792 | &pattern->filter, sizeof (pattern->filter)); |
||
3793 | hash = _cairo_hash_bytes (hash, |
||
3794 | &pattern->extend, sizeof (pattern->extend)); |
||
3795 | hash = _cairo_hash_bytes (hash, |
||
3796 | &pattern->has_component_alpha, |
||
3797 | sizeof (pattern->has_component_alpha)); |
||
3798 | } |
||
3799 | |||
3800 | switch (pattern->type) { |
||
3801 | case CAIRO_PATTERN_TYPE_SOLID: |
||
3959 | Serge | 3802 | return _cairo_solid_pattern_hash (hash, (cairo_solid_pattern_t *) pattern); |
1892 | serge | 3803 | case CAIRO_PATTERN_TYPE_LINEAR: |
3804 | return _cairo_linear_pattern_hash (hash, (cairo_linear_pattern_t *) pattern); |
||
3805 | case CAIRO_PATTERN_TYPE_RADIAL: |
||
3806 | return _cairo_radial_pattern_hash (hash, (cairo_radial_pattern_t *) pattern); |
||
3959 | Serge | 3807 | case CAIRO_PATTERN_TYPE_MESH: |
3808 | return _cairo_mesh_pattern_hash (hash, (cairo_mesh_pattern_t *) pattern); |
||
1892 | serge | 3809 | case CAIRO_PATTERN_TYPE_SURFACE: |
3959 | Serge | 3810 | return _cairo_surface_pattern_hash (hash, (cairo_surface_pattern_t *) pattern); |
3811 | case CAIRO_PATTERN_TYPE_RASTER_SOURCE: |
||
3812 | return _cairo_raster_source_pattern_hash (hash, (cairo_raster_source_pattern_t *) pattern); |
||
1892 | serge | 3813 | default: |
3814 | ASSERT_NOT_REACHED; |
||
3815 | return FALSE; |
||
3816 | } |
||
3817 | } |
||
3818 | |||
3819 | static cairo_bool_t |
||
3959 | Serge | 3820 | _cairo_solid_pattern_equal (const cairo_solid_pattern_t *a, |
3821 | const cairo_solid_pattern_t *b) |
||
1892 | serge | 3822 | { |
3823 | return _cairo_color_equal (&a->color, &b->color); |
||
3824 | } |
||
3825 | |||
3826 | static cairo_bool_t |
||
3827 | _cairo_gradient_color_stops_equal (const cairo_gradient_pattern_t *a, |
||
3828 | const cairo_gradient_pattern_t *b) |
||
3829 | { |
||
3830 | unsigned int n; |
||
3831 | |||
3832 | if (a->n_stops != b->n_stops) |
||
3833 | return FALSE; |
||
3834 | |||
3835 | for (n = 0; n < a->n_stops; n++) { |
||
3836 | if (a->stops[n].offset != b->stops[n].offset) |
||
3837 | return FALSE; |
||
3838 | if (! _cairo_color_stop_equal (&a->stops[n].color, &b->stops[n].color)) |
||
3839 | return FALSE; |
||
3840 | } |
||
3841 | |||
3842 | return TRUE; |
||
3843 | } |
||
3844 | |||
3845 | cairo_bool_t |
||
3846 | _cairo_linear_pattern_equal (const cairo_linear_pattern_t *a, |
||
3847 | const cairo_linear_pattern_t *b) |
||
3848 | { |
||
3959 | Serge | 3849 | if (a->pd1.x != b->pd1.x) |
1892 | serge | 3850 | return FALSE; |
3851 | |||
3959 | Serge | 3852 | if (a->pd1.y != b->pd1.y) |
1892 | serge | 3853 | return FALSE; |
3854 | |||
3959 | Serge | 3855 | if (a->pd2.x != b->pd2.x) |
1892 | serge | 3856 | return FALSE; |
3857 | |||
3959 | Serge | 3858 | if (a->pd2.y != b->pd2.y) |
1892 | serge | 3859 | return FALSE; |
3860 | |||
3861 | return _cairo_gradient_color_stops_equal (&a->base, &b->base); |
||
3862 | } |
||
3863 | |||
3864 | cairo_bool_t |
||
3865 | _cairo_radial_pattern_equal (const cairo_radial_pattern_t *a, |
||
3866 | const cairo_radial_pattern_t *b) |
||
3867 | { |
||
3959 | Serge | 3868 | if (a->cd1.center.x != b->cd1.center.x) |
1892 | serge | 3869 | return FALSE; |
3870 | |||
3959 | Serge | 3871 | if (a->cd1.center.y != b->cd1.center.y) |
1892 | serge | 3872 | return FALSE; |
3873 | |||
3959 | Serge | 3874 | if (a->cd1.radius != b->cd1.radius) |
1892 | serge | 3875 | return FALSE; |
3876 | |||
3959 | Serge | 3877 | if (a->cd2.center.x != b->cd2.center.x) |
1892 | serge | 3878 | return FALSE; |
3879 | |||
3959 | Serge | 3880 | if (a->cd2.center.y != b->cd2.center.y) |
1892 | serge | 3881 | return FALSE; |
3882 | |||
3959 | Serge | 3883 | if (a->cd2.radius != b->cd2.radius) |
1892 | serge | 3884 | return FALSE; |
3885 | |||
3886 | return _cairo_gradient_color_stops_equal (&a->base, &b->base); |
||
3887 | } |
||
3888 | |||
3889 | static cairo_bool_t |
||
3959 | Serge | 3890 | _cairo_mesh_pattern_equal (const cairo_mesh_pattern_t *a, |
3891 | const cairo_mesh_pattern_t *b) |
||
1892 | serge | 3892 | { |
3959 | Serge | 3893 | const cairo_mesh_patch_t *patch_a, *patch_b; |
3894 | unsigned int i, num_patches_a, num_patches_b; |
||
1892 | serge | 3895 | |
3959 | Serge | 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 | |||
3902 | for (i = 0; i < num_patches_a; i++) { |
||
3903 | patch_a = _cairo_array_index_const (&a->patches, i); |
||
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 | } |
||
3911 | |||
3912 | static cairo_bool_t |
||
3913 | _cairo_surface_pattern_equal (const cairo_surface_pattern_t *a, |
||
3914 | const cairo_surface_pattern_t *b) |
||
3915 | { |
||
1892 | serge | 3916 | return a->surface->unique_id == b->surface->unique_id; |
3917 | } |
||
3918 | |||
3959 | Serge | 3919 | static cairo_bool_t |
3920 | _cairo_raster_source_pattern_equal (const cairo_raster_source_pattern_t *a, |
||
3921 | const cairo_raster_source_pattern_t *b) |
||
3922 | { |
||
3923 | return a->user_data == b->user_data; |
||
3924 | } |
||
3925 | |||
1892 | serge | 3926 | cairo_bool_t |
3927 | _cairo_pattern_equal (const cairo_pattern_t *a, const cairo_pattern_t *b) |
||
3928 | { |
||
3929 | if (a->status || b->status) |
||
3930 | return FALSE; |
||
3931 | |||
3932 | if (a == b) |
||
3933 | return TRUE; |
||
3934 | |||
3935 | if (a->type != b->type) |
||
3936 | return FALSE; |
||
3937 | |||
3938 | if (a->has_component_alpha != b->has_component_alpha) |
||
3939 | return FALSE; |
||
3940 | |||
3941 | if (a->type != CAIRO_PATTERN_TYPE_SOLID) { |
||
3942 | if (memcmp (&a->matrix, &b->matrix, sizeof (cairo_matrix_t))) |
||
3943 | return FALSE; |
||
3944 | |||
3945 | if (a->filter != b->filter) |
||
3946 | return FALSE; |
||
3947 | |||
3948 | if (a->extend != b->extend) |
||
3949 | return FALSE; |
||
3950 | } |
||
3951 | |||
3952 | switch (a->type) { |
||
3953 | case CAIRO_PATTERN_TYPE_SOLID: |
||
3959 | Serge | 3954 | return _cairo_solid_pattern_equal ((cairo_solid_pattern_t *) a, |
3955 | (cairo_solid_pattern_t *) b); |
||
1892 | serge | 3956 | case CAIRO_PATTERN_TYPE_LINEAR: |
3957 | return _cairo_linear_pattern_equal ((cairo_linear_pattern_t *) a, |
||
3958 | (cairo_linear_pattern_t *) b); |
||
3959 | case CAIRO_PATTERN_TYPE_RADIAL: |
||
3960 | return _cairo_radial_pattern_equal ((cairo_radial_pattern_t *) a, |
||
3961 | (cairo_radial_pattern_t *) b); |
||
3959 | Serge | 3962 | case CAIRO_PATTERN_TYPE_MESH: |
3963 | return _cairo_mesh_pattern_equal ((cairo_mesh_pattern_t *) a, |
||
3964 | (cairo_mesh_pattern_t *) b); |
||
1892 | serge | 3965 | case CAIRO_PATTERN_TYPE_SURFACE: |
3959 | Serge | 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, |
||
3970 | (cairo_raster_source_pattern_t *) b); |
||
1892 | serge | 3971 | default: |
3972 | ASSERT_NOT_REACHED; |
||
3973 | return FALSE; |
||
3974 | } |
||
3975 | } |
||
3976 | |||
3977 | /** |
||
3959 | Serge | 3978 | * cairo_pattern_get_rgba: |
1892 | serge | 3979 | * @pattern: a #cairo_pattern_t |
3980 | * @red: return value for red component of color, or %NULL |
||
3981 | * @green: return value for green component of color, or %NULL |
||
3982 | * @blue: return value for blue component of color, or %NULL |
||
3983 | * @alpha: return value for alpha component of color, or %NULL |
||
3984 | * |
||
3985 | * Gets the solid color for a solid color pattern. |
||
3986 | * |
||
3987 | * Return value: %CAIRO_STATUS_SUCCESS, or |
||
3988 | * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if the pattern is not a solid |
||
3989 | * color pattern. |
||
3990 | * |
||
3991 | * Since: 1.4 |
||
3992 | **/ |
||
3993 | cairo_status_t |
||
3994 | cairo_pattern_get_rgba (cairo_pattern_t *pattern, |
||
3995 | double *red, double *green, |
||
3996 | double *blue, double *alpha) |
||
3997 | { |
||
3998 | cairo_solid_pattern_t *solid = (cairo_solid_pattern_t*) pattern; |
||
3999 | double r0, g0, b0, a0; |
||
4000 | |||
4001 | if (pattern->status) |
||
4002 | return pattern->status; |
||
4003 | |||
4004 | if (pattern->type != CAIRO_PATTERN_TYPE_SOLID) |
||
4005 | return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
||
4006 | |||
4007 | _cairo_color_get_rgba (&solid->color, &r0, &g0, &b0, &a0); |
||
4008 | |||
4009 | if (red) |
||
4010 | *red = r0; |
||
4011 | if (green) |
||
4012 | *green = g0; |
||
4013 | if (blue) |
||
4014 | *blue = b0; |
||
4015 | if (alpha) |
||
4016 | *alpha = a0; |
||
4017 | |||
4018 | return CAIRO_STATUS_SUCCESS; |
||
4019 | } |
||
4020 | |||
4021 | /** |
||
3959 | Serge | 4022 | * cairo_pattern_get_surface: |
1892 | serge | 4023 | * @pattern: a #cairo_pattern_t |
4024 | * @surface: return value for surface of pattern, or %NULL |
||
4025 | * |
||
4026 | * Gets the surface of a surface pattern. The reference returned in |
||
4027 | * @surface is owned by the pattern; the caller should call |
||
4028 | * cairo_surface_reference() if the surface is to be retained. |
||
4029 | * |
||
4030 | * Return value: %CAIRO_STATUS_SUCCESS, or |
||
4031 | * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if the pattern is not a surface |
||
4032 | * pattern. |
||
4033 | * |
||
4034 | * Since: 1.4 |
||
4035 | **/ |
||
4036 | cairo_status_t |
||
4037 | cairo_pattern_get_surface (cairo_pattern_t *pattern, |
||
4038 | cairo_surface_t **surface) |
||
4039 | { |
||
4040 | cairo_surface_pattern_t *spat = (cairo_surface_pattern_t*) pattern; |
||
4041 | |||
4042 | if (pattern->status) |
||
4043 | return pattern->status; |
||
4044 | |||
4045 | if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE) |
||
4046 | return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
||
4047 | |||
4048 | if (surface) |
||
4049 | *surface = spat->surface; |
||
4050 | |||
4051 | return CAIRO_STATUS_SUCCESS; |
||
4052 | } |
||
4053 | |||
4054 | /** |
||
3959 | Serge | 4055 | * cairo_pattern_get_color_stop_rgba: |
1892 | serge | 4056 | * @pattern: a #cairo_pattern_t |
4057 | * @index: index of the stop to return data for |
||
4058 | * @offset: return value for the offset of the stop, or %NULL |
||
4059 | * @red: return value for red component of color, or %NULL |
||
4060 | * @green: return value for green component of color, or %NULL |
||
4061 | * @blue: return value for blue component of color, or %NULL |
||
4062 | * @alpha: return value for alpha component of color, or %NULL |
||
4063 | * |
||
4064 | * Gets the color and offset information at the given @index for a |
||
4065 | * gradient pattern. Values of @index are 0 to 1 less than the number |
||
4066 | * returned by cairo_pattern_get_color_stop_count(). |
||
4067 | * |
||
4068 | * Return value: %CAIRO_STATUS_SUCCESS, or %CAIRO_STATUS_INVALID_INDEX |
||
4069 | * if @index is not valid for the given pattern. If the pattern is |
||
4070 | * not a gradient pattern, %CAIRO_STATUS_PATTERN_TYPE_MISMATCH is |
||
4071 | * returned. |
||
4072 | * |
||
4073 | * Since: 1.4 |
||
4074 | **/ |
||
4075 | cairo_status_t |
||
4076 | cairo_pattern_get_color_stop_rgba (cairo_pattern_t *pattern, |
||
4077 | int index, double *offset, |
||
4078 | double *red, double *green, |
||
4079 | double *blue, double *alpha) |
||
4080 | { |
||
4081 | cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t*) pattern; |
||
4082 | |||
4083 | if (pattern->status) |
||
4084 | return pattern->status; |
||
4085 | |||
4086 | if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR && |
||
4087 | pattern->type != CAIRO_PATTERN_TYPE_RADIAL) |
||
4088 | return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
||
4089 | |||
4090 | if (index < 0 || (unsigned int) index >= gradient->n_stops) |
||
4091 | return _cairo_error (CAIRO_STATUS_INVALID_INDEX); |
||
4092 | |||
4093 | if (offset) |
||
4094 | *offset = gradient->stops[index].offset; |
||
4095 | if (red) |
||
4096 | *red = gradient->stops[index].color.red; |
||
4097 | if (green) |
||
4098 | *green = gradient->stops[index].color.green; |
||
4099 | if (blue) |
||
4100 | *blue = gradient->stops[index].color.blue; |
||
4101 | if (alpha) |
||
4102 | *alpha = gradient->stops[index].color.alpha; |
||
4103 | |||
4104 | return CAIRO_STATUS_SUCCESS; |
||
4105 | } |
||
4106 | |||
4107 | /** |
||
3959 | Serge | 4108 | * cairo_pattern_get_color_stop_count: |
1892 | serge | 4109 | * @pattern: a #cairo_pattern_t |
4110 | * @count: return value for the number of color stops, or %NULL |
||
4111 | * |
||
4112 | * Gets the number of color stops specified in the given gradient |
||
4113 | * pattern. |
||
4114 | * |
||
4115 | * Return value: %CAIRO_STATUS_SUCCESS, or |
||
4116 | * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a gradient |
||
4117 | * pattern. |
||
4118 | * |
||
4119 | * Since: 1.4 |
||
3959 | Serge | 4120 | **/ |
1892 | serge | 4121 | cairo_status_t |
4122 | cairo_pattern_get_color_stop_count (cairo_pattern_t *pattern, |
||
4123 | int *count) |
||
4124 | { |
||
4125 | cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t*) pattern; |
||
4126 | |||
4127 | if (pattern->status) |
||
4128 | return pattern->status; |
||
4129 | |||
4130 | if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR && |
||
4131 | pattern->type != CAIRO_PATTERN_TYPE_RADIAL) |
||
4132 | return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
||
4133 | |||
4134 | if (count) |
||
4135 | *count = gradient->n_stops; |
||
4136 | |||
4137 | return CAIRO_STATUS_SUCCESS; |
||
4138 | } |
||
4139 | |||
4140 | /** |
||
3959 | Serge | 4141 | * cairo_pattern_get_linear_points: |
1892 | serge | 4142 | * @pattern: a #cairo_pattern_t |
4143 | * @x0: return value for the x coordinate of the first point, or %NULL |
||
4144 | * @y0: return value for the y coordinate of the first point, or %NULL |
||
4145 | * @x1: return value for the x coordinate of the second point, or %NULL |
||
4146 | * @y1: return value for the y coordinate of the second point, or %NULL |
||
4147 | * |
||
4148 | * Gets the gradient endpoints for a linear gradient. |
||
4149 | * |
||
4150 | * Return value: %CAIRO_STATUS_SUCCESS, or |
||
4151 | * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a linear |
||
4152 | * gradient pattern. |
||
4153 | * |
||
4154 | * Since: 1.4 |
||
4155 | **/ |
||
4156 | cairo_status_t |
||
4157 | cairo_pattern_get_linear_points (cairo_pattern_t *pattern, |
||
4158 | double *x0, double *y0, |
||
4159 | double *x1, double *y1) |
||
4160 | { |
||
4161 | cairo_linear_pattern_t *linear = (cairo_linear_pattern_t*) pattern; |
||
4162 | |||
4163 | if (pattern->status) |
||
4164 | return pattern->status; |
||
4165 | |||
4166 | if (pattern->type != CAIRO_PATTERN_TYPE_LINEAR) |
||
4167 | return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
||
4168 | |||
4169 | if (x0) |
||
3959 | Serge | 4170 | *x0 = linear->pd1.x; |
1892 | serge | 4171 | if (y0) |
3959 | Serge | 4172 | *y0 = linear->pd1.y; |
1892 | serge | 4173 | if (x1) |
3959 | Serge | 4174 | *x1 = linear->pd2.x; |
1892 | serge | 4175 | if (y1) |
3959 | Serge | 4176 | *y1 = linear->pd2.y; |
1892 | serge | 4177 | |
4178 | return CAIRO_STATUS_SUCCESS; |
||
4179 | } |
||
4180 | |||
4181 | /** |
||
3959 | Serge | 4182 | * cairo_pattern_get_radial_circles: |
1892 | serge | 4183 | * @pattern: a #cairo_pattern_t |
4184 | * @x0: return value for the x coordinate of the center of the first circle, or %NULL |
||
4185 | * @y0: return value for the y coordinate of the center of the first circle, or %NULL |
||
4186 | * @r0: return value for the radius of the first circle, or %NULL |
||
4187 | * @x1: return value for the x coordinate of the center of the second circle, or %NULL |
||
4188 | * @y1: return value for the y coordinate of the center of the second circle, or %NULL |
||
4189 | * @r1: return value for the radius of the second circle, or %NULL |
||
4190 | * |
||
4191 | * Gets the gradient endpoint circles for a radial gradient, each |
||
4192 | * specified as a center coordinate and a radius. |
||
4193 | * |
||
4194 | * Return value: %CAIRO_STATUS_SUCCESS, or |
||
4195 | * %CAIRO_STATUS_PATTERN_TYPE_MISMATCH if @pattern is not a radial |
||
4196 | * gradient pattern. |
||
4197 | * |
||
4198 | * Since: 1.4 |
||
4199 | **/ |
||
4200 | cairo_status_t |
||
4201 | cairo_pattern_get_radial_circles (cairo_pattern_t *pattern, |
||
4202 | double *x0, double *y0, double *r0, |
||
4203 | double *x1, double *y1, double *r1) |
||
4204 | { |
||
4205 | cairo_radial_pattern_t *radial = (cairo_radial_pattern_t*) pattern; |
||
4206 | |||
4207 | if (pattern->status) |
||
4208 | return pattern->status; |
||
4209 | |||
4210 | if (pattern->type != CAIRO_PATTERN_TYPE_RADIAL) |
||
4211 | return _cairo_error (CAIRO_STATUS_PATTERN_TYPE_MISMATCH); |
||
4212 | |||
4213 | if (x0) |
||
3959 | Serge | 4214 | *x0 = radial->cd1.center.x; |
1892 | serge | 4215 | if (y0) |
3959 | Serge | 4216 | *y0 = radial->cd1.center.y; |
1892 | serge | 4217 | if (r0) |
3959 | Serge | 4218 | *r0 = radial->cd1.radius; |
1892 | serge | 4219 | if (x1) |
3959 | Serge | 4220 | *x1 = radial->cd2.center.x; |
1892 | serge | 4221 | if (y1) |
3959 | Serge | 4222 | *y1 = radial->cd2.center.y; |
1892 | serge | 4223 | if (r1) |
3959 | Serge | 4224 | *r1 = radial->cd2.radius; |
1892 | serge | 4225 | |
4226 | return CAIRO_STATUS_SUCCESS; |
||
4227 | } |
||
4228 | |||
3959 | Serge | 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); |
||
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; |
||
4482 | if (y) |
||
4483 | *y = patch->points[i][j].y; |
||
4484 | |||
4485 | return CAIRO_STATUS_SUCCESS; |
||
4486 | } |
||
4487 | slim_hidden_def (cairo_mesh_pattern_get_control_point); |
||
4488 | |||
1892 | serge | 4489 | void |
4490 | _cairo_pattern_reset_static_data (void) |
||
4491 | { |
||
4492 | int i; |
||
4493 | |||
4494 | for (i = 0; i < ARRAY_LENGTH (freed_pattern_pool); i++) |
||
4495 | _freed_pool_reset (&freed_pattern_pool[i]); |
||
3959 | Serge | 4496 | } |
1892 | serge | 4497 | |
3959 | Serge | 4498 | static void |
4499 | _cairo_debug_print_surface_pattern (FILE *file, |
||
4500 | const cairo_surface_pattern_t *pattern) |
||
4501 | { |
||
4502 | printf (" surface type: %d\n", pattern->surface->type); |
||
1892 | serge | 4503 | } |
3959 | Serge | 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: |
||
4585 | _cairo_debug_print_radial_pattern (file, (cairo_radial_pattern_t *)pattern); |
||
4586 | break; |
||
4587 | case CAIRO_PATTERN_TYPE_MESH: |
||
4588 | _cairo_debug_print_mesh_pattern (file, (cairo_mesh_pattern_t *)pattern); |
||
4589 | break; |
||
4590 | } |
||
4591 | }>>>>>>>>>>>>>>>>>>>>>>>>>>>>=>=>>=>=> |