tizen 2.3.1 release
[framework/graphics/cairo.git] / src / test-base-compositor-surface.c
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 "test-compositor-surface-private.h"
45
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"
53
54 /* The intention is that this is a surface that just works, and most
55  * important of all does not try to be clever!
56  */
57
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);
66
67 static pixman_op_t
68 _pixman_operator (cairo_operator_t op)
69 {
70     switch ((int) op) {
71     case CAIRO_OPERATOR_CLEAR:
72         return PIXMAN_OP_CLEAR;
73
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;
84
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;
95
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;
102
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;
133
134     default:
135         ASSERT_NOT_REACHED;
136         return PIXMAN_OP_OVER;
137     }
138 }
139
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)
145 {
146     cairo_image_surface_t *surface;
147     cairo_int_status_t status;
148
149     TRACE ((stderr, "%s\n", __FUNCTION__));
150
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,
155                                                         0);
156     if (unlikely (surface->base.status))
157         return surface;
158
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;
165
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;
172
173     return surface;
174
175 error:
176     cairo_surface_destroy (&surface->base);
177     return (cairo_image_surface_t *)_cairo_surface_create_in_error (status);
178 }
179
180 /* Handles compositing with a clip surface when the operator allows
181  * us to combine the clip with the mask
182  */
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)
187 {
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;
193
194     TRACE ((stderr, "%s\n", __FUNCTION__));
195
196     mask = create_composite_mask (dst, draw_closure, draw_func, extents);
197     if (unlikely (mask->base.status))
198         return mask->base.status;
199
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;
208     }
209
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);
217
218     pixman_image_unref (src);
219 error:
220     cairo_surface_destroy (&mask->base);
221     return status;
222 }
223
224 /* Handles compositing with a clip surface when we have to do the operation
225  * in two pieces and combine them together.
226  */
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)
231 {
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;
236
237     TRACE ((stderr, "%s\n", __FUNCTION__));
238
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,
244                                                         0);
245     if (unlikely (tmp->base.status))
246         return tmp->base.status;
247
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);
254
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;
261
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;
266
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);
279
280     cairo_surface_destroy (&clip->base);
281
282  error:
283     cairo_surface_destroy (&tmp->base);
284
285     return status;
286 }
287
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))
290  */
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)
295 {
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;
301
302     TRACE ((stderr, "%s\n", __FUNCTION__));
303
304     mask = create_composite_mask (dst, draw_closure, draw_func, extents);
305     if (unlikely (mask->base.status))
306         return mask->base.status;
307
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);
314
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;
323     }
324
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);
331
332     pixman_image_unref (src);
333
334 error:
335     cairo_surface_destroy (&mask->base);
336     return status;
337 }
338
339 static cairo_status_t
340 fixup_unbounded (const cairo_composite_rectangles_t *extents)
341 {
342     cairo_image_surface_t *dst = (cairo_image_surface_t *)extents->surface;
343     pixman_image_t *mask;
344     int mask_x, mask_y;
345
346     TRACE ((stderr, "%s\n", __FUNCTION__));
347
348     if (! _cairo_clip_is_region (extents->clip)) {
349         cairo_image_surface_t *clip;
350
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;
356
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);
364     }
365
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;
372
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);
379     }
380
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;
387
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);
394     }
395
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;
402
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);
409     }
410
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;
417
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);
424     }
425
426     pixman_image_unref (mask);
427
428     return CAIRO_STATUS_SUCCESS;
429 }
430
431 static cairo_int_status_t
432 set_clip_region (cairo_composite_rectangles_t *extents)
433 {
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);
439
440     return CAIRO_STATUS_SUCCESS;
441 }
442
443 static cairo_status_t
444 clip_and_composite (cairo_composite_rectangles_t *extents,
445                     draw_func_t          draw_func,
446                     void                *draw_closure)
447 {
448     cairo_status_t status;
449
450     status = set_clip_region (extents);
451     if (unlikely (status))
452         return status;
453
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;
460         }
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);
473         }
474     }
475
476     if (status == CAIRO_STATUS_SUCCESS && ! extents->is_bounded)
477         status = fixup_unbounded (extents);
478
479     return status;
480 }
481
482 /* high-level compositor interface */
483
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)
492 {
493     cairo_rectangle_int_t sample;
494     pixman_image_t *src;
495     int src_x, src_y;
496
497     TRACE ((stderr, "%s\n", __FUNCTION__));
498
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);
506
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));
511
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);
518
519     pixman_image_unref (src);
520
521     return CAIRO_STATUS_SUCCESS;
522 }
523
524 static cairo_int_status_t
525 base_compositor_paint (const cairo_compositor_t *_compositor,
526                        cairo_composite_rectangles_t *extents)
527 {
528     TRACE ((stderr, "%s\n", __FUNCTION__));
529     return clip_and_composite (extents, composite_paint, NULL);
530 }
531
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)
540 {
541     cairo_rectangle_int_t sample;
542     pixman_image_t *src, *mask;
543     int src_x, src_y;
544     int mask_x, mask_y;
545
546     TRACE ((stderr, "%s\n", __FUNCTION__));
547
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);
554
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);
562     }
563
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);
570
571     pixman_image_unref (mask);
572     pixman_image_unref (src);
573
574     return CAIRO_STATUS_SUCCESS;
575 }
576
577 static cairo_int_status_t
578 base_compositor_mask (const cairo_compositor_t *_compositor,
579                       cairo_composite_rectangles_t *extents)
580 {
581     TRACE ((stderr, "%s\n", __FUNCTION__));
582     return clip_and_composite (extents, composite_mask, &extents->mask_pattern.base);
583 }
584
585 typedef struct {
586     cairo_traps_t traps;
587     cairo_antialias_t antialias;
588 } composite_traps_info_t;
589
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)
598 {
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;
603
604     TRACE ((stderr, "%s\n", __FUNCTION__));
605
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);
612
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);
619     }
620
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);
628
629     pixman_image_unref (mask);
630     pixman_image_unref (src);
631
632     return  CAIRO_STATUS_SUCCESS;
633 }
634
635 static cairo_int_status_t
636 trim_extents_to_traps (cairo_composite_rectangles_t *extents,
637                        cairo_traps_t *traps)
638 {
639     cairo_box_t box;
640
641     /* X trims the affected area to the extents of the trapezoids, so
642      * we need to compensate when fixing up the unbounded area.
643     */
644     _cairo_traps_extents (traps, &box);
645     return _cairo_composite_rectangles_intersect_mask_extents (extents, &box);
646 }
647
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)
657 {
658     composite_traps_info_t info;
659     cairo_int_status_t status;
660
661     TRACE ((stderr, "%s\n", __FUNCTION__));
662
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);
674
675     return status;
676 }
677
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)
685 {
686     composite_traps_info_t info;
687     cairo_int_status_t status;
688
689     TRACE ((stderr, "%s\n", __FUNCTION__));
690
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);
701
702     return status;
703 }
704
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)
713 {
714     cairo_composite_glyphs_info_t *info = closure;
715     pixman_image_t *mask;
716     cairo_status_t status;
717     int i;
718
719     TRACE ((stderr, "%s\n", __FUNCTION__));
720
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);
726
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;
734
735         status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
736                                              CAIRO_SCALED_GLYPH_INFO_SURFACE,
737                                              &scaled_glyph);
738
739         if (unlikely (status))
740             break;
741
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);
750
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);
758         }
759     }
760     _cairo_scaled_font_thaw_cache (info->font);
761
762     if (status == CAIRO_STATUS_SUCCESS) {
763         cairo_rectangle_int_t sample;
764         pixman_image_t *src;
765         int src_x, src_y;
766
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);
783     }
784     pixman_image_unref (mask);
785
786     return status;
787 }
788
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)
796 {
797     cairo_composite_glyphs_info_t info;
798
799     info.font = scaled_font;
800     info.glyphs = glyphs;
801     info.num_glyphs = num_glyphs;
802
803     TRACE ((stderr, "%s\n", __FUNCTION__));
804     return clip_and_composite (extents, composite_glyphs, &info);
805 }
806
807 static const cairo_compositor_t base_compositor = {
808     &__cairo_no_compositor,
809
810     base_compositor_paint,
811     base_compositor_mask,
812     base_compositor_stroke,
813     base_compositor_fill,
814     base_compositor_glyphs,
815 };
816
817 cairo_surface_t *
818 _cairo_test_base_compositor_surface_create (cairo_content_t     content,
819                                             int         width,
820                                             int         height)
821 {
822     return test_compositor_surface_create (&base_compositor,
823                                            content, width, height);
824 }