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
4 * Copyright © 2002 University of Southern California
5 * Copyright © 2005 Red Hat, Inc.
6 * Copyright © 2011 Intel Corporation
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.
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
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/
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.
31 * The Original Code is the cairo graphics library.
33 * The Initial Developer of the Original Code is University of Southern
37 * Carl D. Worth <cworth@cworth.org>
38 * Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
39 * Chris Wilson <chris@chris-wilson.co.uk>
42 /* This compositor renders the shape to a mask using an image surface
43 * then calls composite.
48 #include "cairo-clip-inline.h"
49 #include "cairo-compositor-private.h"
50 #include "cairo-image-surface-private.h"
51 #include "cairo-pattern-inline.h"
52 #include "cairo-region-private.h"
53 #include "cairo-surface-observer-private.h"
54 #include "cairo-surface-offset-private.h"
55 #include "cairo-surface-snapshot-private.h"
56 #include "cairo-surface-subsurface-private.h"
58 typedef cairo_int_status_t
59 (*draw_func_t
) (const cairo_mask_compositor_t
*compositor
,
63 const cairo_pattern_t
*src
,
64 const cairo_rectangle_int_t
*src_sample
,
67 const cairo_rectangle_int_t
*extents
,
70 static void do_unaligned_row(void (*blt
)(void *closure
,
79 int x1
= _cairo_fixed_integer_part (b
->p1
.x
) - tx
;
80 int x2
= _cairo_fixed_integer_part (b
->p2
.x
) - tx
;
82 if (! _cairo_fixed_is_integer (b
->p1
.x
)) {
83 blt(closure
, x1
, y
, 1, h
,
84 coverage
* (256 - _cairo_fixed_fractional_part (b
->p1
.x
)));
89 blt(closure
, x1
, y
, x2
-x1
, h
, (coverage
<< 8) - (coverage
>> 8));
91 if (! _cairo_fixed_is_integer (b
->p2
.x
))
92 blt(closure
, x2
, y
, 1, h
,
93 coverage
* _cairo_fixed_fractional_part (b
->p2
.x
));
95 blt(closure
, x1
, y
, 1, h
,
96 coverage
* (b
->p2
.x
- b
->p1
.x
));
99 static void do_unaligned_box(void (*blt
)(void *closure
,
100 int16_t x
, int16_t y
,
101 int16_t w
, int16_t h
,
104 const cairo_box_t
*b
, int tx
, int ty
)
106 int y1
= _cairo_fixed_integer_part (b
->p1
.y
) - ty
;
107 int y2
= _cairo_fixed_integer_part (b
->p2
.y
) - ty
;
109 if (! _cairo_fixed_is_integer (b
->p1
.y
)) {
110 do_unaligned_row(blt
, closure
, b
, tx
, y1
, 1,
111 256 - _cairo_fixed_fractional_part (b
->p1
.y
));
116 do_unaligned_row(blt
, closure
, b
, tx
, y1
, y2
-y1
, 256);
118 if (! _cairo_fixed_is_integer (b
->p2
.y
))
119 do_unaligned_row(blt
, closure
, b
, tx
, y2
, 1,
120 _cairo_fixed_fractional_part (b
->p2
.y
));
122 do_unaligned_row(blt
, closure
, b
, tx
, y1
, 1,
127 const cairo_mask_compositor_t
*compositor
;
128 cairo_surface_t
*dst
;
131 static void blt_in(void *closure
,
132 int16_t x
, int16_t y
,
133 int16_t w
, int16_t h
,
136 struct blt_in
*info
= closure
;
138 cairo_rectangle_int_t rect
;
140 if (coverage
== 0xffff)
148 _cairo_color_init_rgba (&color
, 0, 0, 0, coverage
/ (double) 0xffff);
149 info
->compositor
->fill_rectangles (info
->dst
, CAIRO_OPERATOR_IN
,
153 static cairo_surface_t
*
154 create_composite_mask (const cairo_mask_compositor_t
*compositor
,
155 cairo_surface_t
*dst
,
157 draw_func_t draw_func
,
158 draw_func_t mask_func
,
159 const cairo_composite_rectangles_t
*extents
)
161 cairo_surface_t
*surface
;
162 cairo_int_status_t status
;
166 surface
= _cairo_surface_create_scratch (dst
, CAIRO_CONTENT_ALPHA
,
167 extents
->bounded
.width
,
168 extents
->bounded
.height
,
170 if (unlikely (surface
->status
))
173 status
= compositor
->acquire (surface
);
174 if (unlikely (status
)) {
175 cairo_surface_destroy (surface
);
176 return _cairo_int_surface_create_in_error (status
);
179 if (!surface
->is_clear
) {
180 cairo_rectangle_int_t rect
;
183 rect
.width
= extents
->bounded
.width
;
184 rect
.height
= extents
->bounded
.height
;
186 status
= compositor
->fill_rectangles (surface
, CAIRO_OPERATOR_CLEAR
,
187 CAIRO_COLOR_TRANSPARENT
,
189 if (unlikely (status
))
194 status
= mask_func (compositor
, surface
, draw_closure
,
195 CAIRO_OPERATOR_SOURCE
, NULL
, NULL
,
196 extents
->bounded
.x
, extents
->bounded
.y
,
197 &extents
->bounded
, extents
->clip
);
198 if (likely (status
!= CAIRO_INT_STATUS_UNSUPPORTED
))
202 /* Is it worth setting the clip region here? */
203 status
= draw_func (compositor
, surface
, draw_closure
,
204 CAIRO_OPERATOR_ADD
, NULL
, NULL
,
205 extents
->bounded
.x
, extents
->bounded
.y
,
206 &extents
->bounded
, NULL
);
207 if (unlikely (status
))
210 info
.compositor
= compositor
;
212 for (i
= 0; i
< extents
->clip
->num_boxes
; i
++) {
213 cairo_box_t
*b
= &extents
->clip
->boxes
[i
];
215 if (! _cairo_fixed_is_integer (b
->p1
.x
) ||
216 ! _cairo_fixed_is_integer (b
->p1
.y
) ||
217 ! _cairo_fixed_is_integer (b
->p2
.x
) ||
218 ! _cairo_fixed_is_integer (b
->p2
.y
))
220 do_unaligned_box(blt_in
, &info
, b
,
226 if (extents
->clip
->path
!= NULL
) {
227 status
= _cairo_clip_combine_with_surface (extents
->clip
, surface
,
230 if (unlikely (status
))
235 compositor
->release (surface
);
236 surface
->is_clear
= FALSE
;
240 compositor
->release (surface
);
241 if (status
!= CAIRO_INT_STATUS_NOTHING_TO_DO
) {
242 cairo_surface_destroy (surface
);
243 surface
= _cairo_int_surface_create_in_error (status
);
248 /* Handles compositing with a clip surface when the operator allows
249 * us to combine the clip with the mask
251 static cairo_status_t
252 clip_and_composite_with_mask (const cairo_mask_compositor_t
*compositor
,
254 draw_func_t draw_func
,
255 draw_func_t mask_func
,
257 cairo_pattern_t
*pattern
,
258 const cairo_composite_rectangles_t
*extents
)
260 cairo_surface_t
*dst
= extents
->surface
;
261 cairo_surface_t
*mask
, *src
;
264 mask
= create_composite_mask (compositor
, dst
, draw_closure
,
265 draw_func
, mask_func
,
267 if (unlikely (mask
->status
))
270 if (pattern
!= NULL
|| dst
->content
!= CAIRO_CONTENT_ALPHA
) {
271 src
= compositor
->pattern_to_surface (dst
,
272 &extents
->source_pattern
.base
,
275 &extents
->source_sample_area
,
277 if (unlikely (src
->status
)) {
278 cairo_surface_destroy (mask
);
282 compositor
->composite (dst
, op
, src
, mask
,
283 extents
->bounded
.x
+ src_x
,
284 extents
->bounded
.y
+ src_y
,
286 extents
->bounded
.x
, extents
->bounded
.y
,
287 extents
->bounded
.width
, extents
->bounded
.height
);
289 cairo_surface_destroy (src
);
291 compositor
->composite (dst
, op
, mask
, NULL
,
294 extents
->bounded
.x
, extents
->bounded
.y
,
295 extents
->bounded
.width
, extents
->bounded
.height
);
297 cairo_surface_destroy (mask
);
299 return CAIRO_STATUS_SUCCESS
;
302 static cairo_surface_t
*
303 get_clip_source (const cairo_mask_compositor_t
*compositor
,
305 cairo_surface_t
*dst
,
306 const cairo_rectangle_int_t
*bounds
,
307 int *out_x
, int *out_y
)
309 cairo_surface_pattern_t pattern
;
310 cairo_rectangle_int_t r
;
311 cairo_surface_t
*surface
;
313 surface
= _cairo_clip_get_image (clip
, dst
, bounds
);
314 if (unlikely (surface
->status
))
317 _cairo_pattern_init_for_surface (&pattern
, surface
);
318 pattern
.base
.filter
= CAIRO_FILTER_NEAREST
;
319 cairo_surface_destroy (surface
);
322 r
.width
= bounds
->width
;
323 r
.height
= bounds
->height
;
325 surface
= compositor
->pattern_to_surface (dst
, &pattern
.base
, TRUE
,
326 &r
, &r
, out_x
, out_y
);
327 _cairo_pattern_fini (&pattern
.base
);
329 *out_x
+= -bounds
->x
;
330 *out_y
+= -bounds
->y
;
334 /* Handles compositing with a clip surface when we have to do the operation
335 * in two pieces and combine them together.
337 static cairo_status_t
338 clip_and_composite_combine (const cairo_mask_compositor_t
*compositor
,
340 draw_func_t draw_func
,
342 const cairo_pattern_t
*pattern
,
343 const cairo_composite_rectangles_t
*extents
)
345 cairo_surface_t
*dst
= extents
->surface
;
346 cairo_surface_t
*tmp
, *clip
;
347 cairo_status_t status
;
350 tmp
= _cairo_surface_create_scratch (dst
, dst
->content
,
351 extents
->bounded
.width
,
352 extents
->bounded
.height
,
354 if (unlikely (tmp
->status
))
357 compositor
->composite (tmp
, CAIRO_OPERATOR_SOURCE
, dst
, NULL
,
358 extents
->bounded
.x
, extents
->bounded
.y
,
361 extents
->bounded
.width
, extents
->bounded
.height
);
363 status
= draw_func (compositor
, tmp
, draw_closure
, op
,
364 pattern
, &extents
->source_sample_area
,
365 extents
->bounded
.x
, extents
->bounded
.y
,
366 &extents
->bounded
, NULL
);
367 if (unlikely (status
))
370 clip
= get_clip_source (compositor
,
371 extents
->clip
, dst
, &extents
->bounded
,
373 if (unlikely ((status
= clip
->status
)))
377 compositor
->composite (dst
, CAIRO_OPERATOR_SOURCE
, tmp
, clip
,
380 extents
->bounded
.x
, extents
->bounded
.y
,
381 extents
->bounded
.width
, extents
->bounded
.height
);
383 /* Punch the clip out of the destination */
384 compositor
->composite (dst
, CAIRO_OPERATOR_DEST_OUT
, clip
, NULL
,
387 extents
->bounded
.x
, extents
->bounded
.y
,
388 extents
->bounded
.width
, extents
->bounded
.height
);
390 /* Now add the two results together */
391 compositor
->composite (dst
, CAIRO_OPERATOR_ADD
, tmp
, clip
,
394 extents
->bounded
.x
, extents
->bounded
.y
,
395 extents
->bounded
.width
, extents
->bounded
.height
);
397 cairo_surface_destroy (clip
);
400 cairo_surface_destroy (tmp
);
404 /* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
405 * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
407 static cairo_status_t
408 clip_and_composite_source (const cairo_mask_compositor_t
*compositor
,
410 draw_func_t draw_func
,
411 draw_func_t mask_func
,
412 cairo_pattern_t
*pattern
,
413 const cairo_composite_rectangles_t
*extents
)
415 cairo_surface_t
*dst
= extents
->surface
;
416 cairo_surface_t
*mask
, *src
;
419 /* Create a surface that is mask IN clip */
420 mask
= create_composite_mask (compositor
, dst
, draw_closure
,
421 draw_func
, mask_func
,
423 if (unlikely (mask
->status
))
426 src
= compositor
->pattern_to_surface (dst
,
430 &extents
->source_sample_area
,
432 if (unlikely (src
->status
)) {
433 cairo_surface_destroy (mask
);
438 compositor
->composite (dst
, CAIRO_OPERATOR_SOURCE
, src
, mask
,
439 extents
->bounded
.x
+ src_x
, extents
->bounded
.y
+ src_y
,
441 extents
->bounded
.x
, extents
->bounded
.y
,
442 extents
->bounded
.width
, extents
->bounded
.height
);
444 /* Compute dest' = dest OUT (mask IN clip) */
445 compositor
->composite (dst
, CAIRO_OPERATOR_DEST_OUT
, mask
, NULL
,
447 extents
->bounded
.x
, extents
->bounded
.y
,
448 extents
->bounded
.width
, extents
->bounded
.height
);
450 /* Now compute (src IN (mask IN clip)) ADD dest' */
451 compositor
->composite (dst
, CAIRO_OPERATOR_ADD
, src
, mask
,
452 extents
->bounded
.x
+ src_x
, extents
->bounded
.y
+ src_y
,
454 extents
->bounded
.x
, extents
->bounded
.y
,
455 extents
->bounded
.width
, extents
->bounded
.height
);
458 cairo_surface_destroy (src
);
459 cairo_surface_destroy (mask
);
461 return CAIRO_STATUS_SUCCESS
;
465 can_reduce_alpha_op (cairo_operator_t op
)
469 case CAIRO_OPERATOR_OVER
:
470 case CAIRO_OPERATOR_SOURCE
:
471 case CAIRO_OPERATOR_ADD
:
479 reduce_alpha_op (cairo_surface_t
*dst
,
481 const cairo_pattern_t
*pattern
)
483 return dst
->is_clear
&&
484 dst
->content
== CAIRO_CONTENT_ALPHA
&&
485 _cairo_pattern_is_opaque_solid (pattern
) &&
486 can_reduce_alpha_op (op
);
489 static cairo_status_t
490 fixup_unbounded (const cairo_mask_compositor_t
*compositor
,
491 cairo_surface_t
*dst
,
492 const cairo_composite_rectangles_t
*extents
)
494 cairo_rectangle_int_t rects
[4];
497 if (extents
->bounded
.width
== extents
->unbounded
.width
&&
498 extents
->bounded
.height
== extents
->unbounded
.height
)
500 return CAIRO_STATUS_SUCCESS
;
504 if (extents
->bounded
.width
== 0 || extents
->bounded
.height
== 0) {
505 rects
[n
].x
= extents
->unbounded
.x
;
506 rects
[n
].width
= extents
->unbounded
.width
;
507 rects
[n
].y
= extents
->unbounded
.y
;
508 rects
[n
].height
= extents
->unbounded
.height
;
512 if (extents
->bounded
.y
!= extents
->unbounded
.y
) {
513 rects
[n
].x
= extents
->unbounded
.x
;
514 rects
[n
].width
= extents
->unbounded
.width
;
515 rects
[n
].y
= extents
->unbounded
.y
;
516 rects
[n
].height
= extents
->bounded
.y
- extents
->unbounded
.y
;
520 if (extents
->bounded
.x
!= extents
->unbounded
.x
) {
521 rects
[n
].x
= extents
->unbounded
.x
;
522 rects
[n
].width
= extents
->bounded
.x
- extents
->unbounded
.x
;
523 rects
[n
].y
= extents
->bounded
.y
;
524 rects
[n
].height
= extents
->bounded
.height
;
528 if (extents
->bounded
.x
+ extents
->bounded
.width
!= extents
->unbounded
.x
+ extents
->unbounded
.width
) {
529 rects
[n
].x
= extents
->bounded
.x
+ extents
->bounded
.width
;
530 rects
[n
].width
= extents
->unbounded
.x
+ extents
->unbounded
.width
- rects
[n
].x
;
531 rects
[n
].y
= extents
->bounded
.y
;
532 rects
[n
].height
= extents
->bounded
.height
;
536 if (extents
->bounded
.y
+ extents
->bounded
.height
!= extents
->unbounded
.y
+ extents
->unbounded
.height
) {
537 rects
[n
].x
= extents
->unbounded
.x
;
538 rects
[n
].width
= extents
->unbounded
.width
;
539 rects
[n
].y
= extents
->bounded
.y
+ extents
->bounded
.height
;
540 rects
[n
].height
= extents
->unbounded
.y
+ extents
->unbounded
.height
- rects
[n
].y
;
545 return compositor
->fill_rectangles (dst
, CAIRO_OPERATOR_CLEAR
,
546 CAIRO_COLOR_TRANSPARENT
,
550 static cairo_status_t
551 fixup_unbounded_with_mask (const cairo_mask_compositor_t
*compositor
,
552 cairo_surface_t
*dst
,
553 const cairo_composite_rectangles_t
*extents
)
555 cairo_surface_t
*mask
;
558 mask
= get_clip_source (compositor
,
559 extents
->clip
, dst
, &extents
->unbounded
,
561 if (unlikely (mask
->status
))
565 if (extents
->bounded
.y
!= extents
->unbounded
.y
) {
566 int x
= extents
->unbounded
.x
;
567 int y
= extents
->unbounded
.y
;
568 int width
= extents
->unbounded
.width
;
569 int height
= extents
->bounded
.y
- y
;
571 compositor
->composite (dst
, CAIRO_OPERATOR_DEST_OUT
, mask
, NULL
,
572 x
+ mask_x
, y
+ mask_y
,
579 if (extents
->bounded
.x
!= extents
->unbounded
.x
) {
580 int x
= extents
->unbounded
.x
;
581 int y
= extents
->bounded
.y
;
582 int width
= extents
->bounded
.x
- x
;
583 int height
= extents
->bounded
.height
;
585 compositor
->composite (dst
, CAIRO_OPERATOR_DEST_OUT
, mask
, NULL
,
586 x
+ mask_x
, y
+ mask_y
,
593 if (extents
->bounded
.x
+ extents
->bounded
.width
!= extents
->unbounded
.x
+ extents
->unbounded
.width
) {
594 int x
= extents
->bounded
.x
+ extents
->bounded
.width
;
595 int y
= extents
->bounded
.y
;
596 int width
= extents
->unbounded
.x
+ extents
->unbounded
.width
- x
;
597 int height
= extents
->bounded
.height
;
599 compositor
->composite (dst
, CAIRO_OPERATOR_DEST_OUT
, mask
, NULL
,
600 x
+ mask_x
, y
+ mask_y
,
607 if (extents
->bounded
.y
+ extents
->bounded
.height
!= extents
->unbounded
.y
+ extents
->unbounded
.height
) {
608 int x
= extents
->unbounded
.x
;
609 int y
= extents
->bounded
.y
+ extents
->bounded
.height
;
610 int width
= extents
->unbounded
.width
;
611 int height
= extents
->unbounded
.y
+ extents
->unbounded
.height
- y
;
613 compositor
->composite (dst
, CAIRO_OPERATOR_DEST_OUT
, mask
, NULL
,
614 x
+ mask_x
, y
+ mask_y
,
620 cairo_surface_destroy (mask
);
622 return CAIRO_STATUS_SUCCESS
;
625 static cairo_status_t
626 fixup_unbounded_boxes (const cairo_mask_compositor_t
*compositor
,
627 const cairo_composite_rectangles_t
*extents
,
628 cairo_boxes_t
*boxes
)
630 cairo_surface_t
*dst
= extents
->surface
;
632 cairo_region_t
*clip_region
;
634 cairo_status_t status
;
635 struct _cairo_boxes_chunk
*chunk
;
638 assert (boxes
->is_pixel_aligned
);
641 if (_cairo_clip_is_region (extents
->clip
) &&
642 (clip_region
= _cairo_clip_get_region (extents
->clip
)) &&
643 cairo_region_contains_rectangle (clip_region
,
644 &extents
->bounded
) == CAIRO_REGION_OVERLAP_IN
)
648 if (boxes
->num_boxes
<= 1 && clip_region
== NULL
)
649 return fixup_unbounded (compositor
, dst
, extents
);
651 _cairo_boxes_init (&clear
);
653 box
.p1
.x
= _cairo_fixed_from_int (extents
->unbounded
.x
+ extents
->unbounded
.width
);
654 box
.p1
.y
= _cairo_fixed_from_int (extents
->unbounded
.y
);
655 box
.p2
.x
= _cairo_fixed_from_int (extents
->unbounded
.x
);
656 box
.p2
.y
= _cairo_fixed_from_int (extents
->unbounded
.y
+ extents
->unbounded
.height
);
658 if (clip_region
== NULL
) {
661 _cairo_boxes_init (&tmp
);
663 status
= _cairo_boxes_add (&tmp
, CAIRO_ANTIALIAS_DEFAULT
, &box
);
664 assert (status
== CAIRO_STATUS_SUCCESS
);
666 tmp
.chunks
.next
= &boxes
->chunks
;
667 tmp
.num_boxes
+= boxes
->num_boxes
;
669 status
= _cairo_bentley_ottmann_tessellate_boxes (&tmp
,
670 CAIRO_FILL_RULE_WINDING
,
673 tmp
.chunks
.next
= NULL
;
675 pixman_box32_t
*pbox
;
677 pbox
= pixman_region32_rectangles (&clip_region
->rgn
, &i
);
678 _cairo_boxes_limit (&clear
, (cairo_box_t
*) pbox
, i
);
680 status
= _cairo_boxes_add (&clear
, CAIRO_ANTIALIAS_DEFAULT
, &box
);
681 assert (status
== CAIRO_STATUS_SUCCESS
);
683 for (chunk
= &boxes
->chunks
; chunk
!= NULL
; chunk
= chunk
->next
) {
684 for (i
= 0; i
< chunk
->count
; i
++) {
685 status
= _cairo_boxes_add (&clear
,
686 CAIRO_ANTIALIAS_DEFAULT
,
688 if (unlikely (status
)) {
689 _cairo_boxes_fini (&clear
);
695 status
= _cairo_bentley_ottmann_tessellate_boxes (&clear
,
696 CAIRO_FILL_RULE_WINDING
,
700 if (likely (status
== CAIRO_STATUS_SUCCESS
)) {
701 status
= compositor
->fill_boxes (dst
,
702 CAIRO_OPERATOR_CLEAR
,
703 CAIRO_COLOR_TRANSPARENT
,
707 _cairo_boxes_fini (&clear
);
713 NEED_CLIP_REGION
= 0x1,
714 NEED_CLIP_SURFACE
= 0x2,
715 FORCE_CLIP_REGION
= 0x4,
719 need_bounded_clip (cairo_composite_rectangles_t
*extents
)
721 unsigned int flags
= NEED_CLIP_REGION
;
722 if (! _cairo_clip_is_region (extents
->clip
))
723 flags
|= NEED_CLIP_SURFACE
;
728 need_unbounded_clip (cairo_composite_rectangles_t
*extents
)
730 unsigned int flags
= 0;
731 if (! extents
->is_bounded
) {
732 flags
|= NEED_CLIP_REGION
;
733 if (! _cairo_clip_is_region (extents
->clip
))
734 flags
|= NEED_CLIP_SURFACE
;
736 if (extents
->clip
->path
!= NULL
)
737 flags
|= NEED_CLIP_SURFACE
;
741 static cairo_status_t
742 clip_and_composite (const cairo_mask_compositor_t
*compositor
,
743 draw_func_t draw_func
,
744 draw_func_t mask_func
,
746 cairo_composite_rectangles_t
*extents
,
747 unsigned int need_clip
)
749 cairo_surface_t
*dst
= extents
->surface
;
750 cairo_operator_t op
= extents
->op
;
751 cairo_pattern_t
*src
= &extents
->source_pattern
.base
;
752 cairo_region_t
*clip_region
= NULL
;
753 cairo_status_t status
;
755 compositor
->acquire (dst
);
757 if (need_clip
& NEED_CLIP_REGION
) {
758 clip_region
= _cairo_clip_get_region (extents
->clip
);
759 if ((need_clip
& FORCE_CLIP_REGION
) == 0 &&
760 _cairo_composite_rectangles_can_reduce_clip (extents
,
763 if (clip_region
!= NULL
) {
764 status
= compositor
->set_clip_region (dst
, clip_region
);
765 if (unlikely (status
)) {
766 compositor
->release (dst
);
772 if (reduce_alpha_op (dst
, op
, &extents
->source_pattern
.base
)) {
773 op
= CAIRO_OPERATOR_ADD
;
777 if (op
== CAIRO_OPERATOR_SOURCE
) {
778 status
= clip_and_composite_source (compositor
,
779 draw_closure
, draw_func
, mask_func
,
782 if (op
== CAIRO_OPERATOR_CLEAR
) {
783 op
= CAIRO_OPERATOR_DEST_OUT
;
787 if (need_clip
& NEED_CLIP_SURFACE
) {
788 if (extents
->is_bounded
) {
789 status
= clip_and_composite_with_mask (compositor
,
795 status
= clip_and_composite_combine (compositor
,
801 status
= draw_func (compositor
,
803 op
, src
, &extents
->source_sample_area
,
810 if (status
== CAIRO_STATUS_SUCCESS
&& ! extents
->is_bounded
) {
811 if (need_clip
& NEED_CLIP_SURFACE
)
812 status
= fixup_unbounded_with_mask (compositor
, dst
, extents
);
814 status
= fixup_unbounded (compositor
, dst
, extents
);
818 compositor
->set_clip_region (dst
, NULL
);
820 compositor
->release (dst
);
825 static cairo_int_status_t
826 trim_extents_to_boxes (cairo_composite_rectangles_t
*extents
,
827 cairo_boxes_t
*boxes
)
831 _cairo_boxes_extents (boxes
, &box
);
832 return _cairo_composite_rectangles_intersect_mask_extents (extents
, &box
);
835 static cairo_status_t
836 upload_boxes (const cairo_mask_compositor_t
*compositor
,
837 cairo_composite_rectangles_t
*extents
,
838 cairo_boxes_t
*boxes
)
840 cairo_surface_t
*dst
= extents
->surface
;
841 const cairo_pattern_t
*source
= &extents
->source_pattern
.base
;
842 cairo_surface_t
*src
;
843 cairo_rectangle_int_t limit
;
844 cairo_int_status_t status
;
847 src
= _cairo_pattern_get_source ((cairo_surface_pattern_t
*)source
, &limit
);
848 if (!(src
->type
== CAIRO_SURFACE_TYPE_IMAGE
|| src
->type
== dst
->type
))
849 return CAIRO_INT_STATUS_UNSUPPORTED
;
851 if (! _cairo_matrix_is_integer_translation (&source
->matrix
, &tx
, &ty
))
852 return CAIRO_INT_STATUS_UNSUPPORTED
;
854 /* Check that the data is entirely within the image */
855 if (extents
->bounded
.x
+ tx
< limit
.x
|| extents
->bounded
.y
+ ty
< limit
.y
)
856 return CAIRO_INT_STATUS_UNSUPPORTED
;
858 if (extents
->bounded
.x
+ extents
->bounded
.width
+ tx
> limit
.x
+ limit
.width
||
859 extents
->bounded
.y
+ extents
->bounded
.height
+ ty
> limit
.y
+ limit
.height
)
860 return CAIRO_INT_STATUS_UNSUPPORTED
;
865 if (src
->type
== CAIRO_SURFACE_TYPE_IMAGE
)
866 status
= compositor
->draw_image_boxes (dst
,
867 (cairo_image_surface_t
*)src
,
870 status
= compositor
->copy_boxes (dst
, src
, boxes
, &extents
->bounded
,
876 static cairo_status_t
877 composite_boxes (const cairo_mask_compositor_t
*compositor
,
878 const cairo_composite_rectangles_t
*extents
,
879 cairo_boxes_t
*boxes
)
881 cairo_surface_t
*dst
= extents
->surface
;
882 cairo_operator_t op
= extents
->op
;
883 const cairo_pattern_t
*source
= &extents
->source_pattern
.base
;
884 cairo_bool_t need_clip_mask
= extents
->clip
->path
!= NULL
;
885 cairo_status_t status
;
887 if (need_clip_mask
&&
888 (! extents
->is_bounded
|| op
== CAIRO_OPERATOR_SOURCE
))
890 return CAIRO_INT_STATUS_UNSUPPORTED
;
893 status
= compositor
->acquire (dst
);
894 if (unlikely (status
))
897 if (! need_clip_mask
&& source
->type
== CAIRO_PATTERN_TYPE_SOLID
) {
898 const cairo_color_t
*color
;
900 color
= &((cairo_solid_pattern_t
*) source
)->color
;
901 status
= compositor
->fill_boxes (dst
, op
, color
, boxes
);
903 cairo_surface_t
*src
, *mask
= NULL
;
905 int mask_x
= 0, mask_y
= 0;
907 if (need_clip_mask
) {
908 mask
= get_clip_source (compositor
,
909 extents
->clip
, dst
, &extents
->bounded
,
911 if (unlikely (mask
->status
))
914 if (op
== CAIRO_OPERATOR_CLEAR
) {
916 op
= CAIRO_OPERATOR_DEST_OUT
;
920 if (source
|| mask
== NULL
) {
921 src
= compositor
->pattern_to_surface (dst
, source
, FALSE
,
923 &extents
->source_sample_area
,
932 status
= compositor
->composite_boxes (dst
, op
, src
, mask
,
936 boxes
, &extents
->bounded
);
938 cairo_surface_destroy (src
);
939 cairo_surface_destroy (mask
);
942 if (status
== CAIRO_STATUS_SUCCESS
&& ! extents
->is_bounded
)
943 status
= fixup_unbounded_boxes (compositor
, extents
, boxes
);
945 compositor
->release (dst
);
950 static cairo_status_t
951 clip_and_composite_boxes (const cairo_mask_compositor_t
*compositor
,
952 cairo_composite_rectangles_t
*extents
,
953 cairo_boxes_t
*boxes
)
955 cairo_surface_t
*dst
= extents
->surface
;
956 cairo_int_status_t status
;
958 if (boxes
->num_boxes
== 0) {
959 if (extents
->is_bounded
)
960 return CAIRO_STATUS_SUCCESS
;
962 return fixup_unbounded_boxes (compositor
, extents
, boxes
);
965 if (! boxes
->is_pixel_aligned
)
966 return CAIRO_INT_STATUS_UNSUPPORTED
;
968 status
= trim_extents_to_boxes (extents
, boxes
);
969 if (unlikely (status
))
972 if (extents
->source_pattern
.base
.type
== CAIRO_PATTERN_TYPE_SURFACE
&&
973 extents
->clip
->path
== NULL
&&
974 (extents
->op
== CAIRO_OPERATOR_SOURCE
||
975 (dst
->is_clear
&& (extents
->op
== CAIRO_OPERATOR_OVER
||
976 extents
->op
== CAIRO_OPERATOR_ADD
))))
978 status
= upload_boxes (compositor
, extents
, boxes
);
979 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
983 return composite_boxes (compositor
, extents
, boxes
);
986 /* high-level compositor interface */
988 static cairo_int_status_t
989 _cairo_mask_compositor_paint (const cairo_compositor_t
*_compositor
,
990 cairo_composite_rectangles_t
*extents
)
992 cairo_mask_compositor_t
*compositor
= (cairo_mask_compositor_t
*)_compositor
;
994 cairo_int_status_t status
;
996 status
= compositor
->check_composite (extents
);
997 if (unlikely (status
))
1000 _cairo_clip_steal_boxes (extents
->clip
, &boxes
);
1001 status
= clip_and_composite_boxes (compositor
, extents
, &boxes
);
1002 _cairo_clip_unsteal_boxes (extents
->clip
, &boxes
);
1007 struct composite_opacity_info
{
1008 const cairo_mask_compositor_t
*compositor
;
1010 cairo_surface_t
*dst
;
1011 cairo_surface_t
*src
;
1016 static void composite_opacity(void *closure
,
1017 int16_t x
, int16_t y
,
1018 int16_t w
, int16_t h
,
1021 struct composite_opacity_info
*info
= closure
;
1022 const cairo_mask_compositor_t
*compositor
= info
->compositor
;
1023 cairo_surface_t
*mask
;
1025 cairo_color_t color
;
1026 cairo_solid_pattern_t solid
;
1028 _cairo_color_init_rgba (&color
, 0, 0, 0, info
->opacity
* coverage
);
1029 _cairo_pattern_init_solid (&solid
, &color
);
1030 mask
= compositor
->pattern_to_surface (info
->dst
, &solid
.base
, TRUE
,
1031 &_cairo_unbounded_rectangle
,
1032 &_cairo_unbounded_rectangle
,
1034 if (likely (mask
->status
== CAIRO_STATUS_SUCCESS
)) {
1036 compositor
->composite (info
->dst
, info
->op
, info
->src
, mask
,
1037 x
+ info
->src_x
, y
+ info
->src_y
,
1042 compositor
->composite (info
->dst
, info
->op
, mask
, NULL
,
1050 cairo_surface_destroy (mask
);
1053 static cairo_int_status_t
1054 composite_opacity_boxes (const cairo_mask_compositor_t
*compositor
,
1055 cairo_surface_t
*dst
,
1057 cairo_operator_t op
,
1058 const cairo_pattern_t
*src_pattern
,
1059 const cairo_rectangle_int_t
*src_sample
,
1062 const cairo_rectangle_int_t
*extents
,
1065 const cairo_solid_pattern_t
*mask_pattern
= closure
;
1066 struct composite_opacity_info info
;
1071 info
.compositor
= compositor
;
1075 if (src_pattern
!= NULL
) {
1076 info
.src
= compositor
->pattern_to_surface (dst
, src_pattern
, FALSE
,
1077 extents
, src_sample
,
1078 &info
.src_x
, &info
.src_y
);
1079 if (unlikely (info
.src
->status
))
1080 return info
.src
->status
;
1084 info
.opacity
= mask_pattern
->color
.alpha
/ (double) 0xffff;
1086 /* XXX for lots of boxes create a clip region for the fully opaque areas */
1087 for (i
= 0; i
< clip
->num_boxes
; i
++)
1088 do_unaligned_box(composite_opacity
, &info
,
1089 &clip
->boxes
[i
], dst_x
, dst_y
);
1090 cairo_surface_destroy (info
.src
);
1092 return CAIRO_STATUS_SUCCESS
;
1095 struct composite_box_info
{
1096 const cairo_mask_compositor_t
*compositor
;
1097 cairo_surface_t
*dst
;
1098 cairo_surface_t
*src
;
1103 static void composite_box(void *closure
,
1104 int16_t x
, int16_t y
,
1105 int16_t w
, int16_t h
,
1108 struct composite_box_info
*info
= closure
;
1109 const cairo_mask_compositor_t
*compositor
= info
->compositor
;
1111 if (! CAIRO_ALPHA_SHORT_IS_OPAQUE (coverage
)) {
1112 cairo_surface_t
*mask
;
1113 cairo_color_t color
;
1114 cairo_solid_pattern_t solid
;
1117 _cairo_color_init_rgba (&color
, 0, 0, 0, coverage
/ (double)0xffff);
1118 _cairo_pattern_init_solid (&solid
, &color
);
1120 mask
= compositor
->pattern_to_surface (info
->dst
, &solid
.base
, FALSE
,
1121 &_cairo_unbounded_rectangle
,
1122 &_cairo_unbounded_rectangle
,
1125 if (likely (mask
->status
== CAIRO_STATUS_SUCCESS
)) {
1126 compositor
->composite (info
->dst
, info
->op
, info
->src
, mask
,
1127 x
+ info
->src_x
, y
+ info
->src_y
,
1133 cairo_surface_destroy (mask
);
1135 compositor
->composite (info
->dst
, info
->op
, info
->src
, NULL
,
1136 x
+ info
->src_x
, y
+ info
->src_y
,
1143 static cairo_int_status_t
1144 composite_mask_clip_boxes (const cairo_mask_compositor_t
*compositor
,
1145 cairo_surface_t
*dst
,
1147 cairo_operator_t op
,
1148 const cairo_pattern_t
*src_pattern
,
1149 const cairo_rectangle_int_t
*src_sample
,
1152 const cairo_rectangle_int_t
*extents
,
1155 cairo_composite_rectangles_t
*composite
= closure
;
1156 struct composite_box_info info
;
1159 assert (src_pattern
== NULL
);
1160 assert (op
== CAIRO_OPERATOR_SOURCE
);
1162 info
.compositor
= compositor
;
1163 info
.op
= CAIRO_OPERATOR_SOURCE
;
1165 info
.src
= compositor
->pattern_to_surface (dst
,
1166 &composite
->mask_pattern
.base
,
1168 &composite
->mask_sample_area
,
1169 &info
.src_x
, &info
.src_y
);
1170 if (unlikely (info
.src
->status
))
1171 return info
.src
->status
;
1173 info
.src_x
+= dst_x
;
1174 info
.src_y
+= dst_y
;
1176 for (i
= 0; i
< clip
->num_boxes
; i
++)
1177 do_unaligned_box(composite_box
, &info
, &clip
->boxes
[i
], dst_x
, dst_y
);
1179 cairo_surface_destroy (info
.src
);
1181 return CAIRO_STATUS_SUCCESS
;
1184 static cairo_int_status_t
1185 composite_mask (const cairo_mask_compositor_t
*compositor
,
1186 cairo_surface_t
*dst
,
1188 cairo_operator_t op
,
1189 const cairo_pattern_t
*src_pattern
,
1190 const cairo_rectangle_int_t
*src_sample
,
1193 const cairo_rectangle_int_t
*extents
,
1196 cairo_composite_rectangles_t
*composite
= closure
;
1197 cairo_surface_t
*src
, *mask
;
1201 if (src_pattern
!= NULL
) {
1202 src
= compositor
->pattern_to_surface (dst
, src_pattern
, FALSE
,
1203 extents
, src_sample
,
1205 if (unlikely (src
->status
))
1208 mask
= compositor
->pattern_to_surface (dst
, &composite
->mask_pattern
.base
, TRUE
,
1209 extents
, &composite
->mask_sample_area
,
1211 if (unlikely (mask
->status
)) {
1212 cairo_surface_destroy (src
);
1213 return mask
->status
;
1216 compositor
->composite (dst
, op
, src
, mask
,
1217 extents
->x
+ src_x
, extents
->y
+ src_y
,
1218 extents
->x
+ mask_x
, extents
->y
+ mask_y
,
1219 extents
->x
- dst_x
, extents
->y
- dst_y
,
1220 extents
->width
, extents
->height
);
1222 cairo_surface_destroy (mask
);
1223 cairo_surface_destroy (src
);
1225 src
= compositor
->pattern_to_surface (dst
, &composite
->mask_pattern
.base
, FALSE
,
1226 extents
, &composite
->mask_sample_area
,
1228 if (unlikely (src
->status
))
1231 compositor
->composite (dst
, op
, src
, NULL
,
1232 extents
->x
+ src_x
, extents
->y
+ src_y
,
1234 extents
->x
- dst_x
, extents
->y
- dst_y
,
1235 extents
->width
, extents
->height
);
1237 cairo_surface_destroy (src
);
1240 return CAIRO_STATUS_SUCCESS
;
1243 static cairo_int_status_t
1244 _cairo_mask_compositor_mask (const cairo_compositor_t
*_compositor
,
1245 cairo_composite_rectangles_t
*extents
)
1247 const cairo_mask_compositor_t
*compositor
= (cairo_mask_compositor_t
*)_compositor
;
1248 cairo_int_status_t status
= CAIRO_INT_STATUS_UNSUPPORTED
;
1250 status
= compositor
->check_composite (extents
);
1251 if (unlikely (status
))
1254 if (extents
->mask_pattern
.base
.type
== CAIRO_PATTERN_TYPE_SOLID
&&
1255 extents
->clip
->path
== NULL
&&
1256 _cairo_clip_is_region (extents
->clip
)) {
1257 status
= clip_and_composite (compositor
,
1258 composite_opacity_boxes
,
1259 composite_opacity_boxes
,
1260 &extents
->mask_pattern
.solid
,
1261 extents
, need_unbounded_clip (extents
));
1263 status
= clip_and_composite (compositor
,
1265 extents
->clip
->path
== NULL
? composite_mask_clip_boxes
: NULL
,
1267 extents
, need_bounded_clip (extents
));
1273 static cairo_int_status_t
1274 _cairo_mask_compositor_stroke (const cairo_compositor_t
*_compositor
,
1275 cairo_composite_rectangles_t
*extents
,
1276 const cairo_path_fixed_t
*path
,
1277 const cairo_stroke_style_t
*style
,
1278 const cairo_matrix_t
*ctm
,
1279 const cairo_matrix_t
*ctm_inverse
,
1281 cairo_antialias_t antialias
)
1283 const cairo_mask_compositor_t
*compositor
= (cairo_mask_compositor_t
*)_compositor
;
1284 cairo_surface_t
*mask
;
1285 cairo_surface_pattern_t pattern
;
1286 cairo_int_status_t status
= CAIRO_INT_STATUS_UNSUPPORTED
;
1288 status
= compositor
->check_composite (extents
);
1289 if (unlikely (status
))
1292 if (_cairo_path_fixed_stroke_is_rectilinear (path
)) {
1293 cairo_boxes_t boxes
;
1295 _cairo_boxes_init_with_clip (&boxes
, extents
->clip
);
1296 status
= _cairo_path_fixed_stroke_rectilinear_to_boxes (path
,
1301 if (likely (status
== CAIRO_INT_STATUS_SUCCESS
))
1302 status
= clip_and_composite_boxes (compositor
, extents
, &boxes
);
1303 _cairo_boxes_fini (&boxes
);
1307 if (status
== CAIRO_INT_STATUS_UNSUPPORTED
) {
1308 mask
= cairo_surface_create_similar_image (extents
->surface
,
1310 extents
->bounded
.width
,
1311 extents
->bounded
.height
);
1312 if (unlikely (mask
->status
))
1313 return mask
->status
;
1315 status
= _cairo_surface_offset_stroke (mask
,
1319 &_cairo_pattern_white
.base
,
1320 path
, style
, ctm
, ctm_inverse
,
1321 tolerance
, antialias
,
1323 if (unlikely (status
)) {
1324 cairo_surface_destroy (mask
);
1328 _cairo_pattern_init_for_surface (&pattern
, mask
);
1329 cairo_surface_destroy (mask
);
1331 cairo_matrix_init_translate (&pattern
.base
.matrix
,
1332 -extents
->bounded
.x
,
1333 -extents
->bounded
.y
);
1334 pattern
.base
.filter
= CAIRO_FILTER_NEAREST
;
1335 pattern
.base
.extend
= CAIRO_EXTEND_NONE
;
1336 status
= _cairo_surface_mask (extents
->surface
,
1338 &extents
->source_pattern
.base
,
1341 _cairo_pattern_fini (&pattern
.base
);
1347 static cairo_int_status_t
1348 _cairo_mask_compositor_fill (const cairo_compositor_t
*_compositor
,
1349 cairo_composite_rectangles_t
*extents
,
1350 const cairo_path_fixed_t
*path
,
1351 cairo_fill_rule_t fill_rule
,
1353 cairo_antialias_t antialias
)
1355 const cairo_mask_compositor_t
*compositor
= (cairo_mask_compositor_t
*)_compositor
;
1356 cairo_surface_t
*mask
;
1357 cairo_surface_pattern_t pattern
;
1358 cairo_int_status_t status
= CAIRO_INT_STATUS_UNSUPPORTED
;
1360 status
= compositor
->check_composite (extents
);
1361 if (unlikely (status
))
1364 if (_cairo_path_fixed_fill_is_rectilinear (path
)) {
1365 cairo_boxes_t boxes
;
1367 _cairo_boxes_init_with_clip (&boxes
, extents
->clip
);
1368 status
= _cairo_path_fixed_fill_rectilinear_to_boxes (path
,
1372 if (likely (status
== CAIRO_INT_STATUS_SUCCESS
))
1373 status
= clip_and_composite_boxes (compositor
, extents
, &boxes
);
1374 _cairo_boxes_fini (&boxes
);
1377 if (status
== CAIRO_INT_STATUS_UNSUPPORTED
) {
1378 mask
= cairo_surface_create_similar_image (extents
->surface
,
1380 extents
->bounded
.width
,
1381 extents
->bounded
.height
);
1382 if (unlikely (mask
->status
))
1383 return mask
->status
;
1385 status
= _cairo_surface_offset_fill (mask
,
1389 &_cairo_pattern_white
.base
,
1390 path
, fill_rule
, tolerance
, antialias
,
1392 if (unlikely (status
)) {
1393 cairo_surface_destroy (mask
);
1397 _cairo_pattern_init_for_surface (&pattern
, mask
);
1398 cairo_surface_destroy (mask
);
1400 cairo_matrix_init_translate (&pattern
.base
.matrix
,
1401 -extents
->bounded
.x
,
1402 -extents
->bounded
.y
);
1403 pattern
.base
.filter
= CAIRO_FILTER_NEAREST
;
1404 pattern
.base
.extend
= CAIRO_EXTEND_NONE
;
1405 status
= _cairo_surface_mask (extents
->surface
,
1407 &extents
->source_pattern
.base
,
1410 _cairo_pattern_fini (&pattern
.base
);
1416 static cairo_int_status_t
1417 _cairo_mask_compositor_glyphs (const cairo_compositor_t
*_compositor
,
1418 cairo_composite_rectangles_t
*extents
,
1419 cairo_scaled_font_t
*scaled_font
,
1420 cairo_glyph_t
*glyphs
,
1422 cairo_bool_t overlap
)
1424 const cairo_mask_compositor_t
*compositor
= (cairo_mask_compositor_t
*)_compositor
;
1425 cairo_surface_t
*mask
;
1426 cairo_surface_pattern_t pattern
;
1427 cairo_int_status_t status
;
1429 status
= compositor
->check_composite (extents
);
1430 if (unlikely (status
))
1431 return CAIRO_INT_STATUS_UNSUPPORTED
;
1433 mask
= cairo_surface_create_similar_image (extents
->surface
,
1435 extents
->bounded
.width
,
1436 extents
->bounded
.height
);
1437 if (unlikely (mask
->status
))
1438 return mask
->status
;
1440 status
= _cairo_surface_offset_glyphs (mask
,
1444 &_cairo_pattern_white
.base
,
1445 scaled_font
, glyphs
, num_glyphs
,
1447 if (unlikely (status
)) {
1448 cairo_surface_destroy (mask
);
1452 _cairo_pattern_init_for_surface (&pattern
, mask
);
1453 cairo_surface_destroy (mask
);
1455 cairo_matrix_init_translate (&pattern
.base
.matrix
,
1456 -extents
->bounded
.x
,
1457 -extents
->bounded
.y
);
1458 pattern
.base
.filter
= CAIRO_FILTER_NEAREST
;
1459 pattern
.base
.extend
= CAIRO_EXTEND_NONE
;
1460 status
= _cairo_surface_mask (extents
->surface
,
1462 &extents
->source_pattern
.base
,
1465 _cairo_pattern_fini (&pattern
.base
);
1471 _cairo_mask_compositor_init (cairo_mask_compositor_t
*compositor
,
1472 const cairo_compositor_t
*delegate
)
1474 compositor
->base
.delegate
= delegate
;
1476 compositor
->base
.paint
= _cairo_mask_compositor_paint
;
1477 compositor
->base
.mask
= _cairo_mask_compositor_mask
;
1478 compositor
->base
.fill
= _cairo_mask_compositor_fill
;
1479 compositor
->base
.stroke
= _cairo_mask_compositor_stroke
;
1480 compositor
->base
.glyphs
= _cairo_mask_compositor_glyphs
;