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>
44 #include "test-compositor-surface-private.h"
46 #include "cairo-clip-private.h"
47 #include "cairo-composite-rectangles-private.h"
48 #include "cairo-compositor-private.h"
49 #include "cairo-error-private.h"
50 #include "cairo-image-surface-private.h"
51 #include "cairo-region-private.h"
52 #include "cairo-traps-private.h"
54 /* The intention is that this is a surface that just works, and most
55 * important of all does not try to be clever!
58 typedef cairo_int_status_t
59 (*draw_func_t
) (cairo_image_surface_t
*dst
,
62 const cairo_pattern_t
*pattern
,
65 const cairo_rectangle_int_t
*extents
);
68 _pixman_operator (cairo_operator_t op
)
71 case CAIRO_OPERATOR_CLEAR
:
72 return PIXMAN_OP_CLEAR
;
74 case CAIRO_OPERATOR_SOURCE
:
76 case CAIRO_OPERATOR_OVER
:
77 return PIXMAN_OP_OVER
;
78 case CAIRO_OPERATOR_IN
:
80 case CAIRO_OPERATOR_OUT
:
82 case CAIRO_OPERATOR_ATOP
:
83 return PIXMAN_OP_ATOP
;
85 case CAIRO_OPERATOR_DEST
:
87 case CAIRO_OPERATOR_DEST_OVER
:
88 return PIXMAN_OP_OVER_REVERSE
;
89 case CAIRO_OPERATOR_DEST_IN
:
90 return PIXMAN_OP_IN_REVERSE
;
91 case CAIRO_OPERATOR_DEST_OUT
:
92 return PIXMAN_OP_OUT_REVERSE
;
93 case CAIRO_OPERATOR_DEST_ATOP
:
94 return PIXMAN_OP_ATOP_REVERSE
;
96 case CAIRO_OPERATOR_XOR
:
98 case CAIRO_OPERATOR_ADD
:
100 case CAIRO_OPERATOR_SATURATE
:
101 return PIXMAN_OP_SATURATE
;
103 case CAIRO_OPERATOR_MULTIPLY
:
104 return PIXMAN_OP_MULTIPLY
;
105 case CAIRO_OPERATOR_SCREEN
:
106 return PIXMAN_OP_SCREEN
;
107 case CAIRO_OPERATOR_OVERLAY
:
108 return PIXMAN_OP_OVERLAY
;
109 case CAIRO_OPERATOR_DARKEN
:
110 return PIXMAN_OP_DARKEN
;
111 case CAIRO_OPERATOR_LIGHTEN
:
112 return PIXMAN_OP_LIGHTEN
;
113 case CAIRO_OPERATOR_COLOR_DODGE
:
114 return PIXMAN_OP_COLOR_DODGE
;
115 case CAIRO_OPERATOR_COLOR_BURN
:
116 return PIXMAN_OP_COLOR_BURN
;
117 case CAIRO_OPERATOR_HARD_LIGHT
:
118 return PIXMAN_OP_HARD_LIGHT
;
119 case CAIRO_OPERATOR_SOFT_LIGHT
:
120 return PIXMAN_OP_SOFT_LIGHT
;
121 case CAIRO_OPERATOR_DIFFERENCE
:
122 return PIXMAN_OP_DIFFERENCE
;
123 case CAIRO_OPERATOR_EXCLUSION
:
124 return PIXMAN_OP_EXCLUSION
;
125 case CAIRO_OPERATOR_HSL_HUE
:
126 return PIXMAN_OP_HSL_HUE
;
127 case CAIRO_OPERATOR_HSL_SATURATION
:
128 return PIXMAN_OP_HSL_SATURATION
;
129 case CAIRO_OPERATOR_HSL_COLOR
:
130 return PIXMAN_OP_HSL_COLOR
;
131 case CAIRO_OPERATOR_HSL_LUMINOSITY
:
132 return PIXMAN_OP_HSL_LUMINOSITY
;
136 return PIXMAN_OP_OVER
;
140 static cairo_image_surface_t
*
141 create_composite_mask (cairo_image_surface_t
*dst
,
143 draw_func_t draw_func
,
144 const cairo_composite_rectangles_t
*extents
)
146 cairo_image_surface_t
*surface
;
147 cairo_int_status_t status
;
149 TRACE ((stderr
, "%s\n", __FUNCTION__
));
151 surface
= (cairo_image_surface_t
*)
152 _cairo_image_surface_create_with_pixman_format (NULL
, PIXMAN_a8
,
153 extents
->bounded
.width
,
154 extents
->bounded
.height
,
156 if (unlikely (surface
->base
.status
))
159 status
= draw_func (surface
, draw_closure
,
160 CAIRO_OPERATOR_ADD
, &_cairo_pattern_white
.base
,
161 extents
->bounded
.x
, extents
->bounded
.y
,
163 if (unlikely (status
))
166 status
= _cairo_clip_combine_with_surface (extents
->clip
,
170 if (unlikely (status
))
176 cairo_surface_destroy (&surface
->base
);
177 return (cairo_image_surface_t
*)_cairo_surface_create_in_error (status
);
180 /* Handles compositing with a clip surface when the operator allows
181 * us to combine the clip with the mask
183 static cairo_status_t
184 clip_and_composite_with_mask (const cairo_composite_rectangles_t
*extents
,
185 draw_func_t draw_func
,
188 cairo_image_surface_t
*dst
= (cairo_image_surface_t
*)extents
->surface
;
189 cairo_image_surface_t
*mask
;
191 cairo_status_t status
= CAIRO_STATUS_SUCCESS
;
194 TRACE ((stderr
, "%s\n", __FUNCTION__
));
196 mask
= create_composite_mask (dst
, draw_closure
, draw_func
, extents
);
197 if (unlikely (mask
->base
.status
))
198 return mask
->base
.status
;
200 src
= _pixman_image_for_pattern (dst
,
201 &extents
->source_pattern
.base
, FALSE
,
203 &extents
->source_sample_area
,
205 if (unlikely (src
== NULL
)) {
206 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
210 pixman_image_composite32 (_pixman_operator (extents
->op
),
211 src
, mask
->pixman_image
, dst
->pixman_image
,
212 extents
->bounded
.x
+ src_x
,
213 extents
->bounded
.y
+ src_y
,
215 extents
->bounded
.x
, extents
->bounded
.y
,
216 extents
->bounded
.width
, extents
->bounded
.height
);
218 pixman_image_unref (src
);
220 cairo_surface_destroy (&mask
->base
);
224 /* Handles compositing with a clip surface when we have to do the operation
225 * in two pieces and combine them together.
227 static cairo_status_t
228 clip_and_composite_combine (const cairo_composite_rectangles_t
*extents
,
229 draw_func_t draw_func
,
232 cairo_image_surface_t
*dst
= (cairo_image_surface_t
*)extents
->surface
;
233 cairo_image_surface_t
*tmp
, *clip
;
235 cairo_status_t status
;
237 TRACE ((stderr
, "%s\n", __FUNCTION__
));
239 tmp
= (cairo_image_surface_t
*)
240 _cairo_image_surface_create_with_pixman_format (NULL
,
242 extents
->bounded
.width
,
243 extents
->bounded
.height
,
245 if (unlikely (tmp
->base
.status
))
246 return tmp
->base
.status
;
248 pixman_image_composite32 (PIXMAN_OP_SRC
,
249 dst
->pixman_image
, NULL
, tmp
->pixman_image
,
250 extents
->bounded
.x
, extents
->bounded
.y
,
253 extents
->bounded
.width
, extents
->bounded
.height
);
255 status
= draw_func (tmp
, draw_closure
,
256 extents
->op
, &extents
->source_pattern
.base
,
257 extents
->bounded
.x
, extents
->bounded
.y
,
259 if (unlikely (status
))
262 clip
= (cairo_image_surface_t
*)
263 _cairo_clip_get_surface (extents
->clip
, &dst
->base
, &clip_x
, &clip_y
);
264 if (unlikely (clip
->base
.status
))
267 pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE
,
268 clip
->pixman_image
, NULL
, dst
->pixman_image
,
269 extents
->bounded
.x
- clip_x
, extents
->bounded
.y
- clip_y
,
271 extents
->bounded
.x
, extents
->bounded
.y
,
272 extents
->bounded
.width
, extents
->bounded
.height
);
273 pixman_image_composite32 (PIXMAN_OP_ADD
,
274 tmp
->pixman_image
, clip
->pixman_image
, dst
->pixman_image
,
276 extents
->bounded
.x
- clip_x
, extents
->bounded
.y
- clip_y
,
277 extents
->bounded
.x
, extents
->bounded
.y
,
278 extents
->bounded
.width
, extents
->bounded
.height
);
280 cairo_surface_destroy (&clip
->base
);
283 cairo_surface_destroy (&tmp
->base
);
288 /* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
289 * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
291 static cairo_status_t
292 clip_and_composite_source (const cairo_composite_rectangles_t
*extents
,
293 draw_func_t draw_func
,
296 cairo_image_surface_t
*dst
= (cairo_image_surface_t
*)extents
->surface
;
297 cairo_image_surface_t
*mask
;
300 cairo_status_t status
= CAIRO_STATUS_SUCCESS
;
302 TRACE ((stderr
, "%s\n", __FUNCTION__
));
304 mask
= create_composite_mask (dst
, draw_closure
, draw_func
, extents
);
305 if (unlikely (mask
->base
.status
))
306 return mask
->base
.status
;
308 pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE
,
309 mask
->pixman_image
, NULL
, dst
->pixman_image
,
312 extents
->bounded
.x
, extents
->bounded
.y
,
313 extents
->bounded
.width
, extents
->bounded
.height
);
315 src
= _pixman_image_for_pattern (dst
,
316 &extents
->source_pattern
.base
, FALSE
,
318 &extents
->source_sample_area
,
320 if (unlikely (src
== NULL
)) {
321 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
325 pixman_image_composite32 (PIXMAN_OP_ADD
,
326 src
, mask
->pixman_image
, dst
->pixman_image
,
327 extents
->bounded
.x
+ src_x
, extents
->bounded
.y
+ src_y
,
329 extents
->bounded
.x
, extents
->bounded
.y
,
330 extents
->bounded
.width
, extents
->bounded
.height
);
332 pixman_image_unref (src
);
335 cairo_surface_destroy (&mask
->base
);
339 static cairo_status_t
340 fixup_unbounded (const cairo_composite_rectangles_t
*extents
)
342 cairo_image_surface_t
*dst
= (cairo_image_surface_t
*)extents
->surface
;
343 pixman_image_t
*mask
;
346 TRACE ((stderr
, "%s\n", __FUNCTION__
));
348 if (! _cairo_clip_is_region (extents
->clip
)) {
349 cairo_image_surface_t
*clip
;
351 clip
= (cairo_image_surface_t
*)
352 _cairo_clip_get_surface (extents
->clip
, &dst
->base
,
354 if (unlikely (clip
->base
.status
))
355 return clip
->base
.status
;
357 mask
= pixman_image_ref (clip
->pixman_image
);
358 cairo_surface_destroy (&clip
->base
);
361 mask
= _pixman_image_for_color (CAIRO_COLOR_WHITE
);
362 if (unlikely (mask
== NULL
))
363 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
367 if (extents
->bounded
.y
!= extents
->unbounded
.y
) {
368 int x
= extents
->unbounded
.x
;
369 int y
= extents
->unbounded
.y
;
370 int width
= extents
->unbounded
.width
;
371 int height
= extents
->bounded
.y
- y
;
373 pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE
,
374 mask
, NULL
, dst
->pixman_image
,
375 x
- mask_x
, y
- mask_y
,
382 if (extents
->bounded
.x
!= extents
->unbounded
.x
) {
383 int x
= extents
->unbounded
.x
;
384 int y
= extents
->bounded
.y
;
385 int width
= extents
->bounded
.x
- x
;
386 int height
= extents
->bounded
.height
;
388 pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE
,
389 mask
, NULL
, dst
->pixman_image
,
390 x
- mask_x
, y
- mask_y
,
397 if (extents
->bounded
.x
+ extents
->bounded
.width
!= extents
->unbounded
.x
+ extents
->unbounded
.width
) {
398 int x
= extents
->bounded
.x
+ extents
->bounded
.width
;
399 int y
= extents
->bounded
.y
;
400 int width
= extents
->unbounded
.x
+ extents
->unbounded
.width
- x
;
401 int height
= extents
->bounded
.height
;
403 pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE
,
404 mask
, NULL
, dst
->pixman_image
,
405 x
- mask_x
, y
- mask_y
,
412 if (extents
->bounded
.y
+ extents
->bounded
.height
!= extents
->unbounded
.y
+ extents
->unbounded
.height
) {
413 int x
= extents
->unbounded
.x
;
414 int y
= extents
->bounded
.y
+ extents
->bounded
.height
;
415 int width
= extents
->unbounded
.width
;
416 int height
= extents
->unbounded
.y
+ extents
->unbounded
.height
- y
;
418 pixman_image_composite32 (PIXMAN_OP_OUT_REVERSE
,
419 mask
, NULL
, dst
->pixman_image
,
420 x
- mask_x
, y
- mask_y
,
426 pixman_image_unref (mask
);
428 return CAIRO_STATUS_SUCCESS
;
431 static cairo_int_status_t
432 set_clip_region (cairo_composite_rectangles_t
*extents
)
434 cairo_image_surface_t
*dst
= (cairo_image_surface_t
*) extents
->surface
;
435 cairo_region_t
*region
= _cairo_clip_get_region (extents
->clip
);
436 pixman_region32_t
*rgn
= region
? ®ion
->rgn
: NULL
;
437 if (! pixman_image_set_clip_region32 (dst
->pixman_image
, rgn
))
438 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
440 return CAIRO_STATUS_SUCCESS
;
443 static cairo_status_t
444 clip_and_composite (cairo_composite_rectangles_t
*extents
,
445 draw_func_t draw_func
,
448 cairo_status_t status
;
450 status
= set_clip_region (extents
);
451 if (unlikely (status
))
454 if (extents
->op
== CAIRO_OPERATOR_SOURCE
) {
455 status
= clip_and_composite_source (extents
, draw_func
, draw_closure
);
457 if (extents
->op
== CAIRO_OPERATOR_CLEAR
) {
458 extents
->source_pattern
.solid
= _cairo_pattern_white
;
459 extents
->op
= CAIRO_OPERATOR_DEST_OUT
;
461 if (! _cairo_clip_is_region (extents
->clip
)) {
462 if (extents
->is_bounded
)
463 status
= clip_and_composite_with_mask (extents
, draw_func
, draw_closure
);
465 status
= clip_and_composite_combine (extents
, draw_func
, draw_closure
);
467 status
= draw_func ((cairo_image_surface_t
*) extents
->surface
,
470 &extents
->source_pattern
.base
,
476 if (status
== CAIRO_STATUS_SUCCESS
&& ! extents
->is_bounded
)
477 status
= fixup_unbounded (extents
);
482 /* high-level compositor interface */
484 static cairo_int_status_t
485 composite_paint (cairo_image_surface_t
*dst
,
488 const cairo_pattern_t
*pattern
,
491 const cairo_rectangle_int_t
*extents
)
493 cairo_rectangle_int_t sample
;
497 TRACE ((stderr
, "%s\n", __FUNCTION__
));
499 _cairo_pattern_sampled_area (pattern
, extents
, &sample
);
500 src
= _pixman_image_for_pattern (dst
,
504 if (unlikely (src
== NULL
))
505 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
507 TRACE ((stderr
, "%s: src=(%d, %d), dst=(%d, %d) size=%dx%d\n", __FUNCTION__
,
508 extents
->x
+ src_x
, extents
->y
+ src_y
,
509 extents
->x
- dst_x
, extents
->y
- dst_y
,
510 extents
->width
, extents
->height
));
512 pixman_image_composite32 (_pixman_operator (op
),
513 src
, NULL
, dst
->pixman_image
,
514 extents
->x
+ src_x
, extents
->y
+ src_y
,
516 extents
->x
- dst_x
, extents
->y
- dst_y
,
517 extents
->width
, extents
->height
);
519 pixman_image_unref (src
);
521 return CAIRO_STATUS_SUCCESS
;
524 static cairo_int_status_t
525 base_compositor_paint (const cairo_compositor_t
*_compositor
,
526 cairo_composite_rectangles_t
*extents
)
528 TRACE ((stderr
, "%s\n", __FUNCTION__
));
529 return clip_and_composite (extents
, composite_paint
, NULL
);
532 static cairo_int_status_t
533 composite_mask (cairo_image_surface_t
*dst
,
536 const cairo_pattern_t
*pattern
,
539 const cairo_rectangle_int_t
*extents
)
541 cairo_rectangle_int_t sample
;
542 pixman_image_t
*src
, *mask
;
546 TRACE ((stderr
, "%s\n", __FUNCTION__
));
548 _cairo_pattern_sampled_area (pattern
, extents
, &sample
);
549 src
= _pixman_image_for_pattern (dst
, pattern
, FALSE
,
552 if (unlikely (src
== NULL
))
553 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
555 _cairo_pattern_sampled_area (closure
, extents
, &sample
);
556 mask
= _pixman_image_for_pattern (dst
, closure
, TRUE
,
559 if (unlikely (mask
== NULL
)) {
560 pixman_image_unref (src
);
561 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
564 pixman_image_composite32 (_pixman_operator (op
),
565 src
, mask
, dst
->pixman_image
,
566 extents
->x
+ src_x
, extents
->y
+ src_y
,
567 extents
->x
+ mask_x
, extents
->y
+ mask_y
,
568 extents
->x
- dst_x
, extents
->y
- dst_y
,
569 extents
->width
, extents
->height
);
571 pixman_image_unref (mask
);
572 pixman_image_unref (src
);
574 return CAIRO_STATUS_SUCCESS
;
577 static cairo_int_status_t
578 base_compositor_mask (const cairo_compositor_t
*_compositor
,
579 cairo_composite_rectangles_t
*extents
)
581 TRACE ((stderr
, "%s\n", __FUNCTION__
));
582 return clip_and_composite (extents
, composite_mask
, &extents
->mask_pattern
.base
);
587 cairo_antialias_t antialias
;
588 } composite_traps_info_t
;
590 static cairo_int_status_t
591 composite_traps (cairo_image_surface_t
*dst
,
594 const cairo_pattern_t
*pattern
,
597 const cairo_rectangle_int_t
*extents
)
599 composite_traps_info_t
*info
= closure
;
600 cairo_rectangle_int_t sample
;
601 pixman_image_t
*src
, *mask
;
604 TRACE ((stderr
, "%s\n", __FUNCTION__
));
606 _cairo_pattern_sampled_area (pattern
, extents
, &sample
);
607 src
= _pixman_image_for_pattern (dst
, pattern
, FALSE
,
610 if (unlikely (src
== NULL
))
611 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
613 mask
= pixman_image_create_bits (info
->antialias
== CAIRO_ANTIALIAS_NONE
? PIXMAN_a1
: PIXMAN_a8
,
614 extents
->width
, extents
->height
,
616 if (unlikely (mask
== NULL
)) {
617 pixman_image_unref (src
);
618 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
621 _pixman_image_add_traps (mask
, extents
->x
, extents
->y
, &info
->traps
);
622 pixman_image_composite32 (_pixman_operator (op
),
623 src
, mask
, dst
->pixman_image
,
624 extents
->x
+ src_x
- dst_x
, extents
->y
+ src_y
- dst_y
,
626 extents
->x
- dst_x
, extents
->y
- dst_y
,
627 extents
->width
, extents
->height
);
629 pixman_image_unref (mask
);
630 pixman_image_unref (src
);
632 return CAIRO_STATUS_SUCCESS
;
635 static cairo_int_status_t
636 trim_extents_to_traps (cairo_composite_rectangles_t
*extents
,
637 cairo_traps_t
*traps
)
641 /* X trims the affected area to the extents of the trapezoids, so
642 * we need to compensate when fixing up the unbounded area.
644 _cairo_traps_extents (traps
, &box
);
645 return _cairo_composite_rectangles_intersect_mask_extents (extents
, &box
);
648 static cairo_int_status_t
649 base_compositor_stroke (const cairo_compositor_t
*_compositor
,
650 cairo_composite_rectangles_t
*extents
,
651 const cairo_path_fixed_t
*path
,
652 const cairo_stroke_style_t
*style
,
653 const cairo_matrix_t
*ctm
,
654 const cairo_matrix_t
*ctm_inverse
,
656 cairo_antialias_t antialias
)
658 composite_traps_info_t info
;
659 cairo_int_status_t status
;
661 TRACE ((stderr
, "%s\n", __FUNCTION__
));
663 info
.antialias
= antialias
;
664 _cairo_traps_init_with_clip (&info
.traps
, extents
->clip
);
665 status
= _cairo_path_fixed_stroke_polygon_to_traps (path
, style
,
669 if (likely (status
== CAIRO_INT_STATUS_SUCCESS
))
670 status
= trim_extents_to_traps (extents
, &info
.traps
);
671 if (likely (status
== CAIRO_INT_STATUS_SUCCESS
))
672 status
= clip_and_composite (extents
, composite_traps
, &info
);
673 _cairo_traps_fini (&info
.traps
);
678 static cairo_int_status_t
679 base_compositor_fill (const cairo_compositor_t
*_compositor
,
680 cairo_composite_rectangles_t
*extents
,
681 const cairo_path_fixed_t
*path
,
682 cairo_fill_rule_t fill_rule
,
684 cairo_antialias_t antialias
)
686 composite_traps_info_t info
;
687 cairo_int_status_t status
;
689 TRACE ((stderr
, "%s\n", __FUNCTION__
));
691 info
.antialias
= antialias
;
692 _cairo_traps_init_with_clip (&info
.traps
, extents
->clip
);
693 status
= _cairo_path_fixed_fill_to_traps (path
,
694 fill_rule
, tolerance
,
696 if (likely (status
== CAIRO_INT_STATUS_SUCCESS
))
697 status
= trim_extents_to_traps (extents
, &info
.traps
);
698 if (likely (status
== CAIRO_INT_STATUS_SUCCESS
))
699 status
= clip_and_composite (extents
, composite_traps
, &info
);
700 _cairo_traps_fini (&info
.traps
);
705 static cairo_int_status_t
706 composite_glyphs (cairo_image_surface_t
*dst
,
709 const cairo_pattern_t
*pattern
,
712 const cairo_rectangle_int_t
*extents
)
714 cairo_composite_glyphs_info_t
*info
= closure
;
715 pixman_image_t
*mask
;
716 cairo_status_t status
;
719 TRACE ((stderr
, "%s\n", __FUNCTION__
));
721 mask
= pixman_image_create_bits (PIXMAN_a8
,
722 extents
->width
, extents
->height
,
724 if (unlikely (mask
== NULL
))
725 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
727 status
= CAIRO_STATUS_SUCCESS
;
728 _cairo_scaled_font_freeze_cache (info
->font
);
729 for (i
= 0; i
< info
->num_glyphs
; i
++) {
730 cairo_image_surface_t
*glyph_surface
;
731 cairo_scaled_glyph_t
*scaled_glyph
;
732 unsigned long glyph_index
= info
->glyphs
[i
].index
;
735 status
= _cairo_scaled_glyph_lookup (info
->font
, glyph_index
,
736 CAIRO_SCALED_GLYPH_INFO_SURFACE
,
739 if (unlikely (status
))
742 glyph_surface
= scaled_glyph
->surface
;
743 if (glyph_surface
->width
&& glyph_surface
->height
) {
744 /* round glyph locations to the nearest pixel */
745 /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
746 x
= _cairo_lround (info
->glyphs
[i
].x
-
747 glyph_surface
->base
.device_transform
.x0
);
748 y
= _cairo_lround (info
->glyphs
[i
].y
-
749 glyph_surface
->base
.device_transform
.y0
);
751 pixman_image_composite32 (PIXMAN_OP_ADD
,
752 glyph_surface
->pixman_image
, NULL
, mask
,
755 x
- extents
->x
, y
- extents
->y
,
756 glyph_surface
->width
,
757 glyph_surface
->height
);
760 _cairo_scaled_font_thaw_cache (info
->font
);
762 if (status
== CAIRO_STATUS_SUCCESS
) {
763 cairo_rectangle_int_t sample
;
767 _cairo_pattern_sampled_area (pattern
, extents
, &sample
);
768 src
= _pixman_image_for_pattern (dst
, pattern
, FALSE
,
772 dst_x
= extents
->x
- dst_x
;
773 dst_y
= extents
->y
- dst_y
;
774 pixman_image_composite32 (_pixman_operator (op
),
775 src
, mask
, dst
->pixman_image
,
776 src_x
+ dst_x
, src_y
+ dst_y
,
779 extents
->width
, extents
->height
);
780 pixman_image_unref (src
);
782 status
= _cairo_error (CAIRO_STATUS_NO_MEMORY
);
784 pixman_image_unref (mask
);
789 static cairo_int_status_t
790 base_compositor_glyphs (const cairo_compositor_t
*_compositor
,
791 cairo_composite_rectangles_t
*extents
,
792 cairo_scaled_font_t
*scaled_font
,
793 cairo_glyph_t
*glyphs
,
795 cairo_bool_t overlap
)
797 cairo_composite_glyphs_info_t info
;
799 info
.font
= scaled_font
;
800 info
.glyphs
= glyphs
;
801 info
.num_glyphs
= num_glyphs
;
803 TRACE ((stderr
, "%s\n", __FUNCTION__
));
804 return clip_and_composite (extents
, composite_glyphs
, &info
);
807 static const cairo_compositor_t base_compositor
= {
808 &__cairo_no_compositor
,
810 base_compositor_paint
,
811 base_compositor_mask
,
812 base_compositor_stroke
,
813 base_compositor_fill
,
814 base_compositor_glyphs
,
818 _cairo_test_base_compositor_surface_create (cairo_content_t content
,
822 return test_compositor_surface_create (&base_compositor
,
823 content
, width
, height
);