sync with trunk
[luatex.git] / source / libs / cairo / cairo-1.14.2 / src / test-base-compositor-surface.c
blobff84b10aff71e00c49ae6743b463a30874ed05ef
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
34 * California.
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>
42 #include "cairoint.h"
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,
60 void *closure,
61 cairo_operator_t op,
62 const cairo_pattern_t *pattern,
63 int dst_x,
64 int dst_y,
65 const cairo_rectangle_int_t *extents);
67 static pixman_op_t
68 _pixman_operator (cairo_operator_t op)
70 switch ((int) op) {
71 case CAIRO_OPERATOR_CLEAR:
72 return PIXMAN_OP_CLEAR;
74 case CAIRO_OPERATOR_SOURCE:
75 return PIXMAN_OP_SRC;
76 case CAIRO_OPERATOR_OVER:
77 return PIXMAN_OP_OVER;
78 case CAIRO_OPERATOR_IN:
79 return PIXMAN_OP_IN;
80 case CAIRO_OPERATOR_OUT:
81 return PIXMAN_OP_OUT;
82 case CAIRO_OPERATOR_ATOP:
83 return PIXMAN_OP_ATOP;
85 case CAIRO_OPERATOR_DEST:
86 return PIXMAN_OP_DST;
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:
97 return PIXMAN_OP_XOR;
98 case CAIRO_OPERATOR_ADD:
99 return PIXMAN_OP_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;
134 default:
135 ASSERT_NOT_REACHED;
136 return PIXMAN_OP_OVER;
140 static cairo_image_surface_t *
141 create_composite_mask (cairo_image_surface_t *dst,
142 void *draw_closure,
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))
157 return surface;
159 status = draw_func (surface, draw_closure,
160 CAIRO_OPERATOR_ADD, &_cairo_pattern_white.base,
161 extents->bounded.x, extents->bounded.y,
162 &extents->bounded);
163 if (unlikely (status))
164 goto error;
166 status = _cairo_clip_combine_with_surface (extents->clip,
167 &surface->base,
168 extents->bounded.x,
169 extents->bounded.y);
170 if (unlikely (status))
171 goto error;
173 return surface;
175 error:
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,
186 void *draw_closure)
188 cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface;
189 cairo_image_surface_t *mask;
190 pixman_image_t *src;
191 cairo_status_t status = CAIRO_STATUS_SUCCESS;
192 int src_x, src_y;
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,
202 &extents->bounded,
203 &extents->source_sample_area,
204 &src_x, &src_y);
205 if (unlikely (src == NULL)) {
206 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
207 goto error;
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,
214 0, 0,
215 extents->bounded.x, extents->bounded.y,
216 extents->bounded.width, extents->bounded.height);
218 pixman_image_unref (src);
219 error:
220 cairo_surface_destroy (&mask->base);
221 return status;
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,
230 void *draw_closure)
232 cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface;
233 cairo_image_surface_t *tmp, *clip;
234 int clip_x, clip_y;
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,
241 dst->pixman_format,
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,
251 0, 0,
252 0, 0,
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,
258 &extents->bounded);
259 if (unlikely (status))
260 goto error;
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))
265 goto error;
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,
270 0, 0,
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,
275 0, 0,
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);
282 error:
283 cairo_surface_destroy (&tmp->base);
285 return status;
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,
294 void *draw_closure)
296 cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface;
297 cairo_image_surface_t *mask;
298 pixman_image_t *src;
299 int src_x, src_y;
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,
310 0, 0,
311 0, 0,
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,
317 &extents->bounded,
318 &extents->source_sample_area,
319 &src_x, &src_y);
320 if (unlikely (src == NULL)) {
321 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
322 goto error;
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,
328 0, 0,
329 extents->bounded.x, extents->bounded.y,
330 extents->bounded.width, extents->bounded.height);
332 pixman_image_unref (src);
334 error:
335 cairo_surface_destroy (&mask->base);
336 return status;
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;
344 int mask_x, mask_y;
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,
353 &mask_x, &mask_y);
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);
359 } else {
360 mask_x = mask_y = 0;
361 mask = _pixman_image_for_color (CAIRO_COLOR_WHITE);
362 if (unlikely (mask == NULL))
363 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
366 /* top */
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,
376 0, 0,
377 x, y,
378 width, height);
381 /* left */
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,
391 0, 0,
392 x, y,
393 width, height);
396 /* right */
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,
406 0, 0,
407 x, y,
408 width, height);
411 /* bottom */
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,
421 0, 0,
422 x, y,
423 width, height);
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 ? &region->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,
446 void *draw_closure)
448 cairo_status_t status;
450 status = set_clip_region (extents);
451 if (unlikely (status))
452 return status;
454 if (extents->op == CAIRO_OPERATOR_SOURCE) {
455 status = clip_and_composite_source (extents, draw_func, draw_closure);
456 } else {
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);
464 else
465 status = clip_and_composite_combine (extents, draw_func, draw_closure);
466 } else {
467 status = draw_func ((cairo_image_surface_t *) extents->surface,
468 draw_closure,
469 extents->op,
470 &extents->source_pattern.base,
471 0, 0,
472 &extents->bounded);
476 if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded)
477 status = fixup_unbounded (extents);
479 return status;
482 /* high-level compositor interface */
484 static cairo_int_status_t
485 composite_paint (cairo_image_surface_t *dst,
486 void *closure,
487 cairo_operator_t op,
488 const cairo_pattern_t *pattern,
489 int dst_x,
490 int dst_y,
491 const cairo_rectangle_int_t *extents)
493 cairo_rectangle_int_t sample;
494 pixman_image_t *src;
495 int src_x, src_y;
497 TRACE ((stderr, "%s\n", __FUNCTION__));
499 _cairo_pattern_sampled_area (pattern, extents, &sample);
500 src = _pixman_image_for_pattern (dst,
501 pattern, FALSE,
502 extents, &sample,
503 &src_x, &src_y);
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,
515 0, 0,
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,
534 void *closure,
535 cairo_operator_t op,
536 const cairo_pattern_t *pattern,
537 int dst_x,
538 int dst_y,
539 const cairo_rectangle_int_t *extents)
541 cairo_rectangle_int_t sample;
542 pixman_image_t *src, *mask;
543 int src_x, src_y;
544 int mask_x, mask_y;
546 TRACE ((stderr, "%s\n", __FUNCTION__));
548 _cairo_pattern_sampled_area (pattern, extents, &sample);
549 src = _pixman_image_for_pattern (dst, pattern, FALSE,
550 extents, &sample,
551 &src_x, &src_y);
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,
557 extents, &sample,
558 &mask_x, &mask_y);
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);
585 typedef struct {
586 cairo_traps_t traps;
587 cairo_antialias_t antialias;
588 } composite_traps_info_t;
590 static cairo_int_status_t
591 composite_traps (cairo_image_surface_t *dst,
592 void *closure,
593 cairo_operator_t op,
594 const cairo_pattern_t *pattern,
595 int dst_x,
596 int dst_y,
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;
602 int src_x, src_y;
604 TRACE ((stderr, "%s\n", __FUNCTION__));
606 _cairo_pattern_sampled_area (pattern, extents, &sample);
607 src = _pixman_image_for_pattern (dst, pattern, FALSE,
608 extents, &sample,
609 &src_x, &src_y);
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,
615 NULL, 0);
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,
625 0, 0,
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)
639 cairo_box_t box;
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,
655 double tolerance,
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,
666 ctm, ctm_inverse,
667 tolerance,
668 &info.traps);
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);
675 return status;
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,
683 double tolerance,
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,
695 &info.traps);
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);
702 return status;
705 static cairo_int_status_t
706 composite_glyphs (cairo_image_surface_t *dst,
707 void *closure,
708 cairo_operator_t op,
709 const cairo_pattern_t *pattern,
710 int dst_x,
711 int dst_y,
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;
717 int i;
719 TRACE ((stderr, "%s\n", __FUNCTION__));
721 mask = pixman_image_create_bits (PIXMAN_a8,
722 extents->width, extents->height,
723 NULL, 0);
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;
733 int x, y;
735 status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
736 CAIRO_SCALED_GLYPH_INFO_SURFACE,
737 &scaled_glyph);
739 if (unlikely (status))
740 break;
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,
753 0, 0,
754 0, 0,
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;
764 pixman_image_t *src;
765 int src_x, src_y;
767 _cairo_pattern_sampled_area (pattern, extents, &sample);
768 src = _pixman_image_for_pattern (dst, pattern, FALSE,
769 extents, &sample,
770 &src_x, &src_y);
771 if (src != NULL) {
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,
777 0, 0,
778 dst_x, dst_y,
779 extents->width, extents->height);
780 pixman_image_unref (src);
781 } else
782 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
784 pixman_image_unref (mask);
786 return status;
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,
794 int num_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,
817 cairo_surface_t *
818 _cairo_test_base_compositor_surface_create (cairo_content_t content,
819 int width,
820 int height)
822 return test_compositor_surface_create (&base_compositor,
823 content, width, height);