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., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, 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-box-inline.h"
41 #include "cairo-default-context-private.h"
42 #include "cairo-error-private.h"
43 #include "cairo-paginated-private.h"
44 #include "cairo-recording-surface-inline.h"
45 #include "cairo-surface-snapshot-inline.h"
46 #include "cairo-surface-subsurface-inline.h"
47 #include "cairo-region-private.h"
52 cairo_surface_t
*target
;
54 cairo_bool_t first_op
;
55 cairo_bool_t has_supported
;
56 cairo_bool_t has_unsupported
;
58 cairo_region_t supported_region
;
59 cairo_region_t fallback_region
;
60 cairo_box_t page_bbox
;
65 } cairo_analysis_surface_t
;
68 _cairo_analysis_surface_merge_status (cairo_int_status_t status_a
,
69 cairo_int_status_t status_b
)
71 /* fatal errors should be checked and propagated at source */
72 assert (! _cairo_int_status_is_error (status_a
));
73 assert (! _cairo_int_status_is_error (status_b
));
75 /* return the most important status */
76 if (status_a
== CAIRO_INT_STATUS_UNSUPPORTED
||
77 status_b
== CAIRO_INT_STATUS_UNSUPPORTED
)
78 return CAIRO_INT_STATUS_UNSUPPORTED
;
80 if (status_a
== CAIRO_INT_STATUS_IMAGE_FALLBACK
||
81 status_b
== CAIRO_INT_STATUS_IMAGE_FALLBACK
)
82 return CAIRO_INT_STATUS_IMAGE_FALLBACK
;
84 if (status_a
== CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN
||
85 status_b
== CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN
)
86 return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN
;
88 if (status_a
== CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY
||
89 status_b
== CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY
)
90 return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY
;
92 /* at this point we have checked all the valid internal codes, so... */
93 assert (status_a
== CAIRO_INT_STATUS_SUCCESS
&&
94 status_b
== CAIRO_INT_STATUS_SUCCESS
);
96 return CAIRO_INT_STATUS_SUCCESS
;
100 cairo_surface_t base
;
101 cairo_surface_t
*target
;
104 static cairo_status_t
105 proxy_finish (void *abstract_surface
)
107 return CAIRO_STATUS_SUCCESS
;
110 static const cairo_surface_backend_t proxy_backend
= {
111 CAIRO_INTERNAL_SURFACE_TYPE_NULL
,
115 static cairo_surface_t
*
116 attach_proxy (cairo_surface_t
*source
,
117 cairo_surface_t
*target
)
121 proxy
= malloc (sizeof (*proxy
));
122 if (unlikely (proxy
== NULL
))
123 return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY
);
125 _cairo_surface_init (&proxy
->base
, &proxy_backend
, NULL
, target
->content
);
127 proxy
->target
= target
;
128 _cairo_surface_attach_snapshot (source
, &proxy
->base
, NULL
);
134 detach_proxy (cairo_surface_t
*proxy
)
136 cairo_surface_finish (proxy
);
137 cairo_surface_destroy (proxy
);
140 static cairo_int_status_t
141 _analyze_recording_surface_pattern (cairo_analysis_surface_t
*surface
,
142 const cairo_pattern_t
*pattern
)
144 const cairo_surface_pattern_t
*surface_pattern
;
145 cairo_analysis_surface_t
*tmp
;
146 cairo_surface_t
*source
, *proxy
;
148 cairo_status_t status
, analysis_status
;
150 assert (pattern
->type
== CAIRO_PATTERN_TYPE_SURFACE
);
151 surface_pattern
= (const cairo_surface_pattern_t
*) pattern
;
152 assert (surface_pattern
->surface
->type
== CAIRO_SURFACE_TYPE_RECORDING
);
153 source
= surface_pattern
->surface
;
155 proxy
= _cairo_surface_has_snapshot (source
, &proxy_backend
);
157 /* nothing untoward found so far */
158 return CAIRO_STATUS_SUCCESS
;
161 tmp
= (cairo_analysis_surface_t
*)
162 _cairo_analysis_surface_create (surface
->target
);
163 if (unlikely (tmp
->base
.status
))
164 return tmp
->base
.status
;
165 proxy
= attach_proxy (source
, &tmp
->base
);
167 p2d
= pattern
->matrix
;
168 status
= cairo_matrix_invert (&p2d
);
169 assert (status
== CAIRO_STATUS_SUCCESS
);
171 cairo_matrix_multiply (&tmp
->ctm
, &p2d
, &surface
->ctm
);
172 tmp
->has_ctm
= ! _cairo_matrix_is_identity (&tmp
->ctm
);
174 source
= _cairo_surface_get_source (source
, NULL
);
175 status
= _cairo_recording_surface_replay_and_create_regions (source
,
177 analysis_status
= tmp
->has_unsupported
? CAIRO_INT_STATUS_IMAGE_FALLBACK
: CAIRO_INT_STATUS_SUCCESS
;
178 detach_proxy (proxy
);
179 cairo_surface_destroy (&tmp
->base
);
181 if (unlikely (status
))
184 return analysis_status
;
187 static cairo_int_status_t
188 _add_operation (cairo_analysis_surface_t
*surface
,
189 cairo_rectangle_int_t
*rect
,
190 cairo_int_status_t backend_status
)
192 cairo_int_status_t status
;
195 if (rect
->width
== 0 || rect
->height
== 0) {
196 /* Even though the operation is not visible we must be careful
197 * to not allow unsupported operations to be replayed to the
198 * backend during CAIRO_PAGINATED_MODE_RENDER */
199 if (backend_status
== CAIRO_INT_STATUS_SUCCESS
||
200 backend_status
== CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY
||
201 backend_status
== CAIRO_INT_STATUS_NOTHING_TO_DO
)
203 return CAIRO_INT_STATUS_SUCCESS
;
207 return CAIRO_INT_STATUS_IMAGE_FALLBACK
;
211 _cairo_box_from_rectangle (&bbox
, rect
);
213 if (surface
->has_ctm
) {
216 if (_cairo_matrix_is_integer_translation (&surface
->ctm
, &tx
, &ty
)) {
220 tx
= _cairo_fixed_from_int (tx
);
224 ty
= _cairo_fixed_from_int (ty
);
228 _cairo_matrix_transform_bounding_box_fixed (&surface
->ctm
,
231 if (bbox
.p1
.x
== bbox
.p2
.x
|| bbox
.p1
.y
== bbox
.p2
.y
) {
232 /* Even though the operation is not visible we must be
233 * careful to not allow unsupported operations to be
234 * replayed to the backend during
235 * CAIRO_PAGINATED_MODE_RENDER */
236 if (backend_status
== CAIRO_INT_STATUS_SUCCESS
||
237 backend_status
== CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY
||
238 backend_status
== CAIRO_INT_STATUS_NOTHING_TO_DO
)
240 return CAIRO_INT_STATUS_SUCCESS
;
244 return CAIRO_INT_STATUS_IMAGE_FALLBACK
;
248 _cairo_box_round_to_rectangle (&bbox
, rect
);
252 if (surface
->first_op
) {
253 surface
->first_op
= FALSE
;
254 surface
->page_bbox
= bbox
;
256 _cairo_box_add_box(&surface
->page_bbox
, &bbox
);
258 /* If the operation is completely enclosed within the fallback
259 * region there is no benefit in emitting a native operation as
260 * the fallback image will be painted on top.
262 if (cairo_region_contains_rectangle (&surface
->fallback_region
, rect
) == CAIRO_REGION_OVERLAP_IN
)
263 return CAIRO_INT_STATUS_IMAGE_FALLBACK
;
265 if (backend_status
== CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY
) {
266 /* A status of CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY indicates
267 * that the backend only supports this operation if the
268 * transparency removed. If the extents of this operation does
269 * not intersect any other native operation, the operation is
270 * natively supported and the backend will blend the
271 * transparency into the white background.
273 if (cairo_region_contains_rectangle (&surface
->supported_region
, rect
) == CAIRO_REGION_OVERLAP_OUT
)
274 backend_status
= CAIRO_INT_STATUS_SUCCESS
;
277 if (backend_status
== CAIRO_INT_STATUS_SUCCESS
) {
278 /* Add the operation to the supported region. Operations in
279 * this region will be emitted as native operations.
281 surface
->has_supported
= TRUE
;
282 return cairo_region_union_rectangle (&surface
->supported_region
, rect
);
285 /* Add the operation to the unsupported region. This region will
286 * be painted as an image after all native operations have been
289 surface
->has_unsupported
= TRUE
;
290 status
= cairo_region_union_rectangle (&surface
->fallback_region
, rect
);
292 /* The status CAIRO_INT_STATUS_IMAGE_FALLBACK is used to indicate
293 * unsupported operations to the recording surface as using
294 * CAIRO_INT_STATUS_UNSUPPORTED would cause cairo-surface to
295 * invoke the cairo-surface-fallback path then return
296 * CAIRO_STATUS_SUCCESS.
298 if (status
== CAIRO_INT_STATUS_SUCCESS
)
299 return CAIRO_INT_STATUS_IMAGE_FALLBACK
;
304 static cairo_status_t
305 _cairo_analysis_surface_finish (void *abstract_surface
)
307 cairo_analysis_surface_t
*surface
= (cairo_analysis_surface_t
*) abstract_surface
;
309 _cairo_region_fini (&surface
->supported_region
);
310 _cairo_region_fini (&surface
->fallback_region
);
312 cairo_surface_destroy (surface
->target
);
314 return CAIRO_STATUS_SUCCESS
;
318 _cairo_analysis_surface_get_extents (void *abstract_surface
,
319 cairo_rectangle_int_t
*rectangle
)
321 cairo_analysis_surface_t
*surface
= abstract_surface
;
323 return _cairo_surface_get_extents (surface
->target
, rectangle
);
327 _rectangle_intersect_clip (cairo_rectangle_int_t
*extents
, const cairo_clip_t
*clip
)
330 _cairo_rectangle_intersect (extents
, _cairo_clip_get_extents (clip
));
334 _cairo_analysis_surface_operation_extents (cairo_analysis_surface_t
*surface
,
336 const cairo_pattern_t
*source
,
337 const cairo_clip_t
*clip
,
338 cairo_rectangle_int_t
*extents
)
340 cairo_bool_t is_empty
;
342 is_empty
= _cairo_surface_get_extents (&surface
->base
, extents
);
344 if (_cairo_operator_bounded_by_source (op
)) {
345 cairo_rectangle_int_t source_extents
;
347 _cairo_pattern_get_extents (source
, &source_extents
);
348 _cairo_rectangle_intersect (extents
, &source_extents
);
351 _rectangle_intersect_clip (extents
, clip
);
354 static cairo_int_status_t
355 _cairo_analysis_surface_paint (void *abstract_surface
,
357 const cairo_pattern_t
*source
,
358 const cairo_clip_t
*clip
)
360 cairo_analysis_surface_t
*surface
= abstract_surface
;
361 cairo_int_status_t backend_status
;
362 cairo_rectangle_int_t extents
;
364 if (surface
->target
->backend
->paint
== NULL
) {
365 backend_status
= CAIRO_INT_STATUS_UNSUPPORTED
;
368 surface
->target
->backend
->paint (surface
->target
,
370 if (_cairo_int_status_is_error (backend_status
))
371 return backend_status
;
374 if (backend_status
== CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN
)
375 backend_status
= _analyze_recording_surface_pattern (surface
, source
);
377 _cairo_analysis_surface_operation_extents (surface
,
381 return _add_operation (surface
, &extents
, backend_status
);
384 static cairo_int_status_t
385 _cairo_analysis_surface_mask (void *abstract_surface
,
387 const cairo_pattern_t
*source
,
388 const cairo_pattern_t
*mask
,
389 const cairo_clip_t
*clip
)
391 cairo_analysis_surface_t
*surface
= abstract_surface
;
392 cairo_int_status_t backend_status
;
393 cairo_rectangle_int_t extents
;
395 if (surface
->target
->backend
->mask
== NULL
) {
396 backend_status
= CAIRO_INT_STATUS_UNSUPPORTED
;
399 surface
->target
->backend
->mask (surface
->target
,
400 op
, source
, mask
, clip
);
401 if (_cairo_int_status_is_error (backend_status
))
402 return backend_status
;
405 if (backend_status
== CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN
) {
406 cairo_int_status_t backend_source_status
= CAIRO_STATUS_SUCCESS
;
407 cairo_int_status_t backend_mask_status
= CAIRO_STATUS_SUCCESS
;
409 if (source
->type
== CAIRO_PATTERN_TYPE_SURFACE
) {
410 cairo_surface_t
*src_surface
= ((cairo_surface_pattern_t
*)source
)->surface
;
411 src_surface
= _cairo_surface_get_source (src_surface
, NULL
);
412 if (_cairo_surface_is_recording (src_surface
)) {
413 backend_source_status
=
414 _analyze_recording_surface_pattern (surface
, source
);
415 if (_cairo_int_status_is_error (backend_source_status
))
416 return backend_source_status
;
420 if (mask
->type
== CAIRO_PATTERN_TYPE_SURFACE
) {
421 cairo_surface_t
*mask_surface
= ((cairo_surface_pattern_t
*)mask
)->surface
;
422 mask_surface
= _cairo_surface_get_source (mask_surface
, NULL
);
423 if (_cairo_surface_is_recording (mask_surface
)) {
424 backend_mask_status
=
425 _analyze_recording_surface_pattern (surface
, mask
);
426 if (_cairo_int_status_is_error (backend_mask_status
))
427 return backend_mask_status
;
432 _cairo_analysis_surface_merge_status (backend_source_status
,
433 backend_mask_status
);
436 _cairo_analysis_surface_operation_extents (surface
,
440 if (_cairo_operator_bounded_by_mask (op
)) {
441 cairo_rectangle_int_t mask_extents
;
443 _cairo_pattern_get_extents (mask
, &mask_extents
);
444 _cairo_rectangle_intersect (&extents
, &mask_extents
);
447 return _add_operation (surface
, &extents
, backend_status
);
450 static cairo_int_status_t
451 _cairo_analysis_surface_stroke (void *abstract_surface
,
453 const cairo_pattern_t
*source
,
454 const cairo_path_fixed_t
*path
,
455 const cairo_stroke_style_t
*style
,
456 const cairo_matrix_t
*ctm
,
457 const cairo_matrix_t
*ctm_inverse
,
459 cairo_antialias_t antialias
,
460 const cairo_clip_t
*clip
)
462 cairo_analysis_surface_t
*surface
= abstract_surface
;
463 cairo_int_status_t backend_status
;
464 cairo_rectangle_int_t extents
;
466 if (surface
->target
->backend
->stroke
== NULL
) {
467 backend_status
= CAIRO_INT_STATUS_UNSUPPORTED
;
470 surface
->target
->backend
->stroke (surface
->target
, op
,
473 tolerance
, antialias
,
475 if (_cairo_int_status_is_error (backend_status
))
476 return backend_status
;
479 if (backend_status
== CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN
)
480 backend_status
= _analyze_recording_surface_pattern (surface
, source
);
482 _cairo_analysis_surface_operation_extents (surface
,
486 if (_cairo_operator_bounded_by_mask (op
)) {
487 cairo_rectangle_int_t mask_extents
;
488 cairo_int_status_t status
;
490 status
= _cairo_path_fixed_stroke_extents (path
, style
,
494 if (unlikely (status
))
497 _cairo_rectangle_intersect (&extents
, &mask_extents
);
500 return _add_operation (surface
, &extents
, backend_status
);
503 static cairo_int_status_t
504 _cairo_analysis_surface_fill (void *abstract_surface
,
506 const cairo_pattern_t
*source
,
507 const cairo_path_fixed_t
*path
,
508 cairo_fill_rule_t fill_rule
,
510 cairo_antialias_t antialias
,
511 const cairo_clip_t
*clip
)
513 cairo_analysis_surface_t
*surface
= abstract_surface
;
514 cairo_int_status_t backend_status
;
515 cairo_rectangle_int_t extents
;
517 if (surface
->target
->backend
->fill
== NULL
) {
518 backend_status
= CAIRO_INT_STATUS_UNSUPPORTED
;
521 surface
->target
->backend
->fill (surface
->target
, op
,
522 source
, path
, fill_rule
,
523 tolerance
, antialias
,
525 if (_cairo_int_status_is_error (backend_status
))
526 return backend_status
;
529 if (backend_status
== CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN
)
530 backend_status
= _analyze_recording_surface_pattern (surface
, source
);
532 _cairo_analysis_surface_operation_extents (surface
,
536 if (_cairo_operator_bounded_by_mask (op
)) {
537 cairo_rectangle_int_t mask_extents
;
539 _cairo_path_fixed_fill_extents (path
, fill_rule
, tolerance
,
542 _cairo_rectangle_intersect (&extents
, &mask_extents
);
545 return _add_operation (surface
, &extents
, backend_status
);
548 static cairo_int_status_t
549 _cairo_analysis_surface_show_glyphs (void *abstract_surface
,
551 const cairo_pattern_t
*source
,
552 cairo_glyph_t
*glyphs
,
554 cairo_scaled_font_t
*scaled_font
,
555 const cairo_clip_t
*clip
)
557 cairo_analysis_surface_t
*surface
= abstract_surface
;
558 cairo_int_status_t status
, backend_status
;
559 cairo_rectangle_int_t extents
, glyph_extents
;
561 /* Adapted from _cairo_surface_show_glyphs */
562 if (surface
->target
->backend
->show_glyphs
!= NULL
) {
564 surface
->target
->backend
->show_glyphs (surface
->target
, op
,
569 if (_cairo_int_status_is_error (backend_status
))
570 return backend_status
;
572 else if (surface
->target
->backend
->show_text_glyphs
!= NULL
)
575 surface
->target
->backend
->show_text_glyphs (surface
->target
, op
,
583 if (_cairo_int_status_is_error (backend_status
))
584 return backend_status
;
588 backend_status
= CAIRO_INT_STATUS_UNSUPPORTED
;
591 if (backend_status
== CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN
)
592 backend_status
= _analyze_recording_surface_pattern (surface
, source
);
594 _cairo_analysis_surface_operation_extents (surface
,
598 if (_cairo_operator_bounded_by_mask (op
)) {
599 status
= _cairo_scaled_font_glyph_device_extents (scaled_font
,
604 if (unlikely (status
))
607 _cairo_rectangle_intersect (&extents
, &glyph_extents
);
610 return _add_operation (surface
, &extents
, backend_status
);
614 _cairo_analysis_surface_has_show_text_glyphs (void *abstract_surface
)
616 cairo_analysis_surface_t
*surface
= abstract_surface
;
618 return cairo_surface_has_show_text_glyphs (surface
->target
);
621 static cairo_int_status_t
622 _cairo_analysis_surface_show_text_glyphs (void *abstract_surface
,
624 const cairo_pattern_t
*source
,
627 cairo_glyph_t
*glyphs
,
629 const cairo_text_cluster_t
*clusters
,
631 cairo_text_cluster_flags_t cluster_flags
,
632 cairo_scaled_font_t
*scaled_font
,
633 const cairo_clip_t
*clip
)
635 cairo_analysis_surface_t
*surface
= abstract_surface
;
636 cairo_int_status_t status
, backend_status
;
637 cairo_rectangle_int_t extents
, glyph_extents
;
639 /* Adapted from _cairo_surface_show_glyphs */
640 backend_status
= CAIRO_INT_STATUS_UNSUPPORTED
;
641 if (surface
->target
->backend
->show_text_glyphs
!= NULL
) {
643 surface
->target
->backend
->show_text_glyphs (surface
->target
, op
,
647 clusters
, num_clusters
,
651 if (_cairo_int_status_is_error (backend_status
))
652 return backend_status
;
654 if (backend_status
== CAIRO_INT_STATUS_UNSUPPORTED
&&
655 surface
->target
->backend
->show_glyphs
!= NULL
)
658 surface
->target
->backend
->show_glyphs (surface
->target
, op
,
663 if (_cairo_int_status_is_error (backend_status
))
664 return backend_status
;
667 if (backend_status
== CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN
)
668 backend_status
= _analyze_recording_surface_pattern (surface
, source
);
670 _cairo_analysis_surface_operation_extents (surface
,
674 if (_cairo_operator_bounded_by_mask (op
)) {
675 status
= _cairo_scaled_font_glyph_device_extents (scaled_font
,
680 if (unlikely (status
))
683 _cairo_rectangle_intersect (&extents
, &glyph_extents
);
686 return _add_operation (surface
, &extents
, backend_status
);
689 static const cairo_surface_backend_t cairo_analysis_surface_backend
= {
690 CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS
,
692 _cairo_analysis_surface_finish
,
695 NULL
, /* create_similar */
696 NULL
, /* create_similar_image */
697 NULL
, /* map_to_image */
701 NULL
, /* acquire_source_image */
702 NULL
, /* release_source_image */
705 NULL
, /* copy_page */
706 NULL
, /* show_page */
708 _cairo_analysis_surface_get_extents
,
709 NULL
, /* get_font_options */
712 NULL
, /* mark_dirty_rectangle */
714 _cairo_analysis_surface_paint
,
715 _cairo_analysis_surface_mask
,
716 _cairo_analysis_surface_stroke
,
717 _cairo_analysis_surface_fill
,
718 NULL
, /* fill_stroke */
719 _cairo_analysis_surface_show_glyphs
,
720 _cairo_analysis_surface_has_show_text_glyphs
,
721 _cairo_analysis_surface_show_text_glyphs
725 _cairo_analysis_surface_create (cairo_surface_t
*target
)
727 cairo_analysis_surface_t
*surface
;
728 cairo_status_t status
;
730 status
= target
->status
;
731 if (unlikely (status
))
732 return _cairo_surface_create_in_error (status
);
734 surface
= malloc (sizeof (cairo_analysis_surface_t
));
735 if (unlikely (surface
== NULL
))
736 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
738 /* I believe the content type here is truly arbitrary. I'm quite
739 * sure nothing will ever use this value. */
740 _cairo_surface_init (&surface
->base
,
741 &cairo_analysis_surface_backend
,
743 CAIRO_CONTENT_COLOR_ALPHA
);
745 cairo_matrix_init_identity (&surface
->ctm
);
746 surface
->has_ctm
= FALSE
;
748 surface
->target
= cairo_surface_reference (target
);
749 surface
->first_op
= TRUE
;
750 surface
->has_supported
= FALSE
;
751 surface
->has_unsupported
= FALSE
;
753 _cairo_region_init (&surface
->supported_region
);
754 _cairo_region_init (&surface
->fallback_region
);
756 surface
->page_bbox
.p1
.x
= 0;
757 surface
->page_bbox
.p1
.y
= 0;
758 surface
->page_bbox
.p2
.x
= 0;
759 surface
->page_bbox
.p2
.y
= 0;
761 return &surface
->base
;
765 _cairo_analysis_surface_set_ctm (cairo_surface_t
*abstract_surface
,
766 const cairo_matrix_t
*ctm
)
768 cairo_analysis_surface_t
*surface
;
770 if (abstract_surface
->status
)
773 surface
= (cairo_analysis_surface_t
*) abstract_surface
;
776 surface
->has_ctm
= ! _cairo_matrix_is_identity (&surface
->ctm
);
780 _cairo_analysis_surface_get_ctm (cairo_surface_t
*abstract_surface
,
783 cairo_analysis_surface_t
*surface
= (cairo_analysis_surface_t
*) abstract_surface
;
790 _cairo_analysis_surface_get_supported (cairo_surface_t
*abstract_surface
)
792 cairo_analysis_surface_t
*surface
= (cairo_analysis_surface_t
*) abstract_surface
;
794 return &surface
->supported_region
;
798 _cairo_analysis_surface_get_unsupported (cairo_surface_t
*abstract_surface
)
800 cairo_analysis_surface_t
*surface
= (cairo_analysis_surface_t
*) abstract_surface
;
802 return &surface
->fallback_region
;
806 _cairo_analysis_surface_has_supported (cairo_surface_t
*abstract_surface
)
808 cairo_analysis_surface_t
*surface
= (cairo_analysis_surface_t
*) abstract_surface
;
810 return surface
->has_supported
;
814 _cairo_analysis_surface_has_unsupported (cairo_surface_t
*abstract_surface
)
816 cairo_analysis_surface_t
*surface
= (cairo_analysis_surface_t
*) abstract_surface
;
818 return surface
->has_unsupported
;
822 _cairo_analysis_surface_get_bounding_box (cairo_surface_t
*abstract_surface
,
825 cairo_analysis_surface_t
*surface
= (cairo_analysis_surface_t
*) abstract_surface
;
827 *bbox
= surface
->page_bbox
;
830 /* null surface type: a surface that does nothing (has no side effects, yay!) */
832 static cairo_int_status_t
833 _return_success (void)
835 return CAIRO_STATUS_SUCCESS
;
838 /* These typedefs are just to silence the compiler... */
839 typedef cairo_int_status_t
840 (*_paint_func
) (void *surface
,
842 const cairo_pattern_t
*source
,
843 const cairo_clip_t
*clip
);
845 typedef cairo_int_status_t
846 (*_mask_func
) (void *surface
,
848 const cairo_pattern_t
*source
,
849 const cairo_pattern_t
*mask
,
850 const cairo_clip_t
*clip
);
852 typedef cairo_int_status_t
853 (*_stroke_func
) (void *surface
,
855 const cairo_pattern_t
*source
,
856 const cairo_path_fixed_t
*path
,
857 const cairo_stroke_style_t
*style
,
858 const cairo_matrix_t
*ctm
,
859 const cairo_matrix_t
*ctm_inverse
,
861 cairo_antialias_t antialias
,
862 const cairo_clip_t
*clip
);
864 typedef cairo_int_status_t
865 (*_fill_func
) (void *surface
,
867 const cairo_pattern_t
*source
,
868 const cairo_path_fixed_t
*path
,
869 cairo_fill_rule_t fill_rule
,
871 cairo_antialias_t antialias
,
872 const cairo_clip_t
*clip
);
874 typedef cairo_int_status_t
875 (*_show_glyphs_func
) (void *surface
,
877 const cairo_pattern_t
*source
,
878 cairo_glyph_t
*glyphs
,
880 cairo_scaled_font_t
*scaled_font
,
881 const cairo_clip_t
*clip
);
883 static const cairo_surface_backend_t cairo_null_surface_backend
= {
884 CAIRO_INTERNAL_SURFACE_TYPE_NULL
,
887 NULL
, /* only accessed through the surface functions */
889 NULL
, /* create_similar */
890 NULL
, /* create similar image */
891 NULL
, /* map to image */
892 NULL
, /* unmap image*/
895 NULL
, /* acquire_source_image */
896 NULL
, /* release_source_image */
899 NULL
, /* copy_page */
900 NULL
, /* show_page */
902 NULL
, /* get_extents */
903 NULL
, /* get_font_options */
906 NULL
, /* mark_dirty_rectangle */
908 (_paint_func
) _return_success
, /* paint */
909 (_mask_func
) _return_success
, /* mask */
910 (_stroke_func
) _return_success
, /* stroke */
911 (_fill_func
) _return_success
, /* fill */
912 NULL
, /* fill_stroke */
913 (_show_glyphs_func
) _return_success
, /* show_glyphs */
914 NULL
, /* has_show_text_glyphs */
915 NULL
/* show_text_glyphs */
919 _cairo_null_surface_create (cairo_content_t content
)
921 cairo_surface_t
*surface
;
923 surface
= malloc (sizeof (cairo_surface_t
));
924 if (unlikely (surface
== NULL
)) {
925 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
928 _cairo_surface_init (surface
,
929 &cairo_null_surface_backend
,