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
36 * Carl D. Worth <cworth@cworth.org>
41 #include "cairo-surface-fallback-private.h"
42 #include "cairo-clip-private.h"
46 cairo_rectangle_int_t extents
;
47 cairo_image_surface_t
*image
;
48 cairo_rectangle_int_t image_rect
;
55 * Acquire destination image surface needed for an image-based
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.
62 static cairo_int_status_t
63 _fallback_init (fallback_state_t
*state
,
70 cairo_status_t status
;
74 state
->extents
.width
= width
;
75 state
->extents
.height
= height
;
79 status
= _cairo_surface_acquire_dest_image (dst
, &state
->extents
,
80 &state
->image
, &state
->image_rect
,
82 if (unlikely (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
90 if (state
->image
== NULL
)
91 return CAIRO_INT_STATUS_NOTHING_TO_DO
;
93 return CAIRO_STATUS_SUCCESS
;
97 _fallback_fini (fallback_state_t
*state
)
99 _cairo_surface_release_dest_image (state
->dst
, &state
->extents
,
100 state
->image
, &state
->image_rect
,
104 typedef cairo_status_t (*cairo_draw_func_t
) (void *closure
,
106 const cairo_pattern_t
*src
,
107 cairo_surface_t
*dst
,
110 const cairo_rectangle_int_t
*extents
);
112 static cairo_status_t
113 _create_composite_mask_pattern (cairo_surface_pattern_t
*mask_pattern
,
115 cairo_draw_func_t draw_func
,
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
,
130 status
= (*draw_func
) (draw_closure
, CAIRO_OPERATOR_ADD
,
132 extents
->x
, extents
->y
,
134 if (unlikely (status
))
135 goto CLEANUP_SURFACE
;
137 if (clip
&& clip
->surface
)
138 status
= _cairo_clip_combine_to_surface (clip
, CAIRO_OPERATOR_IN
,
140 extents
->x
, extents
->y
,
142 if (unlikely (status
))
143 goto CLEANUP_SURFACE
;
145 _cairo_pattern_init_for_surface (mask_pattern
, mask
);
148 cairo_surface_destroy (mask
);
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
,
159 const cairo_pattern_t
*src
,
160 cairo_draw_func_t draw_func
,
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
,
170 draw_func
, draw_closure
,
172 if (unlikely (status
))
175 status
= _cairo_surface_composite (op
,
176 src
, &mask_pattern
.base
, dst
,
177 extents
->x
, extents
->y
,
179 extents
->x
, extents
->y
,
180 extents
->width
, extents
->height
);
182 _cairo_pattern_fini (&mask_pattern
.base
);
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
,
193 const cairo_pattern_t
*src
,
194 cairo_draw_func_t draw_func
,
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
,
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
,
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
,
234 extents
->x
, extents
->y
,
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
,
243 extents
->x
, extents
->y
,
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
,
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
,
265 extents
->x
, extents
->y
,
266 extents
->width
, extents
->height
);
268 _cairo_pattern_fini (&intermediate_pattern
.base
);
271 cairo_surface_destroy (intermediate
);
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
,
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
,
294 draw_func
, draw_closure
,
296 if (unlikely (status
))
299 /* Compute dest' = dest OUT (mask IN clip)
301 status
= _cairo_surface_composite (CAIRO_OPERATOR_DEST_OUT
,
302 &mask_pattern
.base
, NULL
, dst
,
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
,
317 extents
->x
, extents
->y
,
318 extents
->width
, extents
->height
);
320 CLEANUP_MASK_PATTERN
:
321 _cairo_pattern_fini (&mask_pattern
.base
);
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
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
350 * Return value: %CAIRO_STATUS_SUCCESS if the drawing succeeded.
352 static cairo_status_t
353 _clip_and_composite (cairo_clip_t
*clip
,
355 const cairo_pattern_t
*src
,
356 cairo_draw_func_t draw_func
,
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
))
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
,
380 draw_func
, draw_closure
,
382 else if (_cairo_operator_bounded_by_mask (op
))
383 status
= _clip_and_composite_with_mask (clip
, op
,
385 draw_func
, draw_closure
,
388 status
= _clip_and_composite_combine (clip
, op
,
390 draw_func
, draw_closure
,
395 status
= (*draw_func
) (draw_closure
, op
,
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
,
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
;
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
;
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
,
439 if (unlikely (status
))
444 _cairo_pattern_init_for_surface (&mask
, clip_surface
);
446 status
= _cairo_surface_composite (op
,
448 clip_surface
? &mask
.base
: NULL
,
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. */
458 cairo_status_t status2
= _cairo_surface_set_clip (dst
, clip
);
459 if (status
== CAIRO_STATUS_SUCCESS
)
464 _cairo_pattern_fini (&mask
.base
);
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
,
477 const cairo_pattern_t
*src
,
478 cairo_surface_t
*dst
,
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
);
490 _cairo_pattern_init_solid (&pattern
, CAIRO_COLOR_WHITE
,
491 CAIRO_CONTENT_COLOR
);
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
,
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
,
508 cairo_surface_t
*dst
,
509 cairo_traps_t
*traps
,
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
))
526 status
= _cairo_traps_extract_region (traps
, &trap_region
);
527 if (status
&& status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
530 if (_cairo_operator_bounded_by_mask (op
)) {
531 cairo_rectangle_int_t trap_extents
;
534 status
= _cairo_clip_intersect_to_region (clip
, trap_region
);
535 if (unlikely (status
))
538 cairo_region_get_extents (trap_region
, &trap_extents
);
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
;
550 status
= _cairo_clip_intersect_to_rectangle (clip
, &extents
);
551 if (unlikely (status
))
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
))
567 status
= _cairo_clip_intersect_to_region (clip
, clear_region
);
568 if (unlikely (status
))
571 cairo_region_get_extents (clear_region
, &extents
);
573 status
= cairo_region_subtract (clear_region
, trap_region
);
574 if (unlikely (status
))
577 if (cairo_region_is_empty (clear_region
)) {
578 cairo_region_destroy (clear_region
);
582 status
= _cairo_clip_intersect_to_rectangle (clip
, &extents
);
586 if (unlikely (status
))
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
;
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
,
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
,
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
);
653 cairo_region_destroy (trap_region
);
655 cairo_region_destroy (clear_region
);
661 cairo_path_fixed_t
*path
;
662 cairo_fill_rule_t fill_rule
;
664 cairo_antialias_t antialias
;
665 } cairo_composite_spans_fill_info_t
;
667 static cairo_status_t
668 _composite_spans_fill_func (void *closure
,
670 const cairo_pattern_t
*src
,
671 cairo_surface_t
*dst
,
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(). */
693 _cairo_pattern_init_solid (&pattern
, CAIRO_COLOR_WHITE
,
694 CAIRO_CONTENT_COLOR
);
698 return _cairo_path_fixed_fill_using_spans (
699 op
, src
, info
->path
, dst
,
700 info
->fill_rule
, info
->tolerance
, info
->antialias
,
705 _cairo_surface_fallback_paint (cairo_surface_t
*surface
,
707 const cairo_pattern_t
*source
)
709 cairo_status_t status
;
710 cairo_rectangle_int_t extents
;
714 status
= _cairo_surface_get_extents (surface
, &extents
);
715 if (unlikely (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
))
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
))
733 _cairo_box_from_rectangle (&box
, &extents
);
735 _cairo_traps_init_box (&traps
, &box
);
737 status
= _clip_and_composite_trapezoids (source
,
742 CAIRO_ANTIALIAS_NONE
);
744 _cairo_traps_fini (&traps
);
749 static cairo_status_t
750 _cairo_surface_mask_draw_func (void *closure
,
752 const cairo_pattern_t
*src
,
753 cairo_surface_t
*dst
,
756 const cairo_rectangle_int_t
*extents
)
758 cairo_pattern_t
*mask
= closure
;
761 return _cairo_surface_composite (op
,
763 extents
->x
, extents
->y
,
764 extents
->x
, extents
->y
,
765 extents
->x
- dst_x
, extents
->y
- dst_y
,
766 extents
->width
, extents
->height
);
768 return _cairo_surface_composite (op
,
770 extents
->x
, extents
->y
,
772 extents
->x
- dst_x
, extents
->y
- dst_y
,
773 extents
->width
, extents
->height
);
777 _cairo_surface_fallback_mask (cairo_surface_t
*surface
,
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
))
789 if (_cairo_operator_bounded_by_source (op
)) {
790 status
= _cairo_pattern_get_extents (source
, &source_extents
);
791 if (unlikely (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
))
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
))
811 status
= _clip_and_composite (surface
->clip
, op
,
813 _cairo_surface_mask_draw_func
,
822 _cairo_surface_fallback_stroke (cairo_surface_t
*surface
,
824 const cairo_pattern_t
*source
,
825 cairo_path_fixed_t
*path
,
826 cairo_stroke_style_t
*stroke_style
,
828 cairo_matrix_t
*ctm_inverse
,
830 cairo_antialias_t antialias
)
832 cairo_status_t status
;
835 cairo_rectangle_int_t extents
;
837 status
= _cairo_surface_get_extents (surface
, &extents
);
838 if (unlikely (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
))
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
))
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
,
868 if (unlikely (status
))
871 status
= _clip_and_composite_trapezoids (source
,
879 _cairo_traps_fini (&traps
);
885 _cairo_surface_fallback_fill (cairo_surface_t
*surface
,
887 const cairo_pattern_t
*source
,
888 cairo_path_fixed_t
*path
,
889 cairo_fill_rule_t fill_rule
,
891 cairo_antialias_t antialias
)
893 cairo_status_t status
;
896 cairo_rectangle_int_t extents
;
898 status
= _cairo_surface_get_extents (surface
, &extents
);
899 if (unlikely (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
))
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
))
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
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
;
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
,
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
,
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
,
968 if (unlikely (status
)) {
969 _cairo_traps_fini (&traps
);
973 status
= _clip_and_composite_trapezoids (source
,
980 _cairo_traps_fini (&traps
);
986 cairo_scaled_font_t
*font
;
987 cairo_glyph_t
*glyphs
;
989 } cairo_show_glyphs_info_t
;
991 static cairo_status_t
992 _cairo_surface_old_show_glyphs_draw_func (void *closure
,
994 const cairo_pattern_t
*src
,
995 cairo_surface_t
*dst
,
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) {
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
;
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
,
1026 extents
->x
, extents
->y
,
1032 glyph_info
->num_glyphs
);
1033 if (status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
1036 return _cairo_scaled_font_show_glyphs (glyph_info
->font
,
1039 extents
->x
, extents
->y
,
1042 extents
->width
, extents
->height
,
1044 glyph_info
->num_glyphs
);
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
,
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
))
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
,
1070 if (unlikely (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
))
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
,
1088 _cairo_surface_old_show_glyphs_draw_func
,
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
;
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
,
1121 if (cairo_surface_status (snapshot
)) {
1122 _cairo_surface_release_source_image (surface
, image
, image_extra
);
1126 _cairo_pattern_init_for_surface (&pattern
, &image
->base
);
1127 status
= _cairo_surface_composite (CAIRO_OPERATOR_SOURCE
,
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
);
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
,
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
;
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
1175 status
= _cairo_surface_composite (op
, src
, mask
,
1177 src_x
, src_y
, mask_x
, mask_y
,
1178 dst_x
- state
.image_rect
.x
,
1179 dst_y
- state
.image_rect
.y
,
1181 _fallback_fini (&state
);
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
,
1193 fallback_state_t state
;
1194 cairo_rectangle_int_t
*offset_rects
= NULL
;
1195 cairo_status_t status
;
1199 assert (surface
->snapshot_of
== NULL
);
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
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
)
1215 if (rects
[i
].y
< y1
)
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
;
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
);
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
,
1254 free (offset_rects
);
1257 _fallback_fini (&state
);
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
,
1272 unsigned int height
,
1273 cairo_trapezoid_t
*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
;
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
);
1296 _cairo_trapezoid_array_translate_and_scale (offset_traps
, traps
, num_traps
,
1297 - state
.image_rect
.x
, - state
.image_rect
.y
,
1299 traps
= offset_traps
;
1302 status
= _cairo_surface_composite_trapezoids (op
, pattern
,
1306 dst_x
- state
.image_rect
.x
,
1307 dst_y
- state
.image_rect
.y
,
1311 free (offset_traps
);
1314 _fallback_fini (&state
);
1320 _cairo_surface_fallback_clone_similar (cairo_surface_t
*surface
,
1321 cairo_surface_t
*src
,
1322 cairo_content_t content
,
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
,
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
);
1359 *clone_offset_x
= src_x
;
1360 *clone_offset_y
= src_y
;
1361 *clone_out
= new_surface
;
1362 return CAIRO_STATUS_SUCCESS
;