Subversion Repositories Kolibri OS

Rev

Rev 1892 | 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-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. }
  935.