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