LCOV - code coverage report
Current view: top level - gfx/cairo/cairo/src - cairo-analysis-surface.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 280 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 24 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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           0 : _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           0 :     assert (! _cairo_status_is_error (status_a));
      70           0 :     assert (! _cairo_status_is_error (status_b));
      71             : 
      72             :     /* return the most important status */
      73           0 :     if (status_a == CAIRO_INT_STATUS_UNSUPPORTED ||
      74             :         status_b == CAIRO_INT_STATUS_UNSUPPORTED)
      75           0 :         return CAIRO_INT_STATUS_UNSUPPORTED;
      76             : 
      77           0 :     if (status_a == CAIRO_INT_STATUS_IMAGE_FALLBACK ||
      78             :         status_b == CAIRO_INT_STATUS_IMAGE_FALLBACK)
      79           0 :         return CAIRO_INT_STATUS_IMAGE_FALLBACK;
      80             : 
      81           0 :     if (status_a == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN ||
      82             :         status_b == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
      83           0 :         return CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN;
      84             : 
      85           0 :     if (status_a == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY ||
      86             :         status_b == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
      87           0 :         return CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY;
      88             : 
      89             :     /* at this point we have checked all the valid internal codes, so... */
      90           0 :     assert (status_a == CAIRO_STATUS_SUCCESS &&
      91             :             status_b == CAIRO_STATUS_SUCCESS);
      92             : 
      93           0 :     return CAIRO_STATUS_SUCCESS;
      94             : }
      95             : 
      96             : static cairo_int_status_t
      97           0 : _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           0 :     assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
     107           0 :     surface_pattern = (const cairo_surface_pattern_t *) pattern;
     108           0 :     assert (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING);
     109             : 
     110           0 :     old_ctm = surface->ctm;
     111           0 :     old_has_ctm = surface->has_ctm;
     112             : 
     113           0 :     p2d = pattern->matrix;
     114           0 :     status = cairo_matrix_invert (&p2d);
     115           0 :     assert (status == CAIRO_STATUS_SUCCESS);
     116             : 
     117           0 :     cairo_matrix_multiply (&surface->ctm, &p2d, &surface->ctm);
     118           0 :     surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm);
     119             : 
     120           0 :     source = surface_pattern->surface;
     121           0 :     if (source->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
     122           0 :         cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
     123           0 :         source = sub->target;
     124             :     }
     125             : 
     126           0 :     status = _cairo_recording_surface_replay_and_create_regions (source, &surface->base);
     127             : 
     128           0 :     surface->ctm = old_ctm;
     129           0 :     surface->has_ctm = old_has_ctm;
     130             : 
     131           0 :     return status;
     132             : }
     133             : 
     134             : static cairo_int_status_t
     135           0 : _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           0 :     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           0 :         if (backend_status == CAIRO_STATUS_SUCCESS ||
     147             :             backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
     148             :         {
     149           0 :             return CAIRO_STATUS_SUCCESS;
     150             :         }
     151             :         else
     152             :         {
     153           0 :             return CAIRO_INT_STATUS_IMAGE_FALLBACK;
     154             :         }
     155             :     }
     156             : 
     157           0 :     _cairo_box_from_rectangle (&bbox, rect);
     158             : 
     159           0 :     if (surface->has_ctm) {
     160             :         int tx, ty;
     161             : 
     162           0 :         if (_cairo_matrix_is_integer_translation (&surface->ctm, &tx, &ty)) {
     163           0 :             rect->x += tx;
     164           0 :             rect->y += ty;
     165             :         } else {
     166           0 :             _cairo_matrix_transform_bounding_box_fixed (&surface->ctm,
     167             :                                                         &bbox, NULL);
     168             : 
     169           0 :             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           0 :                 if (backend_status == CAIRO_STATUS_SUCCESS ||
     175             :                     backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
     176             :                 {
     177           0 :                     return CAIRO_STATUS_SUCCESS;
     178             :                 }
     179             :                 else
     180             :                 {
     181           0 :                     return CAIRO_INT_STATUS_IMAGE_FALLBACK;
     182             :                 }
     183             :             }
     184             : 
     185           0 :             _cairo_box_round_to_rectangle (&bbox, rect);
     186             :         }
     187             :     }
     188             : 
     189           0 :     if (surface->first_op) {
     190           0 :         surface->first_op = FALSE;
     191           0 :         surface->page_bbox = bbox;
     192             :     } else {
     193           0 :         if (bbox.p1.x < surface->page_bbox.p1.x)
     194           0 :             surface->page_bbox.p1.x = bbox.p1.x;
     195           0 :         if (bbox.p1.y < surface->page_bbox.p1.y)
     196           0 :             surface->page_bbox.p1.y = bbox.p1.y;
     197           0 :         if (bbox.p2.x > surface->page_bbox.p2.x)
     198           0 :             surface->page_bbox.p2.x = bbox.p2.x;
     199           0 :         if (bbox.p2.y > surface->page_bbox.p2.y)
     200           0 :             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           0 :     if (cairo_region_contains_rectangle (&surface->fallback_region, rect) == CAIRO_REGION_OVERLAP_IN)
     208           0 :         return CAIRO_INT_STATUS_IMAGE_FALLBACK;
     209             : 
     210           0 :     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           0 :         if (cairo_region_contains_rectangle (&surface->supported_region, rect) == CAIRO_REGION_OVERLAP_OUT)
     219           0 :             backend_status = CAIRO_STATUS_SUCCESS;
     220             :     }
     221             : 
     222           0 :     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           0 :         surface->has_supported = TRUE;
     227           0 :         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           0 :     surface->has_unsupported = TRUE;
     235           0 :     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           0 :     if (status == CAIRO_STATUS_SUCCESS)
     244           0 :         return CAIRO_INT_STATUS_IMAGE_FALLBACK;
     245             :     else
     246           0 :         return status;
     247             : }
     248             : 
     249             : static cairo_status_t
     250           0 : _cairo_analysis_surface_finish (void *abstract_surface)
     251             : {
     252           0 :     cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
     253             : 
     254           0 :     _cairo_region_fini (&surface->supported_region);
     255           0 :     _cairo_region_fini (&surface->fallback_region);
     256             : 
     257           0 :     cairo_surface_destroy (surface->target);
     258             : 
     259           0 :     return CAIRO_STATUS_SUCCESS;
     260             : }
     261             : 
     262             : static cairo_bool_t
     263           0 : _cairo_analysis_surface_get_extents (void                       *abstract_surface,
     264             :                                      cairo_rectangle_int_t      *rectangle)
     265             : {
     266           0 :     cairo_analysis_surface_t *surface = abstract_surface;
     267             : 
     268           0 :     return _cairo_surface_get_extents (surface->target, rectangle);
     269             : }
     270             : 
     271             : static void
     272           0 : _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           0 :     clip_extents = NULL;
     278           0 :     if (clip != NULL)
     279           0 :         clip_extents = _cairo_clip_get_extents (clip);
     280             : 
     281           0 :     if (clip_extents != NULL)
     282           0 :         is_empty = _cairo_rectangle_intersect (extents, clip_extents);
     283           0 : }
     284             : 
     285             : static void
     286           0 : _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           0 :     is_empty = _cairo_surface_get_extents (&surface->base, extents);
     295             : 
     296           0 :     if (_cairo_operator_bounded_by_source (op)) {
     297             :         cairo_rectangle_int_t source_extents;
     298             : 
     299           0 :         _cairo_pattern_get_extents (source, &source_extents);
     300           0 :         is_empty = _cairo_rectangle_intersect (extents, &source_extents);
     301             :     }
     302             : 
     303           0 :     _rectangle_intersect_clip (extents, clip);
     304           0 : }
     305             : 
     306             : static cairo_int_status_t
     307           0 : _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           0 :     cairo_analysis_surface_t *surface = abstract_surface;
     313             :     cairo_status_t           backend_status;
     314             :     cairo_rectangle_int_t  extents;
     315             : 
     316           0 :     if (surface->target->backend->paint == NULL) {
     317           0 :         backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
     318             :     } else {
     319           0 :         backend_status =
     320           0 :             surface->target->backend->paint (surface->target,
     321             :                                              op, source, clip);
     322           0 :         if (_cairo_status_is_error (backend_status))
     323           0 :             return backend_status;
     324             :     }
     325             : 
     326           0 :     if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
     327           0 :         backend_status = _analyze_recording_surface_pattern (surface, source);
     328             : 
     329           0 :     _cairo_analysis_surface_operation_extents (surface,
     330             :                                                op, source, clip,
     331             :                                                &extents);
     332             : 
     333           0 :     return _add_operation (surface, &extents, backend_status);
     334             : }
     335             : 
     336             : static cairo_int_status_t
     337           0 : _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           0 :     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           0 :     if (surface->target->backend->mask == NULL) {
     349           0 :         backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
     350             :     } else {
     351           0 :         backend_status =
     352           0 :             surface->target->backend->mask (surface->target,
     353             :                                             op, source, mask, clip);
     354           0 :         if (_cairo_status_is_error (backend_status))
     355           0 :             return backend_status;
     356             :     }
     357             : 
     358           0 :     if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN) {
     359           0 :         cairo_int_status_t backend_source_status = CAIRO_STATUS_SUCCESS;
     360           0 :         cairo_int_status_t backend_mask_status = CAIRO_STATUS_SUCCESS;
     361             : 
     362           0 :         if (source->type == CAIRO_PATTERN_TYPE_SURFACE) {
     363           0 :             const cairo_surface_pattern_t *surface_pattern = (const cairo_surface_pattern_t *) source;
     364           0 :             if (_cairo_surface_is_recording (surface_pattern->surface)) {
     365           0 :                 backend_source_status =
     366             :                     _analyze_recording_surface_pattern (surface, source);
     367           0 :                 if (_cairo_status_is_error (backend_source_status))
     368           0 :                     return backend_source_status;
     369             :             }
     370             :         }
     371             : 
     372           0 :         if (mask->type == CAIRO_PATTERN_TYPE_SURFACE) {
     373           0 :             cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) mask;
     374           0 :             if (_cairo_surface_is_recording (surface_pattern->surface)) {
     375           0 :                 backend_mask_status =
     376             :                     _analyze_recording_surface_pattern (surface, mask);
     377           0 :                 if (_cairo_status_is_error (backend_mask_status))
     378           0 :                     return backend_mask_status;
     379             :             }
     380             :         }
     381             : 
     382           0 :         backend_status =
     383             :             _cairo_analysis_surface_merge_status (backend_source_status,
     384             :                                                   backend_mask_status);
     385             :     }
     386             : 
     387           0 :     _cairo_analysis_surface_operation_extents (surface,
     388             :                                                op, source, clip,
     389             :                                                &extents);
     390             : 
     391           0 :     if (_cairo_operator_bounded_by_mask (op)) {
     392             :         cairo_rectangle_int_t mask_extents;
     393             : 
     394           0 :         _cairo_pattern_get_extents (mask, &mask_extents);
     395           0 :         is_empty = _cairo_rectangle_intersect (&extents, &mask_extents);
     396             : 
     397             :     }
     398             : 
     399           0 :     return _add_operation (surface, &extents, backend_status);
     400             : }
     401             : 
     402             : static cairo_int_status_t
     403           0 : _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           0 :     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           0 :     if (surface->target->backend->stroke == NULL) {
     420           0 :         backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
     421             :     } else {
     422           0 :         backend_status =
     423           0 :             surface->target->backend->stroke (surface->target, op,
     424             :                                               source, path, style,
     425             :                                               ctm, ctm_inverse,
     426             :                                               tolerance, antialias,
     427             :                                               clip);
     428           0 :         if (_cairo_status_is_error (backend_status))
     429           0 :             return backend_status;
     430             :     }
     431             : 
     432           0 :     if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
     433           0 :         backend_status = _analyze_recording_surface_pattern (surface, source);
     434             : 
     435           0 :     _cairo_analysis_surface_operation_extents (surface,
     436             :                                                op, source, clip,
     437             :                                                &extents);
     438             : 
     439           0 :     if (_cairo_operator_bounded_by_mask (op)) {
     440             :         cairo_rectangle_int_t mask_extents;
     441             : 
     442             :         /* If the backend can handle the stroke, then mark the approximate
     443             :          * extents of the operation. However, if we need to fallback in order
     444             :          * to draw the stroke, then ensure that the fallback is as tight as
     445             :          * possible -- both to minimise output file size and to ensure good
     446             :          * quality printed output for neighbouring regions.
     447             :          */
     448           0 :         if (backend_status == CAIRO_STATUS_SUCCESS) {
     449           0 :             _cairo_path_fixed_approximate_stroke_extents (path,
     450             :                                                           style, ctm,
     451             :                                                           &mask_extents);
     452             :         } else {
     453             :             cairo_status_t status;
     454             : 
     455           0 :             status = _cairo_path_fixed_stroke_extents (path, style,
     456             :                                                        ctm, ctm_inverse,
     457             :                                                        tolerance,
     458             :                                                        &mask_extents);
     459           0 :             if (unlikely (status))
     460           0 :                 return status;
     461             :         }
     462             : 
     463           0 :         is_empty = _cairo_rectangle_intersect (&extents, &mask_extents);
     464             :     }
     465             : 
     466           0 :     return _add_operation (surface, &extents, backend_status);
     467             : }
     468             : 
     469             : static cairo_int_status_t
     470           0 : _cairo_analysis_surface_fill (void                      *abstract_surface,
     471             :                               cairo_operator_t           op,
     472             :                               const cairo_pattern_t     *source,
     473             :                               cairo_path_fixed_t        *path,
     474             :                               cairo_fill_rule_t          fill_rule,
     475             :                               double                     tolerance,
     476             :                               cairo_antialias_t          antialias,
     477             :                               cairo_clip_t              *clip)
     478             : {
     479           0 :     cairo_analysis_surface_t *surface = abstract_surface;
     480             :     cairo_status_t           backend_status;
     481             :     cairo_rectangle_int_t    extents;
     482             :     cairo_bool_t             is_empty;
     483             : 
     484           0 :     if (surface->target->backend->fill == NULL) {
     485           0 :         backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
     486             :     } else {
     487           0 :         backend_status =
     488           0 :             surface->target->backend->fill (surface->target, op,
     489             :                                             source, path, fill_rule,
     490             :                                             tolerance, antialias,
     491             :                                             clip);
     492           0 :         if (_cairo_status_is_error (backend_status))
     493           0 :             return backend_status;
     494             :     }
     495             : 
     496           0 :     if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
     497           0 :         backend_status = _analyze_recording_surface_pattern (surface, source);
     498             : 
     499           0 :     _cairo_analysis_surface_operation_extents (surface,
     500             :                                                op, source, clip,
     501             :                                                &extents);
     502             : 
     503           0 :     if (_cairo_operator_bounded_by_mask (op)) {
     504             :         cairo_rectangle_int_t mask_extents;
     505             : 
     506             :         /* We want speed for the likely case where the operation can be
     507             :          * performed natively, but accuracy if we have to resort to
     508             :          * using images.
     509             :          */
     510           0 :         if (backend_status == CAIRO_STATUS_SUCCESS) {
     511           0 :             _cairo_path_fixed_approximate_fill_extents (path, &mask_extents);
     512             :         } else {
     513           0 :              _cairo_path_fixed_fill_extents (path, fill_rule, tolerance,
     514             :                                              &mask_extents);
     515             :         }
     516           0 :         is_empty = _cairo_rectangle_intersect (&extents, &mask_extents);
     517             :     }
     518             : 
     519           0 :     return _add_operation (surface, &extents, backend_status);
     520             : }
     521             : 
     522             : static cairo_int_status_t
     523           0 : _cairo_analysis_surface_show_glyphs (void                 *abstract_surface,
     524             :                                      cairo_operator_t      op,
     525             :                                      const cairo_pattern_t *source,
     526             :                                      cairo_glyph_t        *glyphs,
     527             :                                      int                   num_glyphs,
     528             :                                      cairo_scaled_font_t  *scaled_font,
     529             :                                      cairo_clip_t         *clip,
     530             :                                      int                  *remaining_glyphs)
     531             : {
     532           0 :     cairo_analysis_surface_t *surface = abstract_surface;
     533             :     cairo_status_t           status, backend_status;
     534             :     cairo_rectangle_int_t    extents, glyph_extents;
     535             :     cairo_bool_t             is_empty;
     536             : 
     537             :     /* Adapted from _cairo_surface_show_glyphs */
     538           0 :     if (surface->target->backend->show_glyphs != NULL) {
     539           0 :         backend_status =
     540           0 :             surface->target->backend->show_glyphs (surface->target, op,
     541             :                                                    source,
     542             :                                                    glyphs, num_glyphs,
     543             :                                                    scaled_font,
     544             :                                                    clip,
     545             :                                                    remaining_glyphs);
     546           0 :         if (_cairo_status_is_error (backend_status))
     547           0 :             return backend_status;
     548             :     }
     549           0 :     else if (surface->target->backend->show_text_glyphs != NULL)
     550             :     {
     551           0 :         backend_status =
     552           0 :             surface->target->backend->show_text_glyphs (surface->target, op,
     553             :                                                         source,
     554             :                                                         NULL, 0,
     555             :                                                         glyphs, num_glyphs,
     556             :                                                         NULL, 0,
     557             :                                                         FALSE,
     558             :                                                         scaled_font,
     559             :                                                         clip);
     560           0 :         if (_cairo_status_is_error (backend_status))
     561           0 :             return backend_status;
     562             :     }
     563             :     else
     564             :     {
     565           0 :         backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
     566             :     }
     567             : 
     568           0 :     if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
     569           0 :         backend_status = _analyze_recording_surface_pattern (surface, source);
     570             : 
     571           0 :     _cairo_analysis_surface_operation_extents (surface,
     572             :                                                op, source, clip,
     573             :                                                &extents);
     574             : 
     575           0 :     if (_cairo_operator_bounded_by_mask (op)) {
     576           0 :         status = _cairo_scaled_font_glyph_device_extents (scaled_font,
     577             :                                                           glyphs,
     578             :                                                           num_glyphs,
     579             :                                                           &glyph_extents,
     580             :                                                           NULL);
     581           0 :         if (unlikely (status))
     582           0 :             return status;
     583             : 
     584           0 :         is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents);
     585             :     }
     586             : 
     587           0 :     return _add_operation (surface, &extents, backend_status);
     588             : }
     589             : 
     590             : static cairo_bool_t
     591           0 : _cairo_analysis_surface_has_show_text_glyphs (void *abstract_surface)
     592             : {
     593           0 :     cairo_analysis_surface_t *surface = abstract_surface;
     594             : 
     595           0 :     return cairo_surface_has_show_text_glyphs (surface->target);
     596             : }
     597             : 
     598             : static cairo_int_status_t
     599           0 : _cairo_analysis_surface_show_text_glyphs (void                      *abstract_surface,
     600             :                                           cairo_operator_t           op,
     601             :                                           const cairo_pattern_t     *source,
     602             :                                           const char                *utf8,
     603             :                                           int                        utf8_len,
     604             :                                           cairo_glyph_t             *glyphs,
     605             :                                           int                        num_glyphs,
     606             :                                           const cairo_text_cluster_t *clusters,
     607             :                                           int                        num_clusters,
     608             :                                           cairo_text_cluster_flags_t cluster_flags,
     609             :                                           cairo_scaled_font_t       *scaled_font,
     610             :                                           cairo_clip_t              *clip)
     611             : {
     612           0 :     cairo_analysis_surface_t *surface = abstract_surface;
     613             :     cairo_status_t           status, backend_status;
     614             :     cairo_rectangle_int_t    extents, glyph_extents;
     615             :     cairo_bool_t             is_empty;
     616             : 
     617             :     /* Adapted from _cairo_surface_show_glyphs */
     618           0 :     backend_status = CAIRO_INT_STATUS_UNSUPPORTED;
     619           0 :     if (surface->target->backend->show_text_glyphs != NULL) {
     620           0 :         backend_status =
     621           0 :             surface->target->backend->show_text_glyphs (surface->target, op,
     622             :                                                         source,
     623             :                                                         utf8, utf8_len,
     624             :                                                         glyphs, num_glyphs,
     625             :                                                         clusters, num_clusters,
     626             :                                                         cluster_flags,
     627             :                                                         scaled_font,
     628             :                                                         clip);
     629           0 :         if (_cairo_status_is_error (backend_status))
     630           0 :             return backend_status;
     631             :     }
     632           0 :     if (backend_status == CAIRO_INT_STATUS_UNSUPPORTED &&
     633           0 :         surface->target->backend->show_glyphs != NULL)
     634             :     {
     635           0 :         int remaining_glyphs = num_glyphs;
     636           0 :         backend_status =
     637           0 :             surface->target->backend->show_glyphs (surface->target, op,
     638             :                                                    source,
     639             :                                                    glyphs, num_glyphs,
     640             :                                                    scaled_font,
     641             :                                                    clip,
     642             :                                                    &remaining_glyphs);
     643           0 :         if (_cairo_status_is_error (backend_status))
     644           0 :             return backend_status;
     645             : 
     646           0 :         glyphs += num_glyphs - remaining_glyphs;
     647           0 :         num_glyphs = remaining_glyphs;
     648           0 :         if (remaining_glyphs == 0)
     649           0 :             backend_status = CAIRO_STATUS_SUCCESS;
     650             :     }
     651             : 
     652           0 :     if (backend_status == CAIRO_INT_STATUS_ANALYZE_RECORDING_SURFACE_PATTERN)
     653           0 :         backend_status = _analyze_recording_surface_pattern (surface, source);
     654             : 
     655           0 :     _cairo_analysis_surface_operation_extents (surface,
     656             :                                                op, source, clip,
     657             :                                                &extents);
     658             : 
     659           0 :     if (_cairo_operator_bounded_by_mask (op)) {
     660           0 :         status = _cairo_scaled_font_glyph_device_extents (scaled_font,
     661             :                                                           glyphs,
     662             :                                                           num_glyphs,
     663             :                                                           &glyph_extents,
     664             :                                                           NULL);
     665           0 :         if (unlikely (status))
     666           0 :             return status;
     667             : 
     668           0 :         is_empty = _cairo_rectangle_intersect (&extents, &glyph_extents);
     669             :     }
     670             : 
     671           0 :     return _add_operation (surface, &extents, backend_status);
     672             : }
     673             : 
     674             : static const cairo_surface_backend_t cairo_analysis_surface_backend = {
     675             :     CAIRO_INTERNAL_SURFACE_TYPE_ANALYSIS,
     676             :     NULL, /* create_similar */
     677             :     _cairo_analysis_surface_finish,
     678             :     NULL, /* acquire_source_image */
     679             :     NULL, /* release_source_image */
     680             :     NULL, /* acquire_dest_image */
     681             :     NULL, /* release_dest_image */
     682             :     NULL, /* clone_similar */
     683             :     NULL, /* composite */
     684             :     NULL, /* fill_rectangles */
     685             :     NULL, /* composite_trapezoids */
     686             :     NULL, /* create_span_renderer */
     687             :     NULL, /* check_span_renderer */
     688             :     NULL, /* copy_page */
     689             :     NULL, /* show_page */
     690             :     _cairo_analysis_surface_get_extents,
     691             :     NULL, /* old_show_glyphs */
     692             :     NULL, /* get_font_options */
     693             :     NULL, /* flush */
     694             :     NULL, /* mark_dirty_rectangle */
     695             :     NULL, /* scaled_font_fini */
     696             :     NULL, /* scaled_glyph_fini */
     697             :     _cairo_analysis_surface_paint,
     698             :     _cairo_analysis_surface_mask,
     699             :     _cairo_analysis_surface_stroke,
     700             :     _cairo_analysis_surface_fill,
     701             :     _cairo_analysis_surface_show_glyphs,
     702             :     NULL, /* snapshot */
     703             :     NULL, /* is_similar */
     704             :     NULL, /* fill_stroke */
     705             :     NULL, /* create_solid_pattern_surface */
     706             :     NULL, /* can_repaint_solid_pattern_surface */
     707             :     _cairo_analysis_surface_has_show_text_glyphs,
     708             :     _cairo_analysis_surface_show_text_glyphs
     709             : };
     710             : 
     711             : cairo_surface_t *
     712           0 : _cairo_analysis_surface_create (cairo_surface_t         *target)
     713             : {
     714             :     cairo_analysis_surface_t *surface;
     715             :     cairo_status_t status;
     716             : 
     717           0 :     status = target->status;
     718           0 :     if (unlikely (status))
     719           0 :         return _cairo_surface_create_in_error (status);
     720             : 
     721           0 :     surface = malloc (sizeof (cairo_analysis_surface_t));
     722           0 :     if (unlikely (surface == NULL))
     723           0 :         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
     724             : 
     725             :     /* I believe the content type here is truly arbitrary. I'm quite
     726             :      * sure nothing will ever use this value. */
     727           0 :     _cairo_surface_init (&surface->base,
     728             :                          &cairo_analysis_surface_backend,
     729             :                          NULL, /* device */
     730             :                          CAIRO_CONTENT_COLOR_ALPHA);
     731             : 
     732           0 :     cairo_matrix_init_identity (&surface->ctm);
     733           0 :     surface->has_ctm = FALSE;
     734             : 
     735           0 :     surface->target = cairo_surface_reference (target);
     736           0 :     surface->first_op  = TRUE;
     737           0 :     surface->has_supported = FALSE;
     738           0 :     surface->has_unsupported = FALSE;
     739             : 
     740           0 :     _cairo_region_init (&surface->supported_region);
     741           0 :     _cairo_region_init (&surface->fallback_region);
     742             : 
     743           0 :     surface->page_bbox.p1.x = 0;
     744           0 :     surface->page_bbox.p1.y = 0;
     745           0 :     surface->page_bbox.p2.x = 0;
     746           0 :     surface->page_bbox.p2.y = 0;
     747             : 
     748           0 :     return &surface->base;
     749             : }
     750             : 
     751             : void
     752           0 : _cairo_analysis_surface_set_ctm (cairo_surface_t *abstract_surface,
     753             :                                  const cairo_matrix_t  *ctm)
     754             : {
     755             :     cairo_analysis_surface_t    *surface;
     756             : 
     757           0 :     if (abstract_surface->status)
     758           0 :         return;
     759             : 
     760           0 :     surface = (cairo_analysis_surface_t *) abstract_surface;
     761             : 
     762           0 :     surface->ctm = *ctm;
     763           0 :     surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm);
     764             : }
     765             : 
     766             : void
     767           0 : _cairo_analysis_surface_get_ctm (cairo_surface_t *abstract_surface,
     768             :                                  cairo_matrix_t  *ctm)
     769             : {
     770           0 :     cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
     771             : 
     772           0 :     *ctm = surface->ctm;
     773           0 : }
     774             : 
     775             : 
     776             : cairo_region_t *
     777           0 : _cairo_analysis_surface_get_supported (cairo_surface_t *abstract_surface)
     778             : {
     779           0 :     cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
     780             : 
     781           0 :     return &surface->supported_region;
     782             : }
     783             : 
     784             : cairo_region_t *
     785           0 : _cairo_analysis_surface_get_unsupported (cairo_surface_t *abstract_surface)
     786             : {
     787           0 :     cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
     788             : 
     789           0 :     return &surface->fallback_region;
     790             : }
     791             : 
     792             : cairo_bool_t
     793           0 : _cairo_analysis_surface_has_supported (cairo_surface_t *abstract_surface)
     794             : {
     795           0 :     cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
     796             : 
     797           0 :     return surface->has_supported;
     798             : }
     799             : 
     800             : cairo_bool_t
     801           0 : _cairo_analysis_surface_has_unsupported (cairo_surface_t *abstract_surface)
     802             : {
     803           0 :     cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
     804             : 
     805           0 :     return surface->has_unsupported;
     806             : }
     807             : 
     808             : void
     809           0 : _cairo_analysis_surface_get_bounding_box (cairo_surface_t *abstract_surface,
     810             :                                           cairo_box_t     *bbox)
     811             : {
     812           0 :     cairo_analysis_surface_t    *surface = (cairo_analysis_surface_t *) abstract_surface;
     813             : 
     814           0 :     *bbox = surface->page_bbox;
     815           0 : }
     816             : 
     817             : /* null surface type: a surface that does nothing (has no side effects, yay!) */
     818             : 
     819             : static cairo_int_status_t
     820           0 : _return_success (void)
     821             : {
     822           0 :     return CAIRO_STATUS_SUCCESS;
     823             : }
     824             : 
     825             : /* These typedefs are just to silence the compiler... */
     826             : typedef cairo_int_status_t
     827             : (*_paint_func)                  (void                   *surface,
     828             :                                  cairo_operator_t        op,
     829             :                                  const cairo_pattern_t  *source,
     830             :                                  cairo_clip_t           *clip);
     831             : 
     832             : typedef cairo_int_status_t
     833             : (*_mask_func)                   (void                   *surface,
     834             :                                  cairo_operator_t        op,
     835             :                                  const cairo_pattern_t  *source,
     836             :                                  const cairo_pattern_t  *mask,
     837             :                                  cairo_clip_t           *clip);
     838             : 
     839             : typedef cairo_int_status_t
     840             : (*_stroke_func)                 (void                   *surface,
     841             :                                  cairo_operator_t        op,
     842             :                                  const cairo_pattern_t  *source,
     843             :                                  cairo_path_fixed_t     *path,
     844             :                                  const cairo_stroke_style_t     *style,
     845             :                                  const cairo_matrix_t           *ctm,
     846             :                                  const cairo_matrix_t           *ctm_inverse,
     847             :                                  double                  tolerance,
     848             :                                  cairo_antialias_t       antialias,
     849             :                                  cairo_clip_t           *clip);
     850             : 
     851             : typedef cairo_int_status_t
     852             : (*_fill_func)                   (void                   *surface,
     853             :                                  cairo_operator_t        op,
     854             :                                  const cairo_pattern_t  *source,
     855             :                                  cairo_path_fixed_t     *path,
     856             :                                  cairo_fill_rule_t       fill_rule,
     857             :                                  double                  tolerance,
     858             :                                  cairo_antialias_t       antialias,
     859             :                                  cairo_clip_t           *clip);
     860             : 
     861             : typedef cairo_int_status_t
     862             : (*_show_glyphs_func)            (void                   *surface,
     863             :                                  cairo_operator_t        op,
     864             :                                  const cairo_pattern_t  *source,
     865             :                                  cairo_glyph_t          *glyphs,
     866             :                                  int                     num_glyphs,
     867             :                                  cairo_scaled_font_t    *scaled_font,
     868             :                                  cairo_clip_t           *clip,
     869             :                                  int                    *remaining_glyphs);
     870             : 
     871             : static const cairo_surface_backend_t cairo_null_surface_backend = {
     872             :     CAIRO_INTERNAL_SURFACE_TYPE_NULL,
     873             : 
     874             :     NULL, /* create_similar */
     875             :     NULL, /* finish */
     876             :     NULL, /* acquire_source_image */
     877             :     NULL, /* release_source_image */
     878             :     NULL, /* acquire_dest_image */
     879             :     NULL, /* release_dest_image */
     880             :     NULL, /* clone_similar */
     881             :     NULL, /* composite */
     882             :     NULL, /* fill_rectangles */
     883             :     NULL, /* composite_trapezoids */
     884             :     NULL, /* create_span_renderer */
     885             :     NULL, /* check_span_renderer */
     886             :     NULL, /* copy_page */
     887             :     NULL, /* show_page */
     888             :     NULL, /* get_extents */
     889             :     NULL, /* old_show_glyphs */
     890             :     NULL, /* get_font_options */
     891             :     NULL, /* flush */
     892             :     NULL, /* mark_dirty_rectangle */
     893             :     NULL, /* scaled_font_fini */
     894             :     NULL, /* scaled_glyph_fini */
     895             :     (_paint_func) _return_success,          /* paint */
     896             :     (_mask_func) _return_success,           /* mask */
     897             :     (_stroke_func) _return_success,         /* stroke */
     898             :     (_fill_func) _return_success,           /* fill */
     899             :     (_show_glyphs_func) _return_success,    /* show_glyphs */
     900             :     NULL, /* snapshot */
     901             :     NULL, /* is_similar */
     902             :     NULL, /* fill_stroke */
     903             :     NULL, /* create_solid_pattern_surface */
     904             :     NULL, /* can_repaint_solid_pattern_surface */
     905             :     NULL, /* has_show_text_glyphs */
     906             :     NULL  /* show_text_glyphs */
     907             : };
     908             : 
     909             : cairo_surface_t *
     910           0 : cairo_null_surface_create (cairo_content_t content)
     911             : {
     912             :     cairo_surface_t *surface;
     913             : 
     914           0 :     surface = malloc (sizeof (cairo_surface_t));
     915           0 :     if (unlikely (surface == NULL)) {
     916           0 :         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
     917             :     }
     918             : 
     919           0 :     _cairo_surface_init (surface,
     920             :                          &cairo_null_surface_backend,
     921             :                          NULL, /* device */
     922             :                          content);
     923             : 
     924           0 :     return surface;
     925             : }

Generated by: LCOV version 1.13