Updated: Sudoku no longer crashes
[moon.git] / cairo / src / cairo-analysis-surface.c
blob057be529da55a230fb0667daacd0253e5415dbe4
1 /*
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
32 * Contributor(s):
33 * Keith Packard <keithp@keithp.com>
34 * Adrian Johnson <ajohnson@redneon.com>
37 #include "cairoint.h"
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"
44 typedef struct {
45 cairo_surface_t base;
46 int width;
47 int height;
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;
60 cairo_bool_t has_ctm;
61 cairo_matrix_t ctm;
63 } cairo_analysis_surface_t;
65 cairo_int_status_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;
108 int old_width;
109 int old_height;
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)
120 return status;
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,
139 analysis);
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;
149 return status;
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;
158 cairo_box_t bbox;
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;
169 else
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;
191 else
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;
203 } else {
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,
240 rect);
241 return status;
244 /* Add the operation to the unsupported region. This region will
245 * be painted as an image after all native operations have been
246 * emitted.
248 surface->has_unsupported = TRUE;
249 status = _cairo_region_union_rect (&surface->fallback_region,
250 &surface->fallback_region,
251 rect);
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;
261 else
262 return status;
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,
282 double tolerance,
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;
290 if (path == NULL) {
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;
295 } else {
296 cairo_status_t status;
298 status = _cairo_path_fixed_bounds (path, &x1, &y1, &x2, &y2, tolerance);
299 if (status)
300 return status;
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,
324 cairo_operator_t op,
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;
334 else
335 backend_status = (*surface->target->backend->paint) (surface->target, op,
336 source);
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)
343 return status;
345 if (_cairo_operator_bounded_by_source (op)) {
346 cairo_rectangle_int_t source_extents;
348 status = _cairo_pattern_get_extents (source, &source_extents);
349 if (status)
350 return status;
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);
359 return status;
362 static cairo_int_status_t
363 _cairo_analysis_surface_mask (void *abstract_surface,
364 cairo_operator_t op,
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;
375 else
376 backend_status = (*surface->target->backend->mask) (surface->target, op,
377 source, mask);
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;
403 backend_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)
410 return status;
412 if (_cairo_operator_bounded_by_source (op)) {
413 cairo_rectangle_int_t source_extents;
414 status = _cairo_pattern_get_extents (source, &source_extents);
415 if (status)
416 return status;
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);
425 if (status)
426 return status;
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);
435 return status;
438 static cairo_int_status_t
439 _cairo_analysis_surface_stroke (void *abstract_surface,
440 cairo_operator_t op,
441 cairo_pattern_t *source,
442 cairo_path_fixed_t *path,
443 cairo_stroke_style_t *style,
444 cairo_matrix_t *ctm,
445 cairo_matrix_t *ctm_inverse,
446 double tolerance,
447 cairo_antialias_t antialias)
449 cairo_analysis_surface_t *surface = abstract_surface;
450 cairo_status_t status, backend_status;
451 cairo_traps_t traps;
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;
457 else
458 backend_status = (*surface->target->backend->stroke) (surface->target, op,
459 source, path, style,
460 ctm, ctm_inverse,
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)
468 return status;
470 if (_cairo_operator_bounded_by_source (op)) {
471 cairo_rectangle_int_t source_extents;
473 status = _cairo_pattern_get_extents (source, &source_extents);
474 if (status)
475 return status;
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)) {
483 cairo_box_t box;
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,
490 style,
491 ctm, ctm_inverse,
492 tolerance,
493 &traps);
494 if (status) {
495 _cairo_traps_fini (&traps);
496 return status;
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);
507 return status;
510 static cairo_int_status_t
511 _cairo_analysis_surface_fill (void *abstract_surface,
512 cairo_operator_t op,
513 cairo_pattern_t *source,
514 cairo_path_fixed_t *path,
515 cairo_fill_rule_t fill_rule,
516 double tolerance,
517 cairo_antialias_t antialias)
519 cairo_analysis_surface_t *surface = abstract_surface;
520 cairo_status_t status, backend_status;
521 cairo_traps_t traps;
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;
527 else
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)
537 return status;
539 if (_cairo_operator_bounded_by_source (op)) {
540 cairo_rectangle_int_t source_extents;
542 status = _cairo_pattern_get_extents (source, &source_extents);
543 if (status)
544 return status;
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)) {
552 cairo_box_t box;
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,
559 fill_rule,
560 tolerance,
561 &traps);
562 if (status) {
563 _cairo_traps_fini (&traps);
564 return status;
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);
575 return status;
578 static cairo_int_status_t
579 _cairo_analysis_surface_show_glyphs (void *abstract_surface,
580 cairo_operator_t op,
581 cairo_pattern_t *source,
582 cairo_glyph_t *glyphs,
583 int num_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,
595 source,
596 glyphs, num_glyphs,
597 scaled_font,
598 remaining_glyphs);
599 else if (surface->target->backend->show_text_glyphs)
600 backend_status = surface->target->backend->show_text_glyphs (surface->target, op,
601 source,
602 NULL, 0,
603 glyphs, num_glyphs,
604 NULL, 0,
605 FALSE,
606 scaled_font);
607 else
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)
615 return status;
617 if (_cairo_operator_bounded_by_source (op)) {
618 cairo_rectangle_int_t source_extents;
620 status = _cairo_pattern_get_extents (source, &source_extents);
621 if (status)
622 return status;
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,
631 glyphs,
632 num_glyphs,
633 &glyph_extents);
634 if (status)
635 return status;
637 is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents);
640 status = _add_operation (surface, &extents, backend_status);
642 return status;
645 static cairo_bool_t
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,
655 cairo_operator_t op,
656 cairo_pattern_t *source,
657 const char *utf8,
658 int utf8_len,
659 cairo_glyph_t *glyphs,
660 int num_glyphs,
661 const cairo_text_cluster_t *clusters,
662 int num_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,
675 source,
676 utf8, utf8_len,
677 glyphs, num_glyphs,
678 clusters, num_clusters, cluster_flags,
679 scaled_font);
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,
683 source,
684 glyphs, num_glyphs,
685 scaled_font,
686 &remaining_glyphs);
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)
698 return status;
700 if (_cairo_operator_bounded_by_source (op)) {
701 cairo_rectangle_int_t source_extents;
703 status = _cairo_pattern_get_extents (source, &source_extents);
704 if (status)
705 return status;
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,
714 glyphs,
715 num_glyphs,
716 &glyph_extents);
717 if (status)
718 return status;
720 is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents);
723 status = _add_operation (surface, &extents, backend_status);
725 return 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 */
747 NULL, /* flush */
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,
756 NULL, /* snapshot */
757 NULL, /* is_similar */
758 NULL, /* reset */
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
765 cairo_surface_t *
766 _cairo_analysis_surface_create (cairo_surface_t *target,
767 int width,
768 int height)
770 cairo_analysis_surface_t *surface;
771 cairo_status_t status;
773 status = target->status;
774 if (status)
775 return _cairo_surface_create_in_error (status);
777 surface = malloc (sizeof (cairo_analysis_surface_t));
778 if (surface == NULL)
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;
809 } else {
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;
819 void
820 _cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface,
821 cairo_matrix_t *ctm)
823 cairo_analysis_surface_t *surface;
825 if (abstract_surface->status)
826 return;
828 surface = (cairo_analysis_surface_t *) abstract_surface;
830 surface->ctm = *ctm;
831 surface->has_ctm = !_cairo_matrix_is_identity (&surface->ctm);
834 void
835 _cairo_analysis_surface_get_ctm (cairo_surface_t *abstract_surface,
836 cairo_matrix_t *ctm)
838 cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
840 *ctm = surface->ctm;
844 cairo_region_t *
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;
852 cairo_region_t *
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;
860 cairo_bool_t
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;
868 cairo_bool_t
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;
876 void
877 _cairo_analysis_surface_get_bounding_box (cairo_surface_t *abstract_surface,
878 cairo_box_t *bbox)
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,
899 cairo_operator_t op,
900 cairo_pattern_t *source);
902 typedef cairo_int_status_t
903 (*_mask_func) (void *surface,
904 cairo_operator_t op,
905 cairo_pattern_t *source,
906 cairo_pattern_t *mask);
908 typedef cairo_int_status_t
909 (*_stroke_func) (void *surface,
910 cairo_operator_t op,
911 cairo_pattern_t *source,
912 cairo_path_fixed_t *path,
913 cairo_stroke_style_t *style,
914 cairo_matrix_t *ctm,
915 cairo_matrix_t *ctm_inverse,
916 double tolerance,
917 cairo_antialias_t antialias);
919 typedef cairo_int_status_t
920 (*_fill_func) (void *surface,
921 cairo_operator_t op,
922 cairo_pattern_t *source,
923 cairo_path_fixed_t *path,
924 cairo_fill_rule_t fill_rule,
925 double tolerance,
926 cairo_antialias_t antialias);
928 typedef cairo_int_status_t
929 (*_show_glyphs_func) (void *surface,
930 cairo_operator_t op,
931 cairo_pattern_t *source,
932 cairo_glyph_t *glyphs,
933 int num_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 */
941 NULL, /* finish */
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 */
957 NULL, /* flush */
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 */
966 NULL, /* snapshot */
967 NULL, /* is_similar */
968 NULL, /* reset */
969 NULL, /* fill_stroke */
970 NULL, /* create_solid_pattern_surface */
971 NULL, /* has_show_text_glyphs */
972 NULL /* show_text_glyphs */
975 cairo_surface_t *
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);
987 return surface;