Changes.
[cairo/gpu.git] / src / cairo-surface-fallback.c
blob830c1b3de9f2ba9cb4092d9a33c228f43e03437b
1 /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2 /* cairo - a vector graphics library with display and print output
4 * Copyright © 2002 University of Southern California
5 * Copyright © 2005 Red Hat, Inc.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * You should have received a copy of the MPL along with this library
19 * in the file COPYING-MPL-1.1
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/
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.
30 * The Original Code is the cairo graphics library.
32 * The Initial Developer of the Original Code is University of Southern
33 * California.
35 * Contributor(s):
36 * Carl D. Worth <cworth@cworth.org>
39 #include "cairoint.h"
41 #include "cairo-surface-fallback-private.h"
42 #include "cairo-clip-private.h"
44 typedef struct {
45 cairo_surface_t *dst;
46 cairo_rectangle_int_t extents;
47 cairo_image_surface_t *image;
48 cairo_rectangle_int_t image_rect;
49 void *image_extra;
50 } fallback_state_t;
52 /**
53 * _fallback_init:
55 * Acquire destination image surface needed for an image-based
56 * fallback.
58 * Return value: %CAIRO_INT_STATUS_NOTHING_TO_DO if the extents are not
59 * visible, %CAIRO_STATUS_SUCCESS if some portion is visible and all
60 * went well, or some error status otherwise.
61 **/
62 static cairo_int_status_t
63 _fallback_init (fallback_state_t *state,
64 cairo_surface_t *dst,
65 int x,
66 int y,
67 int width,
68 int height)
70 cairo_status_t status;
72 state->extents.x = x;
73 state->extents.y = y;
74 state->extents.width = width;
75 state->extents.height = height;
77 state->dst = dst;
79 status = _cairo_surface_acquire_dest_image (dst, &state->extents,
80 &state->image, &state->image_rect,
81 &state->image_extra);
82 if (unlikely (status))
83 return status;
85 /* XXX: This NULL value tucked away in state->image is a rather
86 * ugly interface. Cleaner would be to push the
87 * CAIRO_INT_STATUS_NOTHING_TO_DO value down into
88 * _cairo_surface_acquire_dest_image and its backend
89 * counterparts. */
90 if (state->image == NULL)
91 return CAIRO_INT_STATUS_NOTHING_TO_DO;
93 return CAIRO_STATUS_SUCCESS;
96 static void
97 _fallback_fini (fallback_state_t *state)
99 _cairo_surface_release_dest_image (state->dst, &state->extents,
100 state->image, &state->image_rect,
101 state->image_extra);
104 typedef cairo_status_t (*cairo_draw_func_t) (void *closure,
105 cairo_operator_t op,
106 const cairo_pattern_t *src,
107 cairo_surface_t *dst,
108 int dst_x,
109 int dst_y,
110 const cairo_rectangle_int_t *extents);
112 static cairo_status_t
113 _create_composite_mask_pattern (cairo_surface_pattern_t *mask_pattern,
114 cairo_clip_t *clip,
115 cairo_draw_func_t draw_func,
116 void *draw_closure,
117 cairo_surface_t *dst,
118 const cairo_rectangle_int_t *extents)
120 cairo_surface_t *mask;
121 cairo_status_t status;
123 mask = cairo_surface_create_similar (dst,
124 CAIRO_CONTENT_ALPHA,
125 extents->width,
126 extents->height);
127 if (mask->status)
128 return mask->status;
130 status = (*draw_func) (draw_closure, CAIRO_OPERATOR_ADD,
131 NULL, mask,
132 extents->x, extents->y,
133 extents);
134 if (unlikely (status))
135 goto CLEANUP_SURFACE;
137 if (clip && clip->surface)
138 status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_IN,
139 mask,
140 extents->x, extents->y,
141 extents);
142 if (unlikely (status))
143 goto CLEANUP_SURFACE;
145 _cairo_pattern_init_for_surface (mask_pattern, mask);
147 CLEANUP_SURFACE:
148 cairo_surface_destroy (mask);
150 return status;
153 /* Handles compositing with a clip surface when the operator allows
154 * us to combine the clip with the mask
156 static cairo_status_t
157 _clip_and_composite_with_mask (cairo_clip_t *clip,
158 cairo_operator_t op,
159 const cairo_pattern_t *src,
160 cairo_draw_func_t draw_func,
161 void *draw_closure,
162 cairo_surface_t *dst,
163 const cairo_rectangle_int_t *extents)
165 cairo_surface_pattern_t mask_pattern;
166 cairo_status_t status;
168 status = _create_composite_mask_pattern (&mask_pattern,
169 clip,
170 draw_func, draw_closure,
171 dst, extents);
172 if (unlikely (status))
173 return status;
175 status = _cairo_surface_composite (op,
176 src, &mask_pattern.base, dst,
177 extents->x, extents->y,
178 0, 0,
179 extents->x, extents->y,
180 extents->width, extents->height);
182 _cairo_pattern_fini (&mask_pattern.base);
184 return status;
187 /* Handles compositing with a clip surface when we have to do the operation
188 * in two pieces and combine them together.
190 static cairo_status_t
191 _clip_and_composite_combine (cairo_clip_t *clip,
192 cairo_operator_t op,
193 const cairo_pattern_t *src,
194 cairo_draw_func_t draw_func,
195 void *draw_closure,
196 cairo_surface_t *dst,
197 const cairo_rectangle_int_t *extents)
199 cairo_surface_t *intermediate;
200 cairo_surface_pattern_t dst_pattern;
201 cairo_surface_pattern_t intermediate_pattern;
202 cairo_status_t status;
204 /* We'd be better off here creating a surface identical in format
205 * to dst, but we have no way of getting that information.
206 * A CAIRO_CONTENT_CLONE or something might be useful.
207 * cairo_surface_create_similar() also unnecessarily clears the surface.
209 intermediate = cairo_surface_create_similar (dst,
210 CAIRO_CONTENT_COLOR_ALPHA,
211 extents->width,
212 extents->height);
213 if (intermediate->status)
214 return intermediate->status;
216 /* Initialize the intermediate surface from the destination surface
218 _cairo_pattern_init_for_surface (&dst_pattern, dst);
220 status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
221 &dst_pattern.base, NULL, intermediate,
222 extents->x, extents->y,
223 0, 0,
224 0, 0,
225 extents->width, extents->height);
227 _cairo_pattern_fini (&dst_pattern.base);
229 if (unlikely (status))
230 goto CLEANUP_SURFACE;
232 status = (*draw_func) (draw_closure, op,
233 src, intermediate,
234 extents->x, extents->y,
235 extents);
236 if (unlikely (status))
237 goto CLEANUP_SURFACE;
239 /* Combine that with the clip
241 status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_DEST_IN,
242 intermediate,
243 extents->x, extents->y,
244 extents);
245 if (unlikely (status))
246 goto CLEANUP_SURFACE;
248 /* Punch the clip out of the destination
250 status = _cairo_clip_combine_to_surface (clip, CAIRO_OPERATOR_DEST_OUT,
251 dst,
252 0, 0,
253 extents);
254 if (unlikely (status))
255 goto CLEANUP_SURFACE;
257 /* Now add the two results together
259 _cairo_pattern_init_for_surface (&intermediate_pattern, intermediate);
261 status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
262 &intermediate_pattern.base, NULL, dst,
263 0, 0,
264 0, 0,
265 extents->x, extents->y,
266 extents->width, extents->height);
268 _cairo_pattern_fini (&intermediate_pattern.base);
270 CLEANUP_SURFACE:
271 cairo_surface_destroy (intermediate);
273 return status;
276 /* Handles compositing for %CAIRO_OPERATOR_SOURCE, which is special; it's
277 * defined as (src IN mask IN clip) ADD (dst OUT (mask IN clip))
279 static cairo_status_t
280 _clip_and_composite_source (cairo_clip_t *clip,
281 const cairo_pattern_t *src,
282 cairo_draw_func_t draw_func,
283 void *draw_closure,
284 cairo_surface_t *dst,
285 const cairo_rectangle_int_t *extents)
287 cairo_surface_pattern_t mask_pattern;
288 cairo_status_t status;
290 /* Create a surface that is mask IN clip
292 status = _create_composite_mask_pattern (&mask_pattern,
293 clip,
294 draw_func, draw_closure,
295 dst, extents);
296 if (unlikely (status))
297 return status;
299 /* Compute dest' = dest OUT (mask IN clip)
301 status = _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT,
302 &mask_pattern.base, NULL, dst,
303 0, 0,
304 0, 0,
305 extents->x, extents->y,
306 extents->width, extents->height);
308 if (unlikely (status))
309 goto CLEANUP_MASK_PATTERN;
311 /* Now compute (src IN (mask IN clip)) ADD dest'
313 status = _cairo_surface_composite (CAIRO_OPERATOR_ADD,
314 src, &mask_pattern.base, dst,
315 extents->x, extents->y,
316 0, 0,
317 extents->x, extents->y,
318 extents->width, extents->height);
320 CLEANUP_MASK_PATTERN:
321 _cairo_pattern_fini (&mask_pattern.base);
322 return status;
325 static int
326 _cairo_rectangle_empty (const cairo_rectangle_int_t *rect)
328 return rect->width == 0 || rect->height == 0;
332 * _clip_and_composite:
333 * @clip: a #cairo_clip_t
334 * @op: the operator to draw with
335 * @src: source pattern
336 * @draw_func: function that can be called to draw with the mask onto a surface.
337 * @draw_closure: data to pass to @draw_func.
338 * @dst: destination surface
339 * @extents: rectangle holding a bounding box for the operation; this
340 * rectangle will be used as the size for the temporary
341 * surface.
343 * When there is a surface clip, we typically need to create an intermediate
344 * surface. This function handles the logic of creating a temporary surface
345 * drawing to it, then compositing the result onto the target surface.
347 * @draw_func is to called to draw the mask; it will be called no more
348 * than once.
350 * Return value: %CAIRO_STATUS_SUCCESS if the drawing succeeded.
352 static cairo_status_t
353 _clip_and_composite (cairo_clip_t *clip,
354 cairo_operator_t op,
355 const cairo_pattern_t *src,
356 cairo_draw_func_t draw_func,
357 void *draw_closure,
358 cairo_surface_t *dst,
359 const cairo_rectangle_int_t *extents)
361 cairo_solid_pattern_t solid_pattern;
362 cairo_status_t status;
364 if (_cairo_rectangle_empty (extents))
365 /* Nothing to do */
366 return CAIRO_STATUS_SUCCESS;
368 if (op == CAIRO_OPERATOR_CLEAR) {
369 _cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
370 CAIRO_CONTENT_COLOR);
371 src = &solid_pattern.base;
372 op = CAIRO_OPERATOR_DEST_OUT;
375 if ((clip && clip->surface) || op == CAIRO_OPERATOR_SOURCE)
377 if (op == CAIRO_OPERATOR_SOURCE)
378 status = _clip_and_composite_source (clip,
379 src,
380 draw_func, draw_closure,
381 dst, extents);
382 else if (_cairo_operator_bounded_by_mask (op))
383 status = _clip_and_composite_with_mask (clip, op,
384 src,
385 draw_func, draw_closure,
386 dst, extents);
387 else
388 status = _clip_and_composite_combine (clip, op,
389 src,
390 draw_func, draw_closure,
391 dst, extents);
393 else
395 status = (*draw_func) (draw_closure, op,
396 src, dst,
397 0, 0,
398 extents);
401 return status;
404 /* Composites a region representing a set of trapezoids.
406 static cairo_status_t
407 _composite_trap_region (cairo_clip_t *clip,
408 const cairo_pattern_t *src,
409 cairo_operator_t op,
410 cairo_surface_t *dst,
411 cairo_region_t *trap_region,
412 cairo_rectangle_int_t *extents)
414 cairo_status_t status;
415 cairo_solid_pattern_t solid_pattern;
416 cairo_surface_pattern_t mask;
417 int num_rects = cairo_region_num_rectangles (trap_region);
418 unsigned int clip_serial;
419 cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
421 if (num_rects == 0)
422 return CAIRO_STATUS_SUCCESS;
424 if (clip_surface && op == CAIRO_OPERATOR_CLEAR) {
425 _cairo_pattern_init_solid (&solid_pattern, CAIRO_COLOR_WHITE,
426 CAIRO_CONTENT_COLOR);
427 src = &solid_pattern.base;
428 op = CAIRO_OPERATOR_DEST_OUT;
431 if (num_rects > 1) {
432 if (_cairo_surface_get_clip_mode (dst) != CAIRO_CLIP_MODE_REGION)
433 return CAIRO_INT_STATUS_UNSUPPORTED;
435 clip_serial = _cairo_surface_allocate_clip_serial (dst);
436 status = _cairo_surface_set_clip_region (dst,
437 trap_region,
438 clip_serial);
439 if (unlikely (status))
440 return status;
443 if (clip_surface)
444 _cairo_pattern_init_for_surface (&mask, clip_surface);
446 status = _cairo_surface_composite (op,
447 src,
448 clip_surface ? &mask.base : NULL,
449 dst,
450 extents->x, extents->y,
451 extents->x - (clip_surface ? clip->surface_rect.x : 0),
452 extents->y - (clip_surface ? clip->surface_rect.y : 0),
453 extents->x, extents->y,
454 extents->width, extents->height);
456 /* Restore the original clip if we modified it temporarily. */
457 if (num_rects > 1) {
458 cairo_status_t status2 = _cairo_surface_set_clip (dst, clip);
459 if (status == CAIRO_STATUS_SUCCESS)
460 status = status2;
463 if (clip_surface)
464 _cairo_pattern_fini (&mask.base);
466 return status;
469 typedef struct {
470 cairo_traps_t *traps;
471 cairo_antialias_t antialias;
472 } cairo_composite_traps_info_t;
474 static cairo_status_t
475 _composite_traps_draw_func (void *closure,
476 cairo_operator_t op,
477 const cairo_pattern_t *src,
478 cairo_surface_t *dst,
479 int dst_x,
480 int dst_y,
481 const cairo_rectangle_int_t *extents)
483 cairo_composite_traps_info_t *info = closure;
484 cairo_solid_pattern_t pattern;
486 if (dst_x != 0 || dst_y != 0)
487 _cairo_traps_translate (info->traps, - dst_x, - dst_y);
489 if (src == NULL) {
490 _cairo_pattern_init_solid (&pattern, CAIRO_COLOR_WHITE,
491 CAIRO_CONTENT_COLOR);
492 src = &pattern.base;
495 return _cairo_surface_composite_trapezoids (op,
496 src, dst, info->antialias,
497 extents->x, extents->y,
498 extents->x - dst_x, extents->y - dst_y,
499 extents->width, extents->height,
500 info->traps->traps,
501 info->traps->num_traps);
504 /* Warning: This call modifies the coordinates of traps */
505 static cairo_status_t
506 _clip_and_composite_trapezoids (const cairo_pattern_t *src,
507 cairo_operator_t op,
508 cairo_surface_t *dst,
509 cairo_traps_t *traps,
510 cairo_clip_t *clip,
511 cairo_antialias_t antialias)
513 cairo_status_t status;
514 cairo_region_t *trap_region = NULL;
515 cairo_region_t *clear_region = NULL;
516 cairo_rectangle_int_t extents;
517 cairo_composite_traps_info_t traps_info;
519 if (_cairo_operator_bounded_by_mask (op) && traps->num_traps == 0)
520 return CAIRO_STATUS_SUCCESS;
522 status = _cairo_surface_get_extents (dst, &extents);
523 if (unlikely (status))
524 return status;
526 status = _cairo_traps_extract_region (traps, &trap_region);
527 if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
528 return status;
530 if (_cairo_operator_bounded_by_mask (op)) {
531 cairo_rectangle_int_t trap_extents;
533 if (trap_region) {
534 status = _cairo_clip_intersect_to_region (clip, trap_region);
535 if (unlikely (status))
536 goto out;
538 cairo_region_get_extents (trap_region, &trap_extents);
539 } else {
540 cairo_box_t trap_box;
541 _cairo_traps_extents (traps, &trap_box);
542 _cairo_box_round_to_rectangle (&trap_box, &trap_extents);
545 if (! _cairo_rectangle_intersect (&extents, &trap_extents)) {
546 status = CAIRO_STATUS_SUCCESS;
547 goto out;
550 status = _cairo_clip_intersect_to_rectangle (clip, &extents);
551 if (unlikely (status))
552 goto out;
553 } else {
554 cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
556 if (trap_region && !clip_surface) {
557 /* If we optimize drawing with an unbounded operator to
558 * _cairo_surface_fill_rectangles() or to drawing with a
559 * clip region, then we have an additional region to clear.
561 clear_region = cairo_region_create_rectangle (&extents);
563 status = cairo_region_status (clear_region);
564 if (unlikely (status))
565 goto out;
567 status = _cairo_clip_intersect_to_region (clip, clear_region);
568 if (unlikely (status))
569 goto out;
571 cairo_region_get_extents (clear_region, &extents);
573 status = cairo_region_subtract (clear_region, trap_region);
574 if (unlikely (status))
575 goto out;
577 if (cairo_region_is_empty (clear_region)) {
578 cairo_region_destroy (clear_region);
579 clear_region = NULL;
581 } else {
582 status = _cairo_clip_intersect_to_rectangle (clip, &extents);
586 if (unlikely (status))
587 goto out;
589 if (trap_region) {
590 cairo_surface_t *clip_surface = clip ? clip->surface : NULL;
592 if ((src->type == CAIRO_PATTERN_TYPE_SOLID ||
593 op == CAIRO_OPERATOR_CLEAR) && !clip_surface) {
594 const cairo_color_t *color;
596 if (op == CAIRO_OPERATOR_CLEAR) {
597 color = CAIRO_COLOR_TRANSPARENT;
598 } else {
599 color = &((cairo_solid_pattern_t *)src)->color;
602 /* Solid rectangles special case */
603 status = _cairo_surface_fill_region (dst, op, color, trap_region);
605 if (!status && clear_region) {
606 status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
607 CAIRO_COLOR_TRANSPARENT,
608 clear_region);
611 goto out;
614 if ((_cairo_operator_bounded_by_mask (op) &&
615 op != CAIRO_OPERATOR_SOURCE) || !clip_surface) {
616 /* For a simple rectangle, we can just use composite(), for more
617 * rectangles, we have to set a clip region. The cost of rasterizing
618 * trapezoids is pretty high for most backends currently, so it's
619 * worthwhile even if a region is needed.
621 * If we have a clip surface, we set it as the mask; this only works
622 * for bounded operators other than SOURCE; for unbounded operators,
623 * clip and mask cannot be interchanged. For SOURCE, the operator
624 * as implemented by the backends is different in its handling
625 * of the mask then what we want.
627 * CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has
628 * more than rectangle and the destination doesn't support clip
629 * regions. In that case, we fall through.
631 status = _composite_trap_region (clip, src, op, dst,
632 trap_region, &extents);
634 if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
635 if (!status && clear_region)
636 status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR,
637 CAIRO_COLOR_TRANSPARENT,
638 clear_region);
639 goto out;
644 traps_info.traps = traps;
645 traps_info.antialias = antialias;
647 status = _clip_and_composite (clip, op, src,
648 _composite_traps_draw_func,
649 &traps_info, dst, &extents);
651 out:
652 if (trap_region)
653 cairo_region_destroy (trap_region);
654 if (clear_region)
655 cairo_region_destroy (clear_region);
657 return status;
660 typedef struct {
661 cairo_path_fixed_t *path;
662 cairo_fill_rule_t fill_rule;
663 double tolerance;
664 cairo_antialias_t antialias;
665 } cairo_composite_spans_fill_info_t;
667 static cairo_status_t
668 _composite_spans_fill_func (void *closure,
669 cairo_operator_t op,
670 const cairo_pattern_t *src,
671 cairo_surface_t *dst,
672 int dst_x,
673 int dst_y,
674 const cairo_rectangle_int_t *extents)
676 cairo_composite_rectangles_t rects;
677 cairo_composite_spans_fill_info_t *info = closure;
678 cairo_solid_pattern_t pattern;
680 _cairo_composite_rectangles_init (
681 &rects, extents->x, extents->y,
682 extents->width, extents->height);
684 /* The incoming dst_x/y are where we're pretending the origin of
685 * the dst surface is -- *not* the offset of a rectangle where
686 * we'd like to place the result. */
687 rects.dst.x -= dst_x;
688 rects.dst.y -= dst_y;
690 /* We're called without a source pattern from
691 * _create_composite_mask_pattern(). */
692 if (src == NULL) {
693 _cairo_pattern_init_solid (&pattern, CAIRO_COLOR_WHITE,
694 CAIRO_CONTENT_COLOR);
695 src = &pattern.base;
698 return _cairo_path_fixed_fill_using_spans (
699 op, src, info->path, dst,
700 info->fill_rule, info->tolerance, info->antialias,
701 &rects);
704 cairo_status_t
705 _cairo_surface_fallback_paint (cairo_surface_t *surface,
706 cairo_operator_t op,
707 const cairo_pattern_t *source)
709 cairo_status_t status;
710 cairo_rectangle_int_t extents;
711 cairo_box_t box;
712 cairo_traps_t traps;
714 status = _cairo_surface_get_extents (surface, &extents);
715 if (unlikely (status))
716 return status;
718 if (_cairo_operator_bounded_by_source (op)) {
719 cairo_rectangle_int_t source_extents;
721 status = _cairo_pattern_get_extents (source, &source_extents);
722 if (unlikely (status))
723 return status;
725 if (! _cairo_rectangle_intersect (&extents, &source_extents))
726 return CAIRO_STATUS_SUCCESS;
729 status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents);
730 if (unlikely (status))
731 return status;
733 _cairo_box_from_rectangle (&box, &extents);
735 _cairo_traps_init_box (&traps, &box);
737 status = _clip_and_composite_trapezoids (source,
739 surface,
740 &traps,
741 surface->clip,
742 CAIRO_ANTIALIAS_NONE);
744 _cairo_traps_fini (&traps);
746 return status;
749 static cairo_status_t
750 _cairo_surface_mask_draw_func (void *closure,
751 cairo_operator_t op,
752 const cairo_pattern_t *src,
753 cairo_surface_t *dst,
754 int dst_x,
755 int dst_y,
756 const cairo_rectangle_int_t *extents)
758 cairo_pattern_t *mask = closure;
760 if (src)
761 return _cairo_surface_composite (op,
762 src, mask, dst,
763 extents->x, extents->y,
764 extents->x, extents->y,
765 extents->x - dst_x, extents->y - dst_y,
766 extents->width, extents->height);
767 else
768 return _cairo_surface_composite (op,
769 mask, NULL, dst,
770 extents->x, extents->y,
771 0, 0, /* unused */
772 extents->x - dst_x, extents->y - dst_y,
773 extents->width, extents->height);
776 cairo_status_t
777 _cairo_surface_fallback_mask (cairo_surface_t *surface,
778 cairo_operator_t op,
779 const cairo_pattern_t *source,
780 const cairo_pattern_t *mask)
782 cairo_status_t status;
783 cairo_rectangle_int_t extents, source_extents, mask_extents;
785 status = _cairo_surface_get_extents (surface, &extents);
786 if (unlikely (status))
787 return status;
789 if (_cairo_operator_bounded_by_source (op)) {
790 status = _cairo_pattern_get_extents (source, &source_extents);
791 if (unlikely (status))
792 return status;
794 if (! _cairo_rectangle_intersect (&extents, &source_extents))
795 return CAIRO_STATUS_SUCCESS;
798 if (_cairo_operator_bounded_by_mask (op)) {
799 status = _cairo_pattern_get_extents (mask, &mask_extents);
800 if (unlikely (status))
801 return status;
803 if (! _cairo_rectangle_intersect (&extents, &mask_extents))
804 return CAIRO_STATUS_SUCCESS;
807 status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents);
808 if (unlikely (status))
809 return status;
811 status = _clip_and_composite (surface->clip, op,
812 source,
813 _cairo_surface_mask_draw_func,
814 (void *) mask,
815 surface,
816 &extents);
818 return status;
821 cairo_status_t
822 _cairo_surface_fallback_stroke (cairo_surface_t *surface,
823 cairo_operator_t op,
824 const cairo_pattern_t *source,
825 cairo_path_fixed_t *path,
826 cairo_stroke_style_t *stroke_style,
827 cairo_matrix_t *ctm,
828 cairo_matrix_t *ctm_inverse,
829 double tolerance,
830 cairo_antialias_t antialias)
832 cairo_status_t status;
833 cairo_traps_t traps;
834 cairo_box_t box;
835 cairo_rectangle_int_t extents;
837 status = _cairo_surface_get_extents (surface, &extents);
838 if (unlikely (status))
839 return status;
841 if (_cairo_operator_bounded_by_source (op)) {
842 cairo_rectangle_int_t source_extents;
843 status = _cairo_pattern_get_extents (source, &source_extents);
844 if (unlikely (status))
845 return status;
847 if (! _cairo_rectangle_intersect (&extents, &source_extents))
848 return CAIRO_STATUS_SUCCESS;
851 status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents);
852 if (unlikely (status))
853 return status;
855 if (extents.width == 0 || extents.height == 0)
856 return CAIRO_STATUS_SUCCESS;
858 _cairo_box_from_rectangle (&box, &extents);
860 _cairo_traps_init (&traps);
861 _cairo_traps_limit (&traps, &box);
863 status = _cairo_path_fixed_stroke_to_traps (path,
864 stroke_style,
865 ctm, ctm_inverse,
866 tolerance,
867 &traps);
868 if (unlikely (status))
869 goto FAIL;
871 status = _clip_and_composite_trapezoids (source,
873 surface,
874 &traps,
875 surface->clip,
876 antialias);
878 FAIL:
879 _cairo_traps_fini (&traps);
881 return status;
884 cairo_status_t
885 _cairo_surface_fallback_fill (cairo_surface_t *surface,
886 cairo_operator_t op,
887 const cairo_pattern_t *source,
888 cairo_path_fixed_t *path,
889 cairo_fill_rule_t fill_rule,
890 double tolerance,
891 cairo_antialias_t antialias)
893 cairo_status_t status;
894 cairo_traps_t traps;
895 cairo_box_t box;
896 cairo_rectangle_int_t extents;
898 status = _cairo_surface_get_extents (surface, &extents);
899 if (unlikely (status))
900 return status;
902 if (_cairo_operator_bounded_by_source (op)) {
903 cairo_rectangle_int_t source_extents;
905 status = _cairo_pattern_get_extents (source, &source_extents);
906 if (unlikely (status))
907 return status;
909 if (! _cairo_rectangle_intersect (&extents, &source_extents))
910 return CAIRO_STATUS_SUCCESS;
913 status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents);
914 if (unlikely (status))
915 return status;
917 if (extents.width == 0 || extents.height == 0)
918 return CAIRO_STATUS_SUCCESS;
920 /* Ask if the surface would like to render this combination of
921 * op/source/dst/antialias with spans or not, but don't actually
922 * make a renderer yet. We'll try to hit the region optimisations
923 * in _clip_and_composite_trapezoids() if it looks like the path
924 * is a region. */
925 /* TODO: Until we have a mono scan converter we won't even try
926 * to use spans for CAIRO_ANTIALIAS_NONE. */
927 /* TODO: The region filling code should be lifted from
928 * _clip_and_composite_trapezoids() and given first priority
929 * explicitly before deciding between spans and trapezoids. */
930 if (antialias != CAIRO_ANTIALIAS_NONE &&
931 !_cairo_path_fixed_is_box (path, &box) &&
932 !_cairo_path_fixed_is_region (path) &&
933 _cairo_surface_check_span_renderer (
934 op, source, surface, antialias, NULL))
936 cairo_composite_spans_fill_info_t info;
937 info.path = path;
938 info.fill_rule = fill_rule;
939 info.tolerance = tolerance;
940 info.antialias = antialias;
942 if (_cairo_operator_bounded_by_mask (op)) {
943 cairo_rectangle_int_t path_extents;
945 _cairo_path_fixed_approximate_clip_extents (path,
946 &path_extents);
947 if (! _cairo_rectangle_intersect (&extents, &path_extents))
948 return CAIRO_STATUS_SUCCESS;
951 return _clip_and_composite (
952 surface->clip, op, source,
953 _composite_spans_fill_func,
954 &info,
955 surface,
956 &extents);
959 /* Fall back to trapezoid fills. */
960 _cairo_box_from_rectangle (&box, &extents);
961 _cairo_traps_init (&traps);
962 _cairo_traps_limit (&traps, &box);
964 status = _cairo_path_fixed_fill_to_traps (path,
965 fill_rule,
966 tolerance,
967 &traps);
968 if (unlikely (status)) {
969 _cairo_traps_fini (&traps);
970 return status;
973 status = _clip_and_composite_trapezoids (source,
975 surface,
976 &traps,
977 surface->clip,
978 antialias);
980 _cairo_traps_fini (&traps);
982 return status;
985 typedef struct {
986 cairo_scaled_font_t *font;
987 cairo_glyph_t *glyphs;
988 int num_glyphs;
989 } cairo_show_glyphs_info_t;
991 static cairo_status_t
992 _cairo_surface_old_show_glyphs_draw_func (void *closure,
993 cairo_operator_t op,
994 const cairo_pattern_t *src,
995 cairo_surface_t *dst,
996 int dst_x,
997 int dst_y,
998 const cairo_rectangle_int_t *extents)
1000 cairo_show_glyphs_info_t *glyph_info = closure;
1001 cairo_solid_pattern_t pattern;
1002 cairo_status_t status;
1004 /* Modifying the glyph array is fine because we know that this function
1005 * will be called only once, and we've already made a copy of the
1006 * glyphs in the wrapper.
1008 if (dst_x != 0 || dst_y != 0) {
1009 int i;
1011 for (i = 0; i < glyph_info->num_glyphs; ++i)
1013 ((cairo_glyph_t *) glyph_info->glyphs)[i].x -= dst_x;
1014 ((cairo_glyph_t *) glyph_info->glyphs)[i].y -= dst_y;
1018 if (src == NULL) {
1019 _cairo_pattern_init_solid (&pattern, CAIRO_COLOR_WHITE,
1020 CAIRO_CONTENT_COLOR);
1021 src = &pattern.base;
1024 status = _cairo_surface_old_show_glyphs (glyph_info->font, op, src,
1025 dst,
1026 extents->x, extents->y,
1027 extents->x - dst_x,
1028 extents->y - dst_y,
1029 extents->width,
1030 extents->height,
1031 glyph_info->glyphs,
1032 glyph_info->num_glyphs);
1033 if (status != CAIRO_INT_STATUS_UNSUPPORTED)
1034 return status;
1036 return _cairo_scaled_font_show_glyphs (glyph_info->font,
1038 src, dst,
1039 extents->x, extents->y,
1040 extents->x - dst_x,
1041 extents->y - dst_y,
1042 extents->width, extents->height,
1043 glyph_info->glyphs,
1044 glyph_info->num_glyphs);
1047 cairo_status_t
1048 _cairo_surface_fallback_show_glyphs (cairo_surface_t *surface,
1049 cairo_operator_t op,
1050 const cairo_pattern_t *source,
1051 cairo_glyph_t *glyphs,
1052 int num_glyphs,
1053 cairo_scaled_font_t *scaled_font)
1055 cairo_status_t status;
1056 cairo_rectangle_int_t extents;
1057 cairo_show_glyphs_info_t glyph_info;
1059 status = _cairo_surface_get_extents (surface, &extents);
1060 if (unlikely (status))
1061 return status;
1063 if (_cairo_operator_bounded_by_mask (op)) {
1064 cairo_rectangle_int_t glyph_extents;
1066 status = _cairo_scaled_font_glyph_device_extents (scaled_font,
1067 glyphs,
1068 num_glyphs,
1069 &glyph_extents);
1070 if (unlikely (status))
1071 return status;
1073 if (! _cairo_rectangle_intersect (&extents, &glyph_extents))
1074 return CAIRO_STATUS_SUCCESS;
1077 status = _cairo_clip_intersect_to_rectangle (surface->clip, &extents);
1078 if (unlikely (status))
1079 return status;
1081 glyph_info.font = scaled_font;
1082 glyph_info.glyphs = glyphs;
1083 glyph_info.num_glyphs = num_glyphs;
1085 status = _clip_and_composite (surface->clip,
1087 source,
1088 _cairo_surface_old_show_glyphs_draw_func,
1089 &glyph_info,
1090 surface,
1091 &extents);
1093 return status;
1096 cairo_surface_t *
1097 _cairo_surface_fallback_snapshot (cairo_surface_t *surface)
1099 cairo_surface_t *snapshot;
1100 cairo_status_t status;
1101 cairo_format_t format;
1102 cairo_surface_pattern_t pattern;
1103 cairo_image_surface_t *image;
1104 void *image_extra;
1106 status = _cairo_surface_acquire_source_image (surface,
1107 &image, &image_extra);
1108 if (unlikely (status))
1109 return _cairo_surface_create_in_error (status);
1111 format = image->format;
1112 if (format == CAIRO_FORMAT_INVALID) {
1113 /* Non-standard images formats can be generated when retrieving
1114 * images from unusual xservers, for example.
1116 format = _cairo_format_from_content (image->base.content);
1118 snapshot = cairo_image_surface_create (format,
1119 image->width,
1120 image->height);
1121 if (cairo_surface_status (snapshot)) {
1122 _cairo_surface_release_source_image (surface, image, image_extra);
1123 return snapshot;
1126 _cairo_pattern_init_for_surface (&pattern, &image->base);
1127 status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE,
1128 &pattern.base,
1129 NULL,
1130 snapshot,
1131 0, 0,
1132 0, 0,
1133 0, 0,
1134 image->width,
1135 image->height);
1136 _cairo_pattern_fini (&pattern.base);
1137 _cairo_surface_release_source_image (surface, image, image_extra);
1138 if (unlikely (status)) {
1139 cairo_surface_destroy (snapshot);
1140 return _cairo_surface_create_in_error (status);
1143 return snapshot;
1146 cairo_status_t
1147 _cairo_surface_fallback_composite (cairo_operator_t op,
1148 const cairo_pattern_t *src,
1149 const cairo_pattern_t *mask,
1150 cairo_surface_t *dst,
1151 int src_x,
1152 int src_y,
1153 int mask_x,
1154 int mask_y,
1155 int dst_x,
1156 int dst_y,
1157 unsigned int width,
1158 unsigned int height)
1160 fallback_state_t state;
1161 cairo_status_t status;
1163 status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
1164 if (unlikely (status)) {
1165 if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
1166 return CAIRO_STATUS_SUCCESS;
1167 return status;
1170 /* We know this will never fail with the image backend; but
1171 * instead of calling into it directly, we call
1172 * _cairo_surface_composite so that we get the correct device
1173 * offset handling.
1175 status = _cairo_surface_composite (op, src, mask,
1176 &state.image->base,
1177 src_x, src_y, mask_x, mask_y,
1178 dst_x - state.image_rect.x,
1179 dst_y - state.image_rect.y,
1180 width, height);
1181 _fallback_fini (&state);
1183 return status;
1186 cairo_status_t
1187 _cairo_surface_fallback_fill_rectangles (cairo_surface_t *surface,
1188 cairo_operator_t op,
1189 const cairo_color_t *color,
1190 cairo_rectangle_int_t *rects,
1191 int num_rects)
1193 fallback_state_t state;
1194 cairo_rectangle_int_t *offset_rects = NULL;
1195 cairo_status_t status;
1196 int x1, y1, x2, y2;
1197 int i;
1199 assert (surface->snapshot_of == NULL);
1201 if (num_rects <= 0)
1202 return CAIRO_STATUS_SUCCESS;
1204 /* Compute the bounds of the rectangles, so that we know what area of the
1205 * destination surface to fetch
1207 x1 = rects[0].x;
1208 y1 = rects[0].y;
1209 x2 = rects[0].x + rects[0].width;
1210 y2 = rects[0].y + rects[0].height;
1212 for (i = 1; i < num_rects; i++) {
1213 if (rects[i].x < x1)
1214 x1 = rects[i].x;
1215 if (rects[i].y < y1)
1216 y1 = rects[i].y;
1218 if ((int) (rects[i].x + rects[i].width) > x2)
1219 x2 = rects[i].x + rects[i].width;
1220 if ((int) (rects[i].y + rects[i].height) > y2)
1221 y2 = rects[i].y + rects[i].height;
1224 status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1);
1225 if (unlikely (status)) {
1226 if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
1227 return CAIRO_STATUS_SUCCESS;
1228 return status;
1231 /* If the fetched image isn't at 0,0, we need to offset the rectangles */
1233 if (state.image_rect.x != 0 || state.image_rect.y != 0) {
1234 offset_rects = _cairo_malloc_ab (num_rects, sizeof (cairo_rectangle_int_t));
1235 if (unlikely (offset_rects == NULL)) {
1236 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1237 goto DONE;
1240 for (i = 0; i < num_rects; i++) {
1241 offset_rects[i].x = rects[i].x - state.image_rect.x;
1242 offset_rects[i].y = rects[i].y - state.image_rect.y;
1243 offset_rects[i].width = rects[i].width;
1244 offset_rects[i].height = rects[i].height;
1247 rects = offset_rects;
1250 status = _cairo_surface_fill_rectangles (&state.image->base,
1251 op, color,
1252 rects, num_rects);
1254 free (offset_rects);
1256 DONE:
1257 _fallback_fini (&state);
1259 return status;
1262 cairo_status_t
1263 _cairo_surface_fallback_composite_trapezoids (cairo_operator_t op,
1264 const cairo_pattern_t *pattern,
1265 cairo_surface_t *dst,
1266 cairo_antialias_t antialias,
1267 int src_x,
1268 int src_y,
1269 int dst_x,
1270 int dst_y,
1271 unsigned int width,
1272 unsigned int height,
1273 cairo_trapezoid_t *traps,
1274 int num_traps)
1276 fallback_state_t state;
1277 cairo_trapezoid_t *offset_traps = NULL;
1278 cairo_status_t status;
1280 status = _fallback_init (&state, dst, dst_x, dst_y, width, height);
1281 if (unlikely (status)) {
1282 if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
1283 return CAIRO_STATUS_SUCCESS;
1284 return status;
1287 /* If the destination image isn't at 0,0, we need to offset the trapezoids */
1289 if (state.image_rect.x != 0 || state.image_rect.y != 0) {
1290 offset_traps = _cairo_malloc_ab (num_traps, sizeof (cairo_trapezoid_t));
1291 if (!offset_traps) {
1292 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
1293 goto DONE;
1296 _cairo_trapezoid_array_translate_and_scale (offset_traps, traps, num_traps,
1297 - state.image_rect.x, - state.image_rect.y,
1298 1.0, 1.0);
1299 traps = offset_traps;
1302 status = _cairo_surface_composite_trapezoids (op, pattern,
1303 &state.image->base,
1304 antialias,
1305 src_x, src_y,
1306 dst_x - state.image_rect.x,
1307 dst_y - state.image_rect.y,
1308 width, height,
1309 traps, num_traps);
1310 if (offset_traps)
1311 free (offset_traps);
1313 DONE:
1314 _fallback_fini (&state);
1316 return status;
1319 cairo_status_t
1320 _cairo_surface_fallback_clone_similar (cairo_surface_t *surface,
1321 cairo_surface_t *src,
1322 cairo_content_t content,
1323 int src_x,
1324 int src_y,
1325 int width,
1326 int height,
1327 int *clone_offset_x,
1328 int *clone_offset_y,
1329 cairo_surface_t **clone_out)
1331 cairo_surface_t *new_surface;
1332 cairo_surface_pattern_t pattern;
1333 cairo_status_t status;
1335 new_surface = _cairo_surface_create_similar_scratch (surface,
1336 src->content & content,
1337 width, height);
1338 if (new_surface->status)
1339 return new_surface->status;
1341 /* We have to copy these here, so that the coordinate spaces are correct */
1342 new_surface->device_transform = src->device_transform;
1343 new_surface->device_transform_inverse = src->device_transform_inverse;
1345 _cairo_pattern_init_for_surface (&pattern, src);
1346 cairo_matrix_init_translate (&pattern.base.matrix, src_x, src_y);
1347 pattern.base.filter = CAIRO_FILTER_NEAREST;
1349 status = _cairo_surface_paint (new_surface,
1350 CAIRO_OPERATOR_SOURCE,
1351 &pattern.base, NULL);
1352 _cairo_pattern_fini (&pattern.base);
1354 if (unlikely (status)) {
1355 cairo_surface_destroy (new_surface);
1356 return status;
1359 *clone_offset_x = src_x;
1360 *clone_offset_y = src_y;
1361 *clone_out = new_surface;
1362 return CAIRO_STATUS_SUCCESS;