2 * Copyright © 2006 Keith Packard
3 * Copyright © 2007 Adrian Johnson
5 * This library is free software; you can redistribute it and/or
6 * modify it either under the terms of the GNU Lesser General Public
7 * License version 2.1 as published by the Free Software Foundation
8 * (the "LGPL") or, at your option, under the terms of the Mozilla
9 * Public License Version 1.1 (the "MPL"). If you do not alter this
10 * notice, a recipient may use your version of this file under either
11 * the MPL or the LGPL.
13 * You should have received a copy of the LGPL along with this library
14 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 * You should have received a copy of the MPL along with this library
17 * in the file COPYING-MPL-1.1
19 * The contents of this file are subject to the Mozilla Public License
20 * Version 1.1 (the "License"); you may not use this file except in
21 * compliance with the License. You may obtain a copy of the License at
22 * http://www.mozilla.org/MPL/
24 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
25 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
26 * the specific language governing rights and limitations.
28 * The Original Code is the cairo graphics library.
30 * The Initial Developer of the Original Code is Keith Packard
33 * Keith Packard <keithp@keithp.com>
34 * Adrian Johnson <ajohnson@redneon.com>
39 #include "cairo-analysis-surface-private.h"
40 #include "cairo-paginated-private.h"
41 #include "cairo-region-private.h"
42 #include "cairo-meta-surface-private.h"
49 cairo_surface_t
*target
;
51 cairo_bool_t first_op
;
52 cairo_bool_t has_supported
;
53 cairo_bool_t has_unsupported
;
55 cairo_region_t supported_region
;
56 cairo_region_t fallback_region
;
57 cairo_rectangle_int_t current_clip
;
58 cairo_box_t page_bbox
;
63 } cairo_analysis_surface_t
;
66 _cairo_analysis_surface_merge_status (cairo_int_status_t status_a
,
67 cairo_int_status_t status_b
)
69 /* fatal errors should be checked and propagated at source */
70 assert (! _cairo_status_is_error (status_a
));
71 assert (! _cairo_status_is_error (status_b
));
73 /* return the most important status */
74 if (status_a
== CAIRO_INT_STATUS_UNSUPPORTED
||
75 status_b
== CAIRO_INT_STATUS_UNSUPPORTED
)
76 return CAIRO_INT_STATUS_UNSUPPORTED
;
78 if (status_a
== CAIRO_INT_STATUS_IMAGE_FALLBACK
||
79 status_b
== CAIRO_INT_STATUS_IMAGE_FALLBACK
)
80 return CAIRO_INT_STATUS_IMAGE_FALLBACK
;
82 if (status_a
== CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN
||
83 status_b
== CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN
)
84 return CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN
;
86 if (status_a
== CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY
||
87 status_b
== CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY
)
88 return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY
;
90 /* at this point we have checked all the valid internal codes, so... */
91 assert (status_a
== CAIRO_STATUS_SUCCESS
&&
92 status_b
== CAIRO_STATUS_SUCCESS
);
94 return CAIRO_STATUS_SUCCESS
;
97 static cairo_int_status_t
98 _analyze_meta_surface_pattern (cairo_analysis_surface_t
*surface
,
99 cairo_pattern_t
*pattern
)
101 cairo_surface_t
*analysis
= &surface
->base
;
102 cairo_surface_pattern_t
*surface_pattern
;
103 cairo_status_t status
;
104 cairo_bool_t old_has_ctm
;
105 cairo_matrix_t old_ctm
, p2d
;
106 cairo_rectangle_int_t old_clip
;
107 cairo_rectangle_int_t meta_extents
;
111 assert (pattern
->type
== CAIRO_PATTERN_TYPE_SURFACE
);
112 surface_pattern
= (cairo_surface_pattern_t
*) pattern
;
113 assert (_cairo_surface_is_meta (surface_pattern
->surface
));
115 old_width
= surface
->width
;
116 old_height
= surface
->height
;
117 old_clip
= surface
->current_clip
;
118 status
= _cairo_surface_get_extents (surface_pattern
->surface
, &meta_extents
);
119 if (status
&& status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
122 surface
->width
= meta_extents
.width
;
123 surface
->height
= meta_extents
.height
;
124 surface
->current_clip
.x
= 0;
125 surface
->current_clip
.y
= 0;
126 surface
->current_clip
.width
= surface
->width
;
127 surface
->current_clip
.height
= surface
->height
;
128 old_ctm
= surface
->ctm
;
129 old_has_ctm
= surface
->has_ctm
;
130 p2d
= pattern
->matrix
;
131 status
= cairo_matrix_invert (&p2d
);
132 /* _cairo_pattern_set_matrix guarantees invertibility */
133 assert (status
== CAIRO_STATUS_SUCCESS
);
135 cairo_matrix_multiply (&surface
->ctm
, &p2d
, &surface
->ctm
);
136 surface
->has_ctm
= !_cairo_matrix_is_identity (&surface
->ctm
);
138 status
= _cairo_meta_surface_replay_and_create_regions (surface_pattern
->surface
,
140 if (status
== CAIRO_STATUS_SUCCESS
)
141 status
= analysis
->status
;
143 surface
->ctm
= old_ctm
;
144 surface
->has_ctm
= old_has_ctm
;
145 surface
->current_clip
= old_clip
;
146 surface
->width
= old_width
;
147 surface
->height
= old_height
;
152 static cairo_int_status_t
153 _add_operation (cairo_analysis_surface_t
*surface
,
154 cairo_rectangle_int_t
*rect
,
155 cairo_int_status_t backend_status
)
157 cairo_int_status_t status
;
160 if (rect
->width
== 0 || rect
->height
== 0) {
161 /* Even though the operation is not visible we must be careful
162 * to not allow unsupported operations to be replayed to the
163 * backend during CAIRO_PAGINATED_MODE_RENDER */
164 if (backend_status
== CAIRO_STATUS_SUCCESS
||
165 backend_status
== CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY
)
167 return CAIRO_STATUS_SUCCESS
;
171 return CAIRO_INT_STATUS_IMAGE_FALLBACK
;
175 _cairo_box_from_rectangle (&bbox
, rect
);
177 if (surface
->has_ctm
) {
179 _cairo_matrix_transform_bounding_box_fixed (&surface
->ctm
, &bbox
, NULL
);
181 if (bbox
.p1
.x
== bbox
.p2
.x
|| bbox
.p1
.y
== bbox
.p2
.y
) {
182 /* Even though the operation is not visible we must be
183 * careful to not allow unsupported operations to be
184 * replayed to the backend during
185 * CAIRO_PAGINATED_MODE_RENDER */
186 if (backend_status
== CAIRO_STATUS_SUCCESS
||
187 backend_status
== CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY
)
189 return CAIRO_STATUS_SUCCESS
;
193 return CAIRO_INT_STATUS_IMAGE_FALLBACK
;
197 _cairo_box_round_to_rectangle (&bbox
, rect
);
200 if (surface
->first_op
) {
201 surface
->first_op
= FALSE
;
202 surface
->page_bbox
= bbox
;
204 if (bbox
.p1
.x
< surface
->page_bbox
.p1
.x
)
205 surface
->page_bbox
.p1
.x
= bbox
.p1
.x
;
206 if (bbox
.p1
.y
< surface
->page_bbox
.p1
.y
)
207 surface
->page_bbox
.p1
.y
= bbox
.p1
.y
;
208 if (bbox
.p2
.x
> surface
->page_bbox
.p2
.x
)
209 surface
->page_bbox
.p2
.x
= bbox
.p2
.x
;
210 if (bbox
.p2
.y
> surface
->page_bbox
.p2
.y
)
211 surface
->page_bbox
.p2
.y
= bbox
.p2
.y
;
214 /* If the operation is completely enclosed within the fallback
215 * region there is no benefit in emitting a native operation as
216 * the fallback image will be painted on top.
218 if (_cairo_region_contains_rectangle (&surface
->fallback_region
, rect
) == PIXMAN_REGION_IN
)
219 return CAIRO_INT_STATUS_IMAGE_FALLBACK
;
221 if (backend_status
== CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY
) {
222 /* A status of CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY indicates
223 * that the backend only supports this operation if the
224 * transparency removed. If the extents of this operation does
225 * not intersect any other native operation, the operation is
226 * natively supported and the backend will blend the
227 * transparency into the white background.
229 if (_cairo_region_contains_rectangle (&surface
->supported_region
, rect
) == PIXMAN_REGION_OUT
)
230 backend_status
= CAIRO_STATUS_SUCCESS
;
233 if (backend_status
== CAIRO_STATUS_SUCCESS
) {
234 /* Add the operation to the supported region. Operations in
235 * this region will be emitted as native operations.
237 surface
->has_supported
= TRUE
;
238 status
= _cairo_region_union_rect (&surface
->supported_region
,
239 &surface
->supported_region
,
244 /* Add the operation to the unsupported region. This region will
245 * be painted as an image after all native operations have been
248 surface
->has_unsupported
= TRUE
;
249 status
= _cairo_region_union_rect (&surface
->fallback_region
,
250 &surface
->fallback_region
,
253 /* The status CAIRO_INT_STATUS_IMAGE_FALLBACK is used to indicate
254 * unsupported operations to the meta surface as using
255 * CAIRO_INT_STATUS_UNSUPPORTED would cause cairo-surface to
256 * invoke the cairo-surface-fallback path then return
257 * CAIRO_STATUS_SUCCESS.
259 if (status
== CAIRO_STATUS_SUCCESS
)
260 return CAIRO_INT_STATUS_IMAGE_FALLBACK
;
265 static cairo_status_t
266 _cairo_analysis_surface_finish (void *abstract_surface
)
268 cairo_analysis_surface_t
*surface
= (cairo_analysis_surface_t
*) abstract_surface
;
270 _cairo_region_fini (&surface
->supported_region
);
271 _cairo_region_fini (&surface
->fallback_region
);
273 cairo_surface_destroy (surface
->target
);
275 return CAIRO_STATUS_SUCCESS
;
278 static cairo_int_status_t
279 _cairo_analysis_surface_intersect_clip_path (void *abstract_surface
,
280 cairo_path_fixed_t
*path
,
281 cairo_fill_rule_t fill_rule
,
283 cairo_antialias_t antialias
)
285 cairo_analysis_surface_t
*surface
= abstract_surface
;
286 double x1
, y1
, x2
, y2
;
287 cairo_rectangle_int_t extent
;
288 cairo_bool_t is_empty
;
291 surface
->current_clip
.x
= 0;
292 surface
->current_clip
.y
= 0;
293 surface
->current_clip
.width
= surface
->width
;
294 surface
->current_clip
.height
= surface
->height
;
296 cairo_status_t status
;
298 status
= _cairo_path_fixed_bounds (path
, &x1
, &y1
, &x2
, &y2
, tolerance
);
302 extent
.x
= floor (x1
);
303 extent
.y
= floor (y1
);
304 extent
.width
= ceil (x2
) - extent
.x
;
305 extent
.height
= ceil (y2
) - extent
.y
;
307 is_empty
= _cairo_rectangle_intersect (&surface
->current_clip
, &extent
);
310 return CAIRO_STATUS_SUCCESS
;
313 static cairo_int_status_t
314 _cairo_analysis_surface_get_extents (void *abstract_surface
,
315 cairo_rectangle_int_t
*rectangle
)
317 cairo_analysis_surface_t
*surface
= abstract_surface
;
319 return _cairo_surface_get_extents (surface
->target
, rectangle
);
322 static cairo_int_status_t
323 _cairo_analysis_surface_paint (void *abstract_surface
,
325 cairo_pattern_t
*source
)
327 cairo_analysis_surface_t
*surface
= abstract_surface
;
328 cairo_status_t status
, backend_status
;
329 cairo_rectangle_int_t extents
;
330 cairo_bool_t is_empty
;
332 if (!surface
->target
->backend
->paint
)
333 backend_status
= CAIRO_INT_STATUS_UNSUPPORTED
;
335 backend_status
= (*surface
->target
->backend
->paint
) (surface
->target
, op
,
338 if (backend_status
== CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN
)
339 backend_status
= _analyze_meta_surface_pattern (surface
, source
);
341 status
= _cairo_surface_get_extents (&surface
->base
, &extents
);
342 if (status
&& status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
345 if (_cairo_operator_bounded_by_source (op
)) {
346 cairo_rectangle_int_t source_extents
;
348 status
= _cairo_pattern_get_extents (source
, &source_extents
);
352 is_empty
= _cairo_rectangle_intersect (&extents
, &source_extents
);
355 is_empty
= _cairo_rectangle_intersect (&extents
, &surface
->current_clip
);
357 status
= _add_operation (surface
, &extents
, backend_status
);
362 static cairo_int_status_t
363 _cairo_analysis_surface_mask (void *abstract_surface
,
365 cairo_pattern_t
*source
,
366 cairo_pattern_t
*mask
)
368 cairo_analysis_surface_t
*surface
= abstract_surface
;
369 cairo_int_status_t status
, backend_status
;
370 cairo_rectangle_int_t extents
;
371 cairo_bool_t is_empty
;
373 if (!surface
->target
->backend
->mask
)
374 backend_status
= CAIRO_INT_STATUS_UNSUPPORTED
;
376 backend_status
= (*surface
->target
->backend
->mask
) (surface
->target
, op
,
379 if (backend_status
== CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN
) {
380 cairo_int_status_t backend_source_status
= CAIRO_STATUS_SUCCESS
;
381 cairo_int_status_t backend_mask_status
= CAIRO_STATUS_SUCCESS
;
383 if (source
->type
== CAIRO_PATTERN_TYPE_SURFACE
) {
384 cairo_surface_pattern_t
*surface_pattern
= (cairo_surface_pattern_t
*) source
;
385 if (_cairo_surface_is_meta (surface_pattern
->surface
)) {
386 backend_source_status
=
387 _analyze_meta_surface_pattern (surface
, source
);
388 if (_cairo_status_is_error (backend_source_status
))
389 return backend_source_status
;
393 if (mask
->type
== CAIRO_PATTERN_TYPE_SURFACE
) {
394 cairo_surface_pattern_t
*surface_pattern
= (cairo_surface_pattern_t
*) mask
;
395 if (_cairo_surface_is_meta (surface_pattern
->surface
)) {
396 backend_mask_status
=
397 _analyze_meta_surface_pattern (surface
, mask
);
398 if (_cairo_status_is_error (backend_mask_status
))
399 return backend_mask_status
;
404 _cairo_analysis_surface_merge_status (backend_source_status
,
405 backend_mask_status
);
408 status
= _cairo_surface_get_extents (&surface
->base
, &extents
);
409 if (status
&& status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
412 if (_cairo_operator_bounded_by_source (op
)) {
413 cairo_rectangle_int_t source_extents
;
414 status
= _cairo_pattern_get_extents (source
, &source_extents
);
418 is_empty
= _cairo_rectangle_intersect (&extents
, &source_extents
);
421 if (_cairo_operator_bounded_by_mask (op
)) {
422 cairo_rectangle_int_t mask_extents
;
424 status
= _cairo_pattern_get_extents (mask
, &mask_extents
);
428 is_empty
= _cairo_rectangle_intersect (&extents
, &mask_extents
);
431 is_empty
= _cairo_rectangle_intersect (&extents
, &surface
->current_clip
);
433 status
= _add_operation (surface
, &extents
, backend_status
);
438 static cairo_int_status_t
439 _cairo_analysis_surface_stroke (void *abstract_surface
,
441 cairo_pattern_t
*source
,
442 cairo_path_fixed_t
*path
,
443 cairo_stroke_style_t
*style
,
445 cairo_matrix_t
*ctm_inverse
,
447 cairo_antialias_t antialias
)
449 cairo_analysis_surface_t
*surface
= abstract_surface
;
450 cairo_status_t status
, backend_status
;
452 cairo_rectangle_int_t extents
;
453 cairo_bool_t is_empty
;
455 if (!surface
->target
->backend
->stroke
)
456 backend_status
= CAIRO_INT_STATUS_UNSUPPORTED
;
458 backend_status
= (*surface
->target
->backend
->stroke
) (surface
->target
, op
,
461 tolerance
, antialias
);
463 if (backend_status
== CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN
)
464 backend_status
= _analyze_meta_surface_pattern (surface
, source
);
466 status
= _cairo_surface_get_extents (&surface
->base
, &extents
);
467 if (status
&& status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
470 if (_cairo_operator_bounded_by_source (op
)) {
471 cairo_rectangle_int_t source_extents
;
473 status
= _cairo_pattern_get_extents (source
, &source_extents
);
477 is_empty
= _cairo_rectangle_intersect (&extents
, &source_extents
);
480 is_empty
= _cairo_rectangle_intersect (&extents
, &surface
->current_clip
);
482 if (_cairo_operator_bounded_by_mask (op
)) {
485 _cairo_box_from_rectangle (&box
, &extents
);
487 _cairo_traps_init (&traps
);
488 _cairo_traps_limit (&traps
, &box
);
489 status
= _cairo_path_fixed_stroke_to_traps (path
,
495 _cairo_traps_fini (&traps
);
499 _cairo_traps_extents (&traps
, &box
);
500 _cairo_traps_fini (&traps
);
502 _cairo_box_round_to_rectangle (&box
, &extents
);
505 status
= _add_operation (surface
, &extents
, backend_status
);
510 static cairo_int_status_t
511 _cairo_analysis_surface_fill (void *abstract_surface
,
513 cairo_pattern_t
*source
,
514 cairo_path_fixed_t
*path
,
515 cairo_fill_rule_t fill_rule
,
517 cairo_antialias_t antialias
)
519 cairo_analysis_surface_t
*surface
= abstract_surface
;
520 cairo_status_t status
, backend_status
;
522 cairo_rectangle_int_t extents
;
523 cairo_bool_t is_empty
;
525 if (!surface
->target
->backend
->fill
)
526 backend_status
= CAIRO_INT_STATUS_UNSUPPORTED
;
528 backend_status
= (*surface
->target
->backend
->fill
) (surface
->target
, op
,
529 source
, path
, fill_rule
,
530 tolerance
, antialias
);
532 if (backend_status
== CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN
)
533 backend_status
= _analyze_meta_surface_pattern (surface
, source
);
535 status
= _cairo_surface_get_extents (&surface
->base
, &extents
);
536 if (status
&& status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
539 if (_cairo_operator_bounded_by_source (op
)) {
540 cairo_rectangle_int_t source_extents
;
542 status
= _cairo_pattern_get_extents (source
, &source_extents
);
546 is_empty
= _cairo_rectangle_intersect (&extents
, &source_extents
);
549 is_empty
= _cairo_rectangle_intersect (&extents
, &surface
->current_clip
);
551 if (_cairo_operator_bounded_by_mask (op
)) {
554 _cairo_box_from_rectangle (&box
, &extents
);
556 _cairo_traps_init (&traps
);
557 _cairo_traps_limit (&traps
, &box
);
558 status
= _cairo_path_fixed_fill_to_traps (path
,
563 _cairo_traps_fini (&traps
);
567 _cairo_traps_extents (&traps
, &box
);
568 _cairo_traps_fini (&traps
);
570 _cairo_box_round_to_rectangle (&box
, &extents
);
573 status
= _add_operation (surface
, &extents
, backend_status
);
578 static cairo_int_status_t
579 _cairo_analysis_surface_show_glyphs (void *abstract_surface
,
581 cairo_pattern_t
*source
,
582 cairo_glyph_t
*glyphs
,
584 cairo_scaled_font_t
*scaled_font
,
585 int *remaining_glyphs
)
587 cairo_analysis_surface_t
*surface
= abstract_surface
;
588 cairo_status_t status
, backend_status
;
589 cairo_rectangle_int_t extents
, glyph_extents
;
590 cairo_bool_t is_empty
;
592 /* Adapted from _cairo_surface_show_glyphs */
593 if (surface
->target
->backend
->show_glyphs
)
594 backend_status
= (*surface
->target
->backend
->show_glyphs
) (surface
->target
, op
,
599 else if (surface
->target
->backend
->show_text_glyphs
)
600 backend_status
= surface
->target
->backend
->show_text_glyphs (surface
->target
, op
,
608 backend_status
= CAIRO_INT_STATUS_UNSUPPORTED
;
610 if (backend_status
== CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN
)
611 backend_status
= _analyze_meta_surface_pattern (surface
, source
);
613 status
= _cairo_surface_get_extents (&surface
->base
, &extents
);
614 if (status
&& status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
617 if (_cairo_operator_bounded_by_source (op
)) {
618 cairo_rectangle_int_t source_extents
;
620 status
= _cairo_pattern_get_extents (source
, &source_extents
);
624 is_empty
= _cairo_rectangle_intersect (&extents
, &source_extents
);
627 is_empty
= _cairo_rectangle_intersect (&extents
, &surface
->current_clip
);
629 if (_cairo_operator_bounded_by_mask (op
)) {
630 status
= _cairo_scaled_font_glyph_device_extents (scaled_font
,
637 is_empty
= _cairo_rectangle_intersect (&extents
, &glyph_extents
);
640 status
= _add_operation (surface
, &extents
, backend_status
);
646 _cairo_analysis_surface_has_show_text_glyphs (void *abstract_surface
)
648 cairo_analysis_surface_t
*surface
= abstract_surface
;
650 return cairo_surface_has_show_text_glyphs (surface
->target
);
653 static cairo_int_status_t
654 _cairo_analysis_surface_show_text_glyphs (void *abstract_surface
,
656 cairo_pattern_t
*source
,
659 cairo_glyph_t
*glyphs
,
661 const cairo_text_cluster_t
*clusters
,
663 cairo_text_cluster_flags_t cluster_flags
,
664 cairo_scaled_font_t
*scaled_font
)
666 cairo_analysis_surface_t
*surface
= abstract_surface
;
667 cairo_status_t status
, backend_status
;
668 cairo_rectangle_int_t extents
, glyph_extents
;
669 cairo_bool_t is_empty
;
671 /* Adapted from _cairo_surface_show_glyphs */
672 backend_status
= CAIRO_INT_STATUS_UNSUPPORTED
;
673 if (surface
->target
->backend
->show_text_glyphs
)
674 backend_status
= surface
->target
->backend
->show_text_glyphs (surface
->target
, op
,
678 clusters
, num_clusters
, cluster_flags
,
680 if (backend_status
== CAIRO_INT_STATUS_UNSUPPORTED
&& surface
->target
->backend
->show_glyphs
) {
681 int remaining_glyphs
= num_glyphs
;
682 backend_status
= surface
->target
->backend
->show_glyphs (surface
->target
, op
,
687 glyphs
+= num_glyphs
- remaining_glyphs
;
688 num_glyphs
= remaining_glyphs
;
689 if (remaining_glyphs
== 0)
690 backend_status
= CAIRO_STATUS_SUCCESS
;
693 if (backend_status
== CAIRO_INT_STATUS_ANALYZE_META_SURFACE_PATTERN
)
694 backend_status
= _analyze_meta_surface_pattern (surface
, source
);
696 status
= _cairo_surface_get_extents (&surface
->base
, &extents
);
697 if (status
&& status
!= CAIRO_INT_STATUS_UNSUPPORTED
)
700 if (_cairo_operator_bounded_by_source (op
)) {
701 cairo_rectangle_int_t source_extents
;
703 status
= _cairo_pattern_get_extents (source
, &source_extents
);
707 is_empty
= _cairo_rectangle_intersect (&extents
, &source_extents
);
710 is_empty
= _cairo_rectangle_intersect (&extents
, &surface
->current_clip
);
712 if (_cairo_operator_bounded_by_mask (op
)) {
713 status
= _cairo_scaled_font_glyph_device_extents (scaled_font
,
720 is_empty
= _cairo_rectangle_intersect (&extents
, &glyph_extents
);
723 status
= _add_operation (surface
, &extents
, backend_status
);
728 static const cairo_surface_backend_t cairo_analysis_surface_backend
= {
729 CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS
,
730 NULL
, /* create_similar */
731 _cairo_analysis_surface_finish
,
732 NULL
, /* acquire_source_image */
733 NULL
, /* release_source_image */
734 NULL
, /* acquire_dest_image */
735 NULL
, /* release_dest_image */
736 NULL
, /* clone_similar */
737 NULL
, /* composite */
738 NULL
, /* fill_rectangles */
739 NULL
, /* composite_trapezoids */
740 NULL
, /* copy_page */
741 NULL
, /* show_page */
742 NULL
, /* set_clip_region */
743 _cairo_analysis_surface_intersect_clip_path
,
744 _cairo_analysis_surface_get_extents
,
745 NULL
, /* old_show_glyphs */
746 NULL
, /* get_font_options */
748 NULL
, /* mark_dirty_rectangle */
749 NULL
, /* scaled_font_fini */
750 NULL
, /* scaled_glyph_fini */
751 _cairo_analysis_surface_paint
,
752 _cairo_analysis_surface_mask
,
753 _cairo_analysis_surface_stroke
,
754 _cairo_analysis_surface_fill
,
755 _cairo_analysis_surface_show_glyphs
,
757 NULL
, /* is_similar */
759 NULL
, /* fill_stroke */
760 NULL
, /* create_solid_pattern_surface */
761 _cairo_analysis_surface_has_show_text_glyphs
,
762 _cairo_analysis_surface_show_text_glyphs
766 _cairo_analysis_surface_create (cairo_surface_t
*target
,
770 cairo_analysis_surface_t
*surface
;
771 cairo_status_t status
;
773 status
= target
->status
;
775 return _cairo_surface_create_in_error (status
);
777 surface
= malloc (sizeof (cairo_analysis_surface_t
));
779 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
781 /* I believe the content type here is truly arbitrary. I'm quite
782 * sure nothing will ever use this value. */
783 _cairo_surface_init (&surface
->base
, &cairo_analysis_surface_backend
,
784 CAIRO_CONTENT_COLOR_ALPHA
);
786 surface
->width
= width
;
787 surface
->height
= height
;
788 cairo_matrix_init_identity (&surface
->ctm
);
789 surface
->has_ctm
= FALSE
;
791 surface
->target
= cairo_surface_reference (target
);
792 surface
->first_op
= TRUE
;
793 surface
->has_supported
= FALSE
;
794 surface
->has_unsupported
= FALSE
;
796 surface
->page_bbox
.p1
.x
= 0;
797 surface
->page_bbox
.p1
.y
= 0;
798 surface
->page_bbox
.p2
.x
= 0;
799 surface
->page_bbox
.p2
.y
= 0;
801 _cairo_region_init (&surface
->supported_region
);
802 _cairo_region_init (&surface
->fallback_region
);
804 if (width
== -1 && height
== -1) {
805 surface
->current_clip
.x
= CAIRO_RECT_INT_MIN
;
806 surface
->current_clip
.y
= CAIRO_RECT_INT_MIN
;
807 surface
->current_clip
.width
= CAIRO_RECT_INT_MAX
- CAIRO_RECT_INT_MIN
;
808 surface
->current_clip
.height
= CAIRO_RECT_INT_MAX
- CAIRO_RECT_INT_MIN
;
810 surface
->current_clip
.x
= 0;
811 surface
->current_clip
.y
= 0;
812 surface
->current_clip
.width
= width
;
813 surface
->current_clip
.height
= height
;
816 return &surface
->base
;
820 _cairo_analysis_surface_set_ctm (cairo_surface_t
*abstract_surface
,
823 cairo_analysis_surface_t
*surface
;
825 if (abstract_surface
->status
)
828 surface
= (cairo_analysis_surface_t
*) abstract_surface
;
831 surface
->has_ctm
= !_cairo_matrix_is_identity (&surface
->ctm
);
835 _cairo_analysis_surface_get_ctm (cairo_surface_t
*abstract_surface
,
838 cairo_analysis_surface_t
*surface
= (cairo_analysis_surface_t
*) abstract_surface
;
845 _cairo_analysis_surface_get_supported (cairo_surface_t
*abstract_surface
)
847 cairo_analysis_surface_t
*surface
= (cairo_analysis_surface_t
*) abstract_surface
;
849 return &surface
->supported_region
;
853 _cairo_analysis_surface_get_unsupported (cairo_surface_t
*abstract_surface
)
855 cairo_analysis_surface_t
*surface
= (cairo_analysis_surface_t
*) abstract_surface
;
857 return &surface
->fallback_region
;
861 _cairo_analysis_surface_has_supported (cairo_surface_t
*abstract_surface
)
863 cairo_analysis_surface_t
*surface
= (cairo_analysis_surface_t
*) abstract_surface
;
865 return surface
->has_supported
;
869 _cairo_analysis_surface_has_unsupported (cairo_surface_t
*abstract_surface
)
871 cairo_analysis_surface_t
*surface
= (cairo_analysis_surface_t
*) abstract_surface
;
873 return surface
->has_unsupported
;
877 _cairo_analysis_surface_get_bounding_box (cairo_surface_t
*abstract_surface
,
880 cairo_analysis_surface_t
*surface
= (cairo_analysis_surface_t
*) abstract_surface
;
882 *bbox
= surface
->page_bbox
;
885 /* null surface type: a surface that does nothing (has no side effects, yay!) */
887 static cairo_int_status_t
888 _return_success (void)
890 return CAIRO_STATUS_SUCCESS
;
893 /* These typedefs are just to silence the compiler... */
894 typedef cairo_int_status_t
895 (*_set_clip_region_func
) (void *surface
,
896 cairo_region_t
*region
);
897 typedef cairo_int_status_t
898 (*_paint_func
) (void *surface
,
900 cairo_pattern_t
*source
);
902 typedef cairo_int_status_t
903 (*_mask_func
) (void *surface
,
905 cairo_pattern_t
*source
,
906 cairo_pattern_t
*mask
);
908 typedef cairo_int_status_t
909 (*_stroke_func
) (void *surface
,
911 cairo_pattern_t
*source
,
912 cairo_path_fixed_t
*path
,
913 cairo_stroke_style_t
*style
,
915 cairo_matrix_t
*ctm_inverse
,
917 cairo_antialias_t antialias
);
919 typedef cairo_int_status_t
920 (*_fill_func
) (void *surface
,
922 cairo_pattern_t
*source
,
923 cairo_path_fixed_t
*path
,
924 cairo_fill_rule_t fill_rule
,
926 cairo_antialias_t antialias
);
928 typedef cairo_int_status_t
929 (*_show_glyphs_func
) (void *surface
,
931 cairo_pattern_t
*source
,
932 cairo_glyph_t
*glyphs
,
934 cairo_scaled_font_t
*scaled_font
,
935 int *remaining_glyphs
);
937 static const cairo_surface_backend_t cairo_null_surface_backend
= {
938 CAIRO_INTERNAL_SURFACE_TYPE_NULL
,
940 NULL
, /* create_similar */
942 NULL
, /* acquire_source_image */
943 NULL
, /* release_source_image */
944 NULL
, /* acquire_dest_image */
945 NULL
, /* release_dest_image */
946 NULL
, /* clone_similar */
947 NULL
, /* composite */
948 NULL
, /* fill_rectangles */
949 NULL
, /* composite_trapezoids */
950 NULL
, /* copy_page */
951 NULL
, /* show_page */
952 (_set_clip_region_func
) _return_success
, /* set_clip_region */
953 NULL
, /* intersect_clip_path */
954 NULL
, /* get_extents */
955 NULL
, /* old_show_glyphs */
956 NULL
, /* get_font_options */
958 NULL
, /* mark_dirty_rectangle */
959 NULL
, /* scaled_font_fini */
960 NULL
, /* scaled_glyph_fini */
961 (_paint_func
) _return_success
, /* paint */
962 (_mask_func
) _return_success
, /* mask */
963 (_stroke_func
) _return_success
, /* stroke */
964 (_fill_func
) _return_success
, /* fill */
965 (_show_glyphs_func
) _return_success
, /* show_glyphs */
967 NULL
, /* is_similar */
969 NULL
, /* fill_stroke */
970 NULL
, /* create_solid_pattern_surface */
971 NULL
, /* has_show_text_glyphs */
972 NULL
/* show_text_glyphs */
976 _cairo_null_surface_create (cairo_content_t content
)
978 cairo_surface_t
*surface
;
980 surface
= malloc (sizeof (cairo_surface_t
));
981 if (surface
== NULL
) {
982 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
985 _cairo_surface_init (surface
, &cairo_null_surface_backend
, content
);