Coverage Report

Created: 2026-08-14 08:24

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