Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
3959 | Serge | 1 | /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */ |
2 | /* cairo - a vector graphics library with display and print output |
||
3 | * |
||
4 | * Copyright © 2002 University of Southern California |
||
5 | * Copyright © 2005 Red Hat, Inc. |
||
6 | * Copyright © 2011 Intel Corporation |
||
7 | * |
||
8 | * This library is free software; you can redistribute it and/or |
||
9 | * modify it either under the terms of the GNU Lesser General Public |
||
10 | * License version 2.1 as published by the Free Software Foundation |
||
11 | * (the "LGPL") or, at your option, under the terms of the Mozilla |
||
12 | * Public License Version 1.1 (the "MPL"). If you do not alter this |
||
13 | * notice, a recipient may use your version of this file under either |
||
14 | * the MPL or the LGPL. |
||
15 | * |
||
16 | * You should have received a copy of the LGPL along with this library |
||
17 | * in the file COPYING-LGPL-2.1; if not, write to the Free Software |
||
18 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA |
||
19 | * You should have received a copy of the MPL along with this library |
||
20 | * in the file COPYING-MPL-1.1 |
||
21 | * |
||
22 | * The contents of this file are subject to the Mozilla Public License |
||
23 | * Version 1.1 (the "License"); you may not use this file except in |
||
24 | * compliance with the License. You may obtain a copy of the License at |
||
25 | * http://www.mozilla.org/MPL/ |
||
26 | * |
||
27 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY |
||
28 | * OF ANY KIND, either express or implied. See the LGPL or the MPL for |
||
29 | * the specific language governing rights and limitations. |
||
30 | * |
||
31 | * The Original Code is the cairo graphics library. |
||
32 | * |
||
33 | * The Initial Developer of the Original Code is University of Southern |
||
34 | * California. |
||
35 | * |
||
36 | * Contributor(s): |
||
37 | * Carl D. Worth |
||
38 | * Joonas Pihlaja |
||
39 | * Chris Wilson |
||
40 | */ |
||
41 | |||
42 | #include "cairoint.h" |
||
43 | |||
44 | #include "cairo-box-inline.h" |
||
45 | #include "cairo-boxes-private.h" |
||
46 | #include "cairo-clip-inline.h" |
||
47 | #include "cairo-clip-private.h" |
||
48 | #include "cairo-composite-rectangles-private.h" |
||
49 | #include "cairo-compositor-private.h" |
||
50 | #include "cairo-error-private.h" |
||
51 | #include "cairo-image-surface-private.h" |
||
52 | #include "cairo-pattern-inline.h" |
||
53 | #include "cairo-paginated-private.h" |
||
54 | #include "cairo-recording-surface-inline.h" |
||
55 | #include "cairo-surface-subsurface-private.h" |
||
56 | #include "cairo-surface-snapshot-inline.h" |
||
57 | #include "cairo-surface-observer-private.h" |
||
58 | #include "cairo-region-private.h" |
||
59 | #include "cairo-spans-private.h" |
||
60 | #include "cairo-traps-private.h" |
||
61 | #include "cairo-tristrip-private.h" |
||
62 | |||
63 | typedef cairo_int_status_t |
||
64 | (*draw_func_t) (const cairo_traps_compositor_t *compositor, |
||
65 | cairo_surface_t *dst, |
||
66 | void *closure, |
||
67 | cairo_operator_t op, |
||
68 | cairo_surface_t *src, |
||
69 | int src_x, |
||
70 | int src_y, |
||
71 | int dst_x, |
||
72 | int dst_y, |
||
73 | const cairo_rectangle_int_t *extents, |
||
74 | cairo_clip_t *clip); |
||
75 | |||
76 | static void do_unaligned_row(void (*blt)(void *closure, |
||
77 | int16_t x, int16_t y, |
||
78 | int16_t w, int16_t h, |
||
79 | uint16_t coverage), |
||
80 | void *closure, |
||
81 | const cairo_box_t *b, |
||
82 | int tx, int y, int h, |
||
83 | uint16_t coverage) |
||
84 | { |
||
85 | int x1 = _cairo_fixed_integer_part (b->p1.x) - tx; |
||
86 | int x2 = _cairo_fixed_integer_part (b->p2.x) - tx; |
||
87 | if (x2 > x1) { |
||
88 | if (! _cairo_fixed_is_integer (b->p1.x)) { |
||
89 | blt(closure, x1, y, 1, h, |
||
90 | coverage * (256 - _cairo_fixed_fractional_part (b->p1.x))); |
||
91 | x1++; |
||
92 | } |
||
93 | |||
94 | if (x2 > x1) |
||
95 | blt(closure, x1, y, x2-x1, h, (coverage << 8) - (coverage >> 8)); |
||
96 | |||
97 | if (! _cairo_fixed_is_integer (b->p2.x)) |
||
98 | blt(closure, x2, y, 1, h, |
||
99 | coverage * _cairo_fixed_fractional_part (b->p2.x)); |
||
100 | } else |
||
101 | blt(closure, x1, y, 1, h, |
||
102 | coverage * (b->p2.x - b->p1.x)); |
||
103 | } |
||
104 | |||
105 | static void do_unaligned_box(void (*blt)(void *closure, |
||
106 | int16_t x, int16_t y, |
||
107 | int16_t w, int16_t h, |
||
108 | uint16_t coverage), |
||
109 | void *closure, |
||
110 | const cairo_box_t *b, int tx, int ty) |
||
111 | { |
||
112 | int y1 = _cairo_fixed_integer_part (b->p1.y) - ty; |
||
113 | int y2 = _cairo_fixed_integer_part (b->p2.y) - ty; |
||
114 | if (y2 > y1) { |
||
115 | if (! _cairo_fixed_is_integer (b->p1.y)) { |
||
116 | do_unaligned_row(blt, closure, b, tx, y1, 1, |
||
117 | 256 - _cairo_fixed_fractional_part (b->p1.y)); |
||
118 | y1++; |
||
119 | } |
||
120 | |||
121 | if (y2 > y1) |
||
122 | do_unaligned_row(blt, closure, b, tx, y1, y2-y1, 256); |
||
123 | |||
124 | if (! _cairo_fixed_is_integer (b->p2.y)) |
||
125 | do_unaligned_row(blt, closure, b, tx, y2, 1, |
||
126 | _cairo_fixed_fractional_part (b->p2.y)); |
||
127 | } else |
||
128 | do_unaligned_row(blt, closure, b, tx, y1, 1, |
||
129 | b->p2.y - b->p1.y); |
||
130 | } |
||
131 | |||
132 | struct blt_in { |
||
133 | const cairo_traps_compositor_t *compositor; |
||
134 | cairo_surface_t *dst; |
||
135 | cairo_boxes_t boxes; |
||
136 | }; |
||
137 | |||
138 | static void blt_in(void *closure, |
||
139 | int16_t x, int16_t y, |
||
140 | int16_t w, int16_t h, |
||
141 | uint16_t coverage) |
||
142 | { |
||
143 | struct blt_in *info = closure; |
||
144 | cairo_color_t color; |
||
145 | |||
146 | if (CAIRO_ALPHA_SHORT_IS_OPAQUE (coverage)) |
||
147 | return; |
||
148 | |||
149 | _cairo_box_from_integers (&info->boxes.chunks.base[0], x, y, w, h); |
||
150 | |||
151 | _cairo_color_init_rgba (&color, 0, 0, 0, coverage / (double) 0xffff); |
||
152 | info->compositor->fill_boxes (info->dst, |
||
153 | CAIRO_OPERATOR_IN, &color, |
||
154 | &info->boxes); |
||
155 | } |
||
156 | |||
157 | static void |
||
158 | add_rect_with_offset (cairo_boxes_t *boxes, int x1, int y1, int x2, int y2, int dx, int dy) |
||
159 | { |
||
160 | cairo_box_t box; |
||
161 | cairo_int_status_t status; |
||
162 | |||
163 | box.p1.x = _cairo_fixed_from_int (x1 - dx); |
||
164 | box.p1.y = _cairo_fixed_from_int (y1 - dy); |
||
165 | box.p2.x = _cairo_fixed_from_int (x2 - dx); |
||
166 | box.p2.y = _cairo_fixed_from_int (y2 - dy); |
||
167 | |||
168 | status = _cairo_boxes_add (boxes, CAIRO_ANTIALIAS_DEFAULT, &box); |
||
169 | assert (status == CAIRO_INT_STATUS_SUCCESS); |
||
170 | } |
||
171 | |||
172 | static cairo_int_status_t |
||
173 | combine_clip_as_traps (const cairo_traps_compositor_t *compositor, |
||
174 | cairo_surface_t *mask, |
||
175 | const cairo_clip_t *clip, |
||
176 | const cairo_rectangle_int_t *extents) |
||
177 | { |
||
178 | cairo_polygon_t polygon; |
||
179 | cairo_fill_rule_t fill_rule; |
||
180 | cairo_antialias_t antialias; |
||
181 | cairo_traps_t traps; |
||
182 | cairo_surface_t *src; |
||
183 | cairo_box_t box; |
||
184 | cairo_rectangle_int_t fixup; |
||
185 | int src_x, src_y; |
||
186 | cairo_int_status_t status; |
||
187 | |||
188 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
189 | |||
190 | status = _cairo_clip_get_polygon (clip, &polygon, |
||
191 | &fill_rule, &antialias); |
||
192 | if (status) |
||
193 | return status; |
||
194 | |||
195 | _cairo_traps_init (&traps); |
||
196 | status = _cairo_bentley_ottmann_tessellate_polygon (&traps, |
||
197 | &polygon, |
||
198 | fill_rule); |
||
199 | _cairo_polygon_fini (&polygon); |
||
200 | if (unlikely (status)) |
||
201 | return status; |
||
202 | |||
203 | src = compositor->pattern_to_surface (mask, NULL, FALSE, |
||
204 | extents, NULL, |
||
205 | &src_x, &src_y); |
||
206 | if (unlikely (src->status)) { |
||
207 | _cairo_traps_fini (&traps); |
||
208 | return src->status; |
||
209 | } |
||
210 | |||
211 | status = compositor->composite_traps (mask, CAIRO_OPERATOR_IN, src, |
||
212 | src_x, src_y, |
||
213 | extents->x, extents->y, |
||
214 | extents, |
||
215 | antialias, &traps); |
||
216 | |||
217 | _cairo_traps_extents (&traps, &box); |
||
218 | _cairo_box_round_to_rectangle (&box, &fixup); |
||
219 | _cairo_traps_fini (&traps); |
||
220 | cairo_surface_destroy (src); |
||
221 | |||
222 | if (unlikely (status)) |
||
223 | return status; |
||
224 | |||
225 | if (! _cairo_rectangle_intersect (&fixup, extents)) |
||
226 | return CAIRO_STATUS_SUCCESS; |
||
227 | |||
228 | if (fixup.width < extents->width || fixup.height < extents->height) { |
||
229 | cairo_boxes_t clear; |
||
230 | |||
231 | _cairo_boxes_init (&clear); |
||
232 | |||
233 | /* top */ |
||
234 | if (fixup.y != extents->y) { |
||
235 | add_rect_with_offset (&clear, |
||
236 | extents->x, extents->y, |
||
237 | extents->x + extents->width, |
||
238 | fixup.y, |
||
239 | extents->x, extents->y); |
||
240 | } |
||
241 | /* left */ |
||
242 | if (fixup.x != extents->x) { |
||
243 | add_rect_with_offset (&clear, |
||
244 | extents->x, fixup.y, |
||
245 | fixup.x, |
||
246 | fixup.y + fixup.height, |
||
247 | extents->x, extents->y); |
||
248 | } |
||
249 | /* right */ |
||
250 | if (fixup.x + fixup.width != extents->x + extents->width) { |
||
251 | add_rect_with_offset (&clear, |
||
252 | fixup.x + fixup.width, |
||
253 | fixup.y, |
||
254 | extents->x + extents->width, |
||
255 | fixup.y + fixup.height, |
||
256 | extents->x, extents->y); |
||
257 | } |
||
258 | /* bottom */ |
||
259 | if (fixup.y + fixup.height != extents->y + extents->height) { |
||
260 | add_rect_with_offset (&clear, |
||
261 | extents->x, |
||
262 | fixup.y + fixup.height, |
||
263 | extents->x + extents->width, |
||
264 | extents->y + extents->height, |
||
265 | extents->x, extents->y); |
||
266 | } |
||
267 | |||
268 | status = compositor->fill_boxes (mask, |
||
269 | CAIRO_OPERATOR_CLEAR, |
||
270 | CAIRO_COLOR_TRANSPARENT, |
||
271 | &clear); |
||
272 | |||
273 | _cairo_boxes_fini (&clear); |
||
274 | } |
||
275 | |||
276 | return status; |
||
277 | } |
||
278 | |||
279 | static cairo_status_t |
||
280 | __clip_to_surface (const cairo_traps_compositor_t *compositor, |
||
281 | const cairo_composite_rectangles_t *composite, |
||
282 | const cairo_rectangle_int_t *extents, |
||
283 | cairo_surface_t **surface) |
||
284 | { |
||
285 | cairo_surface_t *mask; |
||
286 | cairo_polygon_t polygon; |
||
287 | cairo_fill_rule_t fill_rule; |
||
288 | cairo_antialias_t antialias; |
||
289 | cairo_traps_t traps; |
||
290 | cairo_boxes_t clear; |
||
291 | cairo_surface_t *src; |
||
292 | int src_x, src_y; |
||
293 | cairo_int_status_t status; |
||
294 | |||
295 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
296 | |||
297 | status = _cairo_clip_get_polygon (composite->clip, &polygon, |
||
298 | &fill_rule, &antialias); |
||
299 | if (status) |
||
300 | return status; |
||
301 | |||
302 | _cairo_traps_init (&traps); |
||
303 | status = _cairo_bentley_ottmann_tessellate_polygon (&traps, |
||
304 | &polygon, |
||
305 | fill_rule); |
||
306 | _cairo_polygon_fini (&polygon); |
||
307 | if (unlikely (status)) |
||
308 | return status; |
||
309 | |||
310 | mask = _cairo_surface_create_similar_scratch (composite->surface, |
||
311 | CAIRO_CONTENT_ALPHA, |
||
312 | extents->width, |
||
313 | extents->height); |
||
314 | if (unlikely (mask->status)) { |
||
315 | _cairo_traps_fini (&traps); |
||
316 | return status; |
||
317 | } |
||
318 | |||
319 | src = compositor->pattern_to_surface (mask, NULL, FALSE, |
||
320 | extents, NULL, |
||
321 | &src_x, &src_y); |
||
322 | if (unlikely (status = src->status)) |
||
323 | goto error; |
||
324 | |||
325 | status = compositor->acquire (mask); |
||
326 | if (unlikely (status)) |
||
327 | goto error; |
||
328 | |||
329 | _cairo_boxes_init_from_rectangle (&clear, |
||
330 | 0, 0, |
||
331 | extents->width, |
||
332 | extents->height); |
||
333 | status = compositor->fill_boxes (mask, |
||
334 | CAIRO_OPERATOR_CLEAR, |
||
335 | CAIRO_COLOR_TRANSPARENT, |
||
336 | &clear); |
||
337 | if (unlikely (status)) |
||
338 | goto error_release; |
||
339 | |||
340 | status = compositor->composite_traps (mask, CAIRO_OPERATOR_ADD, src, |
||
341 | src_x, src_y, |
||
342 | extents->x, extents->y, |
||
343 | extents, |
||
344 | antialias, &traps); |
||
345 | if (unlikely (status)) |
||
346 | goto error_release; |
||
347 | |||
348 | compositor->release (mask); |
||
349 | *surface = mask; |
||
350 | out: |
||
351 | cairo_surface_destroy (src); |
||
352 | _cairo_traps_fini (&traps); |
||
353 | return status; |
||
354 | |||
355 | error_release: |
||
356 | compositor->release (mask); |
||
357 | error: |
||
358 | cairo_surface_destroy (mask); |
||
359 | goto out; |
||
360 | } |
||
361 | |||
362 | static cairo_surface_t * |
||
363 | traps_get_clip_surface (const cairo_traps_compositor_t *compositor, |
||
364 | const cairo_composite_rectangles_t *composite, |
||
365 | const cairo_rectangle_int_t *extents) |
||
366 | { |
||
367 | cairo_surface_t *surface = NULL; |
||
368 | cairo_int_status_t status; |
||
369 | |||
370 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
371 | |||
372 | status = __clip_to_surface (compositor, composite, extents, &surface); |
||
373 | if (status == CAIRO_INT_STATUS_UNSUPPORTED) { |
||
374 | surface = _cairo_surface_create_similar_solid (composite->surface, |
||
375 | CAIRO_CONTENT_ALPHA, |
||
376 | extents->width, |
||
377 | extents->height, |
||
378 | CAIRO_COLOR_WHITE); |
||
379 | if (unlikely (surface->status)) |
||
380 | return surface; |
||
381 | |||
382 | status = _cairo_clip_combine_with_surface (composite->clip, surface, |
||
383 | extents->x, extents->y); |
||
384 | } |
||
385 | if (unlikely (status)) { |
||
386 | cairo_surface_destroy (surface); |
||
387 | surface = _cairo_surface_create_in_error (status); |
||
388 | } |
||
389 | |||
390 | return surface; |
||
391 | } |
||
392 | |||
393 | static void blt_unaligned_boxes(const cairo_traps_compositor_t *compositor, |
||
394 | cairo_surface_t *surface, |
||
395 | int dx, int dy, |
||
396 | cairo_box_t *boxes, |
||
397 | int num_boxes) |
||
398 | { |
||
399 | struct blt_in info; |
||
400 | int i; |
||
401 | |||
402 | info.compositor = compositor; |
||
403 | info.dst = surface; |
||
404 | _cairo_boxes_init (&info.boxes); |
||
405 | info.boxes.num_boxes = 1; |
||
406 | for (i = 0; i < num_boxes; i++) { |
||
407 | cairo_box_t *b = &boxes[i]; |
||
408 | |||
409 | if (! _cairo_fixed_is_integer (b->p1.x) || |
||
410 | ! _cairo_fixed_is_integer (b->p1.y) || |
||
411 | ! _cairo_fixed_is_integer (b->p2.x) || |
||
412 | ! _cairo_fixed_is_integer (b->p2.y)) |
||
413 | { |
||
414 | do_unaligned_box(blt_in, &info, b, dx, dy); |
||
415 | } |
||
416 | } |
||
417 | } |
||
418 | |||
419 | static cairo_surface_t * |
||
420 | create_composite_mask (const cairo_traps_compositor_t *compositor, |
||
421 | cairo_surface_t *dst, |
||
422 | void *draw_closure, |
||
423 | draw_func_t draw_func, |
||
424 | draw_func_t mask_func, |
||
425 | const cairo_composite_rectangles_t *extents) |
||
426 | { |
||
427 | cairo_surface_t *surface, *src; |
||
428 | cairo_int_status_t status; |
||
429 | int src_x, src_y; |
||
430 | |||
431 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
432 | |||
433 | surface = _cairo_surface_create_similar_scratch (dst, CAIRO_CONTENT_ALPHA, |
||
434 | extents->bounded.width, |
||
435 | extents->bounded.height); |
||
436 | if (unlikely (surface->status)) |
||
437 | return surface; |
||
438 | |||
439 | src = compositor->pattern_to_surface (surface, |
||
440 | &_cairo_pattern_white.base, |
||
441 | FALSE, |
||
442 | &extents->bounded, |
||
443 | &extents->bounded, |
||
444 | &src_x, &src_y); |
||
445 | if (unlikely (src->status)) { |
||
446 | cairo_surface_destroy (surface); |
||
447 | return src; |
||
448 | } |
||
449 | |||
450 | status = compositor->acquire (surface); |
||
451 | if (unlikely (status)) { |
||
452 | cairo_surface_destroy (src); |
||
453 | cairo_surface_destroy (surface); |
||
454 | return _cairo_surface_create_in_error (status); |
||
455 | } |
||
456 | |||
457 | if (!surface->is_clear) { |
||
458 | cairo_boxes_t clear; |
||
459 | |||
460 | _cairo_boxes_init_from_rectangle (&clear, |
||
461 | 0, 0, |
||
462 | extents->bounded.width, |
||
463 | extents->bounded.height); |
||
464 | status = compositor->fill_boxes (surface, |
||
465 | CAIRO_OPERATOR_CLEAR, |
||
466 | CAIRO_COLOR_TRANSPARENT, |
||
467 | &clear); |
||
468 | if (unlikely (status)) |
||
469 | goto error; |
||
470 | |||
471 | surface->is_clear = TRUE; |
||
472 | } |
||
473 | |||
474 | if (mask_func) { |
||
475 | status = mask_func (compositor, surface, draw_closure, |
||
476 | CAIRO_OPERATOR_SOURCE, src, src_x, src_y, |
||
477 | extents->bounded.x, extents->bounded.y, |
||
478 | &extents->bounded, extents->clip); |
||
479 | if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { |
||
480 | surface->is_clear = FALSE; |
||
481 | goto out; |
||
482 | } |
||
483 | if (unlikely (status != CAIRO_INT_STATUS_UNSUPPORTED)) |
||
484 | goto error; |
||
485 | } |
||
486 | |||
487 | /* Is it worth setting the clip region here? */ |
||
488 | status = draw_func (compositor, surface, draw_closure, |
||
489 | CAIRO_OPERATOR_ADD, src, src_x, src_y, |
||
490 | extents->bounded.x, extents->bounded.y, |
||
491 | &extents->bounded, NULL); |
||
492 | if (unlikely (status)) |
||
493 | goto error; |
||
494 | |||
495 | surface->is_clear = FALSE; |
||
496 | if (extents->clip->path != NULL) { |
||
497 | status = combine_clip_as_traps (compositor, surface, |
||
498 | extents->clip, &extents->bounded); |
||
499 | if (status == CAIRO_INT_STATUS_UNSUPPORTED) { |
||
500 | status = _cairo_clip_combine_with_surface (extents->clip, surface, |
||
501 | extents->bounded.x, |
||
502 | extents->bounded.y); |
||
503 | } |
||
504 | if (unlikely (status)) |
||
505 | goto error; |
||
506 | } else if (extents->clip->boxes) { |
||
507 | blt_unaligned_boxes(compositor, surface, |
||
508 | extents->bounded.x, extents->bounded.y, |
||
509 | extents->clip->boxes, extents->clip->num_boxes); |
||
510 | |||
511 | } |
||
512 | |||
513 | out: |
||
514 | compositor->release (surface); |
||
515 | cairo_surface_destroy (src); |
||
516 | return surface; |
||
517 | |||
518 | error: |
||
519 | compositor->release (surface); |
||
520 | if (status != CAIRO_INT_STATUS_NOTHING_TO_DO) { |
||
521 | cairo_surface_destroy (surface); |
||
522 | surface = _cairo_surface_create_in_error (status); |
||
523 | } |
||
524 | cairo_surface_destroy (src); |
||
525 | return surface; |
||
526 | } |
||
527 | |||
528 | /* Handles compositing with a clip surface when the operator allows |
||
529 | * us to combine the clip with the mask |
||
530 | */ |
||
531 | static cairo_status_t |
||
532 | clip_and_composite_with_mask (const cairo_traps_compositor_t *compositor, |
||
533 | const cairo_composite_rectangles_t*extents, |
||
534 | draw_func_t draw_func, |
||
535 | draw_func_t mask_func, |
||
536 | void *draw_closure, |
||
537 | cairo_operator_t op, |
||
538 | cairo_surface_t *src, |
||
539 | int src_x, int src_y) |
||
540 | { |
||
541 | cairo_surface_t *dst = extents->surface; |
||
542 | cairo_surface_t *mask; |
||
543 | |||
544 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
545 | |||
546 | mask = create_composite_mask (compositor, dst, draw_closure, |
||
547 | draw_func, mask_func, |
||
548 | extents); |
||
549 | if (unlikely (mask->status)) |
||
550 | return mask->status; |
||
551 | |||
552 | if (mask->is_clear) |
||
553 | goto skip; |
||
554 | |||
555 | if (src != NULL || dst->content != CAIRO_CONTENT_ALPHA) { |
||
556 | compositor->composite (dst, op, src, mask, |
||
557 | extents->bounded.x + src_x, |
||
558 | extents->bounded.y + src_y, |
||
559 | 0, 0, |
||
560 | extents->bounded.x, extents->bounded.y, |
||
561 | extents->bounded.width, extents->bounded.height); |
||
562 | } else { |
||
563 | compositor->composite (dst, op, mask, NULL, |
||
564 | 0, 0, |
||
565 | 0, 0, |
||
566 | extents->bounded.x, extents->bounded.y, |
||
567 | extents->bounded.width, extents->bounded.height); |
||
568 | } |
||
569 | |||
570 | skip: |
||
571 | cairo_surface_destroy (mask); |
||
572 | return CAIRO_STATUS_SUCCESS; |
||
573 | } |
||
574 | |||
575 | /* Handles compositing with a clip surface when we have to do the operation |
||
576 | * in two pieces and combine them together. |
||
577 | */ |
||
578 | static cairo_status_t |
||
579 | clip_and_composite_combine (const cairo_traps_compositor_t *compositor, |
||
580 | const cairo_composite_rectangles_t*extents, |
||
581 | draw_func_t draw_func, |
||
582 | void *draw_closure, |
||
583 | cairo_operator_t op, |
||
584 | cairo_surface_t *src, |
||
585 | int src_x, int src_y) |
||
586 | { |
||
587 | cairo_surface_t *dst = extents->surface; |
||
588 | cairo_surface_t *tmp, *clip; |
||
589 | cairo_status_t status; |
||
590 | |||
591 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
592 | |||
593 | tmp = _cairo_surface_create_similar_scratch (dst, dst->content, |
||
594 | extents->bounded.width, |
||
595 | extents->bounded.height); |
||
596 | if (unlikely (tmp->status)) |
||
597 | return tmp->status; |
||
598 | |||
599 | status = compositor->acquire (tmp); |
||
600 | if (unlikely (status)) { |
||
601 | cairo_surface_destroy (tmp); |
||
602 | return status; |
||
603 | } |
||
604 | |||
605 | compositor->composite (tmp, |
||
606 | dst->is_clear ? CAIRO_OPERATOR_CLEAR : CAIRO_OPERATOR_SOURCE, |
||
607 | dst, NULL, |
||
608 | extents->bounded.x, extents->bounded.y, |
||
609 | 0, 0, |
||
610 | 0, 0, |
||
611 | extents->bounded.width, extents->bounded.height); |
||
612 | |||
613 | status = draw_func (compositor, tmp, draw_closure, op, |
||
614 | src, src_x, src_y, |
||
615 | extents->bounded.x, extents->bounded.y, |
||
616 | &extents->bounded, NULL); |
||
617 | |||
618 | if (unlikely (status)) |
||
619 | goto cleanup; |
||
620 | |||
621 | clip = traps_get_clip_surface (compositor, extents, &extents->bounded); |
||
622 | if (unlikely ((status = clip->status))) |
||
623 | goto cleanup; |
||
624 | |||
625 | if (dst->is_clear) { |
||
626 | compositor->composite (dst, CAIRO_OPERATOR_SOURCE, tmp, clip, |
||
627 | 0, 0, |
||
628 | 0, 0, |
||
629 | extents->bounded.x, extents->bounded.y, |
||
630 | extents->bounded.width, extents->bounded.height); |
||
631 | } else { |
||
632 | compositor->lerp (dst, tmp, clip, |
||
633 | 0, 0, |
||
634 | 0,0, |
||
635 | extents->bounded.x, extents->bounded.y, |
||
636 | extents->bounded.width, extents->bounded.height); |
||
637 | } |
||
638 | cairo_surface_destroy (clip); |
||
639 | |||
640 | cleanup: |
||
641 | compositor->release (tmp); |
||
642 | cairo_surface_destroy (tmp); |
||
643 | |||
644 | return status; |
||
645 | } |
||
646 | |||
647 | /* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's |
||
648 | * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip)) |
||
649 | */ |
||
650 | static cairo_status_t |
||
651 | clip_and_composite_source (const cairo_traps_compositor_t *compositor, |
||
652 | cairo_surface_t *dst, |
||
653 | draw_func_t draw_func, |
||
654 | draw_func_t mask_func, |
||
655 | void *draw_closure, |
||
656 | cairo_surface_t *src, |
||
657 | int src_x, |
||
658 | int src_y, |
||
659 | const cairo_composite_rectangles_t *extents) |
||
660 | { |
||
661 | cairo_surface_t *mask; |
||
662 | |||
663 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
664 | |||
665 | /* Create a surface that is mask IN clip */ |
||
666 | mask = create_composite_mask (compositor, dst, draw_closure, |
||
667 | draw_func, mask_func, |
||
668 | extents); |
||
669 | if (unlikely (mask->status)) |
||
670 | return mask->status; |
||
671 | |||
672 | if (mask->is_clear) |
||
673 | goto skip; |
||
674 | |||
675 | if (dst->is_clear) { |
||
676 | compositor->composite (dst, CAIRO_OPERATOR_SOURCE, src, mask, |
||
677 | extents->bounded.x + src_x, extents->bounded.y + src_y, |
||
678 | 0, 0, |
||
679 | extents->bounded.x, extents->bounded.y, |
||
680 | extents->bounded.width, extents->bounded.height); |
||
681 | } else { |
||
682 | compositor->lerp (dst, src, mask, |
||
683 | extents->bounded.x + src_x, extents->bounded.y + src_y, |
||
684 | 0, 0, |
||
685 | extents->bounded.x, extents->bounded.y, |
||
686 | extents->bounded.width, extents->bounded.height); |
||
687 | } |
||
688 | |||
689 | skip: |
||
690 | cairo_surface_destroy (mask); |
||
691 | |||
692 | return CAIRO_STATUS_SUCCESS; |
||
693 | } |
||
694 | |||
695 | static cairo_bool_t |
||
696 | can_reduce_alpha_op (cairo_operator_t op) |
||
697 | { |
||
698 | int iop = op; |
||
699 | switch (iop) { |
||
700 | case CAIRO_OPERATOR_OVER: |
||
701 | case CAIRO_OPERATOR_SOURCE: |
||
702 | case CAIRO_OPERATOR_ADD: |
||
703 | return TRUE; |
||
704 | default: |
||
705 | return FALSE; |
||
706 | } |
||
707 | } |
||
708 | |||
709 | static cairo_bool_t |
||
710 | reduce_alpha_op (cairo_composite_rectangles_t *extents) |
||
711 | { |
||
712 | cairo_surface_t *dst = extents->surface; |
||
713 | cairo_operator_t op = extents->op; |
||
714 | const cairo_pattern_t *pattern = &extents->source_pattern.base; |
||
715 | return dst->is_clear && |
||
716 | dst->content == CAIRO_CONTENT_ALPHA && |
||
717 | _cairo_pattern_is_opaque_solid (pattern) && |
||
718 | can_reduce_alpha_op (op); |
||
719 | } |
||
720 | |||
721 | static cairo_status_t |
||
722 | fixup_unbounded_with_mask (const cairo_traps_compositor_t *compositor, |
||
723 | const cairo_composite_rectangles_t *extents) |
||
724 | { |
||
725 | cairo_surface_t *dst = extents->surface; |
||
726 | cairo_surface_t *mask; |
||
727 | |||
728 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
729 | |||
730 | /* XXX can we avoid querying the clip surface again? */ |
||
731 | mask = traps_get_clip_surface (compositor, extents, &extents->unbounded); |
||
732 | if (unlikely (mask->status)) |
||
733 | return mask->status; |
||
734 | |||
735 | /* top */ |
||
736 | if (extents->bounded.y != extents->unbounded.y) { |
||
737 | int x = extents->unbounded.x; |
||
738 | int y = extents->unbounded.y; |
||
739 | int width = extents->unbounded.width; |
||
740 | int height = extents->bounded.y - y; |
||
741 | |||
742 | compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL, |
||
743 | 0, 0, |
||
744 | 0, 0, |
||
745 | x, y, |
||
746 | width, height); |
||
747 | } |
||
748 | |||
749 | /* left */ |
||
750 | if (extents->bounded.x != extents->unbounded.x) { |
||
751 | int x = extents->unbounded.x; |
||
752 | int y = extents->bounded.y; |
||
753 | int width = extents->bounded.x - x; |
||
754 | int height = extents->bounded.height; |
||
755 | |||
756 | compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL, |
||
757 | 0, y - extents->unbounded.y, |
||
758 | 0, 0, |
||
759 | x, y, |
||
760 | width, height); |
||
761 | } |
||
762 | |||
763 | /* right */ |
||
764 | if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) { |
||
765 | int x = extents->bounded.x + extents->bounded.width; |
||
766 | int y = extents->bounded.y; |
||
767 | int width = extents->unbounded.x + extents->unbounded.width - x; |
||
768 | int height = extents->bounded.height; |
||
769 | |||
770 | compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL, |
||
771 | x - extents->unbounded.x, y - extents->unbounded.y, |
||
772 | 0, 0, |
||
773 | x, y, |
||
774 | width, height); |
||
775 | } |
||
776 | |||
777 | /* bottom */ |
||
778 | if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) { |
||
779 | int x = extents->unbounded.x; |
||
780 | int y = extents->bounded.y + extents->bounded.height; |
||
781 | int width = extents->unbounded.width; |
||
782 | int height = extents->unbounded.y + extents->unbounded.height - y; |
||
783 | |||
784 | compositor->composite (dst, CAIRO_OPERATOR_DEST_OUT, mask, NULL, |
||
785 | 0, y - extents->unbounded.y, |
||
786 | 0, 0, |
||
787 | x, y, |
||
788 | width, height); |
||
789 | } |
||
790 | |||
791 | cairo_surface_destroy (mask); |
||
792 | |||
793 | return CAIRO_STATUS_SUCCESS; |
||
794 | } |
||
795 | |||
796 | static void |
||
797 | add_rect (cairo_boxes_t *boxes, int x1, int y1, int x2, int y2) |
||
798 | { |
||
799 | cairo_box_t box; |
||
800 | cairo_int_status_t status; |
||
801 | |||
802 | box.p1.x = _cairo_fixed_from_int (x1); |
||
803 | box.p1.y = _cairo_fixed_from_int (y1); |
||
804 | box.p2.x = _cairo_fixed_from_int (x2); |
||
805 | box.p2.y = _cairo_fixed_from_int (y2); |
||
806 | |||
807 | status = _cairo_boxes_add (boxes, CAIRO_ANTIALIAS_DEFAULT, &box); |
||
808 | assert (status == CAIRO_INT_STATUS_SUCCESS); |
||
809 | } |
||
810 | |||
811 | static cairo_status_t |
||
812 | fixup_unbounded (const cairo_traps_compositor_t *compositor, |
||
813 | cairo_composite_rectangles_t *extents, |
||
814 | cairo_boxes_t *boxes) |
||
815 | { |
||
816 | cairo_surface_t *dst = extents->surface; |
||
817 | cairo_boxes_t clear, tmp; |
||
818 | cairo_box_t box; |
||
819 | cairo_int_status_t status; |
||
820 | |||
821 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
822 | |||
823 | if (extents->bounded.width == extents->unbounded.width && |
||
824 | extents->bounded.height == extents->unbounded.height) |
||
825 | { |
||
826 | return CAIRO_STATUS_SUCCESS; |
||
827 | } |
||
828 | |||
829 | assert (extents->clip->path == NULL); |
||
830 | |||
831 | /* subtract the drawn boxes from the unbounded area */ |
||
832 | _cairo_boxes_init (&clear); |
||
833 | |||
834 | box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width); |
||
835 | box.p1.y = _cairo_fixed_from_int (extents->unbounded.y); |
||
836 | box.p2.x = _cairo_fixed_from_int (extents->unbounded.x); |
||
837 | box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height); |
||
838 | |||
839 | if (boxes == NULL) { |
||
840 | if (extents->bounded.width == 0 || extents->bounded.height == 0) { |
||
841 | goto empty; |
||
842 | } else { |
||
843 | /* top */ |
||
844 | if (extents->bounded.y != extents->unbounded.y) { |
||
845 | add_rect (&clear, |
||
846 | extents->unbounded.x, extents->unbounded.y, |
||
847 | extents->unbounded.x + extents->unbounded.width, |
||
848 | extents->bounded.y); |
||
849 | } |
||
850 | /* left */ |
||
851 | if (extents->bounded.x != extents->unbounded.x) { |
||
852 | add_rect (&clear, |
||
853 | extents->unbounded.x, extents->bounded.y, |
||
854 | extents->bounded.x, |
||
855 | extents->bounded.y + extents->bounded.height); |
||
856 | } |
||
857 | /* right */ |
||
858 | if (extents->bounded.x + extents->bounded.width != extents->unbounded.x + extents->unbounded.width) { |
||
859 | add_rect (&clear, |
||
860 | extents->bounded.x + extents->bounded.width, |
||
861 | extents->bounded.y, |
||
862 | extents->unbounded.x + extents->unbounded.width, |
||
863 | extents->bounded.y + extents->bounded.height); |
||
864 | } |
||
865 | /* bottom */ |
||
866 | if (extents->bounded.y + extents->bounded.height != extents->unbounded.y + extents->unbounded.height) { |
||
867 | add_rect (&clear, |
||
868 | extents->unbounded.x, |
||
869 | extents->bounded.y + extents->bounded.height, |
||
870 | extents->unbounded.x + extents->unbounded.width, |
||
871 | extents->unbounded.y + extents->unbounded.height); |
||
872 | } |
||
873 | } |
||
874 | } else if (boxes->num_boxes) { |
||
875 | _cairo_boxes_init (&tmp); |
||
876 | |||
877 | assert (boxes->is_pixel_aligned); |
||
878 | |||
879 | status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box); |
||
880 | assert (status == CAIRO_INT_STATUS_SUCCESS); |
||
881 | |||
882 | tmp.chunks.next = &boxes->chunks; |
||
883 | tmp.num_boxes += boxes->num_boxes; |
||
884 | |||
885 | status = _cairo_bentley_ottmann_tessellate_boxes (&tmp, |
||
886 | CAIRO_FILL_RULE_WINDING, |
||
887 | &clear); |
||
888 | tmp.chunks.next = NULL; |
||
889 | if (unlikely (status)) |
||
890 | goto error; |
||
891 | } else { |
||
892 | empty: |
||
893 | box.p1.x = _cairo_fixed_from_int (extents->unbounded.x); |
||
894 | box.p2.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width); |
||
895 | |||
896 | status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box); |
||
897 | assert (status == CAIRO_INT_STATUS_SUCCESS); |
||
898 | } |
||
899 | |||
900 | /* Now intersect with the clip boxes */ |
||
901 | if (extents->clip->num_boxes) { |
||
902 | _cairo_boxes_init_for_array (&tmp, |
||
903 | extents->clip->boxes, |
||
904 | extents->clip->num_boxes); |
||
905 | status = _cairo_boxes_intersect (&clear, &tmp, &clear); |
||
906 | if (unlikely (status)) |
||
907 | goto error; |
||
908 | } |
||
909 | |||
910 | status = compositor->fill_boxes (dst, |
||
911 | CAIRO_OPERATOR_CLEAR, |
||
912 | CAIRO_COLOR_TRANSPARENT, |
||
913 | &clear); |
||
914 | |||
915 | error: |
||
916 | _cairo_boxes_fini (&clear); |
||
917 | return status; |
||
918 | } |
||
919 | |||
920 | enum { |
||
921 | NEED_CLIP_REGION = 0x1, |
||
922 | NEED_CLIP_SURFACE = 0x2, |
||
923 | FORCE_CLIP_REGION = 0x4, |
||
924 | }; |
||
925 | |||
926 | static cairo_bool_t |
||
927 | need_bounded_clip (cairo_composite_rectangles_t *extents) |
||
928 | { |
||
929 | unsigned int flags = 0; |
||
930 | |||
931 | if (extents->clip->num_boxes > 1 || |
||
932 | extents->mask.width > extents->unbounded.width || |
||
933 | extents->mask.height > extents->unbounded.height) |
||
934 | { |
||
935 | flags |= NEED_CLIP_REGION; |
||
936 | } |
||
937 | |||
938 | if (extents->clip->num_boxes > 1 || |
||
939 | extents->mask.width > extents->bounded.width || |
||
940 | extents->mask.height > extents->bounded.height) |
||
941 | { |
||
942 | flags |= FORCE_CLIP_REGION; |
||
943 | } |
||
944 | |||
945 | if (! _cairo_clip_is_region (extents->clip)) |
||
946 | flags |= NEED_CLIP_SURFACE; |
||
947 | |||
948 | return flags; |
||
949 | } |
||
950 | |||
951 | static cairo_bool_t |
||
952 | need_unbounded_clip (cairo_composite_rectangles_t *extents) |
||
953 | { |
||
954 | unsigned int flags = 0; |
||
955 | if (! extents->is_bounded) { |
||
956 | flags |= NEED_CLIP_REGION; |
||
957 | if (! _cairo_clip_is_region (extents->clip)) |
||
958 | flags |= NEED_CLIP_SURFACE; |
||
959 | } |
||
960 | if (extents->clip->path != NULL) |
||
961 | flags |= NEED_CLIP_SURFACE; |
||
962 | return flags; |
||
963 | } |
||
964 | |||
965 | static cairo_status_t |
||
966 | clip_and_composite (const cairo_traps_compositor_t *compositor, |
||
967 | cairo_composite_rectangles_t *extents, |
||
968 | draw_func_t draw_func, |
||
969 | draw_func_t mask_func, |
||
970 | void *draw_closure, |
||
971 | unsigned int need_clip) |
||
972 | { |
||
973 | cairo_surface_t *dst = extents->surface; |
||
974 | cairo_operator_t op = extents->op; |
||
975 | cairo_pattern_t *source = &extents->source_pattern.base; |
||
976 | cairo_surface_t *src; |
||
977 | int src_x, src_y; |
||
978 | cairo_region_t *clip_region = NULL; |
||
979 | cairo_status_t status = CAIRO_STATUS_SUCCESS; |
||
980 | |||
981 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
982 | |||
983 | if (reduce_alpha_op (extents)) { |
||
984 | op = CAIRO_OPERATOR_ADD; |
||
985 | source = NULL; |
||
986 | } |
||
987 | |||
988 | if (op == CAIRO_OPERATOR_CLEAR) { |
||
989 | op = CAIRO_OPERATOR_DEST_OUT; |
||
990 | source = NULL; |
||
991 | } |
||
992 | |||
993 | compositor->acquire (dst); |
||
994 | |||
995 | if (need_clip & NEED_CLIP_REGION) { |
||
996 | const cairo_rectangle_int_t *limit; |
||
997 | |||
998 | if ((need_clip & FORCE_CLIP_REGION) == 0) |
||
999 | limit = &extents->unbounded; |
||
1000 | else |
||
1001 | limit = &extents->destination; |
||
1002 | |||
1003 | clip_region = _cairo_clip_get_region (extents->clip); |
||
1004 | if (clip_region != NULL && |
||
1005 | cairo_region_contains_rectangle (clip_region, |
||
1006 | limit) == CAIRO_REGION_OVERLAP_IN) |
||
1007 | clip_region = NULL; |
||
1008 | |||
1009 | if (clip_region != NULL) { |
||
1010 | status = compositor->set_clip_region (dst, clip_region); |
||
1011 | if (unlikely (status)) { |
||
1012 | compositor->release (dst); |
||
1013 | return status; |
||
1014 | } |
||
1015 | } |
||
1016 | } |
||
1017 | |||
1018 | if (extents->bounded.width == 0 || extents->bounded.height == 0) |
||
1019 | goto skip; |
||
1020 | |||
1021 | src = compositor->pattern_to_surface (dst, source, FALSE, |
||
1022 | &extents->bounded, |
||
1023 | &extents->source_sample_area, |
||
1024 | &src_x, &src_y); |
||
1025 | if (unlikely (status = src->status)) |
||
1026 | goto error; |
||
1027 | |||
1028 | if (op == CAIRO_OPERATOR_SOURCE) { |
||
1029 | status = clip_and_composite_source (compositor, dst, |
||
1030 | draw_func, mask_func, draw_closure, |
||
1031 | src, src_x, src_y, |
||
1032 | extents); |
||
1033 | } else { |
||
1034 | if (need_clip & NEED_CLIP_SURFACE) { |
||
1035 | if (extents->is_bounded) { |
||
1036 | status = clip_and_composite_with_mask (compositor, extents, |
||
1037 | draw_func, mask_func, |
||
1038 | draw_closure, |
||
1039 | op, src, src_x, src_y); |
||
1040 | } else { |
||
1041 | status = clip_and_composite_combine (compositor, extents, |
||
1042 | draw_func, draw_closure, |
||
1043 | op, src, src_x, src_y); |
||
1044 | } |
||
1045 | } else { |
||
1046 | status = draw_func (compositor, |
||
1047 | dst, draw_closure, |
||
1048 | op, src, src_x, src_y, |
||
1049 | 0, 0, |
||
1050 | &extents->bounded, |
||
1051 | extents->clip); |
||
1052 | } |
||
1053 | } |
||
1054 | cairo_surface_destroy (src); |
||
1055 | |||
1056 | skip: |
||
1057 | if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) { |
||
1058 | if (need_clip & NEED_CLIP_SURFACE) |
||
1059 | status = fixup_unbounded_with_mask (compositor, extents); |
||
1060 | else |
||
1061 | status = fixup_unbounded (compositor, extents, NULL); |
||
1062 | } |
||
1063 | |||
1064 | error: |
||
1065 | if (clip_region) |
||
1066 | compositor->set_clip_region (dst, NULL); |
||
1067 | |||
1068 | compositor->release (dst); |
||
1069 | |||
1070 | return status; |
||
1071 | } |
||
1072 | |||
1073 | /* meta-ops */ |
||
1074 | |||
1075 | typedef struct { |
||
1076 | cairo_traps_t traps; |
||
1077 | cairo_antialias_t antialias; |
||
1078 | } composite_traps_info_t; |
||
1079 | |||
1080 | static cairo_int_status_t |
||
1081 | composite_traps (const cairo_traps_compositor_t *compositor, |
||
1082 | cairo_surface_t *dst, |
||
1083 | void *closure, |
||
1084 | cairo_operator_t op, |
||
1085 | cairo_surface_t *src, |
||
1086 | int src_x, int src_y, |
||
1087 | int dst_x, int dst_y, |
||
1088 | const cairo_rectangle_int_t *extents, |
||
1089 | cairo_clip_t *clip) |
||
1090 | { |
||
1091 | composite_traps_info_t *info = closure; |
||
1092 | |||
1093 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
1094 | |||
1095 | return compositor->composite_traps (dst, op, src, |
||
1096 | src_x - dst_x, src_y - dst_y, |
||
1097 | dst_x, dst_y, |
||
1098 | extents, |
||
1099 | info->antialias, &info->traps); |
||
1100 | } |
||
1101 | |||
1102 | typedef struct { |
||
1103 | cairo_tristrip_t strip; |
||
1104 | cairo_antialias_t antialias; |
||
1105 | } composite_tristrip_info_t; |
||
1106 | |||
1107 | static cairo_int_status_t |
||
1108 | composite_tristrip (const cairo_traps_compositor_t *compositor, |
||
1109 | cairo_surface_t *dst, |
||
1110 | void *closure, |
||
1111 | cairo_operator_t op, |
||
1112 | cairo_surface_t *src, |
||
1113 | int src_x, int src_y, |
||
1114 | int dst_x, int dst_y, |
||
1115 | const cairo_rectangle_int_t *extents, |
||
1116 | cairo_clip_t *clip) |
||
1117 | { |
||
1118 | composite_tristrip_info_t *info = closure; |
||
1119 | |||
1120 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
1121 | |||
1122 | return compositor->composite_tristrip (dst, op, src, |
||
1123 | src_x - dst_x, src_y - dst_y, |
||
1124 | dst_x, dst_y, |
||
1125 | extents, |
||
1126 | info->antialias, &info->strip); |
||
1127 | } |
||
1128 | |||
1129 | static cairo_bool_t |
||
1130 | is_recording_pattern (const cairo_pattern_t *pattern) |
||
1131 | { |
||
1132 | cairo_surface_t *surface; |
||
1133 | |||
1134 | if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE) |
||
1135 | return FALSE; |
||
1136 | |||
1137 | surface = ((const cairo_surface_pattern_t *) pattern)->surface; |
||
1138 | surface = _cairo_surface_get_source (surface, NULL); |
||
1139 | return _cairo_surface_is_recording (surface); |
||
1140 | } |
||
1141 | |||
1142 | static cairo_surface_t * |
||
1143 | recording_pattern_get_surface (const cairo_pattern_t *pattern) |
||
1144 | { |
||
1145 | cairo_surface_t *surface; |
||
1146 | |||
1147 | surface = ((const cairo_surface_pattern_t *) pattern)->surface; |
||
1148 | return _cairo_surface_get_source (surface, NULL); |
||
1149 | } |
||
1150 | |||
1151 | static cairo_bool_t |
||
1152 | recording_pattern_contains_sample (const cairo_pattern_t *pattern, |
||
1153 | const cairo_rectangle_int_t *sample) |
||
1154 | { |
||
1155 | cairo_recording_surface_t *surface; |
||
1156 | |||
1157 | if (! is_recording_pattern (pattern)) |
||
1158 | return FALSE; |
||
1159 | |||
1160 | if (pattern->extend == CAIRO_EXTEND_NONE) |
||
1161 | return TRUE; |
||
1162 | |||
1163 | surface = (cairo_recording_surface_t *) recording_pattern_get_surface (pattern); |
||
1164 | if (surface->unbounded) |
||
1165 | return TRUE; |
||
1166 | |||
1167 | return _cairo_rectangle_contains_rectangle (&surface->extents, sample); |
||
1168 | } |
||
1169 | |||
1170 | static cairo_bool_t |
||
1171 | op_reduces_to_source (cairo_composite_rectangles_t *extents) |
||
1172 | { |
||
1173 | if (extents->op == CAIRO_OPERATOR_SOURCE) |
||
1174 | return TRUE; |
||
1175 | |||
1176 | if (extents->surface->is_clear) |
||
1177 | return extents->op == CAIRO_OPERATOR_OVER || extents->op == CAIRO_OPERATOR_ADD; |
||
1178 | |||
1179 | return FALSE; |
||
1180 | } |
||
1181 | |||
1182 | static cairo_status_t |
||
1183 | composite_aligned_boxes (const cairo_traps_compositor_t *compositor, |
||
1184 | cairo_composite_rectangles_t *extents, |
||
1185 | cairo_boxes_t *boxes) |
||
1186 | { |
||
1187 | cairo_surface_t *dst = extents->surface; |
||
1188 | cairo_operator_t op = extents->op; |
||
1189 | cairo_bool_t need_clip_mask = ! _cairo_clip_is_region (extents->clip); |
||
1190 | cairo_bool_t op_is_source; |
||
1191 | cairo_status_t status; |
||
1192 | |||
1193 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
1194 | |||
1195 | if (need_clip_mask && |
||
1196 | (! extents->is_bounded || extents->op == CAIRO_OPERATOR_SOURCE)) |
||
1197 | { |
||
1198 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
1199 | } |
||
1200 | |||
1201 | op_is_source = op_reduces_to_source (extents); |
||
1202 | |||
1203 | /* Are we just copying a recording surface? */ |
||
1204 | if (! need_clip_mask && op_is_source && |
||
1205 | recording_pattern_contains_sample (&extents->source_pattern.base, |
||
1206 | &extents->source_sample_area)) |
||
1207 | { |
||
1208 | cairo_clip_t *recording_clip; |
||
1209 | cairo_pattern_t *source = &extents->source_pattern.base; |
||
1210 | |||
1211 | /* XXX could also do tiling repeat modes... */ |
||
1212 | |||
1213 | /* first clear the area about to be overwritten */ |
||
1214 | if (! dst->is_clear) { |
||
1215 | status = compositor->acquire (dst); |
||
1216 | if (unlikely (status)) |
||
1217 | return status; |
||
1218 | |||
1219 | status = compositor->fill_boxes (dst, |
||
1220 | CAIRO_OPERATOR_CLEAR, |
||
1221 | CAIRO_COLOR_TRANSPARENT, |
||
1222 | boxes); |
||
1223 | compositor->release (dst); |
||
1224 | if (unlikely (status)) |
||
1225 | return status; |
||
1226 | } |
||
1227 | |||
1228 | recording_clip = _cairo_clip_from_boxes (boxes); |
||
1229 | status = _cairo_recording_surface_replay_with_clip (recording_pattern_get_surface (source), |
||
1230 | &source->matrix, |
||
1231 | dst, recording_clip); |
||
1232 | _cairo_clip_destroy (recording_clip); |
||
1233 | |||
1234 | return status; |
||
1235 | } |
||
1236 | |||
1237 | status = compositor->acquire (dst); |
||
1238 | if (unlikely (status)) |
||
1239 | return status; |
||
1240 | |||
1241 | if (! need_clip_mask && |
||
1242 | (op == CAIRO_OPERATOR_CLEAR || |
||
1243 | extents->source_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID)) |
||
1244 | { |
||
1245 | const cairo_color_t *color; |
||
1246 | |||
1247 | if (op == CAIRO_OPERATOR_CLEAR) { |
||
1248 | color = CAIRO_COLOR_TRANSPARENT; |
||
1249 | } else { |
||
1250 | color = &((cairo_solid_pattern_t *) &extents->source_pattern)->color; |
||
1251 | if (op_is_source) |
||
1252 | op = CAIRO_OPERATOR_SOURCE; |
||
1253 | } |
||
1254 | |||
1255 | status = compositor->fill_boxes (dst, op, color, boxes); |
||
1256 | } |
||
1257 | else |
||
1258 | { |
||
1259 | cairo_surface_t *src, *mask = NULL; |
||
1260 | cairo_pattern_t *source = &extents->source_pattern.base; |
||
1261 | int src_x, src_y; |
||
1262 | int mask_x = 0, mask_y = 0; |
||
1263 | |||
1264 | if (need_clip_mask) { |
||
1265 | mask = traps_get_clip_surface (compositor, |
||
1266 | extents, &extents->bounded); |
||
1267 | if (unlikely (mask->status)) |
||
1268 | return mask->status; |
||
1269 | |||
1270 | mask_x = -extents->bounded.x; |
||
1271 | mask_y = -extents->bounded.y; |
||
1272 | |||
1273 | if (op == CAIRO_OPERATOR_CLEAR) { |
||
1274 | source = NULL; |
||
1275 | op = CAIRO_OPERATOR_DEST_OUT; |
||
1276 | } |
||
1277 | } else if (op_is_source) |
||
1278 | op = CAIRO_OPERATOR_SOURCE; |
||
1279 | |||
1280 | src = compositor->pattern_to_surface (dst, source, FALSE, |
||
1281 | &extents->bounded, |
||
1282 | &extents->source_sample_area, |
||
1283 | &src_x, &src_y); |
||
1284 | if (likely (src->status == CAIRO_STATUS_SUCCESS)) { |
||
1285 | status = compositor->composite_boxes (dst, op, src, mask, |
||
1286 | src_x, src_y, |
||
1287 | mask_x, mask_y, |
||
1288 | 0, 0, |
||
1289 | boxes, &extents->bounded); |
||
1290 | cairo_surface_destroy (src); |
||
1291 | } else |
||
1292 | status = src->status; |
||
1293 | |||
1294 | cairo_surface_destroy (mask); |
||
1295 | } |
||
1296 | |||
1297 | if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded) |
||
1298 | status = fixup_unbounded (compositor, extents, boxes); |
||
1299 | |||
1300 | compositor->release (dst); |
||
1301 | |||
1302 | return status; |
||
1303 | } |
||
1304 | |||
1305 | static cairo_status_t |
||
1306 | upload_boxes (const cairo_traps_compositor_t *compositor, |
||
1307 | cairo_composite_rectangles_t *extents, |
||
1308 | cairo_boxes_t *boxes) |
||
1309 | { |
||
1310 | cairo_surface_t *dst = extents->surface; |
||
1311 | const cairo_pattern_t *source = &extents->source_pattern.base; |
||
1312 | cairo_surface_t *src; |
||
1313 | cairo_rectangle_int_t limit; |
||
1314 | cairo_int_status_t status; |
||
1315 | int tx, ty; |
||
1316 | |||
1317 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
1318 | |||
1319 | src = _cairo_pattern_get_source((cairo_surface_pattern_t *)source, |
||
1320 | &limit); |
||
1321 | if (!(src->type == CAIRO_SURFACE_TYPE_IMAGE || src->type == dst->type)) |
||
1322 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
1323 | |||
1324 | if (! _cairo_matrix_is_integer_translation (&source->matrix, &tx, &ty)) |
||
1325 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
1326 | |||
1327 | /* Check that the data is entirely within the image */ |
||
1328 | if (extents->bounded.x + tx < limit.x || extents->bounded.y + ty < limit.y) |
||
1329 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
1330 | |||
1331 | if (extents->bounded.x + extents->bounded.width + tx > limit.x + limit.width || |
||
1332 | extents->bounded.y + extents->bounded.height + ty > limit.y + limit.height) |
||
1333 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
1334 | |||
1335 | tx += limit.x; |
||
1336 | ty += limit.y; |
||
1337 | |||
1338 | if (src->type == CAIRO_SURFACE_TYPE_IMAGE) |
||
1339 | status = compositor->draw_image_boxes (dst, |
||
1340 | (cairo_image_surface_t *)src, |
||
1341 | boxes, tx, ty); |
||
1342 | else |
||
1343 | status = compositor->copy_boxes (dst, src, boxes, &extents->bounded, |
||
1344 | tx, ty); |
||
1345 | |||
1346 | return status; |
||
1347 | } |
||
1348 | |||
1349 | static cairo_int_status_t |
||
1350 | trim_extents_to_traps (cairo_composite_rectangles_t *extents, |
||
1351 | cairo_traps_t *traps) |
||
1352 | { |
||
1353 | cairo_box_t box; |
||
1354 | |||
1355 | _cairo_traps_extents (traps, &box); |
||
1356 | return _cairo_composite_rectangles_intersect_mask_extents (extents, &box); |
||
1357 | } |
||
1358 | |||
1359 | static cairo_int_status_t |
||
1360 | trim_extents_to_tristrip (cairo_composite_rectangles_t *extents, |
||
1361 | cairo_tristrip_t *strip) |
||
1362 | { |
||
1363 | cairo_box_t box; |
||
1364 | |||
1365 | _cairo_tristrip_extents (strip, &box); |
||
1366 | return _cairo_composite_rectangles_intersect_mask_extents (extents, &box); |
||
1367 | } |
||
1368 | |||
1369 | static cairo_int_status_t |
||
1370 | trim_extents_to_boxes (cairo_composite_rectangles_t *extents, |
||
1371 | cairo_boxes_t *boxes) |
||
1372 | { |
||
1373 | cairo_box_t box; |
||
1374 | |||
1375 | _cairo_boxes_extents (boxes, &box); |
||
1376 | return _cairo_composite_rectangles_intersect_mask_extents (extents, &box); |
||
1377 | } |
||
1378 | |||
1379 | static cairo_int_status_t |
||
1380 | boxes_for_traps (cairo_boxes_t *boxes, |
||
1381 | cairo_traps_t *traps, |
||
1382 | cairo_antialias_t antialias) |
||
1383 | { |
||
1384 | int i; |
||
1385 | |||
1386 | /* first check that the traps are rectilinear */ |
||
1387 | if (antialias == CAIRO_ANTIALIAS_NONE) { |
||
1388 | for (i = 0; i < traps->num_traps; i++) { |
||
1389 | const cairo_trapezoid_t *t = &traps->traps[i]; |
||
1390 | if (_cairo_fixed_integer_round_down (t->left.p1.x) != |
||
1391 | _cairo_fixed_integer_round_down (t->left.p2.x) || |
||
1392 | _cairo_fixed_integer_round_down (t->right.p1.x) != |
||
1393 | _cairo_fixed_integer_round_down (t->right.p2.x)) |
||
1394 | { |
||
1395 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
1396 | } |
||
1397 | } |
||
1398 | } else { |
||
1399 | for (i = 0; i < traps->num_traps; i++) { |
||
1400 | const cairo_trapezoid_t *t = &traps->traps[i]; |
||
1401 | if (t->left.p1.x != t->left.p2.x || t->right.p1.x != t->right.p2.x) |
||
1402 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
1403 | } |
||
1404 | } |
||
1405 | |||
1406 | _cairo_boxes_init (boxes); |
||
1407 | |||
1408 | boxes->num_boxes = traps->num_traps; |
||
1409 | boxes->chunks.base = (cairo_box_t *) traps->traps; |
||
1410 | boxes->chunks.count = traps->num_traps; |
||
1411 | boxes->chunks.size = traps->num_traps; |
||
1412 | |||
1413 | if (antialias != CAIRO_ANTIALIAS_NONE) { |
||
1414 | for (i = 0; i < traps->num_traps; i++) { |
||
1415 | /* Note the traps and boxes alias so we need to take the local copies first. */ |
||
1416 | cairo_fixed_t x1 = traps->traps[i].left.p1.x; |
||
1417 | cairo_fixed_t x2 = traps->traps[i].right.p1.x; |
||
1418 | cairo_fixed_t y1 = traps->traps[i].top; |
||
1419 | cairo_fixed_t y2 = traps->traps[i].bottom; |
||
1420 | |||
1421 | boxes->chunks.base[i].p1.x = x1; |
||
1422 | boxes->chunks.base[i].p1.y = y1; |
||
1423 | boxes->chunks.base[i].p2.x = x2; |
||
1424 | boxes->chunks.base[i].p2.y = y2; |
||
1425 | |||
1426 | if (boxes->is_pixel_aligned) { |
||
1427 | boxes->is_pixel_aligned = |
||
1428 | _cairo_fixed_is_integer (x1) && _cairo_fixed_is_integer (y1) && |
||
1429 | _cairo_fixed_is_integer (x2) && _cairo_fixed_is_integer (y2); |
||
1430 | } |
||
1431 | } |
||
1432 | } else { |
||
1433 | boxes->is_pixel_aligned = TRUE; |
||
1434 | |||
1435 | for (i = 0; i < traps->num_traps; i++) { |
||
1436 | /* Note the traps and boxes alias so we need to take the local copies first. */ |
||
1437 | cairo_fixed_t x1 = traps->traps[i].left.p1.x; |
||
1438 | cairo_fixed_t x2 = traps->traps[i].right.p1.x; |
||
1439 | cairo_fixed_t y1 = traps->traps[i].top; |
||
1440 | cairo_fixed_t y2 = traps->traps[i].bottom; |
||
1441 | |||
1442 | /* round down here to match Pixman's behavior when using traps. */ |
||
1443 | boxes->chunks.base[i].p1.x = _cairo_fixed_round_down (x1); |
||
1444 | boxes->chunks.base[i].p1.y = _cairo_fixed_round_down (y1); |
||
1445 | boxes->chunks.base[i].p2.x = _cairo_fixed_round_down (x2); |
||
1446 | boxes->chunks.base[i].p2.y = _cairo_fixed_round_down (y2); |
||
1447 | } |
||
1448 | } |
||
1449 | |||
1450 | return CAIRO_INT_STATUS_SUCCESS; |
||
1451 | } |
||
1452 | |||
1453 | static cairo_status_t |
||
1454 | clip_and_composite_boxes (const cairo_traps_compositor_t *compositor, |
||
1455 | cairo_composite_rectangles_t *extents, |
||
1456 | cairo_boxes_t *boxes); |
||
1457 | |||
1458 | static cairo_status_t |
||
1459 | clip_and_composite_polygon (const cairo_traps_compositor_t *compositor, |
||
1460 | cairo_composite_rectangles_t *extents, |
||
1461 | cairo_polygon_t *polygon, |
||
1462 | cairo_antialias_t antialias, |
||
1463 | cairo_fill_rule_t fill_rule, |
||
1464 | cairo_bool_t curvy) |
||
1465 | { |
||
1466 | composite_traps_info_t traps; |
||
1467 | cairo_surface_t *dst = extents->surface; |
||
1468 | cairo_bool_t clip_surface = ! _cairo_clip_is_region (extents->clip); |
||
1469 | cairo_int_status_t status; |
||
1470 | |||
1471 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
1472 | |||
1473 | if (polygon->num_edges == 0) { |
||
1474 | status = CAIRO_INT_STATUS_SUCCESS; |
||
1475 | |||
1476 | if (! extents->is_bounded) { |
||
1477 | cairo_region_t *clip_region = _cairo_clip_get_region (extents->clip); |
||
1478 | |||
1479 | if (clip_region && |
||
1480 | cairo_region_contains_rectangle (clip_region, |
||
1481 | &extents->unbounded) == CAIRO_REGION_OVERLAP_IN) |
||
1482 | clip_region = NULL; |
||
1483 | |||
1484 | if (clip_region != NULL) { |
||
1485 | status = compositor->set_clip_region (dst, clip_region); |
||
1486 | if (unlikely (status)) |
||
1487 | return status; |
||
1488 | } |
||
1489 | |||
1490 | if (clip_surface) |
||
1491 | status = fixup_unbounded_with_mask (compositor, extents); |
||
1492 | else |
||
1493 | status = fixup_unbounded (compositor, extents, NULL); |
||
1494 | |||
1495 | if (clip_region != NULL) |
||
1496 | compositor->set_clip_region (dst, NULL); |
||
1497 | } |
||
1498 | |||
1499 | return status; |
||
1500 | } |
||
1501 | |||
1502 | if (extents->clip->path != NULL && extents->is_bounded) { |
||
1503 | cairo_polygon_t clipper; |
||
1504 | cairo_fill_rule_t clipper_fill_rule; |
||
1505 | cairo_antialias_t clipper_antialias; |
||
1506 | |||
1507 | status = _cairo_clip_get_polygon (extents->clip, |
||
1508 | &clipper, |
||
1509 | &clipper_fill_rule, |
||
1510 | &clipper_antialias); |
||
1511 | if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { |
||
1512 | if (clipper_antialias == antialias) { |
||
1513 | status = _cairo_polygon_intersect (polygon, fill_rule, |
||
1514 | &clipper, clipper_fill_rule); |
||
1515 | if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { |
||
1516 | cairo_clip_t * clip = _cairo_clip_copy_region (extents->clip); |
||
1517 | _cairo_clip_destroy (extents->clip); |
||
1518 | extents->clip = clip; |
||
1519 | |||
1520 | fill_rule = CAIRO_FILL_RULE_WINDING; |
||
1521 | } |
||
1522 | _cairo_polygon_fini (&clipper); |
||
1523 | } |
||
1524 | } |
||
1525 | } |
||
1526 | |||
1527 | if (antialias == CAIRO_ANTIALIAS_NONE && curvy) { |
||
1528 | cairo_boxes_t boxes; |
||
1529 | |||
1530 | _cairo_boxes_init (&boxes); |
||
1531 | status = _cairo_rasterise_polygon_to_boxes (polygon, fill_rule, &boxes); |
||
1532 | if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { |
||
1533 | assert (boxes.is_pixel_aligned); |
||
1534 | status = clip_and_composite_boxes (compositor, extents, &boxes); |
||
1535 | } |
||
1536 | _cairo_boxes_fini (&boxes); |
||
1537 | if ((status != CAIRO_INT_STATUS_UNSUPPORTED)) |
||
1538 | return status; |
||
1539 | } |
||
1540 | |||
1541 | _cairo_traps_init (&traps.traps); |
||
1542 | |||
1543 | if (antialias == CAIRO_ANTIALIAS_NONE && curvy) { |
||
1544 | status = _cairo_rasterise_polygon_to_traps (polygon, fill_rule, antialias, &traps.traps); |
||
1545 | } else { |
||
1546 | status = _cairo_bentley_ottmann_tessellate_polygon (&traps.traps, polygon, fill_rule); |
||
1547 | } |
||
1548 | if (unlikely (status)) |
||
1549 | goto CLEANUP_TRAPS; |
||
1550 | |||
1551 | status = trim_extents_to_traps (extents, &traps.traps); |
||
1552 | if (unlikely (status)) |
||
1553 | goto CLEANUP_TRAPS; |
||
1554 | |||
1555 | /* Use a fast path if the trapezoids consist of a set of boxes. */ |
||
1556 | status = CAIRO_INT_STATUS_UNSUPPORTED; |
||
1557 | if (1) { |
||
1558 | cairo_boxes_t boxes; |
||
1559 | |||
1560 | status = boxes_for_traps (&boxes, &traps.traps, antialias); |
||
1561 | if (status == CAIRO_INT_STATUS_SUCCESS) { |
||
1562 | status = clip_and_composite_boxes (compositor, extents, &boxes); |
||
1563 | /* XXX need to reconstruct the traps! */ |
||
1564 | assert (status != CAIRO_INT_STATUS_UNSUPPORTED); |
||
1565 | } |
||
1566 | } |
||
1567 | if (status == CAIRO_INT_STATUS_UNSUPPORTED) { |
||
1568 | /* Otherwise render the trapezoids to a mask and composite in the usual |
||
1569 | * fashion. |
||
1570 | */ |
||
1571 | unsigned int flags = 0; |
||
1572 | |||
1573 | /* For unbounded operations, the X11 server will estimate the |
||
1574 | * affected rectangle and apply the operation to that. However, |
||
1575 | * there are cases where this is an overestimate (e.g. the |
||
1576 | * clip-fill-{eo,nz}-unbounded test). |
||
1577 | * |
||
1578 | * The clip will trim that overestimate to our expectations. |
||
1579 | */ |
||
1580 | if (! extents->is_bounded) |
||
1581 | flags |= FORCE_CLIP_REGION; |
||
1582 | |||
1583 | traps.antialias = antialias; |
||
1584 | status = clip_and_composite (compositor, extents, |
||
1585 | composite_traps, NULL, &traps, |
||
1586 | need_unbounded_clip (extents) | flags); |
||
1587 | } |
||
1588 | |||
1589 | CLEANUP_TRAPS: |
||
1590 | _cairo_traps_fini (&traps.traps); |
||
1591 | |||
1592 | return status; |
||
1593 | } |
||
1594 | |||
1595 | struct composite_opacity_info { |
||
1596 | const cairo_traps_compositor_t *compositor; |
||
1597 | uint8_t op; |
||
1598 | cairo_surface_t *dst; |
||
1599 | cairo_surface_t *src; |
||
1600 | int src_x, src_y; |
||
1601 | double opacity; |
||
1602 | }; |
||
1603 | |||
1604 | static void composite_opacity(void *closure, |
||
1605 | int16_t x, int16_t y, |
||
1606 | int16_t w, int16_t h, |
||
1607 | uint16_t coverage) |
||
1608 | { |
||
1609 | struct composite_opacity_info *info = closure; |
||
1610 | const cairo_traps_compositor_t *compositor = info->compositor; |
||
1611 | cairo_surface_t *mask; |
||
1612 | int mask_x, mask_y; |
||
1613 | cairo_color_t color; |
||
1614 | cairo_solid_pattern_t solid; |
||
1615 | |||
1616 | _cairo_color_init_rgba (&color, 0, 0, 0, info->opacity * coverage); |
||
1617 | _cairo_pattern_init_solid (&solid, &color); |
||
1618 | mask = compositor->pattern_to_surface (info->dst, &solid.base, TRUE, |
||
1619 | &_cairo_unbounded_rectangle, |
||
1620 | &_cairo_unbounded_rectangle, |
||
1621 | &mask_x, &mask_y); |
||
1622 | if (likely (mask->status == CAIRO_STATUS_SUCCESS)) { |
||
1623 | if (info->src) { |
||
1624 | compositor->composite (info->dst, info->op, info->src, mask, |
||
1625 | x + info->src_x, y + info->src_y, |
||
1626 | mask_x, mask_y, |
||
1627 | x, y, |
||
1628 | w, h); |
||
1629 | } else { |
||
1630 | compositor->composite (info->dst, info->op, mask, NULL, |
||
1631 | mask_x, mask_y, |
||
1632 | 0, 0, |
||
1633 | x, y, |
||
1634 | w, h); |
||
1635 | } |
||
1636 | } |
||
1637 | |||
1638 | cairo_surface_destroy (mask); |
||
1639 | } |
||
1640 | |||
1641 | |||
1642 | static cairo_int_status_t |
||
1643 | composite_opacity_boxes (const cairo_traps_compositor_t *compositor, |
||
1644 | cairo_surface_t *dst, |
||
1645 | void *closure, |
||
1646 | cairo_operator_t op, |
||
1647 | cairo_surface_t *src, |
||
1648 | int src_x, |
||
1649 | int src_y, |
||
1650 | int dst_x, |
||
1651 | int dst_y, |
||
1652 | const cairo_rectangle_int_t *extents, |
||
1653 | cairo_clip_t *clip) |
||
1654 | { |
||
1655 | const cairo_solid_pattern_t *mask = closure; |
||
1656 | struct composite_opacity_info info; |
||
1657 | int i; |
||
1658 | |||
1659 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
1660 | |||
1661 | info.compositor = compositor; |
||
1662 | info.op = op; |
||
1663 | info.dst = dst; |
||
1664 | |||
1665 | info.src = src; |
||
1666 | info.src_x = src_x; |
||
1667 | info.src_y = src_y; |
||
1668 | |||
1669 | info.opacity = mask->color.alpha / (double) 0xffff; |
||
1670 | |||
1671 | /* XXX for lots of boxes create a clip region for the fully opaque areas */ |
||
1672 | for (i = 0; i < clip->num_boxes; i++) |
||
1673 | do_unaligned_box(composite_opacity, &info, |
||
1674 | &clip->boxes[i], dst_x, dst_y); |
||
1675 | |||
1676 | return CAIRO_STATUS_SUCCESS; |
||
1677 | } |
||
1678 | |||
1679 | static cairo_int_status_t |
||
1680 | composite_boxes (const cairo_traps_compositor_t *compositor, |
||
1681 | cairo_surface_t *dst, |
||
1682 | void *closure, |
||
1683 | cairo_operator_t op, |
||
1684 | cairo_surface_t *src, |
||
1685 | int src_x, |
||
1686 | int src_y, |
||
1687 | int dst_x, |
||
1688 | int dst_y, |
||
1689 | const cairo_rectangle_int_t *extents, |
||
1690 | cairo_clip_t *clip) |
||
1691 | { |
||
1692 | cairo_traps_t traps; |
||
1693 | cairo_status_t status; |
||
1694 | |||
1695 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
1696 | |||
1697 | status = _cairo_traps_init_boxes (&traps, closure); |
||
1698 | if (unlikely (status)) |
||
1699 | return status; |
||
1700 | |||
1701 | status = compositor->composite_traps (dst, op, src, |
||
1702 | src_x - dst_x, src_y - dst_y, |
||
1703 | dst_x, dst_y, |
||
1704 | extents, |
||
1705 | CAIRO_ANTIALIAS_DEFAULT, &traps); |
||
1706 | _cairo_traps_fini (&traps); |
||
1707 | |||
1708 | return status; |
||
1709 | } |
||
1710 | |||
1711 | static cairo_status_t |
||
1712 | clip_and_composite_boxes (const cairo_traps_compositor_t *compositor, |
||
1713 | cairo_composite_rectangles_t *extents, |
||
1714 | cairo_boxes_t *boxes) |
||
1715 | { |
||
1716 | cairo_int_status_t status; |
||
1717 | |||
1718 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
1719 | |||
1720 | if (boxes->num_boxes == 0 && extents->is_bounded) |
||
1721 | return CAIRO_STATUS_SUCCESS; |
||
1722 | |||
1723 | status = trim_extents_to_boxes (extents, boxes); |
||
1724 | if (unlikely (status)) |
||
1725 | return status; |
||
1726 | |||
1727 | if (boxes->is_pixel_aligned && extents->clip->path == NULL && |
||
1728 | extents->source_pattern.base.type == CAIRO_PATTERN_TYPE_SURFACE && |
||
1729 | (op_reduces_to_source (extents) || |
||
1730 | (extents->op == CAIRO_OPERATOR_OVER && |
||
1731 | (extents->source_pattern.surface.surface->content & CAIRO_CONTENT_ALPHA) == 0))) |
||
1732 | { |
||
1733 | status = upload_boxes (compositor, extents, boxes); |
||
1734 | if (status != CAIRO_INT_STATUS_UNSUPPORTED) |
||
1735 | return status; |
||
1736 | } |
||
1737 | |||
1738 | /* Can we reduce drawing through a clip-mask to simply drawing the clip? */ |
||
1739 | if (extents->clip->path != NULL && extents->is_bounded) { |
||
1740 | cairo_polygon_t polygon; |
||
1741 | cairo_fill_rule_t fill_rule; |
||
1742 | cairo_antialias_t antialias; |
||
1743 | cairo_clip_t *clip; |
||
1744 | |||
1745 | clip = _cairo_clip_copy (extents->clip); |
||
1746 | clip = _cairo_clip_intersect_boxes (clip, boxes); |
||
1747 | if (_cairo_clip_is_all_clipped (clip)) |
||
1748 | return CAIRO_INT_STATUS_NOTHING_TO_DO; |
||
1749 | |||
1750 | status = _cairo_clip_get_polygon (clip, &polygon, |
||
1751 | &fill_rule, &antialias); |
||
1752 | _cairo_clip_path_destroy (clip->path); |
||
1753 | clip->path = NULL; |
||
1754 | if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { |
||
1755 | cairo_clip_t *saved_clip = extents->clip; |
||
1756 | extents->clip = clip; |
||
1757 | |||
1758 | status = clip_and_composite_polygon (compositor, extents, &polygon, |
||
1759 | antialias, fill_rule, FALSE); |
||
1760 | |||
1761 | clip = extents->clip; |
||
1762 | extents->clip = saved_clip; |
||
1763 | |||
1764 | _cairo_polygon_fini (&polygon); |
||
1765 | } |
||
1766 | _cairo_clip_destroy (clip); |
||
1767 | |||
1768 | if (status != CAIRO_INT_STATUS_UNSUPPORTED) |
||
1769 | return status; |
||
1770 | } |
||
1771 | |||
1772 | /* Use a fast path if the boxes are pixel aligned (or nearly aligned!) */ |
||
1773 | if (boxes->is_pixel_aligned) { |
||
1774 | status = composite_aligned_boxes (compositor, extents, boxes); |
||
1775 | if (status != CAIRO_INT_STATUS_UNSUPPORTED) |
||
1776 | return status; |
||
1777 | } |
||
1778 | |||
1779 | return clip_and_composite (compositor, extents, |
||
1780 | composite_boxes, NULL, boxes, |
||
1781 | need_unbounded_clip (extents)); |
||
1782 | } |
||
1783 | |||
1784 | static cairo_int_status_t |
||
1785 | composite_traps_as_boxes (const cairo_traps_compositor_t *compositor, |
||
1786 | cairo_composite_rectangles_t *extents, |
||
1787 | composite_traps_info_t *info) |
||
1788 | { |
||
1789 | cairo_boxes_t boxes; |
||
1790 | |||
1791 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
1792 | |||
1793 | if (! _cairo_traps_to_boxes (&info->traps, info->antialias, &boxes)) |
||
1794 | return CAIRO_INT_STATUS_UNSUPPORTED; |
||
1795 | |||
1796 | return clip_and_composite_boxes (compositor, extents, &boxes); |
||
1797 | } |
||
1798 | |||
1799 | static cairo_int_status_t |
||
1800 | clip_and_composite_traps (const cairo_traps_compositor_t *compositor, |
||
1801 | cairo_composite_rectangles_t *extents, |
||
1802 | composite_traps_info_t *info, |
||
1803 | unsigned flags) |
||
1804 | { |
||
1805 | cairo_int_status_t status; |
||
1806 | |||
1807 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
1808 | |||
1809 | status = trim_extents_to_traps (extents, &info->traps); |
||
1810 | if (unlikely (status != CAIRO_INT_STATUS_SUCCESS)) |
||
1811 | return status; |
||
1812 | |||
1813 | status = CAIRO_INT_STATUS_UNSUPPORTED; |
||
1814 | if ((flags & FORCE_CLIP_REGION) == 0) |
||
1815 | status = composite_traps_as_boxes (compositor, extents, info); |
||
1816 | if (status == CAIRO_INT_STATUS_UNSUPPORTED) { |
||
1817 | /* For unbounded operations, the X11 server will estimate the |
||
1818 | * affected rectangle and apply the operation to that. However, |
||
1819 | * there are cases where this is an overestimate (e.g. the |
||
1820 | * clip-fill-{eo,nz}-unbounded test). |
||
1821 | * |
||
1822 | * The clip will trim that overestimate to our expectations. |
||
1823 | */ |
||
1824 | if (! extents->is_bounded) |
||
1825 | flags |= FORCE_CLIP_REGION; |
||
1826 | |||
1827 | status = clip_and_composite (compositor, extents, |
||
1828 | composite_traps, NULL, info, |
||
1829 | need_unbounded_clip (extents) | flags); |
||
1830 | } |
||
1831 | |||
1832 | return status; |
||
1833 | } |
||
1834 | |||
1835 | static cairo_int_status_t |
||
1836 | clip_and_composite_tristrip (const cairo_traps_compositor_t *compositor, |
||
1837 | cairo_composite_rectangles_t *extents, |
||
1838 | composite_tristrip_info_t *info) |
||
1839 | { |
||
1840 | cairo_int_status_t status; |
||
1841 | unsigned int flags = 0; |
||
1842 | |||
1843 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
1844 | |||
1845 | status = trim_extents_to_tristrip (extents, &info->strip); |
||
1846 | if (unlikely (status != CAIRO_INT_STATUS_SUCCESS)) |
||
1847 | return status; |
||
1848 | |||
1849 | if (! extents->is_bounded) |
||
1850 | flags |= FORCE_CLIP_REGION; |
||
1851 | |||
1852 | status = clip_and_composite (compositor, extents, |
||
1853 | composite_tristrip, NULL, info, |
||
1854 | need_unbounded_clip (extents) | flags); |
||
1855 | |||
1856 | return status; |
||
1857 | } |
||
1858 | |||
1859 | struct composite_mask { |
||
1860 | cairo_surface_t *mask; |
||
1861 | int mask_x, mask_y; |
||
1862 | }; |
||
1863 | |||
1864 | static cairo_int_status_t |
||
1865 | composite_mask (const cairo_traps_compositor_t *compositor, |
||
1866 | cairo_surface_t *dst, |
||
1867 | void *closure, |
||
1868 | cairo_operator_t op, |
||
1869 | cairo_surface_t *src, |
||
1870 | int src_x, |
||
1871 | int src_y, |
||
1872 | int dst_x, |
||
1873 | int dst_y, |
||
1874 | const cairo_rectangle_int_t *extents, |
||
1875 | cairo_clip_t *clip) |
||
1876 | { |
||
1877 | struct composite_mask *data = closure; |
||
1878 | |||
1879 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
1880 | |||
1881 | if (src != NULL) { |
||
1882 | compositor->composite (dst, op, src, data->mask, |
||
1883 | extents->x + src_x, extents->y + src_y, |
||
1884 | extents->x + data->mask_x, extents->y + data->mask_y, |
||
1885 | extents->x - dst_x, extents->y - dst_y, |
||
1886 | extents->width, extents->height); |
||
1887 | } else { |
||
1888 | compositor->composite (dst, op, data->mask, NULL, |
||
1889 | extents->x + data->mask_x, extents->y + data->mask_y, |
||
1890 | 0, 0, |
||
1891 | extents->x - dst_x, extents->y - dst_y, |
||
1892 | extents->width, extents->height); |
||
1893 | } |
||
1894 | |||
1895 | return CAIRO_STATUS_SUCCESS; |
||
1896 | } |
||
1897 | |||
1898 | struct composite_box_info { |
||
1899 | const cairo_traps_compositor_t *compositor; |
||
1900 | cairo_surface_t *dst; |
||
1901 | cairo_surface_t *src; |
||
1902 | int src_x, src_y; |
||
1903 | uint8_t op; |
||
1904 | }; |
||
1905 | |||
1906 | static void composite_box(void *closure, |
||
1907 | int16_t x, int16_t y, |
||
1908 | int16_t w, int16_t h, |
||
1909 | uint16_t coverage) |
||
1910 | { |
||
1911 | struct composite_box_info *info = closure; |
||
1912 | const cairo_traps_compositor_t *compositor = info->compositor; |
||
1913 | |||
1914 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
1915 | |||
1916 | if (! CAIRO_ALPHA_SHORT_IS_OPAQUE (coverage)) { |
||
1917 | cairo_surface_t *mask; |
||
1918 | cairo_color_t color; |
||
1919 | cairo_solid_pattern_t solid; |
||
1920 | int mask_x, mask_y; |
||
1921 | |||
1922 | _cairo_color_init_rgba (&color, 0, 0, 0, coverage / (double)0xffff); |
||
1923 | _cairo_pattern_init_solid (&solid, &color); |
||
1924 | |||
1925 | mask = compositor->pattern_to_surface (info->dst, &solid.base, FALSE, |
||
1926 | &_cairo_unbounded_rectangle, |
||
1927 | &_cairo_unbounded_rectangle, |
||
1928 | &mask_x, &mask_y); |
||
1929 | |||
1930 | if (likely (mask->status == CAIRO_STATUS_SUCCESS)) { |
||
1931 | compositor->composite (info->dst, info->op, info->src, mask, |
||
1932 | x + info->src_x, y + info->src_y, |
||
1933 | mask_x, mask_y, |
||
1934 | x, y, |
||
1935 | w, h); |
||
1936 | } |
||
1937 | |||
1938 | cairo_surface_destroy (mask); |
||
1939 | } else { |
||
1940 | compositor->composite (info->dst, info->op, info->src, NULL, |
||
1941 | x + info->src_x, y + info->src_y, |
||
1942 | 0, 0, |
||
1943 | x, y, |
||
1944 | w, h); |
||
1945 | } |
||
1946 | } |
||
1947 | |||
1948 | static cairo_int_status_t |
||
1949 | composite_mask_clip_boxes (const cairo_traps_compositor_t *compositor, |
||
1950 | cairo_surface_t *dst, |
||
1951 | void *closure, |
||
1952 | cairo_operator_t op, |
||
1953 | cairo_surface_t *src, |
||
1954 | int src_x, |
||
1955 | int src_y, |
||
1956 | int dst_x, |
||
1957 | int dst_y, |
||
1958 | const cairo_rectangle_int_t *extents, |
||
1959 | cairo_clip_t *clip) |
||
1960 | { |
||
1961 | struct composite_mask *data = closure; |
||
1962 | struct composite_box_info info; |
||
1963 | int i; |
||
1964 | |||
1965 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
1966 | |||
1967 | info.compositor = compositor; |
||
1968 | info.op = CAIRO_OPERATOR_SOURCE; |
||
1969 | info.dst = dst; |
||
1970 | info.src = data->mask; |
||
1971 | info.src_x = data->mask_x; |
||
1972 | info.src_y = data->mask_y; |
||
1973 | |||
1974 | info.src_x += dst_x; |
||
1975 | info.src_y += dst_y; |
||
1976 | |||
1977 | for (i = 0; i < clip->num_boxes; i++) |
||
1978 | do_unaligned_box(composite_box, &info, &clip->boxes[i], dst_x, dst_y); |
||
1979 | |||
1980 | return CAIRO_STATUS_SUCCESS; |
||
1981 | } |
||
1982 | |||
1983 | static cairo_int_status_t |
||
1984 | composite_mask_clip (const cairo_traps_compositor_t *compositor, |
||
1985 | cairo_surface_t *dst, |
||
1986 | void *closure, |
||
1987 | cairo_operator_t op, |
||
1988 | cairo_surface_t *src, |
||
1989 | int src_x, |
||
1990 | int src_y, |
||
1991 | int dst_x, |
||
1992 | int dst_y, |
||
1993 | const cairo_rectangle_int_t *extents, |
||
1994 | cairo_clip_t *clip) |
||
1995 | { |
||
1996 | struct composite_mask *data = closure; |
||
1997 | cairo_polygon_t polygon; |
||
1998 | cairo_fill_rule_t fill_rule; |
||
1999 | composite_traps_info_t info; |
||
2000 | cairo_status_t status; |
||
2001 | |||
2002 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
2003 | |||
2004 | status = _cairo_clip_get_polygon (clip, &polygon, |
||
2005 | &fill_rule, &info.antialias); |
||
2006 | if (unlikely (status)) |
||
2007 | return status; |
||
2008 | |||
2009 | _cairo_traps_init (&info.traps); |
||
2010 | status = _cairo_bentley_ottmann_tessellate_polygon (&info.traps, |
||
2011 | &polygon, |
||
2012 | fill_rule); |
||
2013 | _cairo_polygon_fini (&polygon); |
||
2014 | if (unlikely (status)) |
||
2015 | return status; |
||
2016 | |||
2017 | status = composite_traps (compositor, dst, &info, |
||
2018 | CAIRO_OPERATOR_SOURCE, |
||
2019 | data->mask, |
||
2020 | data->mask_x + dst_x, data->mask_y + dst_y, |
||
2021 | dst_x, dst_y, |
||
2022 | extents, NULL); |
||
2023 | _cairo_traps_fini (&info.traps); |
||
2024 | |||
2025 | return status; |
||
2026 | } |
||
2027 | |||
2028 | /* high-level compositor interface */ |
||
2029 | |||
2030 | static cairo_int_status_t |
||
2031 | _cairo_traps_compositor_paint (const cairo_compositor_t *_compositor, |
||
2032 | cairo_composite_rectangles_t *extents) |
||
2033 | { |
||
2034 | cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t*)_compositor; |
||
2035 | cairo_boxes_t boxes; |
||
2036 | cairo_int_status_t status; |
||
2037 | |||
2038 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
2039 | |||
2040 | status = compositor->check_composite (extents); |
||
2041 | if (unlikely (status)) |
||
2042 | return status; |
||
2043 | |||
2044 | _cairo_clip_steal_boxes (extents->clip, &boxes); |
||
2045 | status = clip_and_composite_boxes (compositor, extents, &boxes); |
||
2046 | _cairo_clip_unsteal_boxes (extents->clip, &boxes); |
||
2047 | |||
2048 | return status; |
||
2049 | } |
||
2050 | |||
2051 | static cairo_int_status_t |
||
2052 | _cairo_traps_compositor_mask (const cairo_compositor_t *_compositor, |
||
2053 | cairo_composite_rectangles_t *extents) |
||
2054 | { |
||
2055 | const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t*)_compositor; |
||
2056 | cairo_int_status_t status; |
||
2057 | |||
2058 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
2059 | |||
2060 | status = compositor->check_composite (extents); |
||
2061 | if (unlikely (status)) |
||
2062 | return status; |
||
2063 | |||
2064 | if (extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID && |
||
2065 | extents->clip->path == NULL) { |
||
2066 | status = clip_and_composite (compositor, extents, |
||
2067 | composite_opacity_boxes, |
||
2068 | composite_opacity_boxes, |
||
2069 | &extents->mask_pattern, |
||
2070 | need_unbounded_clip (extents)); |
||
2071 | } else { |
||
2072 | struct composite_mask data; |
||
2073 | |||
2074 | data.mask = compositor->pattern_to_surface (extents->surface, |
||
2075 | &extents->mask_pattern.base, |
||
2076 | TRUE, |
||
2077 | &extents->bounded, |
||
2078 | &extents->mask_sample_area, |
||
2079 | &data.mask_x, |
||
2080 | &data.mask_y); |
||
2081 | if (unlikely (data.mask->status)) |
||
2082 | return data.mask->status; |
||
2083 | |||
2084 | status = clip_and_composite (compositor, extents, |
||
2085 | composite_mask, |
||
2086 | extents->clip->path ? composite_mask_clip : composite_mask_clip_boxes, |
||
2087 | &data, need_bounded_clip (extents)); |
||
2088 | |||
2089 | cairo_surface_destroy (data.mask); |
||
2090 | } |
||
2091 | |||
2092 | return status; |
||
2093 | } |
||
2094 | |||
2095 | static cairo_int_status_t |
||
2096 | _cairo_traps_compositor_stroke (const cairo_compositor_t *_compositor, |
||
2097 | cairo_composite_rectangles_t *extents, |
||
2098 | const cairo_path_fixed_t *path, |
||
2099 | const cairo_stroke_style_t *style, |
||
2100 | const cairo_matrix_t *ctm, |
||
2101 | const cairo_matrix_t *ctm_inverse, |
||
2102 | double tolerance, |
||
2103 | cairo_antialias_t antialias) |
||
2104 | { |
||
2105 | const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor; |
||
2106 | cairo_int_status_t status; |
||
2107 | |||
2108 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
2109 | |||
2110 | status = compositor->check_composite (extents); |
||
2111 | if (unlikely (status)) |
||
2112 | return status; |
||
2113 | |||
2114 | status = CAIRO_INT_STATUS_UNSUPPORTED; |
||
2115 | if (_cairo_path_fixed_stroke_is_rectilinear (path)) { |
||
2116 | cairo_boxes_t boxes; |
||
2117 | |||
2118 | _cairo_boxes_init_with_clip (&boxes, extents->clip); |
||
2119 | status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path, |
||
2120 | style, |
||
2121 | ctm, |
||
2122 | antialias, |
||
2123 | &boxes); |
||
2124 | if (likely (status == CAIRO_INT_STATUS_SUCCESS)) |
||
2125 | status = clip_and_composite_boxes (compositor, extents, &boxes); |
||
2126 | _cairo_boxes_fini (&boxes); |
||
2127 | } |
||
2128 | |||
2129 | if (status == CAIRO_INT_STATUS_UNSUPPORTED && 0 && |
||
2130 | _cairo_clip_is_region (extents->clip)) /* XXX */ |
||
2131 | { |
||
2132 | composite_tristrip_info_t info; |
||
2133 | |||
2134 | info.antialias = antialias; |
||
2135 | _cairo_tristrip_init_with_clip (&info.strip, extents->clip); |
||
2136 | status = _cairo_path_fixed_stroke_to_tristrip (path, style, |
||
2137 | ctm, ctm_inverse, |
||
2138 | tolerance, |
||
2139 | &info.strip); |
||
2140 | if (likely (status == CAIRO_INT_STATUS_SUCCESS)) |
||
2141 | status = clip_and_composite_tristrip (compositor, extents, &info); |
||
2142 | _cairo_tristrip_fini (&info.strip); |
||
2143 | } |
||
2144 | |||
2145 | if (status == CAIRO_INT_STATUS_UNSUPPORTED && |
||
2146 | path->has_curve_to && antialias == CAIRO_ANTIALIAS_NONE) { |
||
2147 | cairo_polygon_t polygon; |
||
2148 | |||
2149 | _cairo_polygon_init_with_clip (&polygon, extents->clip); |
||
2150 | status = _cairo_path_fixed_stroke_to_polygon (path, style, |
||
2151 | ctm, ctm_inverse, |
||
2152 | tolerance, |
||
2153 | &polygon); |
||
2154 | if (likely (status == CAIRO_INT_STATUS_SUCCESS)) |
||
2155 | status = clip_and_composite_polygon (compositor, |
||
2156 | extents, &polygon, |
||
2157 | CAIRO_ANTIALIAS_NONE, |
||
2158 | CAIRO_FILL_RULE_WINDING, |
||
2159 | TRUE); |
||
2160 | _cairo_polygon_fini (&polygon); |
||
2161 | } |
||
2162 | |||
2163 | if (status == CAIRO_INT_STATUS_UNSUPPORTED) { |
||
2164 | cairo_int_status_t (*func) (const cairo_path_fixed_t *path, |
||
2165 | const cairo_stroke_style_t *stroke_style, |
||
2166 | const cairo_matrix_t *ctm, |
||
2167 | const cairo_matrix_t *ctm_inverse, |
||
2168 | double tolerance, |
||
2169 | cairo_traps_t *traps); |
||
2170 | composite_traps_info_t info; |
||
2171 | unsigned flags; |
||
2172 | |||
2173 | if (antialias == CAIRO_ANTIALIAS_BEST || antialias == CAIRO_ANTIALIAS_GOOD) { |
||
2174 | func = _cairo_path_fixed_stroke_polygon_to_traps; |
||
2175 | flags = 0; |
||
2176 | } else { |
||
2177 | func = _cairo_path_fixed_stroke_to_traps; |
||
2178 | flags = need_bounded_clip (extents) & ~NEED_CLIP_SURFACE; |
||
2179 | } |
||
2180 | |||
2181 | info.antialias = antialias; |
||
2182 | _cairo_traps_init_with_clip (&info.traps, extents->clip); |
||
2183 | status = func (path, style, ctm, ctm_inverse, tolerance, &info.traps); |
||
2184 | if (likely (status == CAIRO_INT_STATUS_SUCCESS)) |
||
2185 | status = clip_and_composite_traps (compositor, extents, &info, flags); |
||
2186 | _cairo_traps_fini (&info.traps); |
||
2187 | } |
||
2188 | |||
2189 | return status; |
||
2190 | } |
||
2191 | |||
2192 | static cairo_int_status_t |
||
2193 | _cairo_traps_compositor_fill (const cairo_compositor_t *_compositor, |
||
2194 | cairo_composite_rectangles_t *extents, |
||
2195 | const cairo_path_fixed_t *path, |
||
2196 | cairo_fill_rule_t fill_rule, |
||
2197 | double tolerance, |
||
2198 | cairo_antialias_t antialias) |
||
2199 | { |
||
2200 | const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor; |
||
2201 | cairo_int_status_t status; |
||
2202 | |||
2203 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
2204 | |||
2205 | status = compositor->check_composite (extents); |
||
2206 | if (unlikely (status)) |
||
2207 | return status; |
||
2208 | |||
2209 | status = CAIRO_INT_STATUS_UNSUPPORTED; |
||
2210 | if (_cairo_path_fixed_fill_is_rectilinear (path)) { |
||
2211 | cairo_boxes_t boxes; |
||
2212 | |||
2213 | _cairo_boxes_init_with_clip (&boxes, extents->clip); |
||
2214 | status = _cairo_path_fixed_fill_rectilinear_to_boxes (path, |
||
2215 | fill_rule, |
||
2216 | antialias, |
||
2217 | &boxes); |
||
2218 | if (likely (status == CAIRO_INT_STATUS_SUCCESS)) |
||
2219 | status = clip_and_composite_boxes (compositor, extents, &boxes); |
||
2220 | _cairo_boxes_fini (&boxes); |
||
2221 | } |
||
2222 | |||
2223 | if (status == CAIRO_INT_STATUS_UNSUPPORTED) { |
||
2224 | cairo_polygon_t polygon; |
||
2225 | |||
2226 | #if 0 |
||
2227 | if (extents->mask.width > extents->unbounded.width || |
||
2228 | extents->mask.height > extents->unbounded.height) |
||
2229 | { |
||
2230 | cairo_box_t limits; |
||
2231 | _cairo_box_from_rectangle (&limits, &extents->unbounded); |
||
2232 | _cairo_polygon_init (&polygon, &limits, 1); |
||
2233 | } |
||
2234 | else |
||
2235 | { |
||
2236 | _cairo_polygon_init (&polygon, NULL, 0); |
||
2237 | } |
||
2238 | |||
2239 | status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon); |
||
2240 | if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { |
||
2241 | status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule, |
||
2242 | extents->clip->boxes, |
||
2243 | extents->clip->num_boxes); |
||
2244 | } |
||
2245 | #else |
||
2246 | _cairo_polygon_init_with_clip (&polygon, extents->clip); |
||
2247 | status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon); |
||
2248 | #endif |
||
2249 | if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { |
||
2250 | status = clip_and_composite_polygon (compositor, extents, &polygon, |
||
2251 | antialias, fill_rule, path->has_curve_to); |
||
2252 | } |
||
2253 | _cairo_polygon_fini (&polygon); |
||
2254 | } |
||
2255 | |||
2256 | return status; |
||
2257 | } |
||
2258 | |||
2259 | static cairo_int_status_t |
||
2260 | composite_glyphs (const cairo_traps_compositor_t *compositor, |
||
2261 | cairo_surface_t *dst, |
||
2262 | void *closure, |
||
2263 | cairo_operator_t op, |
||
2264 | cairo_surface_t *src, |
||
2265 | int src_x, int src_y, |
||
2266 | int dst_x, int dst_y, |
||
2267 | const cairo_rectangle_int_t *extents, |
||
2268 | cairo_clip_t *clip) |
||
2269 | { |
||
2270 | cairo_composite_glyphs_info_t *info = closure; |
||
2271 | |||
2272 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
2273 | |||
2274 | if (op == CAIRO_OPERATOR_ADD && (dst->content & CAIRO_CONTENT_COLOR) == 0) |
||
2275 | info->use_mask = 0; |
||
2276 | |||
2277 | return compositor->composite_glyphs (dst, op, src, |
||
2278 | src_x, src_y, |
||
2279 | dst_x, dst_y, |
||
2280 | info); |
||
2281 | } |
||
2282 | |||
2283 | static cairo_int_status_t |
||
2284 | _cairo_traps_compositor_glyphs (const cairo_compositor_t *_compositor, |
||
2285 | cairo_composite_rectangles_t *extents, |
||
2286 | cairo_scaled_font_t *scaled_font, |
||
2287 | cairo_glyph_t *glyphs, |
||
2288 | int num_glyphs, |
||
2289 | cairo_bool_t overlap) |
||
2290 | { |
||
2291 | const cairo_traps_compositor_t *compositor = (cairo_traps_compositor_t *)_compositor; |
||
2292 | cairo_int_status_t status; |
||
2293 | |||
2294 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
||
2295 | |||
2296 | status = compositor->check_composite (extents); |
||
2297 | if (unlikely (status)) |
||
2298 | return status; |
||
2299 | |||
2300 | _cairo_scaled_font_freeze_cache (scaled_font); |
||
2301 | status = compositor->check_composite_glyphs (extents, |
||
2302 | scaled_font, glyphs, |
||
2303 | &num_glyphs); |
||
2304 | if (likely (status == CAIRO_INT_STATUS_SUCCESS)) { |
||
2305 | cairo_composite_glyphs_info_t info; |
||
2306 | |||
2307 | info.font = scaled_font; |
||
2308 | info.glyphs = glyphs; |
||
2309 | info.num_glyphs = num_glyphs; |
||
2310 | info.use_mask = overlap || ! extents->is_bounded; |
||
2311 | info.extents = extents->bounded; |
||
2312 | |||
2313 | status = clip_and_composite (compositor, extents, |
||
2314 | composite_glyphs, NULL, &info, |
||
2315 | need_bounded_clip (extents) | FORCE_CLIP_REGION); |
||
2316 | } |
||
2317 | _cairo_scaled_font_thaw_cache (scaled_font); |
||
2318 | |||
2319 | return status; |
||
2320 | } |
||
2321 | |||
2322 | void |
||
2323 | _cairo_traps_compositor_init (cairo_traps_compositor_t *compositor, |
||
2324 | const cairo_compositor_t *delegate) |
||
2325 | { |
||
2326 | compositor->base.delegate = delegate; |
||
2327 | |||
2328 | compositor->base.paint = _cairo_traps_compositor_paint; |
||
2329 | compositor->base.mask = _cairo_traps_compositor_mask; |
||
2330 | compositor->base.fill = _cairo_traps_compositor_fill; |
||
2331 | compositor->base.stroke = _cairo_traps_compositor_stroke; |
||
2332 | compositor->base.glyphs = _cairo_traps_compositor_glyphs; |
||
2333 | }>>>>>>>>>>>><> |