Coverage Report

Created: 2026-05-23 06:40

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