new beta-0.90.0
[luatex.git] / source / libs / cairo / cairo-src / src / cairo-analysis-surface.c
blob8516094c200e5e775e1702ad8b6c9b8f8adef423
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., 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
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-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"
49 typedef struct {
50 cairo_surface_t base;
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;
62 cairo_bool_t has_ctm;
63 cairo_matrix_t ctm;
65 } cairo_analysis_surface_t;
67 cairo_int_status_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;
99 struct proxy {
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,
112 proxy_finish,
115 static cairo_surface_t *
116 attach_proxy (cairo_surface_t *source,
117 cairo_surface_t *target)
119 struct proxy *proxy;
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);
130 return &proxy->base;
133 static void
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;
147 cairo_matrix_t p2d;
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);
156 if (proxy != NULL) {
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,
176 &tmp->base);
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))
182 return 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;
193 cairo_box_t bbox;
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;
205 else
207 return CAIRO_INT_STATUS_IMAGE_FALLBACK;
211 _cairo_box_from_rectangle (&bbox, rect);
213 if (surface->has_ctm) {
214 int tx, ty;
216 if (_cairo_matrix_is_integer_translation (&surface->ctm, &tx, &ty)) {
217 rect->x += tx;
218 rect->y += ty;
220 tx = _cairo_fixed_from_int (tx);
221 bbox.p1.x += tx;
222 bbox.p2.x += tx;
224 ty = _cairo_fixed_from_int (ty);
225 bbox.p1.y += ty;
226 bbox.p2.y += ty;
227 } else {
228 _cairo_matrix_transform_bounding_box_fixed (&surface->ctm,
229 &bbox, NULL);
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;
242 else
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;
255 } else
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
287 * emitted.
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;
300 else
301 return status;
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;
317 static cairo_bool_t
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);
326 static void
327 _rectangle_intersect_clip (cairo_rectangle_int_t *extents, const cairo_clip_t *clip)
329 if (clip != NULL)
330 _cairo_rectangle_intersect (extents, _cairo_clip_get_extents (clip));
333 static void
334 _cairo_analysis_surface_operation_extents (cairo_analysis_surface_t *surface,
335 cairo_operator_t op,
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,
356 cairo_operator_t op,
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;
366 } else {
367 backend_status =
368 surface->target->backend->paint (surface->target,
369 op, source, clip);
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,
378 op, source, clip,
379 &extents);
381 return _add_operation (surface, &extents, backend_status);
384 static cairo_int_status_t
385 _cairo_analysis_surface_mask (void *abstract_surface,
386 cairo_operator_t op,
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;
397 } else {
398 backend_status =
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;
431 backend_status =
432 _cairo_analysis_surface_merge_status (backend_source_status,
433 backend_mask_status);
436 _cairo_analysis_surface_operation_extents (surface,
437 op, source, clip,
438 &extents);
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,
452 cairo_operator_t op,
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,
458 double tolerance,
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;
468 } else {
469 backend_status =
470 surface->target->backend->stroke (surface->target, op,
471 source, path, style,
472 ctm, ctm_inverse,
473 tolerance, antialias,
474 clip);
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,
483 op, source, clip,
484 &extents);
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,
491 ctm, ctm_inverse,
492 tolerance,
493 &mask_extents);
494 if (unlikely (status))
495 return 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,
505 cairo_operator_t op,
506 const cairo_pattern_t *source,
507 const cairo_path_fixed_t *path,
508 cairo_fill_rule_t fill_rule,
509 double tolerance,
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;
519 } else {
520 backend_status =
521 surface->target->backend->fill (surface->target, op,
522 source, path, fill_rule,
523 tolerance, antialias,
524 clip);
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,
533 op, source, clip,
534 &extents);
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,
540 &mask_extents);
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,
550 cairo_operator_t op,
551 const cairo_pattern_t *source,
552 cairo_glyph_t *glyphs,
553 int num_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) {
563 backend_status =
564 surface->target->backend->show_glyphs (surface->target, op,
565 source,
566 glyphs, num_glyphs,
567 scaled_font,
568 clip);
569 if (_cairo_int_status_is_error (backend_status))
570 return backend_status;
572 else if (surface->target->backend->show_text_glyphs != NULL)
574 backend_status =
575 surface->target->backend->show_text_glyphs (surface->target, op,
576 source,
577 NULL, 0,
578 glyphs, num_glyphs,
579 NULL, 0,
580 FALSE,
581 scaled_font,
582 clip);
583 if (_cairo_int_status_is_error (backend_status))
584 return backend_status;
586 else
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,
595 op, source, clip,
596 &extents);
598 if (_cairo_operator_bounded_by_mask (op)) {
599 status = _cairo_scaled_font_glyph_device_extents (scaled_font,
600 glyphs,
601 num_glyphs,
602 &glyph_extents,
603 NULL);
604 if (unlikely (status))
605 return status;
607 _cairo_rectangle_intersect (&extents, &glyph_extents);
610 return _add_operation (surface, &extents, backend_status);
613 static cairo_bool_t
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,
623 cairo_operator_t op,
624 const cairo_pattern_t *source,
625 const char *utf8,
626 int utf8_len,
627 cairo_glyph_t *glyphs,
628 int num_glyphs,
629 const cairo_text_cluster_t *clusters,
630 int num_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) {
642 backend_status =
643 surface->target->backend->show_text_glyphs (surface->target, op,
644 source,
645 utf8, utf8_len,
646 glyphs, num_glyphs,
647 clusters, num_clusters,
648 cluster_flags,
649 scaled_font,
650 clip);
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)
657 backend_status =
658 surface->target->backend->show_glyphs (surface->target, op,
659 source,
660 glyphs, num_glyphs,
661 scaled_font,
662 clip);
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,
671 op, source, clip,
672 &extents);
674 if (_cairo_operator_bounded_by_mask (op)) {
675 status = _cairo_scaled_font_glyph_device_extents (scaled_font,
676 glyphs,
677 num_glyphs,
678 &glyph_extents,
679 NULL);
680 if (unlikely (status))
681 return 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,
693 NULL,
695 NULL, /* create_similar */
696 NULL, /* create_similar_image */
697 NULL, /* map_to_image */
698 NULL, /* unmap */
700 NULL, /* source */
701 NULL, /* acquire_source_image */
702 NULL, /* release_source_image */
703 NULL, /* snapshot */
705 NULL, /* copy_page */
706 NULL, /* show_page */
708 _cairo_analysis_surface_get_extents,
709 NULL, /* get_font_options */
711 NULL, /* flush */
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
724 cairo_surface_t *
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,
742 NULL, /* device */
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;
764 void
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)
771 return;
773 surface = (cairo_analysis_surface_t *) abstract_surface;
775 surface->ctm = *ctm;
776 surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm);
779 void
780 _cairo_analysis_surface_get_ctm (cairo_surface_t *abstract_surface,
781 cairo_matrix_t *ctm)
783 cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface;
785 *ctm = surface->ctm;
789 cairo_region_t *
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;
797 cairo_region_t *
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;
805 cairo_bool_t
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;
813 cairo_bool_t
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;
821 void
822 _cairo_analysis_surface_get_bounding_box (cairo_surface_t *abstract_surface,
823 cairo_box_t *bbox)
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,
841 cairo_operator_t op,
842 const cairo_pattern_t *source,
843 const cairo_clip_t *clip);
845 typedef cairo_int_status_t
846 (*_mask_func) (void *surface,
847 cairo_operator_t op,
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,
854 cairo_operator_t op,
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,
860 double tolerance,
861 cairo_antialias_t antialias,
862 const cairo_clip_t *clip);
864 typedef cairo_int_status_t
865 (*_fill_func) (void *surface,
866 cairo_operator_t op,
867 const cairo_pattern_t *source,
868 const cairo_path_fixed_t *path,
869 cairo_fill_rule_t fill_rule,
870 double tolerance,
871 cairo_antialias_t antialias,
872 const cairo_clip_t *clip);
874 typedef cairo_int_status_t
875 (*_show_glyphs_func) (void *surface,
876 cairo_operator_t op,
877 const cairo_pattern_t *source,
878 cairo_glyph_t *glyphs,
879 int num_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,
885 NULL, /* finish */
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*/
894 NULL, /* source */
895 NULL, /* acquire_source_image */
896 NULL, /* release_source_image */
897 NULL, /* snapshot */
899 NULL, /* copy_page */
900 NULL, /* show_page */
902 NULL, /* get_extents */
903 NULL, /* get_font_options */
905 NULL, /* flush */
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 */
918 cairo_surface_t *
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,
930 NULL, /* device */
931 content);
933 return surface;