LCOV - code coverage report
Current view: directory - gfx/cairo/cairo/src - cairo-analysis-surface.c (source / functions) Found Hit Coverage
Test: app.info Lines: 280 0 0.0 %
Date: 2012-06-02 Functions: 24 0 0.0 %

       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.7