Tizen 2.0 Release
[framework/graphics/cairo.git] / src / cairo-analysis-surface.c
1 /*
2  * Copyright © 2006 Keith Packard
3  * Copyright © 2007 Adrian Johnson
4  *
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.
12  *
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
18  *
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/
23  *
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.
27  *
28  * The Original Code is the cairo graphics library.
29  *
30  * The Initial Developer of the Original Code is Keith Packard
31  *
32  * Contributor(s):
33  *      Keith Packard <keithp@keithp.com>
34  *      Adrian Johnson <ajohnson@redneon.com>
35  */
36
37 #include "cairoint.h"
38
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"
48
49 typedef struct {
50     cairo_surface_t base;
51
52     cairo_surface_t *target;
53
54     cairo_bool_t first_op;
55     cairo_bool_t has_supported;
56     cairo_bool_t has_unsupported;
57
58     cairo_region_t supported_region;
59     cairo_region_t fallback_region;
60     cairo_box_t page_bbox;
61
62     cairo_bool_t has_ctm;
63     cairo_matrix_t ctm;
64
65 } cairo_analysis_surface_t;
66
67 cairo_int_status_t
68 _cairo_analysis_surface_merge_status (cairo_int_status_t status_a,
69                                       cairo_int_status_t status_b)
70 {
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));
74
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;
79
80     if (status_a == CAIRO_INT_STATUS_IMAGE_FALLBACK ||
81         status_b == CAIRO_INT_STATUS_IMAGE_FALLBACK)
82         return CAIRO_INT_STATUS_IMAGE_FALLBACK;
83
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;
87
88     if (status_a == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY ||
89         status_b == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
90         return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
91
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);
95
96     return CAIRO_INT_STATUS_SUCCESS;
97 }
98
99 struct proxy {
100     cairo_surface_t base;
101     cairo_surface_t *target;
102 };
103
104 static cairo_status_t
105 proxy_finish (void *abstract_surface)
106 {
107     return CAIRO_STATUS_SUCCESS;
108 }
109
110 static const cairo_surface_backend_t proxy_backend  = {
111     CAIRO_INTERNAL_SURFACE_TYPE_NULL,
112     proxy_finish,
113 };
114
115 static cairo_surface_t *
116 attach_proxy (cairo_surface_t *source,
117               cairo_surface_t *target)
118 {
119     struct proxy *proxy;
120
121     proxy = malloc (sizeof (*proxy));
122     if (unlikely (proxy == NULL))
123         return _cairo_surface_create_in_error (CAIRO_STATUS_NO_MEMORY);
124
125     _cairo_surface_init (&proxy->base, &proxy_backend, NULL, target->content);
126
127     proxy->target = target;
128     _cairo_surface_attach_snapshot (source, &proxy->base, NULL);
129
130     return &proxy->base;
131 }
132
133 static void
134 detach_proxy (cairo_surface_t *proxy)
135 {
136     cairo_surface_finish (proxy);
137     cairo_surface_destroy (proxy);
138 }
139
140 static cairo_int_status_t
141 _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
142                                     const cairo_pattern_t    *pattern)
143 {
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;
149
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;
154
155     proxy = _cairo_surface_has_snapshot (source, &proxy_backend);
156     if (proxy != NULL) {
157         /* nothing untoward found so far */
158         return CAIRO_STATUS_SUCCESS;
159     }
160
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);
166
167     p2d = pattern->matrix;
168     status = cairo_matrix_invert (&p2d);
169     assert (status == CAIRO_STATUS_SUCCESS);
170
171     cairo_matrix_multiply (&tmp->ctm, &p2d, &surface->ctm);
172     tmp->has_ctm = ! _cairo_matrix_is_identity (&tmp->ctm);
173
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);
180
181     if (unlikely (status))
182         return status;
183
184     return analysis_status;
185 }
186
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)
191 {
192     cairo_int_status_t status;
193     cairo_box_t bbox;
194
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)
202         {
203             return CAIRO_INT_STATUS_SUCCESS;
204         }
205         else
206         {
207             return CAIRO_INT_STATUS_IMAGE_FALLBACK;
208         }
209     }
210
211     _cairo_box_from_rectangle (&bbox, rect);
212
213     if (surface->has_ctm) {
214         int tx, ty;
215
216         if (_cairo_matrix_is_integer_translation (&surface->ctm, &tx, &ty)) {
217             rect->x += tx;
218             rect->y += ty;
219
220             tx = _cairo_fixed_from_int (tx);
221             bbox.p1.x += tx;
222             bbox.p2.x += tx;
223
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);
230
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)
239                 {
240                     return CAIRO_INT_STATUS_SUCCESS;
241                 }
242                 else
243                 {
244                     return CAIRO_INT_STATUS_IMAGE_FALLBACK;
245                 }
246             }
247
248             _cairo_box_round_to_rectangle (&bbox, rect);
249         }
250     }
251
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);
257
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.
261      */
262     if (cairo_region_contains_rectangle (&surface->fallback_region, rect) == CAIRO_REGION_OVERLAP_IN)
263         return CAIRO_INT_STATUS_IMAGE_FALLBACK;
264
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.
272          */
273         if (cairo_region_contains_rectangle (&surface->supported_region, rect) == CAIRO_REGION_OVERLAP_OUT)
274             backend_status = CAIRO_INT_STATUS_SUCCESS;
275     }
276
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.
280          */
281         surface->has_supported = TRUE;
282         return cairo_region_union_rectangle (&surface->supported_region, rect);
283     }
284
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.
288      */
289     surface->has_unsupported = TRUE;
290     status = cairo_region_union_rectangle (&surface->fallback_region, rect);
291
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.
297      */
298     if (status == CAIRO_INT_STATUS_SUCCESS)
299         return CAIRO_INT_STATUS_IMAGE_FALLBACK;
300     else
301         return status;
302 }
303
304 static cairo_status_t
305 _cairo_analysis_surface_finish (void *abstract_surface)
306 {
307     cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
308
309     _cairo_region_fini (&surface->supported_region);
310     _cairo_region_fini (&surface->fallback_region);
311
312     cairo_surface_destroy (surface->target);
313
314     return CAIRO_STATUS_SUCCESS;
315 }
316
317 static cairo_bool_t
318 _cairo_analysis_surface_get_extents (void                       *abstract_surface,
319                                      cairo_rectangle_int_t      *rectangle)
320 {
321     cairo_analysis_surface_t *surface = abstract_surface;
322
323     return _cairo_surface_get_extents (surface->target, rectangle);
324 }
325
326 static void
327 _rectangle_intersect_clip (cairo_rectangle_int_t *extents, const cairo_clip_t *clip)
328 {
329     if (clip != NULL)
330         _cairo_rectangle_intersect (extents, _cairo_clip_get_extents (clip));
331 }
332
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)
339 {
340     cairo_bool_t is_empty;
341
342     is_empty = _cairo_surface_get_extents (&surface->base, extents);
343
344     if (_cairo_operator_bounded_by_source (op)) {
345         cairo_rectangle_int_t source_extents;
346
347         _cairo_pattern_get_extents (source, &source_extents);
348         _cairo_rectangle_intersect (extents, &source_extents);
349     }
350
351     _rectangle_intersect_clip (extents, clip);
352 }
353
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)
359 {
360     cairo_analysis_surface_t *surface = abstract_surface;
361     cairo_int_status_t       backend_status;
362     cairo_rectangle_int_t  extents;
363
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;
372     }
373
374     if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
375         backend_status = _analyze_recording_surface_pattern (surface, source);
376
377     _cairo_analysis_surface_operation_extents (surface,
378                                                op, source, clip,
379                                                &extents);
380
381     return _add_operation (surface, &extents, backend_status);
382 }
383
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)
390 {
391     cairo_analysis_surface_t *surface = abstract_surface;
392     cairo_int_status_t        backend_status;
393     cairo_rectangle_int_t   extents;
394
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;
403     }
404
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;
408
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;
417             }
418         }
419
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;
428             }
429         }
430
431         backend_status =
432             _cairo_analysis_surface_merge_status (backend_source_status,
433                                                   backend_mask_status);
434     }
435
436     _cairo_analysis_surface_operation_extents (surface,
437                                                op, source, clip,
438                                                &extents);
439
440     if (_cairo_operator_bounded_by_mask (op)) {
441         cairo_rectangle_int_t mask_extents;
442
443         _cairo_pattern_get_extents (mask, &mask_extents);
444         _cairo_rectangle_intersect (&extents, &mask_extents);
445     }
446
447     return _add_operation (surface, &extents, backend_status);
448 }
449
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)
461 {
462     cairo_analysis_surface_t *surface = abstract_surface;
463     cairo_int_status_t       backend_status;
464     cairo_rectangle_int_t    extents;
465
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;
477     }
478
479     if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
480         backend_status = _analyze_recording_surface_pattern (surface, source);
481
482     _cairo_analysis_surface_operation_extents (surface,
483                                                op, source, clip,
484                                                &extents);
485
486     if (_cairo_operator_bounded_by_mask (op)) {
487         cairo_rectangle_int_t mask_extents;
488         cairo_int_status_t status;
489
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;
496
497         _cairo_rectangle_intersect (&extents, &mask_extents);
498     }
499
500     return _add_operation (surface, &extents, backend_status);
501 }
502
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)
512 {
513     cairo_analysis_surface_t *surface = abstract_surface;
514     cairo_int_status_t       backend_status;
515     cairo_rectangle_int_t    extents;
516
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;
527     }
528
529     if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
530         backend_status = _analyze_recording_surface_pattern (surface, source);
531
532     _cairo_analysis_surface_operation_extents (surface,
533                                                op, source, clip,
534                                                &extents);
535
536     if (_cairo_operator_bounded_by_mask (op)) {
537         cairo_rectangle_int_t mask_extents;
538
539         _cairo_path_fixed_fill_extents (path, fill_rule, tolerance,
540                                         &mask_extents);
541
542         _cairo_rectangle_intersect (&extents, &mask_extents);
543     }
544
545     return _add_operation (surface, &extents, backend_status);
546 }
547
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)
556 {
557     cairo_analysis_surface_t *surface = abstract_surface;
558     cairo_int_status_t       status, backend_status;
559     cairo_rectangle_int_t    extents, glyph_extents;
560
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;
571     }
572     else if (surface->target->backend->show_text_glyphs != NULL)
573     {
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;
585     }
586     else
587     {
588         backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
589     }
590
591     if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
592         backend_status = _analyze_recording_surface_pattern (surface, source);
593
594     _cairo_analysis_surface_operation_extents (surface,
595                                                op, source, clip,
596                                                &extents);
597
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;
606
607         _cairo_rectangle_intersect (&extents, &glyph_extents);
608     }
609
610     return _add_operation (surface, &extents, backend_status);
611 }
612
613 static cairo_bool_t
614 _cairo_analysis_surface_has_show_text_glyphs (void *abstract_surface)
615 {
616     cairo_analysis_surface_t *surface = abstract_surface;
617
618     return cairo_surface_has_show_text_glyphs (surface->target);
619 }
620
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)
634 {
635     cairo_analysis_surface_t *surface = abstract_surface;
636     cairo_int_status_t       status, backend_status;
637     cairo_rectangle_int_t    extents, glyph_extents;
638
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;
653     }
654     if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED &&
655         surface->target->backend->show_glyphs != NULL)
656     {
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;
665     }
666
667     if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
668         backend_status = _analyze_recording_surface_pattern (surface, source);
669
670     _cairo_analysis_surface_operation_extents (surface,
671                                                op, source, clip,
672                                                &extents);
673
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;
682
683         _cairo_rectangle_intersect (&extents, &glyph_extents);
684     }
685
686     return _add_operation (surface, &extents, backend_status);
687 }
688
689 static const cairo_surface_backend_t cairo_analysis_surface_backend = {
690     CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
691
692     _cairo_analysis_surface_finish,
693     NULL,
694
695     NULL, /* create_similar */
696     NULL, /* create_similar_image */
697     NULL, /* map_to_image */
698     NULL, /* unmap */
699
700     NULL, /* source */
701     NULL, /* acquire_source_image */
702     NULL, /* release_source_image */
703     NULL, /* snapshot */
704
705     NULL, /* copy_page */
706     NULL, /* show_page */
707
708     _cairo_analysis_surface_get_extents,
709     NULL, /* get_font_options */
710
711     NULL, /* flush */
712     NULL, /* mark_dirty_rectangle */
713
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
722 };
723
724 cairo_surface_t *
725 _cairo_analysis_surface_create (cairo_surface_t         *target)
726 {
727     cairo_analysis_surface_t *surface;
728     cairo_status_t status;
729
730     status = target->status;
731     if (unlikely (status))
732         return _cairo_surface_create_in_error (status);
733
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));
737
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);
744
745     cairo_matrix_init_identity (&surface->ctm);
746     surface->has_ctm = FALSE;
747
748     surface->target = cairo_surface_reference (target);
749     surface->first_op  = TRUE;
750     surface->has_supported = FALSE;
751     surface->has_unsupported = FALSE;
752
753     _cairo_region_init (&surface->supported_region);
754     _cairo_region_init (&surface->fallback_region);
755
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;
760
761     return &surface->base;
762 }
763
764 void
765 _cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface,
766                                  const cairo_matrix_t  *ctm)
767 {
768     cairo_analysis_surface_t    *surface;
769
770     if (abstract_surface->status)
771         return;
772
773     surface = (cairo_analysis_surface_t *) abstract_surface;
774
775     surface->ctm = *ctm;
776     surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm);
777 }
778
779 void
780 _cairo_analysis_surface_get_ctm (cairo_surface_t *abstract_surface,
781                                  cairo_matrix_t  *ctm)
782 {
783     cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
784
785     *ctm = surface->ctm;
786 }
787
788
789 cairo_region_t *
790 _cairo_analysis_surface_get_supported (cairo_surface_t *abstract_surface)
791 {
792     cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
793
794     return &surface->supported_region;
795 }
796
797 cairo_region_t *
798 _cairo_analysis_surface_get_unsupported (cairo_surface_t *abstract_surface)
799 {
800     cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
801
802     return &surface->fallback_region;
803 }
804
805 cairo_bool_t
806 _cairo_analysis_surface_has_supported (cairo_surface_t *abstract_surface)
807 {
808     cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
809
810     return surface->has_supported;
811 }
812
813 cairo_bool_t
814 _cairo_analysis_surface_has_unsupported (cairo_surface_t *abstract_surface)
815 {
816     cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
817
818     return surface->has_unsupported;
819 }
820
821 void
822 _cairo_analysis_surface_get_bounding_box (cairo_surface_t *abstract_surface,
823                                           cairo_box_t     *bbox)
824 {
825     cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
826
827     *bbox = surface->page_bbox;
828 }
829
830 /* null surface type: a surface that does nothing (has no side effects, yay!) */
831
832 static cairo_int_status_t
833 _return_success (void)
834 {
835     return CAIRO_STATUS_SUCCESS;
836 }
837
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);
844
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);
851
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);
863
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);
873
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);
882
883 static const cairo_surface_backend_t cairo_null_surface_backend = {
884     CAIRO_INTERNAL_SURFACE_TYPE_NULL,
885     NULL, /* finish */
886
887     NULL, /* only accessed through the surface functions */
888
889     NULL, /* create_similar */
890     NULL, /* create similar image */
891     NULL, /* map to image */
892     NULL, /* unmap image*/
893
894     NULL, /* source */
895     NULL, /* acquire_source_image */
896     NULL, /* release_source_image */
897     NULL, /* snapshot */
898
899     NULL, /* copy_page */
900     NULL, /* show_page */
901
902     NULL, /* get_extents */
903     NULL, /* get_font_options */
904
905     NULL, /* flush */
906     NULL, /* mark_dirty_rectangle */
907
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 */
916 };
917
918 cairo_surface_t *
919 _cairo_null_surface_create (cairo_content_t content)
920 {
921     cairo_surface_t *surface;
922
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));
926     }
927
928     _cairo_surface_init (surface,
929                          &cairo_null_surface_backend,
930                          NULL, /* device */
931                          content);
932
933     return surface;
934 }