Bug Summary

File:root/firefox-clang/gfx/cairo/cairo/src/cairo-spans-compositor.c
Warning:line 663, column 3
Value stored to 'status' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_c_gfx_cairo_cairo_src4.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/cairo/cairo/src -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/cairo/cairo/src -resource-dir /usr/lib/llvm-21/lib/clang/21 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D _GLIBCXX_ASSERTIONS -D DEBUG=1 -D HAVE_FT_LOAD_SFNT_TABLE -D PACKAGE_VERSION="moz" -D PACKAGE_BUGREPORT="http://bugzilla.mozilla.org/" -D CAIRO_HAS_PTHREAD -D _GNU_SOURCE -D MOZ_TREE_PIXMAN -D SIZEOF_VOID_P=__SIZEOF_POINTER__ -D SIZEOF_INT=__SIZEOF_INT__ -D SIZEOF_LONG=__SIZEOF_LONG__ -D SIZEOF_LONG_LONG=__SIZEOF_LONG_LONG__ -D HAVE_UINT64_T -D HAVE_CXX11_ATOMIC_PRIMITIVES -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/gfx/cairo/cairo/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/cairo/cairo/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/freetype2 -I /usr/include/libpng16 -internal-isystem /usr/lib/llvm-21/lib/clang/21/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=tautological-type-limit-compare -Wno-range-loop-analysis -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-unknown-warning-option -Wno-enum-compare -Wno-int-to-pointer-cast -Wno-int-conversion -Wno-incompatible-pointer-types -Wno-sign-compare -Wno-type-limits -Wno-missing-field-initializers -Wno-conversion -Wno-narrowing -Wno-switch -Wno-unused -Wno-unused-variable -Wno-error=uninitialized -Wno-absolute-value -Wno-deprecated-register -Wno-incompatible-pointer-types -Wno-macro-redefined -Wno-shift-negative-value -Wno-tautological-compare -Wno-tautological-constant-out-of-range-compare -Wno-unreachable-code -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2025-06-26-231904-1820671-1 -x c Unified_c_gfx_cairo_cairo_src4.c
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 <cworth@cworth.org>
38 * Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
39 * Chris Wilson <chris@chris-wilson.co.uk>
40 */
41
42#include "cairoint.h"
43
44#include "cairo-compositor-private.h"
45#include "cairo-clip-inline.h"
46#include "cairo-clip-private.h"
47#include "cairo-image-surface-private.h"
48#include "cairo-paginated-private.h"
49#include "cairo-pattern-inline.h"
50#include "cairo-region-private.h"
51#include "cairo-recording-surface-inline.h"
52#include "cairo-spans-compositor-private.h"
53#include "cairo-surface-subsurface-private.h"
54#include "cairo-surface-snapshot-private.h"
55#include "cairo-surface-observer-private.h"
56
57typedef struct {
58 cairo_polygon_t *polygon;
59 cairo_fill_rule_t fill_rule;
60 cairo_antialias_t antialias;
61} composite_spans_info_t;
62
63static cairo_int_status_t
64composite_polygon (const cairo_spans_compositor_t *compositor,
65 cairo_composite_rectangles_t *extents,
66 cairo_polygon_t *polygon,
67 cairo_fill_rule_t fill_rule,
68 cairo_antialias_t antialias);
69
70static cairo_int_status_t
71composite_boxes (const cairo_spans_compositor_t *compositor,
72 cairo_composite_rectangles_t *extents,
73 cairo_boxes_t *boxes);
74
75static cairo_int_status_t
76clip_and_composite_polygon (const cairo_spans_compositor_t *compositor,
77 cairo_composite_rectangles_t *extents,
78 cairo_polygon_t *polygon,
79 cairo_fill_rule_t fill_rule,
80 cairo_antialias_t antialias);
81static cairo_surface_t *
82get_clip_surface (const cairo_spans_compositor_t *compositor,
83 cairo_surface_t *dst,
84 const cairo_clip_t *clip,
85 const cairo_rectangle_int_t *extents)
86{
87 cairo_composite_rectangles_t composite;
88 cairo_surface_t *surface;
89 cairo_box_t box;
90 cairo_polygon_t polygon;
91 const cairo_clip_path_t *clip_path;
92 cairo_antialias_t antialias;
93 cairo_fill_rule_t fill_rule;
94 cairo_int_status_t status;
95
96 assert (clip->path)((void) sizeof ((clip->path) ? 1 : 0), __extension__ ({ if
(clip->path) ; else __assert_fail ("clip->path", "/root/firefox-clang/gfx/cairo/cairo/src/cairo-spans-compositor.c"
, 96, __extension__ __PRETTY_FUNCTION__); }))
;
97
98 surface = _cairo_surface_create_scratch (dst,
99 CAIRO_CONTENT_ALPHA,
100 extents->width,
101 extents->height,
102 CAIRO_COLOR_TRANSPARENT_cairo_stock_color (CAIRO_STOCK_TRANSPARENT));
103
104 _cairo_box_from_rectangle (&box, extents);
105 _cairo_polygon_init (&polygon, &box, 1);
106
107 clip_path = clip->path;
108 status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
109 clip_path->tolerance,
110 &polygon);
111 if (unlikely (status)(__builtin_expect (!!(status), 0)))
112 goto cleanup_polygon;
113
114 polygon.num_limits = 0;
115
116 antialias = clip_path->antialias;
117 fill_rule = clip_path->fill_rule;
118
119 if (clip->boxes) {
120 cairo_polygon_t intersect;
121 cairo_boxes_t tmp;
122
123 _cairo_boxes_init_for_array (&tmp, clip->boxes, clip->num_boxes);
124 status= _cairo_polygon_init_boxes (&intersect, &tmp);
125 if (unlikely (status)(__builtin_expect (!!(status), 0)))
126 goto cleanup_polygon;
127
128 status = _cairo_polygon_intersect (&polygon, fill_rule,
129 &intersect, CAIRO_FILL_RULE_WINDING);
130 _cairo_polygon_fini (&intersect);
131
132 if (unlikely (status)(__builtin_expect (!!(status), 0)))
133 goto cleanup_polygon;
134
135 fill_rule = CAIRO_FILL_RULE_WINDING;
136 }
137
138 polygon.limits = NULL((void*)0);
139 polygon.num_limits = 0;
140
141 clip_path = clip_path->prev;
142 while (clip_path) {
143 if (clip_path->antialias == antialias) {
144 cairo_polygon_t next;
145
146 _cairo_polygon_init (&next, NULL((void*)0), 0);
147 status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
148 clip_path->tolerance,
149 &next);
150 if (likely (status == CAIRO_INT_STATUS_SUCCESS)(__builtin_expect (!!(status == CAIRO_INT_STATUS_SUCCESS), 1)
)
)
151 status = _cairo_polygon_intersect (&polygon, fill_rule,
152 &next, clip_path->fill_rule);
153 _cairo_polygon_fini (&next);
154 if (unlikely (status)(__builtin_expect (!!(status), 0)))
155 goto cleanup_polygon;
156
157 fill_rule = CAIRO_FILL_RULE_WINDING;
158 }
159
160 clip_path = clip_path->prev;
161 }
162
163 _cairo_polygon_translate (&polygon, -extents->x, -extents->y);
164 status = _cairo_composite_rectangles_init_for_polygon (&composite, surface,
165 CAIRO_OPERATOR_ADD,
166 &_cairo_pattern_white.base,
167 &polygon,
168 NULL((void*)0));
169 if (unlikely (status)(__builtin_expect (!!(status), 0)))
170 goto cleanup_polygon;
171
172 status = composite_polygon (compositor, &composite,
173 &polygon, fill_rule, antialias);
174 _cairo_composite_rectangles_fini (&composite);
175 _cairo_polygon_fini (&polygon);
176 if (unlikely (status)(__builtin_expect (!!(status), 0)))
177 goto error;
178
179 _cairo_polygon_init (&polygon, &box, 1);
180
181 clip_path = clip->path;
182 antialias = clip_path->antialias == CAIRO_ANTIALIAS_DEFAULT ? CAIRO_ANTIALIAS_NONE : CAIRO_ANTIALIAS_DEFAULT;
183 clip_path = clip_path->prev;
184 while (clip_path) {
185 if (clip_path->antialias == antialias) {
186 if (polygon.num_edges == 0) {
187 status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
188 clip_path->tolerance,
189 &polygon);
190
191 fill_rule = clip_path->fill_rule;
192 polygon.limits = NULL((void*)0);
193 polygon.num_limits = 0;
194 } else {
195 cairo_polygon_t next;
196
197 _cairo_polygon_init (&next, NULL((void*)0), 0);
198 status = _cairo_path_fixed_fill_to_polygon (&clip_path->path,
199 clip_path->tolerance,
200 &next);
201 if (likely (status == CAIRO_INT_STATUS_SUCCESS)(__builtin_expect (!!(status == CAIRO_INT_STATUS_SUCCESS), 1)
)
)
202 status = _cairo_polygon_intersect (&polygon, fill_rule,
203 &next, clip_path->fill_rule);
204 _cairo_polygon_fini (&next);
205 fill_rule = CAIRO_FILL_RULE_WINDING;
206 }
207 if (unlikely (status)(__builtin_expect (!!(status), 0)))
208 goto error;
209 }
210
211 clip_path = clip_path->prev;
212 }
213
214 if (polygon.num_edges) {
215 _cairo_polygon_translate (&polygon, -extents->x, -extents->y);
216 status = _cairo_composite_rectangles_init_for_polygon (&composite, surface,
217 CAIRO_OPERATOR_IN,
218 &_cairo_pattern_white.base,
219 &polygon,
220 NULL((void*)0));
221 if (unlikely (status)(__builtin_expect (!!(status), 0)))
222 goto cleanup_polygon;
223
224 status = composite_polygon (compositor, &composite,
225 &polygon, fill_rule, antialias);
226 _cairo_composite_rectangles_fini (&composite);
227 _cairo_polygon_fini (&polygon);
228 if (unlikely (status)(__builtin_expect (!!(status), 0)))
229 goto error;
230 }
231
232 return surface;
233
234cleanup_polygon:
235 _cairo_polygon_fini (&polygon);
236error:
237 cairo_surface_destroy_moz_cairo_surface_destroy (surface);
238 return _cairo_int_surface_create_in_error (status);
239}
240
241static cairo_int_status_t
242fixup_unbounded_mask (const cairo_spans_compositor_t *compositor,
243 const cairo_composite_rectangles_t *extents,
244 cairo_boxes_t *boxes)
245{
246 cairo_composite_rectangles_t composite;
247 cairo_surface_t *clip;
248 cairo_int_status_t status;
249
250 TRACE((stderr, "%s\n", __FUNCTION__));
251
252 clip = get_clip_surface (compositor, extents->surface, extents->clip,
253 &extents->unbounded);
254 if (unlikely (clip->status)(__builtin_expect (!!(clip->status), 0))) {
255 if ((cairo_int_status_t)clip->status == CAIRO_INT_STATUS_NOTHING_TO_DO)
256 return CAIRO_STATUS_SUCCESS;
257
258 return clip->status;
259 }
260
261 status = _cairo_composite_rectangles_init_for_boxes (&composite,
262 extents->surface,
263 CAIRO_OPERATOR_CLEAR,
264 &_cairo_pattern_clear.base,
265 boxes,
266 NULL((void*)0));
267 if (unlikely (status)(__builtin_expect (!!(status), 0)))
268 goto cleanup_clip;
269
270 _cairo_pattern_init_for_surface (&composite.mask_pattern.surface, clip);
271 composite.mask_pattern.base.filter = CAIRO_FILTER_NEAREST;
272 composite.mask_pattern.base.extend = CAIRO_EXTEND_NONE;
273
274 status = composite_boxes (compositor, &composite, boxes);
275
276 _cairo_pattern_fini (&composite.mask_pattern.base);
277 _cairo_composite_rectangles_fini (&composite);
278
279cleanup_clip:
280 cairo_surface_destroy_moz_cairo_surface_destroy (clip);
281 return status;
282}
283
284static cairo_int_status_t
285fixup_unbounded_polygon (const cairo_spans_compositor_t *compositor,
286 const cairo_composite_rectangles_t *extents,
287 cairo_boxes_t *boxes)
288{
289 cairo_polygon_t polygon, intersect;
290 cairo_composite_rectangles_t composite;
291 cairo_fill_rule_t fill_rule;
292 cairo_antialias_t antialias;
293 cairo_int_status_t status;
294
295 TRACE((stderr, "%s\n", __FUNCTION__));
296
297 /* Can we treat the clip as a regular clear-polygon and use it to fill? */
298 status = _cairo_clip_get_polygon (extents->clip, &polygon,
299 &fill_rule, &antialias);
300 if (status == CAIRO_INT_STATUS_UNSUPPORTED)
301 return status;
302
303 status= _cairo_polygon_init_boxes (&intersect, boxes);
304 if (unlikely (status)(__builtin_expect (!!(status), 0)))
305 goto cleanup_polygon;
306
307 status = _cairo_polygon_intersect (&polygon, fill_rule,
308 &intersect, CAIRO_FILL_RULE_WINDING);
309 _cairo_polygon_fini (&intersect);
310
311 if (unlikely (status)(__builtin_expect (!!(status), 0)))
312 goto cleanup_polygon;
313
314 status = _cairo_composite_rectangles_init_for_polygon (&composite,
315 extents->surface,
316 CAIRO_OPERATOR_CLEAR,
317 &_cairo_pattern_clear.base,
318 &polygon,
319 NULL((void*)0));
320 if (unlikely (status)(__builtin_expect (!!(status), 0)))
321 goto cleanup_polygon;
322
323 status = composite_polygon (compositor, &composite,
324 &polygon, fill_rule, antialias);
325
326 _cairo_composite_rectangles_fini (&composite);
327cleanup_polygon:
328 _cairo_polygon_fini (&polygon);
329
330 return status;
331}
332
333static cairo_int_status_t
334fixup_unbounded_boxes (const cairo_spans_compositor_t *compositor,
335 const cairo_composite_rectangles_t *extents,
336 cairo_boxes_t *boxes)
337{
338 cairo_boxes_t tmp, clear;
339 cairo_box_t box;
340 cairo_int_status_t status;
341
342 assert (boxes->is_pixel_aligned)((void) sizeof ((boxes->is_pixel_aligned) ? 1 : 0), __extension__
({ if (boxes->is_pixel_aligned) ; else __assert_fail ("boxes->is_pixel_aligned"
, "/root/firefox-clang/gfx/cairo/cairo/src/cairo-spans-compositor.c"
, 342, __extension__ __PRETTY_FUNCTION__); }))
;
343
344 TRACE ((stderr, "%s\n", __FUNCTION__));
345 if (extents->bounded.width == extents->unbounded.width &&
346 extents->bounded.height == extents->unbounded.height)
347 {
348 return CAIRO_STATUS_SUCCESS;
349 }
350
351 /* subtract the drawn boxes from the unbounded area */
352 _cairo_boxes_init (&clear);
353
354 box.p1.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
355 box.p1.y = _cairo_fixed_from_int (extents->unbounded.y);
356 box.p2.x = _cairo_fixed_from_int (extents->unbounded.x);
357 box.p2.y = _cairo_fixed_from_int (extents->unbounded.y + extents->unbounded.height);
358
359 if (boxes->num_boxes) {
360 _cairo_boxes_init (&tmp);
361
362 status = _cairo_boxes_add (&tmp, CAIRO_ANTIALIAS_DEFAULT, &box);
363 assert (status == CAIRO_INT_STATUS_SUCCESS)((void) sizeof ((status == CAIRO_INT_STATUS_SUCCESS) ? 1 : 0)
, __extension__ ({ if (status == CAIRO_INT_STATUS_SUCCESS) ; else
__assert_fail ("status == CAIRO_INT_STATUS_SUCCESS", "/root/firefox-clang/gfx/cairo/cairo/src/cairo-spans-compositor.c"
, 363, __extension__ __PRETTY_FUNCTION__); }))
;
364
365 tmp.chunks.next = &boxes->chunks;
366 tmp.num_boxes += boxes->num_boxes;
367
368 status = _cairo_bentley_ottmann_tessellate_boxes (&tmp,
369 CAIRO_FILL_RULE_WINDING,
370 &clear);
371 tmp.chunks.next = NULL((void*)0);
372 if (unlikely (status)(__builtin_expect (!!(status), 0)))
373 goto error;
374 } else {
375 box.p1.x = _cairo_fixed_from_int (extents->unbounded.x);
376 box.p2.x = _cairo_fixed_from_int (extents->unbounded.x + extents->unbounded.width);
377
378 status = _cairo_boxes_add (&clear, CAIRO_ANTIALIAS_DEFAULT, &box);
379 assert (status == CAIRO_INT_STATUS_SUCCESS)((void) sizeof ((status == CAIRO_INT_STATUS_SUCCESS) ? 1 : 0)
, __extension__ ({ if (status == CAIRO_INT_STATUS_SUCCESS) ; else
__assert_fail ("status == CAIRO_INT_STATUS_SUCCESS", "/root/firefox-clang/gfx/cairo/cairo/src/cairo-spans-compositor.c"
, 379, __extension__ __PRETTY_FUNCTION__); }))
;
380 }
381
382 /* If we have a clip polygon, we need to intersect with that as well */
383 if (extents->clip->path) {
384 status = fixup_unbounded_polygon (compositor, extents, &clear);
385 if (status == CAIRO_INT_STATUS_UNSUPPORTED)
386 status = fixup_unbounded_mask (compositor, extents, &clear);
387 } else {
388 /* Otherwise just intersect with the clip boxes */
389 if (extents->clip->num_boxes) {
390 _cairo_boxes_init_for_array (&tmp,
391 extents->clip->boxes,
392 extents->clip->num_boxes);
393 status = _cairo_boxes_intersect (&clear, &tmp, &clear);
394 if (unlikely (status)(__builtin_expect (!!(status), 0)))
395 goto error;
396 }
397
398 if (clear.is_pixel_aligned) {
399 status = compositor->fill_boxes (extents->surface,
400 CAIRO_OPERATOR_CLEAR,
401 CAIRO_COLOR_TRANSPARENT_cairo_stock_color (CAIRO_STOCK_TRANSPARENT),
402 &clear);
403 } else {
404 cairo_composite_rectangles_t composite;
405
406 status = _cairo_composite_rectangles_init_for_boxes (&composite,
407 extents->surface,
408 CAIRO_OPERATOR_CLEAR,
409 &_cairo_pattern_clear.base,
410 &clear,
411 NULL((void*)0));
412 if (likely (status == CAIRO_INT_STATUS_SUCCESS)(__builtin_expect (!!(status == CAIRO_INT_STATUS_SUCCESS), 1)
)
) {
413 status = composite_boxes (compositor, &composite, &clear);
414 _cairo_composite_rectangles_fini (&composite);
415 }
416 }
417 }
418
419error:
420 _cairo_boxes_fini (&clear);
421 return status;
422}
423
424static cairo_surface_t *
425unwrap_source (const cairo_pattern_t *pattern)
426{
427 cairo_rectangle_int_t limit;
428
429 return _cairo_pattern_get_source ((cairo_surface_pattern_t *)pattern,
430 &limit);
431}
432
433static cairo_bool_t
434is_recording_pattern (const cairo_pattern_t *pattern)
435{
436 cairo_surface_t *surface;
437
438 if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE)
439 return FALSE0;
440
441 surface = ((const cairo_surface_pattern_t *) pattern)->surface;
442 return _cairo_surface_is_recording (surface);
443}
444
445static cairo_bool_t
446recording_pattern_contains_sample (const cairo_pattern_t *pattern,
447 const cairo_rectangle_int_t *sample)
448{
449 cairo_recording_surface_t *surface;
450
451 if (! is_recording_pattern (pattern))
452 return FALSE0;
453
454 if (pattern->extend == CAIRO_EXTEND_NONE)
455 return TRUE1;
456
457 surface = (cairo_recording_surface_t *) unwrap_source (pattern);
458 if (surface->unbounded)
459 return TRUE1;
460
461 return _cairo_rectangle_contains_rectangle (&surface->extents, sample);
462}
463
464static cairo_bool_t
465op_reduces_to_source (const cairo_composite_rectangles_t *extents,
466 cairo_bool_t no_mask)
467{
468 if (extents->op == CAIRO_OPERATOR_SOURCE)
469 return TRUE1;
470
471 if (extents->surface->is_clear)
472 return extents->op == CAIRO_OPERATOR_OVER || extents->op == CAIRO_OPERATOR_ADD;
473
474 if (no_mask && extents->op == CAIRO_OPERATOR_OVER)
475 return _cairo_pattern_is_opaque (&extents->source_pattern.base,
476 &extents->source_sample_area);
477
478 return FALSE0;
479}
480
481static cairo_status_t
482upload_boxes (const cairo_spans_compositor_t *compositor,
483 const cairo_composite_rectangles_t *extents,
484 cairo_boxes_t *boxes)
485{
486 cairo_surface_t *dst = extents->surface;
487 const cairo_surface_pattern_t *source = &extents->source_pattern.surface;
488 cairo_surface_t *src;
489 cairo_rectangle_int_t limit;
490 cairo_int_status_t status;
491 int tx, ty;
492
493 TRACE ((stderr, "%s\n", __FUNCTION__));
494
495 src = _cairo_pattern_get_source(source, &limit);
496 if (!(src->type == CAIRO_SURFACE_TYPE_IMAGE || src->type == dst->type))
497 return CAIRO_INT_STATUS_UNSUPPORTED;
498
499 if (! _cairo_matrix_is_integer_translation (&source->base.matrix, &tx, &ty))
500 return CAIRO_INT_STATUS_UNSUPPORTED;
501
502 /* Check that the data is entirely within the image */
503 if (extents->bounded.x + tx < limit.x || extents->bounded.y + ty < limit.y)
504 return CAIRO_INT_STATUS_UNSUPPORTED;
505
506 if (extents->bounded.x + extents->bounded.width + tx > limit.x + limit.width ||
507 extents->bounded.y + extents->bounded.height + ty > limit.y + limit.height)
508 return CAIRO_INT_STATUS_UNSUPPORTED;
509
510 tx += limit.x;
511 ty += limit.y;
512
513 if (src->type == CAIRO_SURFACE_TYPE_IMAGE)
514 status = compositor->draw_image_boxes (dst,
515 (cairo_image_surface_t *)src,
516 boxes, tx, ty);
517 else
518 status = compositor->copy_boxes (dst, src, boxes, &extents->bounded,
519 tx, ty);
520
521 return status;
522}
523
524static cairo_bool_t
525_clip_is_region (const cairo_clip_t *clip)
526{
527 int i;
528
529 if (clip->is_region)
530 return TRUE1;
531
532 if (clip->path)
533 return FALSE0;
534
535 for (i = 0; i < clip->num_boxes; i++) {
536 const cairo_box_t *b = &clip->boxes[i];
537 if (!_cairo_fixed_is_integer (b->p1.x | b->p1.y | b->p2.x | b->p2.y))
538 return FALSE0;
539 }
540
541 return TRUE1;
542}
543
544static cairo_int_status_t
545composite_aligned_boxes (const cairo_spans_compositor_t *compositor,
546 const cairo_composite_rectangles_t *extents,
547 cairo_boxes_t *boxes)
548{
549 cairo_surface_t *dst = extents->surface;
550 cairo_operator_t op = extents->op;
551 const cairo_pattern_t *source = &extents->source_pattern.base;
552 cairo_int_status_t status;
553 cairo_bool_t need_clip_mask = ! _clip_is_region (extents->clip);
554 cairo_bool_t op_is_source;
555 cairo_bool_t no_mask;
556 cairo_bool_t inplace;
557
558 TRACE ((stderr, "%s: need_clip_mask=%d, is-bounded=%d\n",
559 __FUNCTION__, need_clip_mask, extents->is_bounded));
560 if (need_clip_mask && ! extents->is_bounded) {
561 TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__));
562 return CAIRO_INT_STATUS_UNSUPPORTED;
563 }
564
565 no_mask = extents->mask_pattern.base.type == CAIRO_PATTERN_TYPE_SOLID &&
566 CAIRO_COLOR_IS_OPAQUE (&extents->mask_pattern.solid.color)(((&extents->mask_pattern.solid.color)->alpha_short
) >= 0xff00)
;
567 op_is_source = op_reduces_to_source (extents, no_mask);
568 inplace = ! need_clip_mask && op_is_source && no_mask;
569
570 TRACE ((stderr, "%s: op-is-source=%d [op=%d], no-mask=%d, inplace=%d\n",
571 __FUNCTION__, op_is_source, op, no_mask, inplace));
572
573 if (op == CAIRO_OPERATOR_SOURCE && (need_clip_mask || ! no_mask)) {
574 /* SOURCE with a mask is actually a LERP in cairo semantics */
575 if ((compositor->flags & CAIRO_SPANS_COMPOSITOR_HAS_LERP0x1) == 0) {
576 TRACE ((stderr, "%s: unsupported lerp\n", __FUNCTION__));
577 return CAIRO_INT_STATUS_UNSUPPORTED;
578 }
579 }
580
581 /* Are we just copying a recording surface? */
582 if (inplace &&
583 recording_pattern_contains_sample (&extents->source_pattern.base,
584 &extents->source_sample_area))
585 {
586 cairo_clip_t *recording_clip;
587 const cairo_pattern_t *source = &extents->source_pattern.base;
588 const cairo_matrix_t *m;
589 cairo_matrix_t matrix;
590
591 /* XXX could also do tiling repeat modes... */
592
593 /* first clear the area about to be overwritten */
594 if (! dst->is_clear) {
595 status = compositor->fill_boxes (dst,
596 CAIRO_OPERATOR_CLEAR,
597 CAIRO_COLOR_TRANSPARENT_cairo_stock_color (CAIRO_STOCK_TRANSPARENT),
598 boxes);
599 if (unlikely (status)(__builtin_expect (!!(status), 0)))
600 return status;
601
602 dst->is_clear = TRUE1;
603 }
604
605 m = &source->matrix;
606 if (_cairo_surface_has_device_transform (dst)) {
607 cairo_matrix_multiply_moz_cairo_matrix_multiply (&matrix,
608 &source->matrix,
609 &dst->device_transform);
610 m = &matrix;
611 }
612
613 recording_clip = _cairo_clip_from_boxes (boxes);
614 status = _cairo_recording_surface_replay_with_clip (unwrap_source (source),
615 m, dst, recording_clip);
616 _cairo_clip_destroy (recording_clip);
617
618 return status;
619 }
620
621 status = CAIRO_INT_STATUS_UNSUPPORTED;
622 if (! need_clip_mask && no_mask && source->type == CAIRO_PATTERN_TYPE_SOLID) {
623 const cairo_color_t *color;
624
625 color = &((cairo_solid_pattern_t *) source)->color;
626 if (op_is_source)
627 op = CAIRO_OPERATOR_SOURCE;
628 status = compositor->fill_boxes (dst, op, color, boxes);
629 } else if (inplace && source->type == CAIRO_PATTERN_TYPE_SURFACE) {
630 status = upload_boxes (compositor, extents, boxes);
631 }
632 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
633 cairo_surface_t *src;
634 cairo_surface_t *mask = NULL((void*)0);
635 int src_x, src_y;
636 int mask_x = 0, mask_y = 0;
637
638 /* All typical cases will have been resolved before now... */
639 if (need_clip_mask) {
640 mask = get_clip_surface (compositor, dst, extents->clip,
641 &extents->bounded);
642 if (unlikely (mask->status)(__builtin_expect (!!(mask->status), 0)))
643 return mask->status;
644
645 mask_x = -extents->bounded.x;
646 mask_y = -extents->bounded.y;
647 }
648
649 /* XXX but this is still ugly */
650 if (! no_mask) {
651 src = compositor->pattern_to_surface (dst,
652 &extents->mask_pattern.base,
653 TRUE1,
654 &extents->bounded,
655 &extents->mask_sample_area,
656 &src_x, &src_y);
657 if (unlikely (src->status)(__builtin_expect (!!(src->status), 0))) {
658 cairo_surface_destroy_moz_cairo_surface_destroy (mask);
659 return src->status;
660 }
661
662 if (mask != NULL((void*)0)) {
663 status = compositor->composite_boxes (mask, CAIRO_OPERATOR_IN,
Value stored to 'status' is never read
664 src, NULL((void*)0),
665 src_x, src_y,
666 0, 0,
667 mask_x, mask_y,
668 boxes, &extents->bounded);
669
670 cairo_surface_destroy_moz_cairo_surface_destroy (src);
671 } else {
672 mask = src;
673 mask_x = src_x;
674 mask_y = src_y;
675 }
676 }
677
678 src = compositor->pattern_to_surface (dst, source, FALSE0,
679 &extents->bounded,
680 &extents->source_sample_area,
681 &src_x, &src_y);
682 if (likely (src->status == CAIRO_STATUS_SUCCESS)(__builtin_expect (!!(src->status == CAIRO_STATUS_SUCCESS)
, 1))
) {
683 status = compositor->composite_boxes (dst, op, src, mask,
684 src_x, src_y,
685 mask_x, mask_y,
686 0, 0,
687 boxes, &extents->bounded);
688 cairo_surface_destroy_moz_cairo_surface_destroy (src);
689 } else
690 status = src->status;
691
692 cairo_surface_destroy_moz_cairo_surface_destroy (mask);
693 }
694
695 if (status == CAIRO_INT_STATUS_SUCCESS && ! extents->is_bounded)
696 status = fixup_unbounded_boxes (compositor, extents, boxes);
697
698 return status;
699}
700
701static cairo_bool_t
702composite_needs_clip (const cairo_composite_rectangles_t *composite,
703 const cairo_box_t *extents)
704{
705 return !_cairo_clip_contains_box (composite->clip, extents);
706}
707
708static cairo_int_status_t
709composite_boxes (const cairo_spans_compositor_t *compositor,
710 cairo_composite_rectangles_t *extents,
711 cairo_boxes_t *boxes)
712{
713 cairo_abstract_span_renderer_t renderer;
714 cairo_rectangular_scan_converter_t converter;
715 const struct _cairo_boxes_chunk *chunk;
716 cairo_int_status_t status;
717 cairo_box_t box;
718
719 TRACE ((stderr, "%s\n", __FUNCTION__));
720 _cairo_box_from_rectangle (&box, &extents->unbounded);
721 if (composite_needs_clip (extents, &box)) {
722 TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__));
723 return CAIRO_INT_STATUS_UNSUPPORTED;
724 }
725
726 _cairo_rectangular_scan_converter_init (&converter, &extents->unbounded);
727 for (chunk = &boxes->chunks; chunk != NULL((void*)0); chunk = chunk->next) {
728 const cairo_box_t *box = chunk->base;
729 int i;
730
731 for (i = 0; i < chunk->count; i++) {
732 status = _cairo_rectangular_scan_converter_add_box (&converter, &box[i], 1);
733 if (unlikely (status)(__builtin_expect (!!(status), 0)))
734 goto cleanup_converter;
735 }
736 }
737
738 status = compositor->renderer_init (&renderer, extents,
739 CAIRO_ANTIALIAS_DEFAULT, FALSE0);
740 if (likely (status == CAIRO_INT_STATUS_SUCCESS)(__builtin_expect (!!(status == CAIRO_INT_STATUS_SUCCESS), 1)
)
)
741 status = converter.base.generate (&converter.base, &renderer.base);
742 compositor->renderer_fini (&renderer, status);
743
744cleanup_converter:
745 converter.base.destroy (&converter.base);
746 return status;
747}
748
749static cairo_int_status_t
750composite_polygon (const cairo_spans_compositor_t *compositor,
751 cairo_composite_rectangles_t *extents,
752 cairo_polygon_t *polygon,
753 cairo_fill_rule_t fill_rule,
754 cairo_antialias_t antialias)
755{
756 cairo_abstract_span_renderer_t renderer;
757 cairo_scan_converter_t *converter;
758 cairo_bool_t needs_clip;
759 cairo_int_status_t status;
760
761 if (extents->is_bounded)
762 needs_clip = extents->clip->path != NULL((void*)0);
763 else
764 needs_clip = !_clip_is_region (extents->clip) || extents->clip->num_boxes > 1;
765 TRACE ((stderr, "%s - needs_clip=%d\n", __FUNCTION__, needs_clip));
766 if (needs_clip) {
767 TRACE ((stderr, "%s: unsupported clip\n", __FUNCTION__));
768 return CAIRO_INT_STATUS_UNSUPPORTED;
769 converter = _cairo_clip_tor_scan_converter_create (extents->clip,
770 polygon,
771 fill_rule, antialias);
772 } else {
773 const cairo_rectangle_int_t *r = &extents->unbounded;
774
775 if (antialias == CAIRO_ANTIALIAS_FAST) {
776 converter = _cairo_tor22_scan_converter_create (r->x, r->y,
777 r->x + r->width,
778 r->y + r->height,
779 fill_rule, antialias);
780 status = _cairo_tor22_scan_converter_add_polygon (converter, polygon);
781 } else if (antialias == CAIRO_ANTIALIAS_NONE) {
782 converter = _cairo_mono_scan_converter_create (r->x, r->y,
783 r->x + r->width,
784 r->y + r->height,
785 fill_rule);
786 status = _cairo_mono_scan_converter_add_polygon (converter, polygon);
787 } else {
788 converter = _cairo_tor_scan_converter_create (r->x, r->y,
789 r->x + r->width,
790 r->y + r->height,
791 fill_rule, antialias);
792 status = _cairo_tor_scan_converter_add_polygon (converter, polygon);
793 }
794 }
795 if (unlikely (status)(__builtin_expect (!!(status), 0)))
796 goto cleanup_converter;
797
798 status = compositor->renderer_init (&renderer, extents,
799 antialias, needs_clip);
800 if (likely (status == CAIRO_INT_STATUS_SUCCESS)(__builtin_expect (!!(status == CAIRO_INT_STATUS_SUCCESS), 1)
)
)
801 status = converter->generate (converter, &renderer.base);
802 compositor->renderer_fini (&renderer, status);
803
804cleanup_converter:
805 converter->destroy (converter);
806 return status;
807}
808
809static cairo_int_status_t
810trim_extents_to_boxes (cairo_composite_rectangles_t *extents,
811 cairo_boxes_t *boxes)
812{
813 cairo_box_t box;
814
815 _cairo_boxes_extents (boxes, &box);
816 return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
817}
818
819static cairo_int_status_t
820trim_extents_to_polygon (cairo_composite_rectangles_t *extents,
821 cairo_polygon_t *polygon)
822{
823 return _cairo_composite_rectangles_intersect_mask_extents (extents,
824 &polygon->extents);
825}
826
827static cairo_int_status_t
828clip_and_composite_boxes (const cairo_spans_compositor_t *compositor,
829 cairo_composite_rectangles_t *extents,
830 cairo_boxes_t *boxes)
831{
832 cairo_int_status_t status;
833 cairo_polygon_t polygon;
834
835 TRACE ((stderr, "%s\n", __FUNCTION__));
836 status = trim_extents_to_boxes (extents, boxes);
837 if (unlikely (status)(__builtin_expect (!!(status), 0)))
838 return status;
839
840 if (boxes->num_boxes == 0) {
841 if (extents->is_bounded)
842 return CAIRO_STATUS_SUCCESS;
843
844 return fixup_unbounded_boxes (compositor, extents, boxes);
845 }
846
847 /* Can we reduce drawing through a clip-mask to simply drawing the clip? */
848 if (extents->clip->path != NULL((void*)0) && extents->is_bounded) {
849 cairo_polygon_t polygon;
850 cairo_fill_rule_t fill_rule;
851 cairo_antialias_t antialias;
852 cairo_clip_t *clip;
853
854 clip = _cairo_clip_copy (extents->clip);
855 clip = _cairo_clip_intersect_boxes (clip, boxes);
856 if (_cairo_clip_is_all_clipped (clip))
857 return CAIRO_INT_STATUS_NOTHING_TO_DO;
858
859 status = _cairo_clip_get_polygon (clip, &polygon,
860 &fill_rule, &antialias);
861 _cairo_clip_path_destroy (clip->path);
862 clip->path = NULL((void*)0);
863 if (likely (status == CAIRO_INT_STATUS_SUCCESS)(__builtin_expect (!!(status == CAIRO_INT_STATUS_SUCCESS), 1)
)
) {
864 cairo_clip_t *saved_clip = extents->clip;
865 extents->clip = clip;
866
867 status = clip_and_composite_polygon (compositor, extents, &polygon,
868 fill_rule, antialias);
869
870 clip = extents->clip;
871 extents->clip = saved_clip;
872
873 _cairo_polygon_fini (&polygon);
874 }
875 _cairo_clip_destroy (clip);
876
877 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
878 return status;
879 }
880
881 if (boxes->is_pixel_aligned) {
882 status = composite_aligned_boxes (compositor, extents, boxes);
883 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
884 return status;
885 }
886
887 status = composite_boxes (compositor, extents, boxes);
888 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
889 return status;
890
891 status = _cairo_polygon_init_boxes (&polygon, boxes);
892 if (unlikely (status)(__builtin_expect (!!(status), 0)))
893 return status;
894
895 status = composite_polygon (compositor, extents, &polygon,
896 CAIRO_FILL_RULE_WINDING,
897 CAIRO_ANTIALIAS_DEFAULT);
898 _cairo_polygon_fini (&polygon);
899
900 return status;
901}
902
903static cairo_int_status_t
904clip_and_composite_polygon (const cairo_spans_compositor_t *compositor,
905 cairo_composite_rectangles_t *extents,
906 cairo_polygon_t *polygon,
907 cairo_fill_rule_t fill_rule,
908 cairo_antialias_t antialias)
909{
910 cairo_int_status_t status;
911
912 TRACE ((stderr, "%s\n", __FUNCTION__));
913
914 /* XXX simply uses polygon limits.point extemities, tessellation? */
915 status = trim_extents_to_polygon (extents, polygon);
916 if (unlikely (status)(__builtin_expect (!!(status), 0)))
917 return status;
918
919 if (_cairo_polygon_is_empty (polygon)) {
920 cairo_boxes_t boxes;
921
922 if (extents->is_bounded)
923 return CAIRO_STATUS_SUCCESS;
924
925 _cairo_boxes_init (&boxes);
926 extents->bounded.width = extents->bounded.height = 0;
927 return fixup_unbounded_boxes (compositor, extents, &boxes);
928 }
929
930 if (extents->is_bounded && extents->clip->path) {
931 cairo_polygon_t clipper;
932 cairo_antialias_t clip_antialias;
933 cairo_fill_rule_t clip_fill_rule;
934
935 TRACE((stderr, "%s - combining shape with clip polygon\n",
936 __FUNCTION__));
937
938 status = _cairo_clip_get_polygon (extents->clip,
939 &clipper,
940 &clip_fill_rule,
941 &clip_antialias);
942 if (likely (status == CAIRO_INT_STATUS_SUCCESS)(__builtin_expect (!!(status == CAIRO_INT_STATUS_SUCCESS), 1)
)
) {
943 cairo_clip_t *old_clip;
944
945 if (clip_antialias == antialias) {
946 status = _cairo_polygon_intersect (polygon, fill_rule,
947 &clipper, clip_fill_rule);
948 _cairo_polygon_fini (&clipper);
949 if (unlikely (status)(__builtin_expect (!!(status), 0)))
950 return status;
951
952 old_clip = extents->clip;
953 extents->clip = _cairo_clip_copy_region (extents->clip);
954 _cairo_clip_destroy (old_clip);
955
956 status = trim_extents_to_polygon (extents, polygon);
957 if (unlikely (status)(__builtin_expect (!!(status), 0)))
958 return status;
959
960 fill_rule = CAIRO_FILL_RULE_WINDING;
961 } else {
962 _cairo_polygon_fini (&clipper);
963 }
964 }
965 }
966
967 return composite_polygon (compositor, extents,
968 polygon, fill_rule, antialias);
969}
970
971/* high-level compositor interface */
972
973static cairo_int_status_t
974_cairo_spans_compositor_paint (const cairo_compositor_t *_compositor,
975 cairo_composite_rectangles_t *extents)
976{
977 const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
978 cairo_boxes_t boxes;
979 cairo_int_status_t status;
980
981 TRACE ((stderr, "%s\n", __FUNCTION__));
982 _cairo_clip_steal_boxes (extents->clip, &boxes);
983 status = clip_and_composite_boxes (compositor, extents, &boxes);
984 _cairo_clip_unsteal_boxes (extents->clip, &boxes);
985
986 return status;
987}
988
989static cairo_int_status_t
990_cairo_spans_compositor_mask (const cairo_compositor_t *_compositor,
991 cairo_composite_rectangles_t *extents)
992{
993 const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
994 cairo_int_status_t status;
995 cairo_boxes_t boxes;
996
997 TRACE ((stderr, "%s\n", __FUNCTION__));
998 _cairo_clip_steal_boxes (extents->clip, &boxes);
999 status = clip_and_composite_boxes (compositor, extents, &boxes);
1000 _cairo_clip_unsteal_boxes (extents->clip, &boxes);
1001
1002 return status;
1003}
1004
1005static cairo_int_status_t
1006_cairo_spans_compositor_stroke (const cairo_compositor_t *_compositor,
1007 cairo_composite_rectangles_t *extents,
1008 const cairo_path_fixed_t *path,
1009 const cairo_stroke_style_t *style,
1010 const cairo_matrix_t *ctm,
1011 const cairo_matrix_t *ctm_inverse,
1012 double tolerance,
1013 cairo_antialias_t antialias)
1014{
1015 const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
1016 cairo_int_status_t status;
1017
1018 TRACE ((stderr, "%s\n", __FUNCTION__));
1019 TRACE_ (_cairo_debug_print_path (stderr, path));
1020 TRACE_ (_cairo_debug_print_clip (stderr, extents->clip));
1021
1022 status = CAIRO_INT_STATUS_UNSUPPORTED;
1023 if (_cairo_path_fixed_stroke_is_rectilinear (path)) {
1024 cairo_boxes_t boxes;
1025
1026 _cairo_boxes_init (&boxes);
1027 if (! _cairo_clip_contains_rectangle (extents->clip, &extents->mask))
1028 _cairo_boxes_limit (&boxes,
1029 extents->clip->boxes,
1030 extents->clip->num_boxes);
1031
1032 status = _cairo_path_fixed_stroke_rectilinear_to_boxes (path,
1033 style,
1034 ctm,
1035 antialias,
1036 &boxes);
1037 if (likely (status == CAIRO_INT_STATUS_SUCCESS)(__builtin_expect (!!(status == CAIRO_INT_STATUS_SUCCESS), 1)
)
)
1038 status = clip_and_composite_boxes (compositor, extents, &boxes);
1039 _cairo_boxes_fini (&boxes);
1040 }
1041
1042 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1043 cairo_polygon_t polygon;
1044 cairo_box_t limits;
1045 cairo_fill_rule_t fill_rule = CAIRO_FILL_RULE_WINDING;
1046
1047 if (! _cairo_rectangle_contains_rectangle (&extents->unbounded,
1048 &extents->mask))
1049 {
1050 if (extents->clip->num_boxes == 1) {
1051 _cairo_polygon_init (&polygon, extents->clip->boxes, 1);
1052 } else {
1053 _cairo_box_from_rectangle (&limits, &extents->unbounded);
1054 _cairo_polygon_init (&polygon, &limits, 1);
1055 }
1056 }
1057 else
1058 {
1059 _cairo_polygon_init (&polygon, NULL((void*)0), 0);
1060 }
1061 status = _cairo_path_fixed_stroke_to_polygon (path,
1062 style,
1063 ctm, ctm_inverse,
1064 tolerance,
1065 &polygon);
1066 TRACE_ (_cairo_debug_print_polygon (stderr, &polygon));
1067 polygon.num_limits = 0;
1068
1069 if (status == CAIRO_INT_STATUS_SUCCESS && extents->clip->num_boxes > 1) {
1070 status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule,
1071 extents->clip->boxes,
1072 extents->clip->num_boxes);
1073 }
1074 if (likely (status == CAIRO_INT_STATUS_SUCCESS)(__builtin_expect (!!(status == CAIRO_INT_STATUS_SUCCESS), 1)
)
) {
1075 cairo_clip_t *saved_clip = extents->clip;
1076
1077 if (extents->is_bounded) {
1078 extents->clip = _cairo_clip_copy_path (extents->clip);
1079 extents->clip = _cairo_clip_intersect_box(extents->clip,
1080 &polygon.extents);
1081 }
1082
1083 status = clip_and_composite_polygon (compositor, extents, &polygon,
1084 fill_rule, antialias);
1085
1086 if (extents->is_bounded) {
1087 _cairo_clip_destroy (extents->clip);
1088 extents->clip = saved_clip;
1089 }
1090 }
1091 _cairo_polygon_fini (&polygon);
1092 }
1093
1094 return status;
1095}
1096
1097static cairo_int_status_t
1098_cairo_spans_compositor_fill (const cairo_compositor_t *_compositor,
1099 cairo_composite_rectangles_t *extents,
1100 const cairo_path_fixed_t *path,
1101 cairo_fill_rule_t fill_rule,
1102 double tolerance,
1103 cairo_antialias_t antialias)
1104{
1105 const cairo_spans_compositor_t *compositor = (cairo_spans_compositor_t*)_compositor;
1106 cairo_int_status_t status;
1107
1108 TRACE((stderr, "%s op=%d, antialias=%d\n", __FUNCTION__, extents->op, antialias));
1109
1110 status = CAIRO_INT_STATUS_UNSUPPORTED;
1111 if (_cairo_path_fixed_fill_is_rectilinear (path)) {
1112 cairo_boxes_t boxes;
1113
1114 TRACE((stderr, "%s - rectilinear\n", __FUNCTION__));
1115
1116 _cairo_boxes_init (&boxes);
1117 if (! _cairo_clip_contains_rectangle (extents->clip, &extents->mask))
1118 _cairo_boxes_limit (&boxes,
1119 extents->clip->boxes,
1120 extents->clip->num_boxes);
1121 status = _cairo_path_fixed_fill_rectilinear_to_boxes (path,
1122 fill_rule,
1123 antialias,
1124 &boxes);
1125 if (likely (status == CAIRO_INT_STATUS_SUCCESS)(__builtin_expect (!!(status == CAIRO_INT_STATUS_SUCCESS), 1)
)
)
1126 status = clip_and_composite_boxes (compositor, extents, &boxes);
1127 _cairo_boxes_fini (&boxes);
1128 }
1129 if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1130 cairo_polygon_t polygon;
1131 cairo_box_t limits;
1132
1133 TRACE((stderr, "%s - polygon\n", __FUNCTION__));
1134
1135 if (! _cairo_rectangle_contains_rectangle (&extents->unbounded,
1136 &extents->mask))
1137 {
1138 TRACE((stderr, "%s - clipping to bounds\n", __FUNCTION__));
1139 if (extents->clip->num_boxes == 1) {
1140 _cairo_polygon_init (&polygon, extents->clip->boxes, 1);
1141 } else {
1142 _cairo_box_from_rectangle (&limits, &extents->unbounded);
1143 _cairo_polygon_init (&polygon, &limits, 1);
1144 }
1145 }
1146 else
1147 {
1148 _cairo_polygon_init (&polygon, NULL((void*)0), 0);
1149 }
1150
1151 status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
1152 TRACE_ (_cairo_debug_print_polygon (stderr, &polygon));
1153 polygon.num_limits = 0;
1154
1155 if (status == CAIRO_INT_STATUS_SUCCESS && extents->clip->num_boxes > 1) {
1156 TRACE((stderr, "%s - polygon intersect with %d clip boxes\n",
1157 __FUNCTION__, extents->clip->num_boxes));
1158 status = _cairo_polygon_intersect_with_boxes (&polygon, &fill_rule,
1159 extents->clip->boxes,
1160 extents->clip->num_boxes);
1161 }
1162 TRACE_ (_cairo_debug_print_polygon (stderr, &polygon));
1163 if (likely (status == CAIRO_INT_STATUS_SUCCESS)(__builtin_expect (!!(status == CAIRO_INT_STATUS_SUCCESS), 1)
)
) {
1164 cairo_clip_t *saved_clip = extents->clip;
1165
1166 if (extents->is_bounded) {
1167 TRACE((stderr, "%s - polygon discard clip boxes\n",
1168 __FUNCTION__));
1169 extents->clip = _cairo_clip_copy_path (extents->clip);
1170 extents->clip = _cairo_clip_intersect_box(extents->clip,
1171 &polygon.extents);
1172 }
1173
1174 status = clip_and_composite_polygon (compositor, extents, &polygon,
1175 fill_rule, antialias);
1176
1177 if (extents->is_bounded) {
1178 _cairo_clip_destroy (extents->clip);
1179 extents->clip = saved_clip;
1180 }
1181 }
1182 _cairo_polygon_fini (&polygon);
1183
1184 TRACE((stderr, "%s - polygon status=%d\n", __FUNCTION__, status));
1185 }
1186
1187 return status;
1188}
1189
1190void
1191_cairo_spans_compositor_init (cairo_spans_compositor_t *compositor,
1192 const cairo_compositor_t *delegate)
1193{
1194 compositor->base.delegate = delegate;
1195
1196 compositor->base.paint = _cairo_spans_compositor_paint;
1197 compositor->base.mask = _cairo_spans_compositor_mask;
1198 compositor->base.fill = _cairo_spans_compositor_fill;
1199 compositor->base.stroke = _cairo_spans_compositor_stroke;
1200 compositor->base.glyphs = NULL((void*)0);
1201}