Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  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-error-private.h"
  41. #include "cairo-paginated-private.h"
  42. #include "cairo-recording-surface-private.h"
  43. #include "cairo-surface-subsurface-private.h"
  44. #include "cairo-region-private.h"
  45.  
  46. typedef struct {
  47.     cairo_surface_t base;
  48.  
  49.     cairo_surface_t *target;
  50.  
  51.     cairo_bool_t first_op;
  52.     cairo_bool_t has_supported;
  53.     cairo_bool_t has_unsupported;
  54.  
  55.     cairo_region_t supported_region;
  56.     cairo_region_t fallback_region;
  57.     cairo_box_t page_bbox;
  58.  
  59.     cairo_bool_t has_ctm;
  60.     cairo_matrix_t ctm;
  61.  
  62. } cairo_analysis_surface_t;
  63.  
  64. cairo_int_status_t
  65. _cairo_analysis_surface_merge_status (cairo_int_status_t status_a,
  66.                                       cairo_int_status_t status_b)
  67. {
  68.     /* fatal errors should be checked and propagated at source */
  69.     assert (! _cairo_status_is_error (status_a));
  70.     assert (! _cairo_status_is_error (status_b));
  71.  
  72.     /* return the most important status */
  73.     if (status_a == CAIRO_INT_STATUS_UNSUPPORTED ||
  74.         status_b == CAIRO_INT_STATUS_UNSUPPORTED)
  75.         return CAIRO_INT_STATUS_UNSUPPORTED;
  76.  
  77.     if (status_a == CAIRO_INT_STATUS_IMAGE_FALLBACK ||
  78.         status_b == CAIRO_INT_STATUS_IMAGE_FALLBACK)
  79.         return CAIRO_INT_STATUS_IMAGE_FALLBACK;
  80.  
  81.     if (status_a == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN ||
  82.         status_b == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
  83.         return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
  84.  
  85.     if (status_a == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY ||
  86.         status_b == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
  87.         return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
  88.  
  89.     /* at this point we have checked all the valid internal codes, so... */
  90.     assert (status_a == CAIRO_STATUS_SUCCESS &&
  91.             status_b == CAIRO_STATUS_SUCCESS);
  92.  
  93.     return CAIRO_STATUS_SUCCESS;
  94. }
  95.  
  96. static cairo_int_status_t
  97. _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
  98.                                     const cairo_pattern_t    *pattern)
  99. {
  100.     const cairo_surface_pattern_t *surface_pattern;
  101.     cairo_bool_t old_has_ctm;
  102.     cairo_matrix_t old_ctm, p2d;
  103.     cairo_status_t status;
  104.     cairo_surface_t *source;
  105.  
  106.     assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
  107.     surface_pattern = (const cairo_surface_pattern_t *) pattern;
  108.     assert (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING);
  109.  
  110.     old_ctm = surface->ctm;
  111.     old_has_ctm = surface->has_ctm;
  112.  
  113.     p2d = pattern->matrix;
  114.     status = cairo_matrix_invert (&p2d);
  115.     assert (status == CAIRO_STATUS_SUCCESS);
  116.  
  117.     cairo_matrix_multiply (&surface->ctm, &p2d, &surface->ctm);
  118.     surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm);
  119.  
  120.     source = surface_pattern->surface;
  121.     if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
  122.         cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
  123.         source = sub->target;
  124.     }
  125.  
  126.     status = _cairo_recording_surface_replay_and_create_regions (source, &surface->base);
  127.  
  128.     surface->ctm = old_ctm;
  129.     surface->has_ctm = old_has_ctm;
  130.  
  131.     return status;
  132. }
  133.  
  134. static cairo_int_status_t
  135. _add_operation (cairo_analysis_surface_t *surface,
  136.                 cairo_rectangle_int_t    *rect,
  137.                 cairo_int_status_t        backend_status)
  138. {
  139.     cairo_int_status_t status;
  140.     cairo_box_t bbox;
  141.  
  142.     if (rect->width == 0 || rect->height == 0) {
  143.         /* Even though the operation is not visible we must be careful
  144.          * to not allow unsupported operations to be replayed to the
  145.          * backend during CAIRO_PAGINATED_MODE_RENDER */
  146.         if (backend_status == CAIRO_STATUS_SUCCESS ||
  147.             backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
  148.         {
  149.             return CAIRO_STATUS_SUCCESS;
  150.         }
  151.         else
  152.         {
  153.             return CAIRO_INT_STATUS_IMAGE_FALLBACK;
  154.         }
  155.     }
  156.  
  157.     _cairo_box_from_rectangle (&bbox, rect);
  158.  
  159.     if (surface->has_ctm) {
  160.         int tx, ty;
  161.  
  162.         if (_cairo_matrix_is_integer_translation (&surface->ctm, &tx, &ty)) {
  163.             rect->x += tx;
  164.             rect->y += ty;
  165.         } else {
  166.             _cairo_matrix_transform_bounding_box_fixed (&surface->ctm,
  167.                                                         &bbox, NULL);
  168.  
  169.             if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) {
  170.                 /* Even though the operation is not visible we must be
  171.                  * careful to not allow unsupported operations to be
  172.                  * replayed to the backend during
  173.                  * CAIRO_PAGINATED_MODE_RENDER */
  174.                 if (backend_status == CAIRO_STATUS_SUCCESS ||
  175.                     backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
  176.                 {
  177.                     return CAIRO_STATUS_SUCCESS;
  178.                 }
  179.                 else
  180.                 {
  181.                     return CAIRO_INT_STATUS_IMAGE_FALLBACK;
  182.                 }
  183.             }
  184.  
  185.             _cairo_box_round_to_rectangle (&bbox, rect);
  186.         }
  187.     }
  188.  
  189.     if (surface->first_op) {
  190.         surface->first_op = FALSE;
  191.         surface->page_bbox = bbox;
  192.     } else {
  193.         if (bbox.p1.x < surface->page_bbox.p1.x)
  194.             surface->page_bbox.p1.x = bbox.p1.x;
  195.         if (bbox.p1.y < surface->page_bbox.p1.y)
  196.             surface->page_bbox.p1.y = bbox.p1.y;
  197.         if (bbox.p2.x > surface->page_bbox.p2.x)
  198.             surface->page_bbox.p2.x = bbox.p2.x;
  199.         if (bbox.p2.y > surface->page_bbox.p2.y)
  200.             surface->page_bbox.p2.y = bbox.p2.y;
  201.     }
  202.  
  203.     /* If the operation is completely enclosed within the fallback
  204.      * region there is no benefit in emitting a native operation as
  205.      * the fallback image will be painted on top.
  206.      */
  207.     if (cairo_region_contains_rectangle (&surface->fallback_region, rect) == CAIRO_REGION_OVERLAP_IN)
  208.         return CAIRO_INT_STATUS_IMAGE_FALLBACK;
  209.  
  210.     if (backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) {
  211.         /* A status of CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY indicates
  212.          * that the backend only supports this operation if the
  213.          * transparency removed. If the extents of this operation does
  214.          * not intersect any other native operation, the operation is
  215.          * natively supported and the backend will blend the
  216.          * transparency into the white background.
  217.          */
  218.         if (cairo_region_contains_rectangle (&surface->supported_region, rect) == CAIRO_REGION_OVERLAP_OUT)
  219.             backend_status = CAIRO_STATUS_SUCCESS;
  220.     }
  221.  
  222.     if (backend_status == CAIRO_STATUS_SUCCESS) {
  223.         /* Add the operation to the supported region. Operations in
  224.          * this region will be emitted as native operations.
  225.          */
  226.         surface->has_supported = TRUE;
  227.         return cairo_region_union_rectangle (&surface->supported_region, rect);
  228.     }
  229.  
  230.     /* Add the operation to the unsupported region. This region will
  231.      * be painted as an image after all native operations have been
  232.      * emitted.
  233.      */
  234.     surface->has_unsupported = TRUE;
  235.     status = cairo_region_union_rectangle (&surface->fallback_region, rect);
  236.  
  237.     /* The status CAIRO_INT_STATUS_IMAGE_FALLBACK is used to indicate
  238.      * unsupported operations to the recording surface as using
  239.      * CAIRO_INT_STATUS_UNSUPPORTED would cause cairo-surface to
  240.      * invoke the cairo-surface-fallback path then return
  241.      * CAIRO_STATUS_SUCCESS.
  242.      */
  243.     if (status == CAIRO_STATUS_SUCCESS)
  244.         return CAIRO_INT_STATUS_IMAGE_FALLBACK;
  245.     else
  246.         return status;
  247. }
  248.  
  249. static cairo_status_t
  250. _cairo_analysis_surface_finish (void *abstract_surface)
  251. {
  252.     cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
  253.  
  254.     _cairo_region_fini (&surface->supported_region);
  255.     _cairo_region_fini (&surface->fallback_region);
  256.  
  257.     cairo_surface_destroy (surface->target);
  258.  
  259.     return CAIRO_STATUS_SUCCESS;
  260. }
  261.  
  262. static cairo_bool_t
  263. _cairo_analysis_surface_get_extents (void                       *abstract_surface,
  264.                                      cairo_rectangle_int_t      *rectangle)
  265. {
  266.     cairo_analysis_surface_t *surface = abstract_surface;
  267.  
  268.     return _cairo_surface_get_extents (surface->target, rectangle);
  269. }
  270.  
  271. static void
  272. _rectangle_intersect_clip (cairo_rectangle_int_t *extents, cairo_clip_t *clip)
  273. {
  274.     const cairo_rectangle_int_t *clip_extents;
  275.     cairo_bool_t is_empty;
  276.  
  277.     clip_extents = NULL;
  278.     if (clip != NULL)
  279.         clip_extents = _cairo_clip_get_extents (clip);
  280.  
  281.     if (clip_extents != NULL)
  282.         is_empty = _cairo_rectangle_intersect (extents, clip_extents);
  283. }
  284.  
  285. static void
  286. _cairo_analysis_surface_operation_extents (cairo_analysis_surface_t *surface,
  287.                                            cairo_operator_t op,
  288.                                            const cairo_pattern_t *source,
  289.                                            cairo_clip_t *clip,
  290.                                            cairo_rectangle_int_t *extents)
  291. {
  292.     cairo_bool_t is_empty;
  293.  
  294.     is_empty = _cairo_surface_get_extents (&surface->base, extents);
  295.  
  296.     if (_cairo_operator_bounded_by_source (op)) {
  297.         cairo_rectangle_int_t source_extents;
  298.  
  299.         _cairo_pattern_get_extents (source, &source_extents);
  300.         is_empty = _cairo_rectangle_intersect (extents, &source_extents);
  301.     }
  302.  
  303.     _rectangle_intersect_clip (extents, clip);
  304. }
  305.  
  306. static cairo_int_status_t
  307. _cairo_analysis_surface_paint (void                     *abstract_surface,
  308.                                cairo_operator_t         op,
  309.                                const cairo_pattern_t    *source,
  310.                                cairo_clip_t             *clip)
  311. {
  312.     cairo_analysis_surface_t *surface = abstract_surface;
  313.     cairo_status_t           backend_status;
  314.     cairo_rectangle_int_t  extents;
  315.  
  316.     if (surface->target->backend->paint == NULL) {
  317.         backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
  318.     } else {
  319.         backend_status =
  320.             surface->target->backend->paint (surface->target,
  321.                                              op, source, clip);
  322.         if (_cairo_status_is_error (backend_status))
  323.             return backend_status;
  324.     }
  325.  
  326.     if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
  327.         backend_status = _analyze_recording_surface_pattern (surface, source);
  328.  
  329.     _cairo_analysis_surface_operation_extents (surface,
  330.                                                op, source, clip,
  331.                                                &extents);
  332.  
  333.     return _add_operation (surface, &extents, backend_status);
  334. }
  335.  
  336. static cairo_int_status_t
  337. _cairo_analysis_surface_mask (void                      *abstract_surface,
  338.                               cairo_operator_t           op,
  339.                               const cairo_pattern_t     *source,
  340.                               const cairo_pattern_t     *mask,
  341.                               cairo_clip_t              *clip)
  342. {
  343.     cairo_analysis_surface_t *surface = abstract_surface;
  344.     cairo_int_status_t        backend_status;
  345.     cairo_rectangle_int_t   extents;
  346.     cairo_bool_t is_empty;
  347.  
  348.     if (surface->target->backend->mask == NULL) {
  349.         backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
  350.     } else {
  351.         backend_status =
  352.             surface->target->backend->mask (surface->target,
  353.                                             op, source, mask, clip);
  354.         if (_cairo_status_is_error (backend_status))
  355.             return backend_status;
  356.     }
  357.  
  358.     if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
  359.         cairo_int_status_t backend_source_status = CAIRO_STATUS_SUCCESS;
  360.         cairo_int_status_t backend_mask_status = CAIRO_STATUS_SUCCESS;
  361.  
  362.         if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
  363.             const cairo_surface_pattern_t *surface_pattern = (const cairo_surface_pattern_t *) source;
  364.             if (_cairo_surface_is_recording (surface_pattern->surface)) {
  365.                 backend_source_status =
  366.                     _analyze_recording_surface_pattern (surface, source);
  367.                 if (_cairo_status_is_error (backend_source_status))
  368.                     return backend_source_status;
  369.             }
  370.         }
  371.  
  372.         if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
  373.             cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) mask;
  374.             if (_cairo_surface_is_recording (surface_pattern->surface)) {
  375.                 backend_mask_status =
  376.                     _analyze_recording_surface_pattern (surface, mask);
  377.                 if (_cairo_status_is_error (backend_mask_status))
  378.                     return backend_mask_status;
  379.             }
  380.         }
  381.  
  382.         backend_status =
  383.             _cairo_analysis_surface_merge_status (backend_source_status,
  384.                                                   backend_mask_status);
  385.     }
  386.  
  387.     _cairo_analysis_surface_operation_extents (surface,
  388.                                                op, source, clip,
  389.                                                &extents);
  390.  
  391.     if (_cairo_operator_bounded_by_mask (op)) {
  392.         cairo_rectangle_int_t mask_extents;
  393.  
  394.         _cairo_pattern_get_extents (mask, &mask_extents);
  395.         is_empty = _cairo_rectangle_intersect (&extents, &mask_extents);
  396.  
  397.     }
  398.  
  399.     return _add_operation (surface, &extents, backend_status);
  400. }
  401.  
  402. static cairo_int_status_t
  403. _cairo_analysis_surface_stroke (void                    *abstract_surface,
  404.                                 cairo_operator_t         op,
  405.                                 const cairo_pattern_t   *source,
  406.                                 cairo_path_fixed_t      *path,
  407.                                 const cairo_stroke_style_t      *style,
  408.                                 const cairo_matrix_t            *ctm,
  409.                                 const cairo_matrix_t            *ctm_inverse,
  410.                                 double                   tolerance,
  411.                                 cairo_antialias_t        antialias,
  412.                                 cairo_clip_t            *clip)
  413. {
  414.     cairo_analysis_surface_t *surface = abstract_surface;
  415.     cairo_status_t           backend_status;
  416.     cairo_rectangle_int_t    extents;
  417.     cairo_bool_t             is_empty;
  418.  
  419.     if (surface->target->backend->stroke == NULL) {
  420.         backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
  421.     } else {
  422.         backend_status =
  423.             surface->target->backend->stroke (surface->target, op,
  424.                                               source, path, style,
  425.                                               ctm, ctm_inverse,
  426.                                               tolerance, antialias,
  427.                                               clip);
  428.         if (_cairo_status_is_error (backend_status))
  429.             return backend_status;
  430.     }
  431.  
  432.     if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
  433.         backend_status = _analyze_recording_surface_pattern (surface, source);
  434.  
  435.     _cairo_analysis_surface_operation_extents (surface,
  436.                                                op, source, clip,
  437.                                                &extents);
  438.  
  439.     if (_cairo_operator_bounded_by_mask (op)) {
  440.         cairo_rectangle_int_t mask_extents;
  441.         cairo_status_t status;
  442.  
  443.         status = _cairo_path_fixed_stroke_extents (path, style,
  444.                                                    ctm, ctm_inverse,
  445.                                                    tolerance,
  446.                                                    &mask_extents);
  447.         if (unlikely (status))
  448.             return status;
  449.  
  450.         is_empty = _cairo_rectangle_intersect (&extents, &mask_extents);
  451.     }
  452.  
  453.     return _add_operation (surface, &extents, backend_status);
  454. }
  455.  
  456. static cairo_int_status_t
  457. _cairo_analysis_surface_fill (void                      *abstract_surface,
  458.                               cairo_operator_t           op,
  459.                               const cairo_pattern_t     *source,
  460.                               cairo_path_fixed_t        *path,
  461.                               cairo_fill_rule_t          fill_rule,
  462.                               double                     tolerance,
  463.                               cairo_antialias_t          antialias,
  464.                               cairo_clip_t              *clip)
  465. {
  466.     cairo_analysis_surface_t *surface = abstract_surface;
  467.     cairo_status_t           backend_status;
  468.     cairo_rectangle_int_t    extents;
  469.     cairo_bool_t             is_empty;
  470.  
  471.     if (surface->target->backend->fill == NULL) {
  472.         backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
  473.     } else {
  474.         backend_status =
  475.             surface->target->backend->fill (surface->target, op,
  476.                                             source, path, fill_rule,
  477.                                             tolerance, antialias,
  478.                                             clip);
  479.         if (_cairo_status_is_error (backend_status))
  480.             return backend_status;
  481.     }
  482.  
  483.     if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
  484.         backend_status = _analyze_recording_surface_pattern (surface, source);
  485.  
  486.     _cairo_analysis_surface_operation_extents (surface,
  487.                                                op, source, clip,
  488.                                                &extents);
  489.  
  490.     if (_cairo_operator_bounded_by_mask (op)) {
  491.         cairo_rectangle_int_t mask_extents;
  492.  
  493.         _cairo_path_fixed_fill_extents (path, fill_rule, tolerance,
  494.                                         &mask_extents);
  495.  
  496.         is_empty = _cairo_rectangle_intersect (&extents, &mask_extents);
  497.     }
  498.  
  499.     return _add_operation (surface, &extents, backend_status);
  500. }
  501.  
  502. static cairo_int_status_t
  503. _cairo_analysis_surface_show_glyphs (void                 *abstract_surface,
  504.                                      cairo_operator_t      op,
  505.                                      const cairo_pattern_t *source,
  506.                                      cairo_glyph_t        *glyphs,
  507.                                      int                   num_glyphs,
  508.                                      cairo_scaled_font_t  *scaled_font,
  509.                                      cairo_clip_t         *clip,
  510.                                      int                  *remaining_glyphs)
  511. {
  512.     cairo_analysis_surface_t *surface = abstract_surface;
  513.     cairo_status_t           status, backend_status;
  514.     cairo_rectangle_int_t    extents, glyph_extents;
  515.     cairo_bool_t             is_empty;
  516.  
  517.     /* Adapted from _cairo_surface_show_glyphs */
  518.     if (surface->target->backend->show_glyphs != NULL) {
  519.         backend_status =
  520.             surface->target->backend->show_glyphs (surface->target, op,
  521.                                                    source,
  522.                                                    glyphs, num_glyphs,
  523.                                                    scaled_font,
  524.                                                    clip,
  525.                                                    remaining_glyphs);
  526.         if (_cairo_status_is_error (backend_status))
  527.             return backend_status;
  528.     }
  529.     else if (surface->target->backend->show_text_glyphs != NULL)
  530.     {
  531.         backend_status =
  532.             surface->target->backend->show_text_glyphs (surface->target, op,
  533.                                                         source,
  534.                                                         NULL, 0,
  535.                                                         glyphs, num_glyphs,
  536.                                                         NULL, 0,
  537.                                                         FALSE,
  538.                                                         scaled_font,
  539.                                                         clip);
  540.         if (_cairo_status_is_error (backend_status))
  541.             return backend_status;
  542.     }
  543.     else
  544.     {
  545.         backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
  546.     }
  547.  
  548.     if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
  549.         backend_status = _analyze_recording_surface_pattern (surface, source);
  550.  
  551.     _cairo_analysis_surface_operation_extents (surface,
  552.                                                op, source, clip,
  553.                                                &extents);
  554.  
  555.     if (_cairo_operator_bounded_by_mask (op)) {
  556.         status = _cairo_scaled_font_glyph_device_extents (scaled_font,
  557.                                                           glyphs,
  558.                                                           num_glyphs,
  559.                                                           &glyph_extents,
  560.                                                           NULL);
  561.         if (unlikely (status))
  562.             return status;
  563.  
  564.         is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents);
  565.     }
  566.  
  567.     return _add_operation (surface, &extents, backend_status);
  568. }
  569.  
  570. static cairo_bool_t
  571. _cairo_analysis_surface_has_show_text_glyphs (void *abstract_surface)
  572. {
  573.     cairo_analysis_surface_t *surface = abstract_surface;
  574.  
  575.     return cairo_surface_has_show_text_glyphs (surface->target);
  576. }
  577.  
  578. static cairo_int_status_t
  579. _cairo_analysis_surface_show_text_glyphs (void                      *abstract_surface,
  580.                                           cairo_operator_t           op,
  581.                                           const cairo_pattern_t     *source,
  582.                                           const char                *utf8,
  583.                                           int                        utf8_len,
  584.                                           cairo_glyph_t             *glyphs,
  585.                                           int                        num_glyphs,
  586.                                           const cairo_text_cluster_t *clusters,
  587.                                           int                        num_clusters,
  588.                                           cairo_text_cluster_flags_t cluster_flags,
  589.                                           cairo_scaled_font_t       *scaled_font,
  590.                                           cairo_clip_t              *clip)
  591. {
  592.     cairo_analysis_surface_t *surface = abstract_surface;
  593.     cairo_status_t           status, backend_status;
  594.     cairo_rectangle_int_t    extents, glyph_extents;
  595.     cairo_bool_t             is_empty;
  596.  
  597.     /* Adapted from _cairo_surface_show_glyphs */
  598.     backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
  599.     if (surface->target->backend->show_text_glyphs != NULL) {
  600.         backend_status =
  601.             surface->target->backend->show_text_glyphs (surface->target, op,
  602.                                                         source,
  603.                                                         utf8, utf8_len,
  604.                                                         glyphs, num_glyphs,
  605.                                                         clusters, num_clusters,
  606.                                                         cluster_flags,
  607.                                                         scaled_font,
  608.                                                         clip);
  609.         if (_cairo_status_is_error (backend_status))
  610.             return backend_status;
  611.     }
  612.     if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED &&
  613.         surface->target->backend->show_glyphs != NULL)
  614.     {
  615.         int remaining_glyphs = num_glyphs;
  616.         backend_status =
  617.             surface->target->backend->show_glyphs (surface->target, op,
  618.                                                    source,
  619.                                                    glyphs, num_glyphs,
  620.                                                    scaled_font,
  621.                                                    clip,
  622.                                                    &remaining_glyphs);
  623.         if (_cairo_status_is_error (backend_status))
  624.             return backend_status;
  625.  
  626.         glyphs += num_glyphs - remaining_glyphs;
  627.         num_glyphs = remaining_glyphs;
  628.         if (remaining_glyphs == 0)
  629.             backend_status = CAIRO_STATUS_SUCCESS;
  630.     }
  631.  
  632.     if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
  633.         backend_status = _analyze_recording_surface_pattern (surface, source);
  634.  
  635.     _cairo_analysis_surface_operation_extents (surface,
  636.                                                op, source, clip,
  637.                                                &extents);
  638.  
  639.     if (_cairo_operator_bounded_by_mask (op)) {
  640.         status = _cairo_scaled_font_glyph_device_extents (scaled_font,
  641.                                                           glyphs,
  642.                                                           num_glyphs,
  643.                                                           &glyph_extents,
  644.                                                           NULL);
  645.         if (unlikely (status))
  646.             return status;
  647.  
  648.         is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents);
  649.     }
  650.  
  651.     return _add_operation (surface, &extents, backend_status);
  652. }
  653.  
  654. static const cairo_surface_backend_t cairo_analysis_surface_backend = {
  655.     CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
  656.     NULL, /* create_similar */
  657.     _cairo_analysis_surface_finish,
  658.     NULL, /* acquire_source_image */
  659.     NULL, /* release_source_image */
  660.     NULL, /* acquire_dest_image */
  661.     NULL, /* release_dest_image */
  662.     NULL, /* clone_similar */
  663.     NULL, /* composite */
  664.     NULL, /* fill_rectangles */
  665.     NULL, /* composite_trapezoids */
  666.     NULL, /* create_span_renderer */
  667.     NULL, /* check_span_renderer */
  668.     NULL, /* copy_page */
  669.     NULL, /* show_page */
  670.     _cairo_analysis_surface_get_extents,
  671.     NULL, /* old_show_glyphs */
  672.     NULL, /* get_font_options */
  673.     NULL, /* flush */
  674.     NULL, /* mark_dirty_rectangle */
  675.     NULL, /* scaled_font_fini */
  676.     NULL, /* scaled_glyph_fini */
  677.     _cairo_analysis_surface_paint,
  678.     _cairo_analysis_surface_mask,
  679.     _cairo_analysis_surface_stroke,
  680.     _cairo_analysis_surface_fill,
  681.     _cairo_analysis_surface_show_glyphs,
  682.     NULL, /* snapshot */
  683.     NULL, /* is_similar */
  684.     NULL, /* fill_stroke */
  685.     NULL, /* create_solid_pattern_surface */
  686.     NULL, /* can_repaint_solid_pattern_surface */
  687.     _cairo_analysis_surface_has_show_text_glyphs,
  688.     _cairo_analysis_surface_show_text_glyphs
  689. };
  690.  
  691. cairo_surface_t *
  692. _cairo_analysis_surface_create (cairo_surface_t         *target)
  693. {
  694.     cairo_analysis_surface_t *surface;
  695.     cairo_status_t status;
  696.  
  697.     status = target->status;
  698.     if (unlikely (status))
  699.         return _cairo_surface_create_in_error (status);
  700.  
  701.     surface = malloc (sizeof (cairo_analysis_surface_t));
  702.     if (unlikely (surface == NULL))
  703.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  704.  
  705.     /* I believe the content type here is truly arbitrary. I'm quite
  706.      * sure nothing will ever use this value. */
  707.     _cairo_surface_init (&surface->base,
  708.                          &cairo_analysis_surface_backend,
  709.                          NULL, /* device */
  710.                          CAIRO_CONTENT_COLOR_ALPHA);
  711.  
  712.     cairo_matrix_init_identity (&surface->ctm);
  713.     surface->has_ctm = FALSE;
  714.  
  715.     surface->target = cairo_surface_reference (target);
  716.     surface->first_op  = TRUE;
  717.     surface->has_supported = FALSE;
  718.     surface->has_unsupported = FALSE;
  719.  
  720.     _cairo_region_init (&surface->supported_region);
  721.     _cairo_region_init (&surface->fallback_region);
  722.  
  723.     surface->page_bbox.p1.x = 0;
  724.     surface->page_bbox.p1.y = 0;
  725.     surface->page_bbox.p2.x = 0;
  726.     surface->page_bbox.p2.y = 0;
  727.  
  728.     return &surface->base;
  729. }
  730.  
  731. void
  732. _cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface,
  733.                                  const cairo_matrix_t  *ctm)
  734. {
  735.     cairo_analysis_surface_t    *surface;
  736.  
  737.     if (abstract_surface->status)
  738.         return;
  739.  
  740.     surface = (cairo_analysis_surface_t *) abstract_surface;
  741.  
  742.     surface->ctm = *ctm;
  743.     surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm);
  744. }
  745.  
  746. void
  747. _cairo_analysis_surface_get_ctm (cairo_surface_t *abstract_surface,
  748.                                  cairo_matrix_t  *ctm)
  749. {
  750.     cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
  751.  
  752.     *ctm = surface->ctm;
  753. }
  754.  
  755.  
  756. cairo_region_t *
  757. _cairo_analysis_surface_get_supported (cairo_surface_t *abstract_surface)
  758. {
  759.     cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
  760.  
  761.     return &surface->supported_region;
  762. }
  763.  
  764. cairo_region_t *
  765. _cairo_analysis_surface_get_unsupported (cairo_surface_t *abstract_surface)
  766. {
  767.     cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
  768.  
  769.     return &surface->fallback_region;
  770. }
  771.  
  772. cairo_bool_t
  773. _cairo_analysis_surface_has_supported (cairo_surface_t *abstract_surface)
  774. {
  775.     cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
  776.  
  777.     return surface->has_supported;
  778. }
  779.  
  780. cairo_bool_t
  781. _cairo_analysis_surface_has_unsupported (cairo_surface_t *abstract_surface)
  782. {
  783.     cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
  784.  
  785.     return surface->has_unsupported;
  786. }
  787.  
  788. void
  789. _cairo_analysis_surface_get_bounding_box (cairo_surface_t *abstract_surface,
  790.                                           cairo_box_t     *bbox)
  791. {
  792.     cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
  793.  
  794.     *bbox = surface->page_bbox;
  795. }
  796.  
  797. /* null surface type: a surface that does nothing (has no side effects, yay!) */
  798.  
  799. static cairo_int_status_t
  800. _return_success (void)
  801. {
  802.     return CAIRO_STATUS_SUCCESS;
  803. }
  804.  
  805. /* These typedefs are just to silence the compiler... */
  806. typedef cairo_int_status_t
  807. (*_paint_func)                  (void                   *surface,
  808.                                  cairo_operator_t        op,
  809.                                  const cairo_pattern_t  *source,
  810.                                  cairo_clip_t           *clip);
  811.  
  812. typedef cairo_int_status_t
  813. (*_mask_func)                   (void                   *surface,
  814.                                  cairo_operator_t        op,
  815.                                  const cairo_pattern_t  *source,
  816.                                  const cairo_pattern_t  *mask,
  817.                                  cairo_clip_t           *clip);
  818.  
  819. typedef cairo_int_status_t
  820. (*_stroke_func)                 (void                   *surface,
  821.                                  cairo_operator_t        op,
  822.                                  const cairo_pattern_t  *source,
  823.                                  cairo_path_fixed_t     *path,
  824.                                  const cairo_stroke_style_t     *style,
  825.                                  const cairo_matrix_t           *ctm,
  826.                                  const cairo_matrix_t           *ctm_inverse,
  827.                                  double                  tolerance,
  828.                                  cairo_antialias_t       antialias,
  829.                                  cairo_clip_t           *clip);
  830.  
  831. typedef cairo_int_status_t
  832. (*_fill_func)                   (void                   *surface,
  833.                                  cairo_operator_t        op,
  834.                                  const cairo_pattern_t  *source,
  835.                                  cairo_path_fixed_t     *path,
  836.                                  cairo_fill_rule_t       fill_rule,
  837.                                  double                  tolerance,
  838.                                  cairo_antialias_t       antialias,
  839.                                  cairo_clip_t           *clip);
  840.  
  841. typedef cairo_int_status_t
  842. (*_show_glyphs_func)            (void                   *surface,
  843.                                  cairo_operator_t        op,
  844.                                  const cairo_pattern_t  *source,
  845.                                  cairo_glyph_t          *glyphs,
  846.                                  int                     num_glyphs,
  847.                                  cairo_scaled_font_t    *scaled_font,
  848.                                  cairo_clip_t           *clip,
  849.                                  int                    *remaining_glyphs);
  850.  
  851. static const cairo_surface_backend_t cairo_null_surface_backend = {
  852.     CAIRO_INTERNAL_SURFACE_TYPE_NULL,
  853.  
  854.     NULL, /* create_similar */
  855.     NULL, /* finish */
  856.     NULL, /* acquire_source_image */
  857.     NULL, /* release_source_image */
  858.     NULL, /* acquire_dest_image */
  859.     NULL, /* release_dest_image */
  860.     NULL, /* clone_similar */
  861.     NULL, /* composite */
  862.     NULL, /* fill_rectangles */
  863.     NULL, /* composite_trapezoids */
  864.     NULL, /* create_span_renderer */
  865.     NULL, /* check_span_renderer */
  866.     NULL, /* copy_page */
  867.     NULL, /* show_page */
  868.     NULL, /* get_extents */
  869.     NULL, /* old_show_glyphs */
  870.     NULL, /* get_font_options */
  871.     NULL, /* flush */
  872.     NULL, /* mark_dirty_rectangle */
  873.     NULL, /* scaled_font_fini */
  874.     NULL, /* scaled_glyph_fini */
  875.     (_paint_func) _return_success,          /* paint */
  876.     (_mask_func) _return_success,           /* mask */
  877.     (_stroke_func) _return_success,         /* stroke */
  878.     (_fill_func) _return_success,           /* fill */
  879.     (_show_glyphs_func) _return_success,    /* show_glyphs */
  880.     NULL, /* snapshot */
  881.     NULL, /* is_similar */
  882.     NULL, /* fill_stroke */
  883.     NULL, /* create_solid_pattern_surface */
  884.     NULL, /* can_repaint_solid_pattern_surface */
  885.     NULL, /* has_show_text_glyphs */
  886.     NULL  /* show_text_glyphs */
  887. };
  888.  
  889. cairo_surface_t *
  890. _cairo_null_surface_create (cairo_content_t content)
  891. {
  892.     cairo_surface_t *surface;
  893.  
  894.     surface = malloc (sizeof (cairo_surface_t));
  895.     if (unlikely (surface == NULL)) {
  896.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  897.     }
  898.  
  899.     _cairo_surface_init (surface,
  900.                          &cairo_null_surface_backend,
  901.                          NULL, /* device */
  902.                          content);
  903.  
  904.     return surface;
  905. }
  906.