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  *
7  * This library is free software; you can redistribute it and/or
8  * modify it either under the terms of the GNU Lesser General Public
9  * License version 2.1 as published by the Free Software Foundation
10  * (the "LGPL") or, at your option, under the terms of the Mozilla
11  * Public License Version 1.1 (the "MPL"). If you do not alter this
12  * notice, a recipient may use your version of this file under either
13  * the MPL or the LGPL.
14  *
15  * You should have received a copy of the LGPL along with this library
16  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
18  * You should have received a copy of the MPL along with this library
19  * in the file COPYING-MPL-1.1
20  *
21  * The contents of this file are subject to the Mozilla Public License
22  * Version 1.1 (the "License"); you may not use this file except in
23  * compliance with the License. You may obtain a copy of the License at
24  * http://www.mozilla.org/MPL/
25  *
26  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28  * the specific language governing rights and limitations.
29  *
30  * The Original Code is the cairo graphics library.
31  *
32  * The Initial Developer of the Original Code is University of Southern
33  * California.
34  *
35  * Contributor(s):
36  *	Carl D. Worth <cworth@cworth.org>
37  *      Joonas Pihlaja <jpihlaja@cc.helsinki.fi>
38  *	Chris Wilson <chris@chris-wilson.co.uk>
39  */
40 
41 #include "cairoint.h"
42 
43 #include "cairo-boxes-private.h"
44 #include "cairo-clip-private.h"
45 #include "cairo-composite-rectangles-private.h"
46 #include "cairo-error-private.h"
47 #include "cairo-region-private.h"
48 #include "cairo-spans-private.h"
49 #include "cairo-surface-fallback-private.h"
50 
51 typedef struct {
52     cairo_surface_t *dst;
53     cairo_rectangle_int_t extents;
54     cairo_image_surface_t *image;
55     cairo_rectangle_int_t image_rect;
56     void *image_extra;
57 } fallback_state_t;
58 
59 /**
60  * _fallback_init:
61  *
62  * Acquire destination image surface needed for an image-based
63  * fallback.
64  *
65  * Return value: %CAIRO_INT_STATUS_NOTHING_TO_DO if the extents are not
66  * visible, %CAIRO_STATUS_SUCCESS if some portion is visible and all
67  * went well, or some error status otherwise.
68  **/
69 static cairo_int_status_t
_fallback_init(fallback_state_t * state,cairo_surface_t * dst,int x,int y,int width,int height)70 _fallback_init (fallback_state_t *state,
71 		cairo_surface_t  *dst,
72 		int               x,
73 		int               y,
74 		int               width,
75 		int               height)
76 {
77     cairo_status_t status;
78 
79     state->extents.x = x;
80     state->extents.y = y;
81     state->extents.width = width;
82     state->extents.height = height;
83 
84     state->dst = dst;
85 
86     status = _cairo_surface_acquire_dest_image (dst, &state->extents,
87 						&state->image, &state->image_rect,
88 						&state->image_extra);
89     if (unlikely (status))
90 	return status;
91 
92 
93     /* XXX: This NULL value tucked away in state->image is a rather
94      * ugly interface. Cleaner would be to push the
95      * CAIRO_INT_STATUS_NOTHING_TO_DO value down into
96      * _cairo_surface_acquire_dest_image and its backend
97      * counterparts. */
98     assert (state->image != NULL);
99 
100     return CAIRO_STATUS_SUCCESS;
101 }
102 
103 static void
_fallback_fini(fallback_state_t * state)104 _fallback_fini (fallback_state_t *state)
105 {
106     _cairo_surface_release_dest_image (state->dst, &state->extents,
107 				       state->image, &state->image_rect,
108 				       state->image_extra);
109 }
110 
111 typedef cairo_status_t
112 (*cairo_draw_func_t) (void                          *closure,
113 		      cairo_operator_t               op,
114 		      const cairo_pattern_t         *src,
115 		      cairo_surface_t               *dst,
116 		      int                            dst_x,
117 		      int                            dst_y,
118 		      const cairo_rectangle_int_t   *extents,
119 		      cairo_region_t		    *clip_region);
120 
121 static cairo_status_t
_create_composite_mask_pattern(cairo_surface_pattern_t * mask_pattern,cairo_clip_t * clip,cairo_draw_func_t draw_func,void * draw_closure,cairo_surface_t * dst,const cairo_rectangle_int_t * extents)122 _create_composite_mask_pattern (cairo_surface_pattern_t       *mask_pattern,
123 				cairo_clip_t                  *clip,
124 				cairo_draw_func_t              draw_func,
125 				void                          *draw_closure,
126 				cairo_surface_t               *dst,
127 				const cairo_rectangle_int_t   *extents)
128 {
129     cairo_surface_t *mask;
130     cairo_region_t *clip_region = NULL, *fallback_region = NULL;
131     cairo_status_t status;
132     cairo_bool_t clip_surface = FALSE;
133 
134     if (clip != NULL) {
135 	status = _cairo_clip_get_region (clip, &clip_region);
136 	if (unlikely (_cairo_status_is_error (status) ||
137 		      status == CAIRO_INT_STATUS_NOTHING_TO_DO))
138 	{
139 	    return status;
140 	}
141 
142 	clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
143     }
144 
145     /* We need to use solid here, because to use CAIRO_OPERATOR_SOURCE with
146      * a mask (as called via _cairo_surface_mask) triggers assertion failures.
147      */
148     mask = _cairo_surface_create_similar_solid (dst,
149 						CAIRO_CONTENT_ALPHA,
150 						extents->width,
151 						extents->height,
152 						CAIRO_COLOR_TRANSPARENT,
153 						TRUE);
154     if (unlikely (mask->status))
155 	return mask->status;
156 
157     if (clip_region && (extents->x || extents->y)) {
158 	fallback_region = cairo_region_copy (clip_region);
159 	status = fallback_region->status;
160 	if (unlikely (status))
161 	    goto CLEANUP_SURFACE;
162 
163 	cairo_region_translate (fallback_region,
164 				-extents->x,
165 				-extents->y);
166 	clip_region = fallback_region;
167     }
168 
169     status = draw_func (draw_closure, CAIRO_OPERATOR_ADD,
170 			&_cairo_pattern_white.base, mask,
171 			extents->x, extents->y,
172 			extents,
173 			clip_region);
174     if (unlikely (status))
175 	goto CLEANUP_SURFACE;
176 
177     if (clip_surface)
178 	status = _cairo_clip_combine_with_surface (clip, mask, extents->x, extents->y);
179 
180     _cairo_pattern_init_for_surface (mask_pattern, mask);
181 
182  CLEANUP_SURFACE:
183     if (fallback_region)
184         cairo_region_destroy (fallback_region);
185     cairo_surface_destroy (mask);
186 
187     return status;
188 }
189 
190 /* Handles compositing with a clip surface when the operator allows
191  * us to combine the clip with the mask
192  */
193 static cairo_status_t
_clip_and_composite_with_mask(cairo_clip_t * clip,cairo_operator_t op,const cairo_pattern_t * src,cairo_draw_func_t draw_func,void * draw_closure,cairo_surface_t * dst,const cairo_rectangle_int_t * extents)194 _clip_and_composite_with_mask (cairo_clip_t                  *clip,
195 			       cairo_operator_t               op,
196 			       const cairo_pattern_t         *src,
197 			       cairo_draw_func_t              draw_func,
198 			       void                          *draw_closure,
199 			       cairo_surface_t               *dst,
200 			       const cairo_rectangle_int_t   *extents)
201 {
202     cairo_surface_pattern_t mask_pattern;
203     cairo_status_t status;
204 
205     status = _create_composite_mask_pattern (&mask_pattern,
206 					     clip,
207 					     draw_func, draw_closure,
208 					     dst, extents);
209     if (likely (status == CAIRO_STATUS_SUCCESS)) {
210 	status = _cairo_surface_composite (op,
211 					   src, &mask_pattern.base, dst,
212 					   extents->x,     extents->y,
213 					   0,              0,
214 					   extents->x,     extents->y,
215 					   extents->width, extents->height,
216 					   NULL);
217 
218 	_cairo_pattern_fini (&mask_pattern.base);
219     }
220 
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
_clip_and_composite_combine(cairo_clip_t * clip,cairo_operator_t op,const cairo_pattern_t * src,cairo_draw_func_t draw_func,void * draw_closure,cairo_surface_t * dst,const cairo_rectangle_int_t * extents)228 _clip_and_composite_combine (cairo_clip_t                  *clip,
229 			     cairo_operator_t               op,
230 			     const cairo_pattern_t         *src,
231 			     cairo_draw_func_t              draw_func,
232 			     void                          *draw_closure,
233 			     cairo_surface_t               *dst,
234 			     const cairo_rectangle_int_t   *extents)
235 {
236     cairo_surface_t *intermediate;
237     cairo_surface_pattern_t pattern;
238     cairo_surface_pattern_t clip_pattern;
239     cairo_surface_t *clip_surface;
240     int clip_x, clip_y;
241     cairo_status_t status;
242 
243     /* We'd be better off here creating a surface identical in format
244      * to dst, but we have no way of getting that information. Instead
245      * we ask the backend to create a similar surface of identical content,
246      * in the belief that the backend will do something useful - like use
247      * an identical format. For example, the xlib backend will endeavor to
248      * use a compatible depth to enable core protocol routines.
249      */
250     intermediate =
251 	_cairo_surface_create_similar_scratch (dst, dst->content,
252 					       extents->width,
253 					       extents->height);
254     if (intermediate == NULL) {
255 	intermediate =
256 	    _cairo_image_surface_create_with_content (dst->content,
257 						      extents->width,
258 						      extents->width);
259     }
260     if (unlikely (intermediate->status))
261 	return intermediate->status;
262 
263     /* Initialize the intermediate surface from the destination surface */
264     _cairo_pattern_init_for_surface (&pattern, dst);
265     status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
266 				       &pattern.base, NULL, intermediate,
267 				       extents->x,     extents->y,
268 				       0,              0,
269 				       0,              0,
270 				       extents->width, extents->height,
271 				       NULL);
272     _cairo_pattern_fini (&pattern.base);
273     if (unlikely (status))
274 	goto CLEANUP_SURFACE;
275 
276     status = (*draw_func) (draw_closure, op,
277 			   src, intermediate,
278 			   extents->x, extents->y,
279 			   extents,
280 			   NULL);
281     if (unlikely (status))
282 	goto CLEANUP_SURFACE;
283 
284     assert (clip->path != NULL);
285     clip_surface = _cairo_clip_get_surface (clip, dst, &clip_x, &clip_y);
286     if (unlikely (clip_surface->status))
287 	goto CLEANUP_SURFACE;
288 
289     _cairo_pattern_init_for_surface (&clip_pattern, clip_surface);
290 
291     /* Combine that with the clip */
292     status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_IN,
293 				       &clip_pattern.base, NULL, intermediate,
294 				       extents->x - clip_x,
295 				       extents->y - clip_y,
296 				       0, 0,
297 				       0, 0,
298 				       extents->width, extents->height,
299 				       NULL);
300     if (unlikely (status))
301 	goto CLEANUP_CLIP;
302 
303     /* Punch the clip out of the destination */
304     status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT,
305 				       &clip_pattern.base, NULL, dst,
306 				       extents->x - clip_x,
307 				       extents->y - clip_y,
308 				       0, 0,
309 				       extents->x, extents->y,
310 				       extents->width, extents->height,
311 				       NULL);
312     if (unlikely (status))
313 	goto CLEANUP_CLIP;
314 
315     /* Now add the two results together */
316     _cairo_pattern_init_for_surface (&pattern, intermediate);
317     status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
318 				       &pattern.base, NULL, dst,
319 				       0,              0,
320 				       0,              0,
321 				       extents->x,     extents->y,
322 				       extents->width, extents->height,
323 				       NULL);
324     _cairo_pattern_fini (&pattern.base);
325 
326  CLEANUP_CLIP:
327     _cairo_pattern_fini (&clip_pattern.base);
328  CLEANUP_SURFACE:
329     cairo_surface_destroy (intermediate);
330 
331     return status;
332 }
333 
334 /* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
335  * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
336  */
337 static cairo_status_t
_clip_and_composite_source(cairo_clip_t * clip,const cairo_pattern_t * src,cairo_draw_func_t draw_func,void * draw_closure,cairo_surface_t * dst,const cairo_rectangle_int_t * extents)338 _clip_and_composite_source (cairo_clip_t                  *clip,
339 			    const cairo_pattern_t         *src,
340 			    cairo_draw_func_t              draw_func,
341 			    void                          *draw_closure,
342 			    cairo_surface_t               *dst,
343 			    const cairo_rectangle_int_t   *extents)
344 {
345     cairo_surface_pattern_t mask_pattern;
346     cairo_region_t *clip_region = NULL;
347     cairo_status_t status;
348 
349     if (clip != NULL) {
350 	status = _cairo_clip_get_region (clip, &clip_region);
351 	if (unlikely (_cairo_status_is_error (status) ||
352 		      status == CAIRO_INT_STATUS_NOTHING_TO_DO))
353 	{
354 	    return status;
355 	}
356     }
357 
358     /* Create a surface that is mask IN clip */
359     status = _create_composite_mask_pattern (&mask_pattern,
360 					     clip,
361 					     draw_func, draw_closure,
362 					     dst, extents);
363     if (unlikely (status))
364 	return status;
365 
366     /* Compute dest' = dest OUT (mask IN clip) */
367     status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT,
368 				       &mask_pattern.base, NULL, dst,
369 				       0,              0,
370 				       0,              0,
371 				       extents->x,     extents->y,
372 				       extents->width, extents->height,
373 				       clip_region);
374 
375     if (unlikely (status))
376 	goto CLEANUP_MASK_PATTERN;
377 
378     /* Now compute (src IN (mask IN clip)) ADD dest' */
379     status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
380 				       src, &mask_pattern.base, dst,
381 				       extents->x,     extents->y,
382 				       0,              0,
383 				       extents->x,     extents->y,
384 				       extents->width, extents->height,
385 				       clip_region);
386 
387  CLEANUP_MASK_PATTERN:
388     _cairo_pattern_fini (&mask_pattern.base);
389     return status;
390 }
391 
392 static int
_cairo_rectangle_empty(const cairo_rectangle_int_t * rect)393 _cairo_rectangle_empty (const cairo_rectangle_int_t *rect)
394 {
395     return rect->width == 0 || rect->height == 0;
396 }
397 
398 /**
399  * _clip_and_composite:
400  * @clip: a #cairo_clip_t
401  * @op: the operator to draw with
402  * @src: source pattern
403  * @draw_func: function that can be called to draw with the mask onto a surface.
404  * @draw_closure: data to pass to @draw_func.
405  * @dst: destination surface
406  * @extents: rectangle holding a bounding box for the operation; this
407  *           rectangle will be used as the size for the temporary
408  *           surface.
409  *
410  * When there is a surface clip, we typically need to create an intermediate
411  * surface. This function handles the logic of creating a temporary surface
412  * drawing to it, then compositing the result onto the target surface.
413  *
414  * @draw_func is to called to draw the mask; it will be called no more
415  * than once.
416  *
417  * Return value: %CAIRO_STATUS_SUCCESS if the drawing succeeded.
418  **/
419 static cairo_status_t
_clip_and_composite(cairo_clip_t * clip,cairo_operator_t op,const cairo_pattern_t * src,cairo_draw_func_t draw_func,void * draw_closure,cairo_surface_t * dst,const cairo_rectangle_int_t * extents)420 _clip_and_composite (cairo_clip_t                  *clip,
421 		     cairo_operator_t               op,
422 		     const cairo_pattern_t         *src,
423 		     cairo_draw_func_t              draw_func,
424 		     void                          *draw_closure,
425 		     cairo_surface_t               *dst,
426 		     const cairo_rectangle_int_t   *extents)
427 {
428     cairo_status_t status;
429 
430     if (_cairo_rectangle_empty (extents))
431 	/* Nothing to do */
432 	return CAIRO_STATUS_SUCCESS;
433 
434     if (op == CAIRO_OPERATOR_CLEAR) {
435 	src = &_cairo_pattern_white.base;
436 	op = CAIRO_OPERATOR_DEST_OUT;
437     }
438 
439     if (op == CAIRO_OPERATOR_SOURCE) {
440 	status = _clip_and_composite_source (clip,
441 					     src,
442 					     draw_func, draw_closure,
443 					     dst, extents);
444     } else {
445 	cairo_bool_t clip_surface = FALSE;
446 	cairo_region_t *clip_region = NULL;
447 
448 	if (clip != NULL) {
449 	    status = _cairo_clip_get_region (clip, &clip_region);
450 	    if (unlikely (_cairo_status_is_error (status) ||
451 			  status == CAIRO_INT_STATUS_NOTHING_TO_DO))
452 	    {
453 		return status;
454 	    }
455 
456 	    clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
457 	}
458 
459 	if (clip_surface) {
460 	    if (_cairo_operator_bounded_by_mask (op)) {
461 		status = _clip_and_composite_with_mask (clip, op,
462 							src,
463 							draw_func, draw_closure,
464 							dst, extents);
465 	    } else {
466 		status = _clip_and_composite_combine (clip, op,
467 						      src,
468 						      draw_func, draw_closure,
469 						      dst, extents);
470 	    }
471 	} else {
472 	    status = draw_func (draw_closure, op,
473 				src, dst,
474 				0, 0,
475 				extents,
476 				clip_region);
477 	}
478     }
479 
480     return status;
481 }
482 
483 /* Composites a region representing a set of trapezoids.
484  */
485 static cairo_status_t
_composite_trap_region(cairo_clip_t * clip,const cairo_pattern_t * src,cairo_operator_t op,cairo_surface_t * dst,cairo_region_t * trap_region,const cairo_rectangle_int_t * extents)486 _composite_trap_region (cairo_clip_t            *clip,
487 			const cairo_pattern_t	*src,
488 			cairo_operator_t         op,
489 			cairo_surface_t         *dst,
490 			cairo_region_t          *trap_region,
491 			const cairo_rectangle_int_t   *extents)
492 {
493     cairo_status_t status;
494     cairo_surface_pattern_t mask_pattern;
495     cairo_pattern_t *mask = NULL;
496     int mask_x = 0, mask_y =0;
497 
498     if (clip != NULL) {
499 	cairo_surface_t *clip_surface = NULL;
500 	int clip_x, clip_y;
501 
502 	clip_surface = _cairo_clip_get_surface (clip, dst, &clip_x, &clip_y);
503 	if (unlikely (clip_surface->status))
504 	    return clip_surface->status;
505 
506 	if (op == CAIRO_OPERATOR_CLEAR) {
507 	    src = &_cairo_pattern_white.base;
508 	    op = CAIRO_OPERATOR_DEST_OUT;
509 	}
510 
511 	_cairo_pattern_init_for_surface (&mask_pattern, clip_surface);
512 	mask_x = extents->x - clip_x;
513 	mask_y = extents->y - clip_y;
514 	mask = &mask_pattern.base;
515     }
516 
517     status = _cairo_surface_composite (op, src, mask, dst,
518 				       extents->x, extents->y,
519 				       mask_x, mask_y,
520 				       extents->x, extents->y,
521 				       extents->width, extents->height,
522 				       trap_region);
523 
524     if (mask != NULL)
525       _cairo_pattern_fini (mask);
526 
527     return status;
528 }
529 
530 typedef struct {
531     cairo_traps_t *traps;
532     cairo_antialias_t antialias;
533 } cairo_composite_traps_info_t;
534 
535 static cairo_status_t
_composite_traps_draw_func(void * closure,cairo_operator_t op,const cairo_pattern_t * src,cairo_surface_t * dst,int dst_x,int dst_y,const cairo_rectangle_int_t * extents,cairo_region_t * clip_region)536 _composite_traps_draw_func (void                          *closure,
537 			    cairo_operator_t               op,
538 			    const cairo_pattern_t         *src,
539 			    cairo_surface_t               *dst,
540 			    int                            dst_x,
541 			    int                            dst_y,
542 			    const cairo_rectangle_int_t   *extents,
543 			    cairo_region_t		  *clip_region)
544 {
545     cairo_composite_traps_info_t *info = closure;
546     cairo_status_t status;
547     cairo_region_t *extents_region = NULL;
548 
549     if (dst_x != 0 || dst_y != 0)
550 	_cairo_traps_translate (info->traps, - dst_x, - dst_y);
551 
552     if (clip_region == NULL &&
553         !_cairo_operator_bounded_by_source (op)) {
554         extents_region = cairo_region_create_rectangle (extents);
555         if (unlikely (extents_region->status))
556             return extents_region->status;
557         cairo_region_translate (extents_region, -dst_x, -dst_y);
558         clip_region = extents_region;
559     }
560 
561     status = _cairo_surface_composite_trapezoids (op,
562                                                   src, dst, info->antialias,
563                                                   extents->x,         extents->y,
564                                                   extents->x - dst_x, extents->y - dst_y,
565                                                   extents->width,     extents->height,
566                                                   info->traps->traps,
567                                                   info->traps->num_traps,
568                                                   clip_region);
569 
570     if (extents_region)
571         cairo_region_destroy (extents_region);
572 
573     return status;
574 }
575 
576 enum {
577     HAS_CLEAR_REGION = 0x1,
578 };
579 
580 static cairo_status_t
_clip_and_composite_region(const cairo_pattern_t * src,cairo_operator_t op,cairo_surface_t * dst,cairo_region_t * trap_region,cairo_clip_t * clip,cairo_rectangle_int_t * extents)581 _clip_and_composite_region (const cairo_pattern_t *src,
582 			    cairo_operator_t op,
583 			    cairo_surface_t *dst,
584 			    cairo_region_t *trap_region,
585 			    cairo_clip_t *clip,
586 			    cairo_rectangle_int_t *extents)
587 {
588     cairo_region_t clear_region;
589     unsigned int has_region = 0;
590     cairo_status_t status;
591 
592     if (! _cairo_operator_bounded_by_mask (op) && clip == NULL) {
593 	/* If we optimize drawing with an unbounded operator to
594 	 * _cairo_surface_fill_rectangles() or to drawing with a
595 	 * clip region, then we have an additional region to clear.
596 	 */
597 	_cairo_region_init_rectangle (&clear_region, extents);
598 	status = cairo_region_subtract (&clear_region, trap_region);
599 	if (unlikely (status))
600 	    return status;
601 
602 	if (! cairo_region_is_empty (&clear_region))
603 	    has_region |= HAS_CLEAR_REGION;
604     }
605 
606     if ((src->type == CAIRO_PATTERN_TYPE_SOLID || op == CAIRO_OPERATOR_CLEAR) &&
607 	clip == NULL)
608     {
609 	const cairo_color_t *color;
610 
611 	if (op == CAIRO_OPERATOR_CLEAR)
612 	    color = CAIRO_COLOR_TRANSPARENT;
613 	else
614 	    color = &((cairo_solid_pattern_t *)src)->color;
615 
616 	/* Solid rectangles special case */
617 	status = _cairo_surface_fill_region (dst, op, color, trap_region);
618     } else {
619 	/* For a simple rectangle, we can just use composite(), for more
620 	 * rectangles, we have to set a clip region. The cost of rasterizing
621 	 * trapezoids is pretty high for most backends currently, so it's
622 	 * worthwhile even if a region is needed.
623 	 *
624 	 * If we have a clip surface, we set it as the mask; this only works
625 	 * for bounded operators other than SOURCE; for unbounded operators,
626 	 * clip and mask cannot be interchanged. For SOURCE, the operator
627 	 * as implemented by the backends is different in its handling
628 	 * of the mask then what we want.
629 	 *
630 	 * CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has
631 	 * more than rectangle and the destination doesn't support clip
632 	 * regions. In that case, we fall through.
633 	 */
634 	status = _composite_trap_region (clip, src, op, dst,
635 					 trap_region, extents);
636     }
637 
638     if (has_region & HAS_CLEAR_REGION) {
639 	if (status == CAIRO_STATUS_SUCCESS) {
640 	    status = _cairo_surface_fill_region (dst,
641 						 CAIRO_OPERATOR_CLEAR,
642 						 CAIRO_COLOR_TRANSPARENT,
643 						 &clear_region);
644 	}
645 	_cairo_region_fini (&clear_region);
646     }
647 
648     return status;
649 }
650 
651 /* avoid using region code to re-validate boxes */
652 static cairo_status_t
_fill_rectangles(cairo_surface_t * dst,cairo_operator_t op,const cairo_pattern_t * src,cairo_traps_t * traps,cairo_clip_t * clip)653 _fill_rectangles (cairo_surface_t *dst,
654 		  cairo_operator_t op,
655 		  const cairo_pattern_t *src,
656 		  cairo_traps_t *traps,
657 		  cairo_clip_t *clip)
658 {
659     const cairo_color_t *color;
660     cairo_rectangle_int_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
661     cairo_rectangle_int_t *rects = stack_rects;
662     cairo_status_t status;
663     int i;
664 
665     if (! traps->is_rectilinear || ! traps->maybe_region)
666 	return CAIRO_INT_STATUS_UNSUPPORTED;
667 
668     /* XXX: convert clip region to geometric boxes? */
669     if (clip != NULL)
670 	return CAIRO_INT_STATUS_UNSUPPORTED;
671 
672     /* XXX: fallback for the region_subtract() operation */
673     if (! _cairo_operator_bounded_by_mask (op))
674 	return CAIRO_INT_STATUS_UNSUPPORTED;
675 
676     if (! (src->type == CAIRO_PATTERN_TYPE_SOLID || op == CAIRO_OPERATOR_CLEAR))
677 	return CAIRO_INT_STATUS_UNSUPPORTED;
678 
679     if (traps->has_intersections) {
680 	if (traps->is_rectangular) {
681 	    status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING);
682 	} else {
683 	    status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING);
684 	}
685 	if (unlikely (status))
686 	    return status;
687     }
688 
689     for (i = 0; i < traps->num_traps; i++) {
690 	if (! _cairo_fixed_is_integer (traps->traps[i].top)          ||
691 	    ! _cairo_fixed_is_integer (traps->traps[i].bottom)       ||
692 	    ! _cairo_fixed_is_integer (traps->traps[i].left.p1.x)    ||
693 	    ! _cairo_fixed_is_integer (traps->traps[i].right.p1.x))
694 	{
695 	    traps->maybe_region = FALSE;
696 	    return CAIRO_INT_STATUS_UNSUPPORTED;
697 	}
698     }
699 
700     if (traps->num_traps > ARRAY_LENGTH (stack_rects)) {
701 	rects = _cairo_malloc_ab (traps->num_traps,
702 				  sizeof (cairo_rectangle_int_t));
703 	if (unlikely (rects == NULL))
704 	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
705     }
706 
707     for (i = 0; i < traps->num_traps; i++) {
708 	int x1 = _cairo_fixed_integer_part (traps->traps[i].left.p1.x);
709 	int y1 = _cairo_fixed_integer_part (traps->traps[i].top);
710 	int x2 = _cairo_fixed_integer_part (traps->traps[i].right.p1.x);
711 	int y2 = _cairo_fixed_integer_part (traps->traps[i].bottom);
712 
713 	rects[i].x = x1;
714 	rects[i].y = y1;
715 	rects[i].width = x2 - x1;
716 	rects[i].height = y2 - y1;
717     }
718 
719     if (op == CAIRO_OPERATOR_CLEAR)
720 	color = CAIRO_COLOR_TRANSPARENT;
721     else
722 	color = &((cairo_solid_pattern_t *)src)->color;
723 
724     status =  _cairo_surface_fill_rectangles (dst, op, color, rects, i);
725 
726     if (rects != stack_rects)
727 	free (rects);
728 
729     return status;
730 }
731 
732 /* fast-path for very common composite of a single rectangle */
733 static cairo_status_t
_composite_rectangle(cairo_surface_t * dst,cairo_operator_t op,const cairo_pattern_t * src,cairo_traps_t * traps,cairo_clip_t * clip)734 _composite_rectangle (cairo_surface_t *dst,
735 		      cairo_operator_t op,
736 		      const cairo_pattern_t *src,
737 		      cairo_traps_t *traps,
738 		      cairo_clip_t *clip)
739 {
740     cairo_rectangle_int_t rect;
741 
742     if (clip != NULL)
743 	return CAIRO_INT_STATUS_UNSUPPORTED;
744 
745     if (traps->num_traps > 1 || ! traps->is_rectilinear || ! traps->maybe_region)
746 	return CAIRO_INT_STATUS_UNSUPPORTED;
747 
748     if (! _cairo_fixed_is_integer (traps->traps[0].top)          ||
749 	! _cairo_fixed_is_integer (traps->traps[0].bottom)       ||
750 	! _cairo_fixed_is_integer (traps->traps[0].left.p1.x)    ||
751 	! _cairo_fixed_is_integer (traps->traps[0].right.p1.x))
752     {
753 	traps->maybe_region = FALSE;
754 	return CAIRO_INT_STATUS_UNSUPPORTED;
755     }
756 
757     rect.x = _cairo_fixed_integer_part (traps->traps[0].left.p1.x);
758     rect.y = _cairo_fixed_integer_part (traps->traps[0].top);
759     rect.width  = _cairo_fixed_integer_part (traps->traps[0].right.p1.x) - rect.x;
760     rect.height = _cairo_fixed_integer_part (traps->traps[0].bottom) - rect.y;
761 
762     return _cairo_surface_composite (op, src, NULL, dst,
763 				     rect.x, rect.y,
764 				     0, 0,
765 				     rect.x, rect.y,
766 				     rect.width, rect.height,
767 				     NULL);
768 }
769 
770 /* Warning: This call modifies the coordinates of traps */
771 static cairo_status_t
_clip_and_composite_trapezoids(const cairo_pattern_t * src,cairo_operator_t op,cairo_surface_t * dst,cairo_traps_t * traps,cairo_antialias_t antialias,cairo_clip_t * clip,cairo_rectangle_int_t * extents)772 _clip_and_composite_trapezoids (const cairo_pattern_t *src,
773 				cairo_operator_t op,
774 				cairo_surface_t *dst,
775 				cairo_traps_t *traps,
776 				cairo_antialias_t antialias,
777 				cairo_clip_t *clip,
778 				cairo_rectangle_int_t *extents)
779 {
780     cairo_composite_traps_info_t traps_info;
781     cairo_region_t *clip_region = NULL;
782     cairo_bool_t clip_surface = FALSE;
783     cairo_status_t status;
784 
785     if (traps->num_traps == 0 && _cairo_operator_bounded_by_mask (op))
786 	return CAIRO_STATUS_SUCCESS;
787 
788     if (clip != NULL) {
789 	status = _cairo_clip_get_region (clip, &clip_region);
790 	if (unlikely (_cairo_status_is_error (status)))
791 	    return status;
792 	if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
793 	    return CAIRO_STATUS_SUCCESS;
794 
795 	clip_surface = status == CAIRO_INT_STATUS_UNSUPPORTED;
796     }
797 
798     /* Use a fast path if the trapezoids consist of a simple region,
799      * but we can only do this if we do not have a clip surface, or can
800      * substitute the mask with the clip.
801      */
802     if (! clip_surface ||
803 	(_cairo_operator_bounded_by_mask (op) && op != CAIRO_OPERATOR_SOURCE))
804     {
805 	cairo_region_t *trap_region = NULL;
806 
807         if (_cairo_operator_bounded_by_source (op)) {
808             status = _fill_rectangles (dst, op, src, traps, clip);
809             if (status != CAIRO_INT_STATUS_UNSUPPORTED)
810                 return status;
811 
812             status = _composite_rectangle (dst, op, src, traps, clip);
813             if (status != CAIRO_INT_STATUS_UNSUPPORTED)
814                 return status;
815         }
816 
817 	status = _cairo_traps_extract_region (traps, &trap_region);
818 	if (unlikely (_cairo_status_is_error (status)))
819 	    return status;
820 
821 	if (trap_region != NULL) {
822 	    status = cairo_region_intersect_rectangle (trap_region, extents);
823 	    if (unlikely (status)) {
824 		cairo_region_destroy (trap_region);
825 		return status;
826 	    }
827 
828 	    if (clip_region != NULL) {
829 		status = cairo_region_intersect (trap_region, clip_region);
830 		if (unlikely (status)) {
831 		    cairo_region_destroy (trap_region);
832 		    return status;
833 		}
834 	    }
835 
836 	    if (_cairo_operator_bounded_by_mask (op)) {
837 		cairo_rectangle_int_t trap_extents;
838 
839 		cairo_region_get_extents (trap_region, &trap_extents);
840 		if (! _cairo_rectangle_intersect (extents, &trap_extents)) {
841 		    cairo_region_destroy (trap_region);
842 		    return CAIRO_STATUS_SUCCESS;
843 		}
844 	    }
845 
846 	    status = _clip_and_composite_region (src, op, dst,
847 						 trap_region,
848 						 clip_surface ? clip : NULL,
849 						 extents);
850 	    cairo_region_destroy (trap_region);
851 
852 	    if (likely (status != CAIRO_INT_STATUS_UNSUPPORTED))
853 		return status;
854 	}
855     }
856 
857     /* No fast path, exclude self-intersections and clip trapezoids. */
858     if (traps->has_intersections) {
859 	if (traps->is_rectangular)
860 	    status = _cairo_bentley_ottmann_tessellate_rectangular_traps (traps, CAIRO_FILL_RULE_WINDING);
861 	else if (traps->is_rectilinear)
862 	    status = _cairo_bentley_ottmann_tessellate_rectilinear_traps (traps, CAIRO_FILL_RULE_WINDING);
863 	else
864 	    status = _cairo_bentley_ottmann_tessellate_traps (traps, CAIRO_FILL_RULE_WINDING);
865 	if (unlikely (status))
866 	    return status;
867     }
868 
869     /* Otherwise render the trapezoids to a mask and composite in the usual
870      * fashion.
871      */
872     traps_info.traps = traps;
873     traps_info.antialias = antialias;
874 
875     return _clip_and_composite (clip, op, src,
876 				_composite_traps_draw_func,
877 				&traps_info, dst, extents);
878 }
879 
880 cairo_status_t
_cairo_surface_fallback_paint(cairo_surface_t * surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_clip_t * clip)881 _cairo_surface_fallback_paint (cairo_surface_t		*surface,
882 			       cairo_operator_t		 op,
883 			       const cairo_pattern_t	*source,
884 			       cairo_clip_t		*clip)
885 {
886     cairo_composite_rectangles_t extents;
887     cairo_rectangle_int_t rect;
888     cairo_clip_path_t *clip_path = clip ? clip->path : NULL;
889     cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
890     cairo_boxes_t  boxes;
891     int num_boxes = ARRAY_LENGTH (boxes_stack);
892     cairo_status_t status;
893     cairo_traps_t traps;
894 
895     if (!_cairo_surface_get_extents (surface, &rect))
896         ASSERT_NOT_REACHED;
897 
898     status = _cairo_composite_rectangles_init_for_paint (&extents,
899 							 &rect,
900 							 op, source,
901 							 clip);
902     if (unlikely (status))
903 	return status;
904 
905     if (_cairo_clip_contains_extents (clip, &extents))
906 	clip = NULL;
907 
908     status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
909     if (unlikely (status))
910 	return status;
911 
912     /* If the clip cannot be reduced to a set of boxes, we will need to
913      * use a clipmask. Paint is special as it is the only operation that
914      * does not implicitly use a mask, so we may be able to reduce this
915      * operation to a fill...
916      */
917     if (clip != NULL && clip_path->prev == NULL &&
918 	_cairo_operator_bounded_by_mask (op))
919     {
920 	return _cairo_surface_fill (surface, op, source,
921 				    &clip_path->path,
922 				    clip_path->fill_rule,
923 				    clip_path->tolerance,
924 				    clip_path->antialias,
925 				    NULL);
926     }
927 
928     /* meh, surface-fallback is dying anyway... */
929     _cairo_boxes_init_for_array (&boxes, clip_boxes, num_boxes);
930     status = _cairo_traps_init_boxes (&traps, &boxes);
931     if (unlikely (status))
932 	goto CLEANUP_BOXES;
933 
934     status = _clip_and_composite_trapezoids (source, op, surface,
935 					     &traps, CAIRO_ANTIALIAS_DEFAULT,
936 					     clip,
937                                              extents.is_bounded ? &extents.bounded : &extents.unbounded);
938     _cairo_traps_fini (&traps);
939 
940 CLEANUP_BOXES:
941     if (clip_boxes != boxes_stack)
942 	free (clip_boxes);
943 
944     return status;
945 }
946 
947 static cairo_status_t
_cairo_surface_mask_draw_func(void * closure,cairo_operator_t op,const cairo_pattern_t * src,cairo_surface_t * dst,int dst_x,int dst_y,const cairo_rectangle_int_t * extents,cairo_region_t * clip_region)948 _cairo_surface_mask_draw_func (void                        *closure,
949 			       cairo_operator_t             op,
950 			       const cairo_pattern_t       *src,
951 			       cairo_surface_t             *dst,
952 			       int                          dst_x,
953 			       int                          dst_y,
954 			       const cairo_rectangle_int_t *extents,
955 			       cairo_region_t		   *clip_region)
956 {
957     cairo_pattern_t *mask = closure;
958     cairo_status_t status;
959     cairo_region_t *extents_region = NULL;
960 
961     if (clip_region == NULL &&
962         !_cairo_operator_bounded_by_source (op)) {
963         extents_region = cairo_region_create_rectangle (extents);
964         if (unlikely (extents_region->status))
965             return extents_region->status;
966         cairo_region_translate (extents_region, -dst_x, -dst_y);
967         clip_region = extents_region;
968     }
969 
970     if (src) {
971 	status = _cairo_surface_composite (op,
972                                            src, mask, dst,
973                                            extents->x,         extents->y,
974                                            extents->x,         extents->y,
975                                            extents->x - dst_x, extents->y - dst_y,
976                                            extents->width,     extents->height,
977                                            clip_region);
978     } else {
979 	status = _cairo_surface_composite (op,
980                                            mask, NULL, dst,
981                                            extents->x,         extents->y,
982                                            0,                  0, /* unused */
983                                            extents->x - dst_x, extents->y - dst_y,
984                                            extents->width,     extents->height,
985                                            clip_region);
986     }
987 
988     if (extents_region)
989         cairo_region_destroy (extents_region);
990 
991     return status;
992 }
993 
994 cairo_status_t
_cairo_surface_fallback_mask(cairo_surface_t * surface,cairo_operator_t op,const cairo_pattern_t * source,const cairo_pattern_t * mask,cairo_clip_t * clip)995 _cairo_surface_fallback_mask (cairo_surface_t		*surface,
996 			      cairo_operator_t		 op,
997 			      const cairo_pattern_t	*source,
998 			      const cairo_pattern_t	*mask,
999 			      cairo_clip_t		*clip)
1000 {
1001     cairo_composite_rectangles_t extents;
1002     cairo_rectangle_int_t rect;
1003     cairo_status_t status;
1004 
1005     if (!_cairo_surface_get_extents (surface, &rect))
1006         ASSERT_NOT_REACHED;
1007 
1008     status = _cairo_composite_rectangles_init_for_mask (&extents,
1009 							&rect,
1010 							op, source, mask, clip);
1011     if (unlikely (status))
1012 	return status;
1013 
1014     if (_cairo_clip_contains_extents (clip, &extents))
1015 	clip = NULL;
1016 
1017     if (clip != NULL && extents.is_bounded) {
1018 	status = _cairo_clip_rectangle (clip, &extents.bounded);
1019 	if (unlikely (status))
1020 	    return status;
1021     }
1022 
1023     return _clip_and_composite (clip, op, source,
1024 				_cairo_surface_mask_draw_func,
1025 				(void *) mask,
1026 				surface,
1027                                 extents.is_bounded ? &extents.bounded : &extents.unbounded);
1028 }
1029 
1030 cairo_status_t
_cairo_surface_fallback_stroke(cairo_surface_t * surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_path_fixed_t * path,const cairo_stroke_style_t * stroke_style,const cairo_matrix_t * ctm,const cairo_matrix_t * ctm_inverse,double tolerance,cairo_antialias_t antialias,cairo_clip_t * clip)1031 _cairo_surface_fallback_stroke (cairo_surface_t		*surface,
1032 				cairo_operator_t	 op,
1033 				const cairo_pattern_t	*source,
1034 				cairo_path_fixed_t	*path,
1035 				const cairo_stroke_style_t	*stroke_style,
1036 				const cairo_matrix_t		*ctm,
1037 				const cairo_matrix_t		*ctm_inverse,
1038 				double			 tolerance,
1039 				cairo_antialias_t	 antialias,
1040 				cairo_clip_t		*clip)
1041 {
1042     cairo_polygon_t polygon;
1043     cairo_traps_t traps;
1044     cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
1045     int num_boxes = ARRAY_LENGTH (boxes_stack);
1046     cairo_composite_rectangles_t extents;
1047     cairo_rectangle_int_t rect;
1048     cairo_status_t status;
1049 
1050     if (!_cairo_surface_get_extents (surface, &rect))
1051         ASSERT_NOT_REACHED;
1052 
1053     status = _cairo_composite_rectangles_init_for_stroke (&extents,
1054 							  &rect,
1055 							  op, source,
1056 							  path, stroke_style, ctm,
1057 							  clip);
1058     if (unlikely (status))
1059 	return status;
1060 
1061     if (_cairo_clip_contains_extents (clip, &extents))
1062 	clip = NULL;
1063 
1064     status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
1065     if (unlikely (status))
1066 	return status;
1067 
1068     _cairo_polygon_init (&polygon);
1069     _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
1070 
1071     _cairo_traps_init (&traps);
1072     _cairo_traps_limit (&traps, clip_boxes, num_boxes);
1073 
1074     if (path->is_rectilinear) {
1075 	status = _cairo_path_fixed_stroke_rectilinear_to_traps (path,
1076 								stroke_style,
1077 								ctm,
1078 								&traps);
1079 	if (likely (status == CAIRO_STATUS_SUCCESS))
1080 	    goto DO_TRAPS;
1081 
1082 	if (_cairo_status_is_error (status))
1083 	    goto CLEANUP;
1084     }
1085 
1086     status = _cairo_path_fixed_stroke_to_polygon (path,
1087 						  stroke_style,
1088 						  ctm, ctm_inverse,
1089 						  tolerance,
1090 						  &polygon);
1091     if (unlikely (status))
1092 	goto CLEANUP;
1093 
1094     if (polygon.num_edges == 0)
1095 	goto DO_TRAPS;
1096 
1097     if (_cairo_operator_bounded_by_mask (op)) {
1098 	_cairo_box_round_to_rectangle (&polygon.extents, &extents.mask);
1099 	if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
1100 	    goto CLEANUP;
1101     }
1102 
1103     /* Fall back to trapezoid fills. */
1104     status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
1105 							&polygon,
1106 							CAIRO_FILL_RULE_WINDING);
1107     if (unlikely (status))
1108 	goto CLEANUP;
1109 
1110   DO_TRAPS:
1111     status = _clip_and_composite_trapezoids (source, op, surface,
1112 					     &traps, antialias,
1113 					     clip,
1114                                              extents.is_bounded ? &extents.bounded : &extents.unbounded);
1115   CLEANUP:
1116     _cairo_traps_fini (&traps);
1117     _cairo_polygon_fini (&polygon);
1118     if (clip_boxes != boxes_stack)
1119 	free (clip_boxes);
1120 
1121     return status;
1122 }
1123 
1124 cairo_status_t
_cairo_surface_fallback_fill(cairo_surface_t * surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_path_fixed_t * path,cairo_fill_rule_t fill_rule,double tolerance,cairo_antialias_t antialias,cairo_clip_t * clip)1125 _cairo_surface_fallback_fill (cairo_surface_t		*surface,
1126 			      cairo_operator_t		 op,
1127 			      const cairo_pattern_t	*source,
1128 			      cairo_path_fixed_t	*path,
1129 			      cairo_fill_rule_t		 fill_rule,
1130 			      double			 tolerance,
1131 			      cairo_antialias_t		 antialias,
1132 			      cairo_clip_t		*clip)
1133 {
1134     cairo_polygon_t polygon;
1135     cairo_traps_t traps;
1136     cairo_box_t boxes_stack[32], *clip_boxes = boxes_stack;
1137     int num_boxes = ARRAY_LENGTH (boxes_stack);
1138     cairo_bool_t is_rectilinear;
1139     cairo_composite_rectangles_t extents;
1140     cairo_rectangle_int_t rect;
1141     cairo_status_t status;
1142 
1143     if (!_cairo_surface_get_extents (surface, &rect))
1144         ASSERT_NOT_REACHED;
1145 
1146     status = _cairo_composite_rectangles_init_for_fill (&extents,
1147 							&rect,
1148 							op, source, path,
1149 							clip);
1150     if (unlikely (status))
1151 	return status;
1152 
1153     if (_cairo_clip_contains_extents (clip, &extents))
1154 	clip = NULL;
1155 
1156     status = _cairo_clip_to_boxes (&clip, &extents, &clip_boxes, &num_boxes);
1157     if (unlikely (status))
1158 	return status;
1159 
1160     _cairo_traps_init (&traps);
1161     _cairo_traps_limit (&traps, clip_boxes, num_boxes);
1162 
1163     _cairo_polygon_init (&polygon);
1164     _cairo_polygon_limit (&polygon, clip_boxes, num_boxes);
1165 
1166     if (path->is_empty_fill)
1167 	goto DO_TRAPS;
1168 
1169     is_rectilinear = _cairo_path_fixed_is_rectilinear_fill (path);
1170     if (is_rectilinear) {
1171 	status = _cairo_path_fixed_fill_rectilinear_to_traps (path,
1172 							      fill_rule,
1173 							      &traps);
1174 	if (likely (status == CAIRO_STATUS_SUCCESS))
1175 	    goto DO_TRAPS;
1176 
1177 	if (_cairo_status_is_error (status))
1178 	    goto CLEANUP;
1179     }
1180 
1181     status = _cairo_path_fixed_fill_to_polygon (path, tolerance, &polygon);
1182     if (unlikely (status))
1183 	goto CLEANUP;
1184 
1185     if (polygon.num_edges == 0)
1186 	goto DO_TRAPS;
1187 
1188     if (_cairo_operator_bounded_by_mask (op)) {
1189 	_cairo_box_round_to_rectangle (&polygon.extents, &extents.mask);
1190 	if (! _cairo_rectangle_intersect (&extents.bounded, &extents.mask))
1191 	    goto CLEANUP;
1192     }
1193 
1194     if (is_rectilinear) {
1195 	status = _cairo_bentley_ottmann_tessellate_rectilinear_polygon (&traps,
1196 									&polygon,
1197 									fill_rule);
1198 	if (likely (status == CAIRO_STATUS_SUCCESS))
1199 	    goto DO_TRAPS;
1200 
1201 	if (unlikely (_cairo_status_is_error (status)))
1202 	    goto CLEANUP;
1203     }
1204 
1205     /* Fall back to trapezoid fills. */
1206     status = _cairo_bentley_ottmann_tessellate_polygon (&traps,
1207 							&polygon,
1208 							fill_rule);
1209     if (unlikely (status))
1210 	goto CLEANUP;
1211 
1212   DO_TRAPS:
1213     status = _clip_and_composite_trapezoids (source, op, surface,
1214 					     &traps, antialias,
1215 					     clip,
1216                                              extents.is_bounded ? &extents.bounded : &extents.unbounded);
1217   CLEANUP:
1218     _cairo_traps_fini (&traps);
1219     _cairo_polygon_fini (&polygon);
1220     if (clip_boxes != boxes_stack)
1221 	free (clip_boxes);
1222 
1223     return status;
1224 }
1225 
1226 typedef struct {
1227     cairo_scaled_font_t *font;
1228     cairo_glyph_t *glyphs;
1229     int num_glyphs;
1230 } cairo_show_glyphs_info_t;
1231 
1232 static cairo_status_t
_cairo_surface_old_show_glyphs_draw_func(void * closure,cairo_operator_t op,const cairo_pattern_t * src,cairo_surface_t * dst,int dst_x,int dst_y,const cairo_rectangle_int_t * extents,cairo_region_t * clip_region)1233 _cairo_surface_old_show_glyphs_draw_func (void                          *closure,
1234 					  cairo_operator_t               op,
1235 					  const cairo_pattern_t         *src,
1236 					  cairo_surface_t               *dst,
1237 					  int                            dst_x,
1238 					  int                            dst_y,
1239 					  const cairo_rectangle_int_t	*extents,
1240 					  cairo_region_t		*clip_region)
1241 {
1242     cairo_show_glyphs_info_t *glyph_info = closure;
1243     cairo_status_t status;
1244     cairo_region_t *extents_region = NULL;
1245 
1246     if (clip_region == NULL &&
1247         !_cairo_operator_bounded_by_source (op)) {
1248         extents_region = cairo_region_create_rectangle (extents);
1249         if (unlikely (extents_region->status))
1250             return extents_region->status;
1251         cairo_region_translate (extents_region, -dst_x, -dst_y);
1252         clip_region = extents_region;
1253     }
1254 
1255     /* Modifying the glyph array is fine because we know that this function
1256      * will be called only once, and we've already made a copy of the
1257      * glyphs in the wrapper.
1258      */
1259     if (dst_x != 0 || dst_y != 0) {
1260 	int i;
1261 
1262 	for (i = 0; i < glyph_info->num_glyphs; ++i) {
1263 	    ((cairo_glyph_t *) glyph_info->glyphs)[i].x -= dst_x;
1264 	    ((cairo_glyph_t *) glyph_info->glyphs)[i].y -= dst_y;
1265 	}
1266     }
1267 
1268     status = _cairo_surface_old_show_glyphs (glyph_info->font, op, src,
1269 					     dst,
1270 					     extents->x, extents->y,
1271 					     extents->x - dst_x,
1272 					     extents->y - dst_y,
1273 					     extents->width,
1274 					     extents->height,
1275 					     glyph_info->glyphs,
1276 					     glyph_info->num_glyphs,
1277 					     clip_region);
1278 
1279     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
1280 	status = _cairo_scaled_font_show_glyphs (glyph_info->font,
1281                                                  op,
1282                                                  src, dst,
1283                                                  extents->x,         extents->y,
1284                                                  extents->x - dst_x,
1285                                                  extents->y - dst_y,
1286                                                  extents->width,     extents->height,
1287                                                  glyph_info->glyphs,
1288                                                  glyph_info->num_glyphs,
1289                                                  clip_region);
1290     }
1291 
1292     if (extents_region)
1293         cairo_region_destroy (extents_region);
1294 
1295     return status;
1296 }
1297 
1298 cairo_status_t
_cairo_surface_fallback_show_glyphs(cairo_surface_t * surface,cairo_operator_t op,const cairo_pattern_t * source,cairo_glyph_t * glyphs,int num_glyphs,cairo_scaled_font_t * scaled_font,cairo_clip_t * clip)1299 _cairo_surface_fallback_show_glyphs (cairo_surface_t		*surface,
1300 				     cairo_operator_t		 op,
1301 				     const cairo_pattern_t	*source,
1302 				     cairo_glyph_t		*glyphs,
1303 				     int			 num_glyphs,
1304 				     cairo_scaled_font_t	*scaled_font,
1305 				     cairo_clip_t		*clip)
1306 {
1307     cairo_show_glyphs_info_t glyph_info;
1308     cairo_composite_rectangles_t extents;
1309     cairo_rectangle_int_t rect;
1310     cairo_status_t status;
1311 
1312     if (!_cairo_surface_get_extents (surface, &rect))
1313         ASSERT_NOT_REACHED;
1314 
1315     status = _cairo_composite_rectangles_init_for_glyphs (&extents,
1316 							  &rect,
1317 							  op, source,
1318 							  scaled_font,
1319 							  glyphs, num_glyphs,
1320 							  clip,
1321 							  NULL);
1322     if (unlikely (status))
1323 	return status;
1324 
1325     if (_cairo_clip_contains_rectangle (clip, &extents.mask))
1326 	clip = NULL;
1327 
1328     if (clip != NULL && extents.is_bounded) {
1329 	status = _cairo_clip_rectangle (clip, &extents.bounded);
1330 	if (unlikely (status))
1331 	    return status;
1332     }
1333 
1334     glyph_info.font = scaled_font;
1335     glyph_info.glyphs = glyphs;
1336     glyph_info.num_glyphs = num_glyphs;
1337 
1338     return _clip_and_composite (clip, op, source,
1339 				_cairo_surface_old_show_glyphs_draw_func,
1340 				&glyph_info,
1341 				surface,
1342                                 extents.is_bounded ? &extents.bounded : &extents.unbounded);
1343 }
1344 
1345 cairo_surface_t *
_cairo_surface_fallback_snapshot(cairo_surface_t * surface)1346 _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
1347 {
1348     cairo_surface_t *snapshot;
1349     cairo_status_t status;
1350     cairo_format_t format;
1351     cairo_surface_pattern_t pattern;
1352     cairo_image_surface_t *image;
1353     void *image_extra;
1354 
1355     status = _cairo_surface_acquire_source_image (surface,
1356 						  &image, &image_extra);
1357     if (unlikely (status))
1358 	return _cairo_surface_create_in_error (status);
1359 
1360     format = image->format;
1361     if (format == CAIRO_FORMAT_INVALID) {
1362 	/* Non-standard images formats can be generated when retrieving
1363 	 * images from unusual xservers, for example.
1364 	 */
1365 	format = _cairo_format_from_content (image->base.content);
1366     }
1367     snapshot = cairo_image_surface_create (format,
1368 					   image->width,
1369 					   image->height);
1370     if (cairo_surface_status (snapshot)) {
1371 	_cairo_surface_release_source_image (surface, image, image_extra);
1372 	return snapshot;
1373     }
1374 
1375     _cairo_pattern_init_for_surface (&pattern, &image->base);
1376     status = _cairo_surface_paint (snapshot,
1377 				   CAIRO_OPERATOR_SOURCE,
1378 				   &pattern.base,
1379 				   NULL);
1380     _cairo_pattern_fini (&pattern.base);
1381     _cairo_surface_release_source_image (surface, image, image_extra);
1382     if (unlikely (status)) {
1383 	cairo_surface_destroy (snapshot);
1384 	return _cairo_surface_create_in_error (status);
1385     }
1386 
1387     return snapshot;
1388 }
1389 
1390 cairo_status_t
_cairo_surface_fallback_composite(cairo_operator_t op,const cairo_pattern_t * src,const cairo_pattern_t * mask,cairo_surface_t * dst,int src_x,int src_y,int mask_x,int mask_y,int dst_x,int dst_y,unsigned int width,unsigned int height,cairo_region_t * clip_region)1391 _cairo_surface_fallback_composite (cairo_operator_t		 op,
1392 				   const cairo_pattern_t	*src,
1393 				   const cairo_pattern_t	*mask,
1394 				   cairo_surface_t		*dst,
1395 				   int				 src_x,
1396 				   int				 src_y,
1397 				   int				 mask_x,
1398 				   int				 mask_y,
1399 				   int				 dst_x,
1400 				   int				 dst_y,
1401 				   unsigned int			 width,
1402 				   unsigned int			 height,
1403 				   cairo_region_t		*clip_region)
1404 {
1405     fallback_state_t state;
1406     cairo_region_t *fallback_region = NULL;
1407     cairo_status_t status;
1408 
1409     status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
1410     if (unlikely (status))
1411 	return status;
1412 
1413     /* We know this will never fail with the image backend; but
1414      * instead of calling into it directly, we call
1415      * _cairo_surface_composite so that we get the correct device
1416      * offset handling.
1417      */
1418 
1419     if (clip_region != NULL && (state.image_rect.x || state.image_rect.y)) {
1420 	fallback_region = cairo_region_copy (clip_region);
1421 	status = fallback_region->status;
1422 	if (unlikely (status))
1423 	    goto FAIL;
1424 
1425 	cairo_region_translate (fallback_region,
1426 				-state.image_rect.x,
1427 				-state.image_rect.y);
1428 	clip_region = fallback_region;
1429     }
1430 
1431     status = _cairo_surface_composite (op, src, mask,
1432 				       &state.image->base,
1433 				       src_x, src_y, mask_x, mask_y,
1434 				       dst_x - state.image_rect.x,
1435 				       dst_y - state.image_rect.y,
1436 				       width, height,
1437 				       clip_region);
1438   FAIL:
1439     if (fallback_region != NULL)
1440 	cairo_region_destroy (fallback_region);
1441     _fallback_fini (&state);
1442 
1443     return status;
1444 }
1445 
1446 cairo_status_t
_cairo_surface_fallback_fill_rectangles(cairo_surface_t * surface,cairo_operator_t op,const cairo_color_t * color,cairo_rectangle_int_t * rects,int num_rects)1447 _cairo_surface_fallback_fill_rectangles (cairo_surface_t         *surface,
1448 					 cairo_operator_t	  op,
1449 					 const cairo_color_t	 *color,
1450 					 cairo_rectangle_int_t   *rects,
1451 					 int			  num_rects)
1452 {
1453     fallback_state_t state;
1454     cairo_rectangle_int_t *offset_rects = NULL;
1455     cairo_status_t status;
1456     int x1, y1, x2, y2;
1457     int i;
1458 
1459     assert (surface->snapshot_of == NULL);
1460 
1461     if (num_rects <= 0)
1462 	return CAIRO_STATUS_SUCCESS;
1463 
1464     /* Compute the bounds of the rectangles, so that we know what area of the
1465      * destination surface to fetch
1466      */
1467     x1 = rects[0].x;
1468     y1 = rects[0].y;
1469     x2 = rects[0].x + rects[0].width;
1470     y2 = rects[0].y + rects[0].height;
1471 
1472     for (i = 1; i < num_rects; i++) {
1473 	if (rects[i].x < x1)
1474 	    x1 = rects[i].x;
1475 	if (rects[i].y < y1)
1476 	    y1 = rects[i].y;
1477 
1478 	if ((int) (rects[i].x + rects[i].width) > x2)
1479 	    x2 = rects[i].x + rects[i].width;
1480 	if ((int) (rects[i].y + rects[i].height) > y2)
1481 	    y2 = rects[i].y + rects[i].height;
1482     }
1483 
1484     status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1);
1485     if (unlikely (status))
1486 	return status;
1487 
1488     /* If the fetched image isn't at 0,0, we need to offset the rectangles */
1489 
1490     if (state.image_rect.x != 0 || state.image_rect.y != 0) {
1491 	offset_rects = _cairo_malloc_ab (num_rects, sizeof (cairo_rectangle_int_t));
1492 	if (unlikely (offset_rects == NULL)) {
1493 	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1494 	    goto DONE;
1495 	}
1496 
1497 	for (i = 0; i < num_rects; i++) {
1498 	    offset_rects[i].x = rects[i].x - state.image_rect.x;
1499 	    offset_rects[i].y = rects[i].y - state.image_rect.y;
1500 	    offset_rects[i].width = rects[i].width;
1501 	    offset_rects[i].height = rects[i].height;
1502 	}
1503 
1504 	rects = offset_rects;
1505     }
1506 
1507     status = _cairo_surface_fill_rectangles (&state.image->base,
1508 					     op, color,
1509 					     rects, num_rects);
1510 
1511     free (offset_rects);
1512 
1513  DONE:
1514     _fallback_fini (&state);
1515 
1516     return status;
1517 }
1518 
1519 cairo_status_t
_cairo_surface_fallback_composite_trapezoids(cairo_operator_t op,const cairo_pattern_t * pattern,cairo_surface_t * dst,cairo_antialias_t antialias,int src_x,int src_y,int dst_x,int dst_y,unsigned int width,unsigned int height,cairo_trapezoid_t * traps,int num_traps,cairo_region_t * clip_region)1520 _cairo_surface_fallback_composite_trapezoids (cairo_operator_t		op,
1521 					      const cairo_pattern_t    *pattern,
1522 					      cairo_surface_t	       *dst,
1523 					      cairo_antialias_t		antialias,
1524 					      int			src_x,
1525 					      int			src_y,
1526 					      int			dst_x,
1527 					      int			dst_y,
1528 					      unsigned int		width,
1529 					      unsigned int		height,
1530 					      cairo_trapezoid_t	       *traps,
1531 					      int			num_traps,
1532 					      cairo_region_t		*clip_region)
1533 {
1534     fallback_state_t state;
1535     cairo_region_t *fallback_region = NULL;
1536     cairo_trapezoid_t *offset_traps = NULL;
1537     cairo_status_t status;
1538 
1539     status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
1540     if (unlikely (status))
1541 	return status;
1542 
1543     /* If the destination image isn't at 0,0, we need to offset the trapezoids */
1544 
1545     if (state.image_rect.x != 0 || state.image_rect.y != 0) {
1546 	offset_traps = _cairo_malloc_ab (num_traps, sizeof (cairo_trapezoid_t));
1547 	if (offset_traps == NULL) {
1548 	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1549 	    goto FAIL;
1550 	}
1551 
1552 	_cairo_trapezoid_array_translate_and_scale (offset_traps, traps, num_traps,
1553                                                     - state.image_rect.x, - state.image_rect.y,
1554                                                     1.0, 1.0);
1555 	traps = offset_traps;
1556 
1557 	/* similarly we need to adjust the region */
1558 	if (clip_region != NULL) {
1559 	    fallback_region = cairo_region_copy (clip_region);
1560 	    status = fallback_region->status;
1561 	    if (unlikely (status))
1562 		goto FAIL;
1563 
1564 	    cairo_region_translate (fallback_region,
1565 				    -state.image_rect.x,
1566 				    -state.image_rect.y);
1567 	    clip_region = fallback_region;
1568 	}
1569     }
1570 
1571     status = _cairo_surface_composite_trapezoids (op, pattern,
1572 					          &state.image->base,
1573 						  antialias,
1574 						  src_x, src_y,
1575 						  dst_x - state.image_rect.x,
1576 						  dst_y - state.image_rect.y,
1577 						  width, height,
1578 						  traps, num_traps,
1579 						  clip_region);
1580  FAIL:
1581     if (offset_traps != NULL)
1582 	free (offset_traps);
1583 
1584     if (fallback_region != NULL)
1585 	cairo_region_destroy (fallback_region);
1586 
1587     _fallback_fini (&state);
1588 
1589     return status;
1590 }
1591 
1592 cairo_status_t
_cairo_surface_fallback_clone_similar(cairo_surface_t * surface,cairo_surface_t * src,int src_x,int src_y,int width,int height,int * clone_offset_x,int * clone_offset_y,cairo_surface_t ** clone_out)1593 _cairo_surface_fallback_clone_similar (cairo_surface_t	*surface,
1594 				       cairo_surface_t	*src,
1595 				       int		 src_x,
1596 				       int		 src_y,
1597 				       int		 width,
1598 				       int		 height,
1599 				       int		*clone_offset_x,
1600 				       int		*clone_offset_y,
1601 				       cairo_surface_t **clone_out)
1602 {
1603     cairo_surface_t *new_surface;
1604     cairo_surface_pattern_t pattern;
1605     cairo_status_t status;
1606 
1607     new_surface = _cairo_surface_create_similar_scratch (surface,
1608 							 src->content,
1609 							 width, height);
1610     if (new_surface == NULL)
1611 	return CAIRO_INT_STATUS_UNSUPPORTED;
1612     if (unlikely (new_surface->status))
1613 	return new_surface->status;
1614 
1615     /* We have to copy these here, so that the coordinate spaces are correct */
1616     new_surface->device_transform = src->device_transform;
1617     new_surface->device_transform_inverse = src->device_transform_inverse;
1618 
1619     _cairo_pattern_init_for_surface (&pattern, src);
1620     cairo_matrix_init_translate (&pattern.base.matrix, src_x, src_y);
1621     pattern.base.filter = CAIRO_FILTER_NEAREST;
1622 
1623     status = _cairo_surface_paint (new_surface,
1624 				   CAIRO_OPERATOR_SOURCE,
1625 				   &pattern.base,
1626 				   NULL);
1627     _cairo_pattern_fini (&pattern.base);
1628 
1629     if (unlikely (status)) {
1630 	cairo_surface_destroy (new_surface);
1631 	return status;
1632     }
1633 
1634     *clone_offset_x = src_x;
1635     *clone_offset_y = src_y;
1636     *clone_out = new_surface;
1637     return CAIRO_STATUS_SUCCESS;
1638 }
1639