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

       1                 : /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
       2                 : /* cairo - a vector graphics library with display and print output
       3                 :  *
       4                 :  * Copyright © 2005 Red Hat, Inc
       5                 :  * Copyright © 2007 Adrian Johnson
       6                 :  *
       7                 :  * This library is free software; you can redistribute it and/or
       8                 :  * modify it either under the terms of the GNU Lesser General Public
       9                 :  * License version 2.1 as published by the Free Software Foundation
      10                 :  * (the "LGPL") or, at your option, under the terms of the Mozilla
      11                 :  * Public License Version 1.1 (the "MPL"). If you do not alter this
      12                 :  * notice, a recipient may use your version of this file under either
      13                 :  * the MPL or the LGPL.
      14                 :  *
      15                 :  * You should have received a copy of the LGPL along with this library
      16                 :  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
      17                 :  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
      18                 :  * You should have received a copy of the MPL along with this library
      19                 :  * in the file COPYING-MPL-1.1
      20                 :  *
      21                 :  * The contents of this file are subject to the Mozilla Public License
      22                 :  * Version 1.1 (the "License"); you may not use this file except in
      23                 :  * compliance with the License. You may obtain a copy of the License at
      24                 :  * http://www.mozilla.org/MPL/
      25                 :  *
      26                 :  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
      27                 :  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
      28                 :  * the specific language governing rights and limitations.
      29                 :  *
      30                 :  * The Original Code is the cairo graphics library.
      31                 :  *
      32                 :  * The Initial Developer of the Original Code is Red Hat, Inc.
      33                 :  *
      34                 :  * Contributor(s):
      35                 :  *      Kristian Høgsberg <krh@redhat.com>
      36                 :  *      Carl Worth <cworth@cworth.org>
      37                 :  *      Adrian Johnson <ajohnson@redneon.com>
      38                 :  */
      39                 : 
      40                 : /**
      41                 :  * SECTION:cairo-recording
      42                 :  * @Title: Recording Surfaces
      43                 :  * @Short_Description: Records all drawing operations
      44                 :  * @See_Also: #cairo_surface_t
      45                 :  *
      46                 :  * A recording surface is a surface that records all drawing operations at
      47                 :  * the highest level of the surface backend interface, (that is, the
      48                 :  * level of paint, mask, stroke, fill, and show_text_glyphs). The recording
      49                 :  * surface can then be "replayed" against any target surface by using it
      50                 :  * as a source surface.
      51                 :  *
      52                 :  * If you want to replay a surface so that the results in target will be
      53                 :  * identical to the results that would have been obtained if the original
      54                 :  * operations applied to the recording surface had instead been applied to the
      55                 :  * target surface, you can use code like this:
      56                 :  * <informalexample><programlisting>
      57                 :  *      cairo_t *cr;
      58                 :  *
      59                 :  *      cr = cairo_create (target);
      60                 :  *      cairo_set_source_surface (cr, recording_surface, 0.0, 0.0);
      61                 :  *      cairo_paint (cr);
      62                 :  *      cairo_destroy (cr);
      63                 :  * </programlisting></informalexample>
      64                 :  *
      65                 :  * A recording surface is logically unbounded, i.e. it has no implicit constraint
      66                 :  * on the size of the drawing surface. However, in practice this is rarely
      67                 :  * useful as you wish to replay against a particular target surface with
      68                 :  * known bounds. For this case, it is more efficient to specify the target
      69                 :  * extents to the recording surface upon creation.
      70                 :  *
      71                 :  * The recording phase of the recording surface is careful to snapshot all
      72                 :  * necessary objects (paths, patterns, etc.), in order to achieve
      73                 :  * accurate replay. The efficiency of the recording surface could be
      74                 :  * improved by improving the implementation of snapshot for the
      75                 :  * various objects. For example, it would be nice to have a
      76                 :  * copy-on-write implementation for _cairo_surface_snapshot.
      77                 :  */
      78                 : 
      79                 : #include "cairoint.h"
      80                 : #include "cairo-analysis-surface-private.h"
      81                 : #include "cairo-clip-private.h"
      82                 : #include "cairo-error-private.h"
      83                 : #include "cairo-recording-surface-private.h"
      84                 : #include "cairo-surface-wrapper-private.h"
      85                 : 
      86                 : typedef enum {
      87                 :     CAIRO_RECORDING_REPLAY,
      88                 :     CAIRO_RECORDING_CREATE_REGIONS
      89                 : } cairo_recording_replay_type_t;
      90                 : 
      91                 : static const cairo_surface_backend_t cairo_recording_surface_backend;
      92                 : 
      93                 : /**
      94                 :  * CAIRO_HAS_RECORDING_SURFACE:
      95                 :  *
      96                 :  * Defined if the recording surface backend is available.
      97                 :  * The recording surface backend is always built in.
      98                 :  * This macro was added for completeness in cairo 1.10.
      99                 :  *
     100                 :  * Since: 1.10
     101                 :  */
     102                 : 
     103                 : /* Currently all recording surfaces do have a size which should be passed
     104                 :  * in as the maximum size of any target surface against which the
     105                 :  * recording-surface will ever be replayed.
     106                 :  *
     107                 :  * XXX: The naming of "pixels" in the size here is a misnomer. It's
     108                 :  * actually a size in whatever device-space units are desired (again,
     109                 :  * according to the intended replay target).
     110                 :  */
     111                 : 
     112                 : /**
     113                 :  * cairo_recording_surface_create:
     114                 :  * @content: the content of the recording surface
     115                 :  * @extents: the extents to record in pixels, can be %NULL to record
     116                 :  *           unbounded operations.
     117                 :  *
     118                 :  * Creates a recording-surface which can be used to record all drawing operations
     119                 :  * at the highest level (that is, the level of paint, mask, stroke, fill
     120                 :  * and show_text_glyphs). The recording surface can then be "replayed" against
     121                 :  * any target surface by using it as a source to drawing operations.
     122                 :  *
     123                 :  * The recording phase of the recording surface is careful to snapshot all
     124                 :  * necessary objects (paths, patterns, etc.), in order to achieve
     125                 :  * accurate replay.
     126                 :  *
     127                 :  * Return value: a pointer to the newly created surface. The caller
     128                 :  * owns the surface and should call cairo_surface_destroy() when done
     129                 :  * with it.
     130                 :  *
     131                 :  * Since: 1.10
     132                 :  **/
     133                 : cairo_surface_t *
     134               0 : cairo_recording_surface_create (cairo_content_t          content,
     135                 :                                 const cairo_rectangle_t *extents)
     136                 : {
     137                 :     cairo_recording_surface_t *recording_surface;
     138                 :     cairo_status_t status;
     139                 : 
     140               0 :     recording_surface = malloc (sizeof (cairo_recording_surface_t));
     141               0 :     if (unlikely (recording_surface == NULL))
     142               0 :         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
     143                 : 
     144               0 :     _cairo_surface_init (&recording_surface->base,
     145                 :                          &cairo_recording_surface_backend,
     146                 :                          NULL, /* device */
     147                 :                          content);
     148                 : 
     149               0 :     recording_surface->content = content;
     150                 : 
     151               0 :     recording_surface->unbounded = TRUE;
     152               0 :     _cairo_clip_init (&recording_surface->clip);
     153                 : 
     154                 :     /* unbounded -> 'infinite' extents */
     155               0 :     if (extents != NULL) {
     156               0 :         recording_surface->extents_pixels = *extents;
     157                 : 
     158                 :         /* XXX check for overflow */
     159               0 :         recording_surface->extents.x = floor (extents->x);
     160               0 :         recording_surface->extents.y = floor (extents->y);
     161               0 :         recording_surface->extents.width = ceil (extents->x + extents->width) - recording_surface->extents.x;
     162               0 :         recording_surface->extents.height = ceil (extents->y + extents->height) - recording_surface->extents.y;
     163                 : 
     164               0 :         status = _cairo_clip_rectangle (&recording_surface->clip,
     165               0 :                                         &recording_surface->extents);
     166               0 :         if (unlikely (status)) {
     167               0 :             free (recording_surface);
     168               0 :             return _cairo_surface_create_in_error (status);
     169                 :         }
     170                 : 
     171               0 :         recording_surface->unbounded = FALSE;
     172                 :     }
     173                 : 
     174               0 :     _cairo_array_init (&recording_surface->commands, sizeof (cairo_command_t *));
     175                 : 
     176               0 :     recording_surface->replay_start_idx = 0;
     177               0 :     recording_surface->base.is_clear = TRUE;
     178                 : 
     179               0 :     return &recording_surface->base;
     180                 : }
     181                 : slim_hidden_def (cairo_recording_surface_create);
     182                 : 
     183                 : static cairo_surface_t *
     184               0 : _cairo_recording_surface_create_similar (void                  *abstract_surface,
     185                 :                                          cairo_content_t        content,
     186                 :                                          int                    width,
     187                 :                                          int                    height)
     188                 : {
     189                 :     cairo_rectangle_t extents;
     190               0 :     extents.x = extents.y = 0;
     191               0 :     extents.width = width;
     192               0 :     extents.height = height;
     193               0 :     return cairo_recording_surface_create (content, &extents);
     194                 : }
     195                 : 
     196                 : static cairo_status_t
     197               0 : _cairo_recording_surface_finish (void *abstract_surface)
     198                 : {
     199               0 :     cairo_recording_surface_t *recording_surface = abstract_surface;
     200                 :     cairo_command_t **elements;
     201                 :     int i, num_elements;
     202                 : 
     203               0 :     num_elements = recording_surface->commands.num_elements;
     204               0 :     elements = _cairo_array_index (&recording_surface->commands, 0);
     205               0 :     for (i = 0; i < num_elements; i++) {
     206               0 :         cairo_command_t *command = elements[i];
     207                 : 
     208               0 :         switch (command->header.type) {
     209                 :         case CAIRO_COMMAND_PAINT:
     210               0 :             _cairo_pattern_fini (&command->paint.source.base);
     211               0 :             break;
     212                 : 
     213                 :         case CAIRO_COMMAND_MASK:
     214               0 :             _cairo_pattern_fini (&command->mask.source.base);
     215               0 :             _cairo_pattern_fini (&command->mask.mask.base);
     216               0 :             break;
     217                 : 
     218                 :         case CAIRO_COMMAND_STROKE:
     219               0 :             _cairo_pattern_fini (&command->stroke.source.base);
     220               0 :             _cairo_path_fixed_fini (&command->stroke.path);
     221               0 :             _cairo_stroke_style_fini (&command->stroke.style);
     222               0 :             break;
     223                 : 
     224                 :         case CAIRO_COMMAND_FILL:
     225               0 :             _cairo_pattern_fini (&command->fill.source.base);
     226               0 :             _cairo_path_fixed_fini (&command->fill.path);
     227               0 :             break;
     228                 : 
     229                 :         case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
     230               0 :             _cairo_pattern_fini (&command->show_text_glyphs.source.base);
     231               0 :             free (command->show_text_glyphs.utf8);
     232               0 :             free (command->show_text_glyphs.glyphs);
     233               0 :             free (command->show_text_glyphs.clusters);
     234               0 :             cairo_scaled_font_destroy (command->show_text_glyphs.scaled_font);
     235               0 :             break;
     236                 : 
     237                 :         default:
     238               0 :             ASSERT_NOT_REACHED;
     239                 :         }
     240                 : 
     241               0 :         _cairo_clip_fini (&command->header.clip);
     242               0 :         free (command);
     243                 :     }
     244                 : 
     245               0 :     _cairo_array_fini (&recording_surface->commands);
     246               0 :     _cairo_clip_fini (&recording_surface->clip);
     247                 : 
     248               0 :     return CAIRO_STATUS_SUCCESS;
     249                 : }
     250                 : 
     251                 : static cairo_status_t
     252               0 : _cairo_recording_surface_acquire_source_image (void                      *abstract_surface,
     253                 :                                                cairo_image_surface_t    **image_out,
     254                 :                                                void                     **image_extra)
     255                 : {
     256                 :     cairo_status_t status;
     257               0 :     cairo_recording_surface_t *surface = abstract_surface;
     258                 :     cairo_surface_t *image;
     259                 : 
     260               0 :     image = _cairo_surface_has_snapshot (&surface->base,
     261                 :                                          &_cairo_image_surface_backend);
     262               0 :     if (image != NULL) {
     263               0 :         *image_out = (cairo_image_surface_t *) cairo_surface_reference (image);
     264               0 :         *image_extra = NULL;
     265               0 :         return CAIRO_STATUS_SUCCESS;
     266                 :     }
     267                 : 
     268               0 :     image = _cairo_image_surface_create_with_content (surface->content,
     269                 :                                                       surface->extents.width,
     270                 :                                                       surface->extents.height);
     271               0 :     if (unlikely (image->status))
     272               0 :         return image->status;
     273                 : 
     274               0 :     cairo_surface_set_device_offset (image,
     275               0 :                                      -surface->extents.x,
     276               0 :                                      -surface->extents.y);
     277                 : 
     278               0 :     status = _cairo_recording_surface_replay (&surface->base, image);
     279               0 :     if (unlikely (status)) {
     280               0 :         cairo_surface_destroy (image);
     281               0 :         return status;
     282                 :     }
     283                 : 
     284               0 :     cairo_surface_attach_snapshot (&surface->base, image, NULL);
     285                 : 
     286               0 :     *image_out = (cairo_image_surface_t *) image;
     287               0 :     *image_extra = NULL;
     288               0 :     return CAIRO_STATUS_SUCCESS;
     289                 : }
     290                 : 
     291                 : static void
     292               0 : _cairo_recording_surface_release_source_image (void                     *abstract_surface,
     293                 :                                                cairo_image_surface_t    *image,
     294                 :                                                void                     *image_extra)
     295                 : {
     296               0 :     cairo_surface_destroy (&image->base);
     297               0 : }
     298                 : 
     299                 : static cairo_status_t
     300               0 : _command_init (cairo_recording_surface_t *recording_surface,
     301                 :                cairo_command_header_t *command,
     302                 :                cairo_command_type_t type,
     303                 :                cairo_operator_t op,
     304                 :                cairo_clip_t *clip)
     305                 : {
     306               0 :     cairo_status_t status = CAIRO_STATUS_SUCCESS;
     307                 : 
     308               0 :     command->type = type;
     309               0 :     command->op = op;
     310               0 :     command->region = CAIRO_RECORDING_REGION_ALL;
     311               0 :     _cairo_clip_init_copy (&command->clip, clip);
     312               0 :     if (recording_surface->clip.path != NULL)
     313               0 :         status = _cairo_clip_apply_clip (&command->clip, &recording_surface->clip);
     314                 : 
     315               0 :     return status;
     316                 : }
     317                 : 
     318                 : static cairo_int_status_t
     319               0 : _cairo_recording_surface_paint (void                      *abstract_surface,
     320                 :                                 cairo_operator_t           op,
     321                 :                                 const cairo_pattern_t     *source,
     322                 :                                 cairo_clip_t              *clip)
     323                 : {
     324                 :     cairo_status_t status;
     325               0 :     cairo_recording_surface_t *recording_surface = abstract_surface;
     326                 :     cairo_command_paint_t *command;
     327                 : 
     328               0 :     command = malloc (sizeof (cairo_command_paint_t));
     329               0 :     if (unlikely (command == NULL))
     330               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     331                 : 
     332               0 :     status = _command_init (recording_surface,
     333               0 :                             &command->header, CAIRO_COMMAND_PAINT, op, clip);
     334               0 :     if (unlikely (status))
     335               0 :         goto CLEANUP_COMMAND;
     336                 : 
     337               0 :     status = _cairo_pattern_init_snapshot (&command->source.base, source);
     338               0 :     if (unlikely (status))
     339               0 :         goto CLEANUP_COMMAND;
     340                 : 
     341               0 :     status = _cairo_array_append (&recording_surface->commands, &command);
     342               0 :     if (unlikely (status))
     343               0 :         goto CLEANUP_SOURCE;
     344                 : 
     345                 :     /* An optimisation that takes care to not replay what was done
     346                 :      * before surface is cleared. We don't erase recorded commands
     347                 :      * since we may have earlier snapshots of this surface. */
     348               0 :     if (op == CAIRO_OPERATOR_CLEAR && clip == NULL)
     349               0 :         recording_surface->replay_start_idx = recording_surface->commands.num_elements;
     350                 : 
     351               0 :     return CAIRO_STATUS_SUCCESS;
     352                 : 
     353                 :   CLEANUP_SOURCE:
     354               0 :     _cairo_pattern_fini (&command->source.base);
     355                 :   CLEANUP_COMMAND:
     356               0 :     _cairo_clip_fini (&command->header.clip);
     357               0 :     free (command);
     358               0 :     return status;
     359                 : }
     360                 : 
     361                 : static cairo_int_status_t
     362               0 : _cairo_recording_surface_mask (void                     *abstract_surface,
     363                 :                                cairo_operator_t          op,
     364                 :                                const cairo_pattern_t    *source,
     365                 :                                const cairo_pattern_t    *mask,
     366                 :                                cairo_clip_t             *clip)
     367                 : {
     368                 :     cairo_status_t status;
     369               0 :     cairo_recording_surface_t *recording_surface = abstract_surface;
     370                 :     cairo_command_mask_t *command;
     371                 : 
     372               0 :     command = malloc (sizeof (cairo_command_mask_t));
     373               0 :     if (unlikely (command == NULL))
     374               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     375                 : 
     376               0 :     status = _command_init (recording_surface,
     377               0 :                             &command->header, CAIRO_COMMAND_MASK, op, clip);
     378               0 :     if (unlikely (status))
     379               0 :         goto CLEANUP_COMMAND;
     380                 : 
     381               0 :     status = _cairo_pattern_init_snapshot (&command->source.base, source);
     382               0 :     if (unlikely (status))
     383               0 :         goto CLEANUP_COMMAND;
     384                 : 
     385               0 :     status = _cairo_pattern_init_snapshot (&command->mask.base, mask);
     386               0 :     if (unlikely (status))
     387               0 :         goto CLEANUP_SOURCE;
     388                 : 
     389               0 :     status = _cairo_array_append (&recording_surface->commands, &command);
     390               0 :     if (unlikely (status))
     391               0 :         goto CLEANUP_MASK;
     392                 : 
     393               0 :     return CAIRO_STATUS_SUCCESS;
     394                 : 
     395                 :   CLEANUP_MASK:
     396               0 :     _cairo_pattern_fini (&command->mask.base);
     397                 :   CLEANUP_SOURCE:
     398               0 :     _cairo_pattern_fini (&command->source.base);
     399                 :   CLEANUP_COMMAND:
     400               0 :     _cairo_clip_fini (&command->header.clip);
     401               0 :     free (command);
     402               0 :     return status;
     403                 : }
     404                 : 
     405                 : static cairo_int_status_t
     406               0 : _cairo_recording_surface_stroke (void                   *abstract_surface,
     407                 :                                  cairo_operator_t        op,
     408                 :                                  const cairo_pattern_t  *source,
     409                 :                                  cairo_path_fixed_t     *path,
     410                 :                                  const cairo_stroke_style_t     *style,
     411                 :                                  const cairo_matrix_t           *ctm,
     412                 :                                  const cairo_matrix_t           *ctm_inverse,
     413                 :                                  double                  tolerance,
     414                 :                                  cairo_antialias_t       antialias,
     415                 :                                  cairo_clip_t           *clip)
     416                 : {
     417                 :     cairo_status_t status;
     418               0 :     cairo_recording_surface_t *recording_surface = abstract_surface;
     419                 :     cairo_command_stroke_t *command;
     420                 : 
     421               0 :     command = malloc (sizeof (cairo_command_stroke_t));
     422               0 :     if (unlikely (command == NULL))
     423               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     424                 : 
     425               0 :     status = _command_init (recording_surface,
     426               0 :                             &command->header, CAIRO_COMMAND_STROKE, op, clip);
     427               0 :     if (unlikely (status))
     428               0 :         goto CLEANUP_COMMAND;
     429                 : 
     430               0 :     status = _cairo_pattern_init_snapshot (&command->source.base, source);
     431               0 :     if (unlikely (status))
     432               0 :         goto CLEANUP_COMMAND;
     433                 : 
     434               0 :     status = _cairo_path_fixed_init_copy (&command->path, path);
     435               0 :     if (unlikely (status))
     436               0 :         goto CLEANUP_SOURCE;
     437                 : 
     438               0 :     status = _cairo_stroke_style_init_copy (&command->style, style);
     439               0 :     if (unlikely (status))
     440               0 :         goto CLEANUP_PATH;
     441                 : 
     442               0 :     command->ctm = *ctm;
     443               0 :     command->ctm_inverse = *ctm_inverse;
     444               0 :     command->tolerance = tolerance;
     445               0 :     command->antialias = antialias;
     446                 : 
     447               0 :     status = _cairo_array_append (&recording_surface->commands, &command);
     448               0 :     if (unlikely (status))
     449               0 :         goto CLEANUP_STYLE;
     450                 : 
     451               0 :     return CAIRO_STATUS_SUCCESS;
     452                 : 
     453                 :   CLEANUP_STYLE:
     454               0 :     _cairo_stroke_style_fini (&command->style);
     455                 :   CLEANUP_PATH:
     456               0 :     _cairo_path_fixed_fini (&command->path);
     457                 :   CLEANUP_SOURCE:
     458               0 :     _cairo_pattern_fini (&command->source.base);
     459                 :   CLEANUP_COMMAND:
     460               0 :     _cairo_clip_fini (&command->header.clip);
     461               0 :     free (command);
     462               0 :     return status;
     463                 : }
     464                 : 
     465                 : static cairo_int_status_t
     466               0 : _cairo_recording_surface_fill (void                     *abstract_surface,
     467                 :                                cairo_operator_t          op,
     468                 :                                const cairo_pattern_t    *source,
     469                 :                                cairo_path_fixed_t       *path,
     470                 :                                cairo_fill_rule_t         fill_rule,
     471                 :                                double                    tolerance,
     472                 :                                cairo_antialias_t         antialias,
     473                 :                                cairo_clip_t             *clip)
     474                 : {
     475                 :     cairo_status_t status;
     476               0 :     cairo_recording_surface_t *recording_surface = abstract_surface;
     477                 :     cairo_command_fill_t *command;
     478                 : 
     479               0 :     command = malloc (sizeof (cairo_command_fill_t));
     480               0 :     if (unlikely (command == NULL))
     481               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     482                 : 
     483               0 :     status =_command_init (recording_surface,
     484               0 :                            &command->header, CAIRO_COMMAND_FILL, op, clip);
     485               0 :     if (unlikely (status))
     486               0 :         goto CLEANUP_COMMAND;
     487                 : 
     488               0 :     status = _cairo_pattern_init_snapshot (&command->source.base, source);
     489               0 :     if (unlikely (status))
     490               0 :         goto CLEANUP_COMMAND;
     491                 : 
     492               0 :     status = _cairo_path_fixed_init_copy (&command->path, path);
     493               0 :     if (unlikely (status))
     494               0 :         goto CLEANUP_SOURCE;
     495                 : 
     496               0 :     command->fill_rule = fill_rule;
     497               0 :     command->tolerance = tolerance;
     498               0 :     command->antialias = antialias;
     499                 : 
     500               0 :     status = _cairo_array_append (&recording_surface->commands, &command);
     501               0 :     if (unlikely (status))
     502               0 :         goto CLEANUP_PATH;
     503                 : 
     504               0 :     return CAIRO_STATUS_SUCCESS;
     505                 : 
     506                 :   CLEANUP_PATH:
     507               0 :     _cairo_path_fixed_fini (&command->path);
     508                 :   CLEANUP_SOURCE:
     509               0 :     _cairo_pattern_fini (&command->source.base);
     510                 :   CLEANUP_COMMAND:
     511               0 :     _cairo_clip_fini (&command->header.clip);
     512               0 :     free (command);
     513               0 :     return status;
     514                 : }
     515                 : 
     516                 : static cairo_bool_t
     517               0 : _cairo_recording_surface_has_show_text_glyphs (void *abstract_surface)
     518                 : {
     519               0 :     return TRUE;
     520                 : }
     521                 : 
     522                 : static cairo_int_status_t
     523               0 : _cairo_recording_surface_show_text_glyphs (void                         *abstract_surface,
     524                 :                                            cairo_operator_t              op,
     525                 :                                            const cairo_pattern_t        *source,
     526                 :                                            const char                   *utf8,
     527                 :                                            int                           utf8_len,
     528                 :                                            cairo_glyph_t                *glyphs,
     529                 :                                            int                           num_glyphs,
     530                 :                                            const cairo_text_cluster_t   *clusters,
     531                 :                                            int                           num_clusters,
     532                 :                                            cairo_text_cluster_flags_t    cluster_flags,
     533                 :                                            cairo_scaled_font_t          *scaled_font,
     534                 :                                            cairo_clip_t                 *clip)
     535                 : {
     536                 :     cairo_status_t status;
     537               0 :     cairo_recording_surface_t *recording_surface = abstract_surface;
     538                 :     cairo_command_show_text_glyphs_t *command;
     539                 : 
     540               0 :     command = malloc (sizeof (cairo_command_show_text_glyphs_t));
     541               0 :     if (unlikely (command == NULL))
     542               0 :         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
     543                 : 
     544               0 :     status = _command_init (recording_surface,
     545               0 :                             &command->header, CAIRO_COMMAND_SHOW_TEXT_GLYPHS,
     546                 :                             op, clip);
     547               0 :     if (unlikely (status))
     548               0 :         goto CLEANUP_COMMAND;
     549                 : 
     550               0 :     status = _cairo_pattern_init_snapshot (&command->source.base, source);
     551               0 :     if (unlikely (status))
     552               0 :         goto CLEANUP_COMMAND;
     553                 : 
     554               0 :     command->utf8 = NULL;
     555               0 :     command->utf8_len = utf8_len;
     556               0 :     command->glyphs = NULL;
     557               0 :     command->num_glyphs = num_glyphs;
     558               0 :     command->clusters = NULL;
     559               0 :     command->num_clusters = num_clusters;
     560                 : 
     561               0 :     if (utf8_len) {
     562               0 :         command->utf8 = malloc (utf8_len);
     563               0 :         if (unlikely (command->utf8 == NULL)) {
     564               0 :             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
     565               0 :             goto CLEANUP_ARRAYS;
     566                 :         }
     567               0 :         memcpy (command->utf8, utf8, utf8_len);
     568                 :     }
     569               0 :     if (num_glyphs) {
     570               0 :         command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (glyphs[0]));
     571               0 :         if (unlikely (command->glyphs == NULL)) {
     572               0 :             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
     573               0 :             goto CLEANUP_ARRAYS;
     574                 :         }
     575               0 :         memcpy (command->glyphs, glyphs, sizeof (glyphs[0]) * num_glyphs);
     576                 :     }
     577               0 :     if (num_clusters) {
     578               0 :         command->clusters = _cairo_malloc_ab (num_clusters, sizeof (clusters[0]));
     579               0 :         if (unlikely (command->clusters == NULL)) {
     580               0 :             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
     581               0 :             goto CLEANUP_ARRAYS;
     582                 :         }
     583               0 :         memcpy (command->clusters, clusters, sizeof (clusters[0]) * num_clusters);
     584                 :     }
     585                 : 
     586               0 :     command->cluster_flags = cluster_flags;
     587                 : 
     588               0 :     command->scaled_font = cairo_scaled_font_reference (scaled_font);
     589                 : 
     590               0 :     status = _cairo_array_append (&recording_surface->commands, &command);
     591               0 :     if (unlikely (status))
     592               0 :         goto CLEANUP_SCALED_FONT;
     593                 : 
     594               0 :     return CAIRO_STATUS_SUCCESS;
     595                 : 
     596                 :   CLEANUP_SCALED_FONT:
     597               0 :     cairo_scaled_font_destroy (command->scaled_font);
     598                 :   CLEANUP_ARRAYS:
     599               0 :     free (command->utf8);
     600               0 :     free (command->glyphs);
     601               0 :     free (command->clusters);
     602                 : 
     603               0 :     _cairo_pattern_fini (&command->source.base);
     604                 :   CLEANUP_COMMAND:
     605               0 :     _cairo_clip_fini (&command->header.clip);
     606               0 :     free (command);
     607               0 :     return status;
     608                 : }
     609                 : 
     610                 : /**
     611                 :  * _cairo_recording_surface_snapshot
     612                 :  * @surface: a #cairo_surface_t which must be a recording surface
     613                 :  *
     614                 :  * Make an immutable copy of @surface. It is an error to call a
     615                 :  * surface-modifying function on the result of this function.
     616                 :  *
     617                 :  * The caller owns the return value and should call
     618                 :  * cairo_surface_destroy() when finished with it. This function will not
     619                 :  * return %NULL, but will return a nil surface instead.
     620                 :  *
     621                 :  * Return value: The snapshot surface.
     622                 :  **/
     623                 : static cairo_surface_t *
     624               0 : _cairo_recording_surface_snapshot (void *abstract_other)
     625                 : {
     626               0 :     cairo_recording_surface_t *other = abstract_other;
     627                 :     cairo_recording_surface_t *recording_surface;
     628                 :     cairo_status_t status;
     629                 : 
     630               0 :     recording_surface = malloc (sizeof (cairo_recording_surface_t));
     631               0 :     if (unlikely (recording_surface == NULL))
     632               0 :         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
     633                 : 
     634               0 :     _cairo_surface_init (&recording_surface->base,
     635                 :                          &cairo_recording_surface_backend,
     636                 :                          NULL, /* device */
     637                 :                          other->base.content);
     638                 : 
     639               0 :     recording_surface->extents_pixels = other->extents_pixels;
     640               0 :     recording_surface->extents = other->extents;
     641               0 :     recording_surface->unbounded = other->unbounded;
     642               0 :     recording_surface->content = other->content;
     643                 : 
     644               0 :     _cairo_clip_init_copy (&recording_surface->clip, &other->clip);
     645                 : 
     646                 :     /* XXX We should in theory be able to reuse the original array, but we
     647                 :      * need to handle reference cycles during subsurface and self-copy.
     648                 :      */
     649               0 :     recording_surface->replay_start_idx = 0;
     650               0 :     recording_surface->base.is_clear = TRUE;
     651                 : 
     652               0 :     _cairo_array_init (&recording_surface->commands, sizeof (cairo_command_t *));
     653               0 :     status = _cairo_recording_surface_replay (&other->base, &recording_surface->base);
     654               0 :     if (unlikely (status)) {
     655               0 :         cairo_surface_destroy (&recording_surface->base);
     656               0 :         return _cairo_surface_create_in_error (status);
     657                 :     }
     658                 : 
     659               0 :     return &recording_surface->base;
     660                 : }
     661                 : 
     662                 : static cairo_bool_t
     663               0 : _cairo_recording_surface_get_extents (void                  *abstract_surface,
     664                 :                                       cairo_rectangle_int_t *rectangle)
     665                 : {
     666               0 :     cairo_recording_surface_t *surface = abstract_surface;
     667                 : 
     668               0 :     if (surface->unbounded)
     669               0 :         return FALSE;
     670                 : 
     671               0 :     *rectangle = surface->extents;
     672               0 :     return TRUE;
     673                 : }
     674                 : 
     675                 : /**
     676                 :  * _cairo_surface_is_recording:
     677                 :  * @surface: a #cairo_surface_t
     678                 :  *
     679                 :  * Checks if a surface is a #cairo_recording_surface_t
     680                 :  *
     681                 :  * Return value: %TRUE if the surface is a recording surface
     682                 :  **/
     683                 : cairo_bool_t
     684               0 : _cairo_surface_is_recording (const cairo_surface_t *surface)
     685                 : {
     686               0 :     return surface->backend == &cairo_recording_surface_backend;
     687                 : }
     688                 : 
     689                 : static const cairo_surface_backend_t cairo_recording_surface_backend = {
     690                 :     CAIRO_SURFACE_TYPE_RECORDING,
     691                 :     _cairo_recording_surface_create_similar,
     692                 :     _cairo_recording_surface_finish,
     693                 :     _cairo_recording_surface_acquire_source_image,
     694                 :     _cairo_recording_surface_release_source_image,
     695                 :     NULL, /* acquire_dest_image */
     696                 :     NULL, /* release_dest_image */
     697                 :     NULL, /* clone_similar */
     698                 :     NULL, /* composite */
     699                 :     NULL, /* fill_rectangles */
     700                 :     NULL, /* composite_trapezoids */
     701                 :     NULL, /* create_span_renderer */
     702                 :     NULL, /* check_span_renderer */
     703                 :     NULL, /* copy_page */
     704                 :     NULL, /* show_page */
     705                 :     _cairo_recording_surface_get_extents,
     706                 :     NULL, /* old_show_glyphs */
     707                 :     NULL, /* get_font_options */
     708                 :     NULL, /* flush */
     709                 :     NULL, /* mark_dirty_rectangle */
     710                 :     NULL, /* scaled_font_fini */
     711                 :     NULL, /* scaled_glyph_fini */
     712                 : 
     713                 :     /* Here are the 5 basic drawing operations, (which are in some
     714                 :      * sense the only things that cairo_recording_surface should need to
     715                 :      * implement).  However, we implement the more generic show_text_glyphs
     716                 :      * instead of show_glyphs.  One or the other is eough. */
     717                 : 
     718                 :     _cairo_recording_surface_paint,
     719                 :     _cairo_recording_surface_mask,
     720                 :     _cairo_recording_surface_stroke,
     721                 :     _cairo_recording_surface_fill,
     722                 :     NULL,
     723                 : 
     724                 :     _cairo_recording_surface_snapshot,
     725                 : 
     726                 :     NULL, /* is_similar */
     727                 :     NULL, /* fill_stroke */
     728                 :     NULL, /* create_solid_pattern_surface */
     729                 :     NULL, /* can_repaint_solid_pattern_surface */
     730                 : 
     731                 :     _cairo_recording_surface_has_show_text_glyphs,
     732                 :     _cairo_recording_surface_show_text_glyphs
     733                 : };
     734                 : 
     735                 : cairo_int_status_t
     736               0 : _cairo_recording_surface_get_path (cairo_surface_t    *surface,
     737                 :                                    cairo_path_fixed_t *path)
     738                 : {
     739                 :     cairo_recording_surface_t *recording_surface;
     740                 :     cairo_command_t **elements;
     741                 :     int i, num_elements;
     742                 :     cairo_int_status_t status;
     743                 : 
     744               0 :     if (surface->status)
     745               0 :         return surface->status;
     746                 : 
     747               0 :     recording_surface = (cairo_recording_surface_t *) surface;
     748               0 :     status = CAIRO_STATUS_SUCCESS;
     749                 : 
     750               0 :     num_elements = recording_surface->commands.num_elements;
     751               0 :     elements = _cairo_array_index (&recording_surface->commands, 0);
     752               0 :     for (i = recording_surface->replay_start_idx; i < num_elements; i++) {
     753               0 :         cairo_command_t *command = elements[i];
     754                 : 
     755               0 :         switch (command->header.type) {
     756                 :         case CAIRO_COMMAND_PAINT:
     757                 :         case CAIRO_COMMAND_MASK:
     758               0 :             status = CAIRO_INT_STATUS_UNSUPPORTED;
     759               0 :             break;
     760                 : 
     761                 :         case CAIRO_COMMAND_STROKE:
     762                 :         {
     763                 :             cairo_traps_t traps;
     764                 : 
     765               0 :             _cairo_traps_init (&traps);
     766                 : 
     767                 :             /* XXX call cairo_stroke_to_path() when that is implemented */
     768               0 :             status = _cairo_path_fixed_stroke_to_traps (&command->stroke.path,
     769               0 :                                                         &command->stroke.style,
     770               0 :                                                         &command->stroke.ctm,
     771               0 :                                                         &command->stroke.ctm_inverse,
     772                 :                                                         command->stroke.tolerance,
     773                 :                                                         &traps);
     774                 : 
     775               0 :             if (status == CAIRO_STATUS_SUCCESS)
     776               0 :                 status = _cairo_traps_path (&traps, path);
     777                 : 
     778               0 :             _cairo_traps_fini (&traps);
     779               0 :             break;
     780                 :         }
     781                 :         case CAIRO_COMMAND_FILL:
     782                 :         {
     783               0 :             status = _cairo_path_fixed_append (path,
     784               0 :                                                &command->fill.path, CAIRO_DIRECTION_FORWARD,
     785                 :                                                0, 0);
     786               0 :             break;
     787                 :         }
     788                 :         case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
     789                 :         {
     790               0 :             status = _cairo_scaled_font_glyph_path (command->show_text_glyphs.scaled_font,
     791               0 :                                                     command->show_text_glyphs.glyphs,
     792               0 :                                                     command->show_text_glyphs.num_glyphs,
     793                 :                                                     path);
     794               0 :             break;
     795                 :         }
     796                 : 
     797                 :         default:
     798               0 :             ASSERT_NOT_REACHED;
     799                 :         }
     800                 : 
     801               0 :         if (unlikely (status))
     802               0 :             break;
     803                 :     }
     804                 : 
     805               0 :     return _cairo_surface_set_error (surface, status);
     806                 : }
     807                 : 
     808                 : #define _clip(c) ((c)->header.clip.path ? &(c)->header.clip : NULL)
     809                 : static cairo_status_t
     810               0 : _cairo_recording_surface_replay_internal (cairo_surface_t            *surface,
     811                 :                                           const cairo_rectangle_int_t *surface_extents,
     812                 :                                           cairo_surface_t            *target,
     813                 :                                           cairo_recording_replay_type_t type,
     814                 :                                           cairo_recording_region_type_t region)
     815                 : {
     816                 :     cairo_recording_surface_t *recording_surface;
     817                 :     cairo_command_t **elements;
     818                 :     int i, num_elements;
     819                 :     cairo_int_status_t status;
     820                 :     cairo_surface_wrapper_t wrapper;
     821                 : 
     822               0 :     if (unlikely (surface->status))
     823               0 :         return surface->status;
     824                 : 
     825               0 :     if (unlikely (target->status))
     826               0 :         return target->status;
     827                 : 
     828               0 :     if (unlikely (surface->finished))
     829               0 :         return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
     830                 : 
     831               0 :     if (surface->is_clear)
     832               0 :         return CAIRO_STATUS_SUCCESS;
     833                 : 
     834               0 :     assert (_cairo_surface_is_recording (surface));
     835                 : 
     836               0 :     _cairo_surface_wrapper_init (&wrapper, target);
     837               0 :     _cairo_surface_wrapper_set_extents (&wrapper, surface_extents);
     838                 : 
     839               0 :     recording_surface = (cairo_recording_surface_t *) surface;
     840               0 :     status = CAIRO_STATUS_SUCCESS;
     841                 : 
     842               0 :     num_elements = recording_surface->commands.num_elements;
     843               0 :     elements = _cairo_array_index (&recording_surface->commands, 0);
     844                 : 
     845               0 :     for (i = recording_surface->replay_start_idx; i < num_elements; i++) {
     846               0 :         cairo_command_t *command = elements[i];
     847                 : 
     848               0 :         if (type == CAIRO_RECORDING_REPLAY && region != CAIRO_RECORDING_REGION_ALL) {
     849               0 :             if (command->header.region != region)
     850               0 :                 continue;
     851                 :         }
     852                 : 
     853               0 :         switch (command->header.type) {
     854                 :         case CAIRO_COMMAND_PAINT:
     855               0 :             status = _cairo_surface_wrapper_paint (&wrapper,
     856                 :                                                    command->header.op,
     857               0 :                                                    &command->paint.source.base,
     858               0 :                                                    _clip (command));
     859               0 :             break;
     860                 : 
     861                 :         case CAIRO_COMMAND_MASK:
     862               0 :             status = _cairo_surface_wrapper_mask (&wrapper,
     863                 :                                                   command->header.op,
     864               0 :                                                   &command->mask.source.base,
     865               0 :                                                   &command->mask.mask.base,
     866               0 :                                                   _clip (command));
     867               0 :             break;
     868                 : 
     869                 :         case CAIRO_COMMAND_STROKE:
     870                 :         {
     871               0 :             status = _cairo_surface_wrapper_stroke (&wrapper,
     872                 :                                                     command->header.op,
     873               0 :                                                     &command->stroke.source.base,
     874                 :                                                     &command->stroke.path,
     875               0 :                                                     &command->stroke.style,
     876               0 :                                                     &command->stroke.ctm,
     877               0 :                                                     &command->stroke.ctm_inverse,
     878                 :                                                     command->stroke.tolerance,
     879                 :                                                     command->stroke.antialias,
     880               0 :                                                     _clip (command));
     881               0 :             break;
     882                 :         }
     883                 :         case CAIRO_COMMAND_FILL:
     884                 :         {
     885                 :             cairo_command_t *stroke_command;
     886                 : 
     887               0 :             stroke_command = NULL;
     888               0 :             if (type != CAIRO_RECORDING_CREATE_REGIONS && i < num_elements - 1)
     889               0 :                 stroke_command = elements[i + 1];
     890                 : 
     891               0 :             if (stroke_command != NULL &&
     892               0 :                 type == CAIRO_RECORDING_REPLAY &&
     893                 :                 region != CAIRO_RECORDING_REGION_ALL)
     894                 :             {
     895               0 :                 if (stroke_command->header.region != region)
     896               0 :                     stroke_command = NULL;
     897                 :             }
     898                 : 
     899               0 :             if (stroke_command != NULL &&
     900               0 :                 stroke_command->header.type == CAIRO_COMMAND_STROKE &&
     901               0 :                 _cairo_path_fixed_is_equal (&command->fill.path,
     902               0 :                                             &stroke_command->stroke.path))
     903                 :             {
     904               0 :                 status = _cairo_surface_wrapper_fill_stroke (&wrapper,
     905                 :                                                              command->header.op,
     906               0 :                                                              &command->fill.source.base,
     907                 :                                                              command->fill.fill_rule,
     908                 :                                                              command->fill.tolerance,
     909                 :                                                              command->fill.antialias,
     910                 :                                                              &command->fill.path,
     911                 :                                                              stroke_command->header.op,
     912               0 :                                                              &stroke_command->stroke.source.base,
     913               0 :                                                              &stroke_command->stroke.style,
     914               0 :                                                              &stroke_command->stroke.ctm,
     915               0 :                                                              &stroke_command->stroke.ctm_inverse,
     916                 :                                                              stroke_command->stroke.tolerance,
     917                 :                                                              stroke_command->stroke.antialias,
     918               0 :                                                              _clip (command));
     919               0 :                 i++;
     920                 :             }
     921                 :             else
     922                 :             {
     923               0 :                 status = _cairo_surface_wrapper_fill (&wrapper,
     924                 :                                                       command->header.op,
     925               0 :                                                       &command->fill.source.base,
     926                 :                                                       &command->fill.path,
     927                 :                                                       command->fill.fill_rule,
     928                 :                                                       command->fill.tolerance,
     929                 :                                                       command->fill.antialias,
     930               0 :                                                       _clip (command));
     931                 :             }
     932               0 :             break;
     933                 :         }
     934                 :         case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
     935                 :         {
     936               0 :             cairo_glyph_t *glyphs = command->show_text_glyphs.glyphs;
     937                 :             cairo_glyph_t *glyphs_copy;
     938               0 :             int num_glyphs = command->show_text_glyphs.num_glyphs;
     939                 : 
     940                 :             /* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed
     941                 :              * to modify the glyph array that's passed in.  We must always
     942                 :              * copy the array before handing it to the backend.
     943                 :              */
     944               0 :             glyphs_copy = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
     945               0 :             if (unlikely (glyphs_copy == NULL)) {
     946               0 :                 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
     947               0 :                 break;
     948                 :             }
     949                 : 
     950               0 :             memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
     951                 : 
     952               0 :             status = _cairo_surface_wrapper_show_text_glyphs (&wrapper,
     953                 :                                                               command->header.op,
     954               0 :                                                               &command->show_text_glyphs.source.base,
     955               0 :                                                               command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len,
     956                 :                                                               glyphs_copy, num_glyphs,
     957               0 :                                                               command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters,
     958                 :                                                               command->show_text_glyphs.cluster_flags,
     959                 :                                                               command->show_text_glyphs.scaled_font,
     960               0 :                                                               _clip (command));
     961               0 :             free (glyphs_copy);
     962               0 :             break;
     963                 :         }
     964                 :         default:
     965               0 :             ASSERT_NOT_REACHED;
     966                 :         }
     967                 : 
     968               0 :         if (type == CAIRO_RECORDING_CREATE_REGIONS) {
     969               0 :             if (status == CAIRO_STATUS_SUCCESS) {
     970               0 :                 command->header.region = CAIRO_RECORDING_REGION_NATIVE;
     971               0 :             } else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) {
     972               0 :                 command->header.region = CAIRO_RECORDING_REGION_IMAGE_FALLBACK;
     973               0 :                 status = CAIRO_STATUS_SUCCESS;
     974                 :             } else {
     975               0 :                 assert (_cairo_status_is_error (status));
     976                 :             }
     977                 :         }
     978                 : 
     979               0 :         if (unlikely (status))
     980               0 :             break;
     981                 :     }
     982                 : 
     983                 :     /* free up any caches */
     984               0 :     for (i = recording_surface->replay_start_idx; i < num_elements; i++) {
     985               0 :         cairo_command_t *command = elements[i];
     986                 : 
     987               0 :         _cairo_clip_drop_cache (&command->header.clip);
     988                 :     }
     989                 : 
     990               0 :     _cairo_surface_wrapper_fini (&wrapper);
     991                 : 
     992               0 :     return _cairo_surface_set_error (surface, status);
     993                 : }
     994                 : 
     995                 : /**
     996                 :  * _cairo_recording_surface_replay:
     997                 :  * @surface: the #cairo_recording_surface_t
     998                 :  * @target: a target #cairo_surface_t onto which to replay the operations
     999                 :  * @width_pixels: width of the surface, in pixels
    1000                 :  * @height_pixels: height of the surface, in pixels
    1001                 :  *
    1002                 :  * A recording surface can be "replayed" against any target surface,
    1003                 :  * after which the results in target will be identical to the results
    1004                 :  * that would have been obtained if the original operations applied to
    1005                 :  * the recording surface had instead been applied to the target surface.
    1006                 :  **/
    1007                 : cairo_status_t
    1008               0 : _cairo_recording_surface_replay (cairo_surface_t *surface,
    1009                 :                                  cairo_surface_t *target)
    1010                 : {
    1011               0 :     return _cairo_recording_surface_replay_internal (surface, NULL,
    1012                 :                                                      target,
    1013                 :                                                      CAIRO_RECORDING_REPLAY,
    1014                 :                                                      CAIRO_RECORDING_REGION_ALL);
    1015                 : }
    1016                 : 
    1017                 : /* Replay recording to surface. When the return status of each operation is
    1018                 :  * one of %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED, or
    1019                 :  * %CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY the status of each operation
    1020                 :  * will be stored in the recording surface. Any other status will abort the
    1021                 :  * replay and return the status.
    1022                 :  */
    1023                 : cairo_status_t
    1024               0 : _cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
    1025                 :                                                     cairo_surface_t *target)
    1026                 : {
    1027               0 :     return _cairo_recording_surface_replay_internal (surface, NULL,
    1028                 :                                                      target,
    1029                 :                                                      CAIRO_RECORDING_CREATE_REGIONS,
    1030                 :                                                      CAIRO_RECORDING_REGION_ALL);
    1031                 : }
    1032                 : 
    1033                 : cairo_status_t
    1034               0 : _cairo_recording_surface_replay_region (cairo_surface_t          *surface,
    1035                 :                                         const cairo_rectangle_int_t *surface_extents,
    1036                 :                                         cairo_surface_t          *target,
    1037                 :                                         cairo_recording_region_type_t  region)
    1038                 : {
    1039               0 :     return _cairo_recording_surface_replay_internal (surface, surface_extents,
    1040                 :                                                      target,
    1041                 :                                                      CAIRO_RECORDING_REPLAY,
    1042                 :                                                      region);
    1043                 : }
    1044                 : 
    1045                 : static cairo_status_t
    1046               0 : _recording_surface_get_ink_bbox (cairo_recording_surface_t *surface,
    1047                 :                                  cairo_box_t *bbox,
    1048                 :                                  const cairo_matrix_t *transform)
    1049                 : {
    1050                 :     cairo_surface_t *null_surface;
    1051                 :     cairo_surface_t *analysis_surface;
    1052                 :     cairo_status_t status;
    1053                 : 
    1054               0 :     null_surface = cairo_null_surface_create (surface->content);
    1055               0 :     analysis_surface = _cairo_analysis_surface_create (null_surface);
    1056               0 :     cairo_surface_destroy (null_surface);
    1057                 : 
    1058               0 :     status = analysis_surface->status;
    1059               0 :     if (unlikely (status))
    1060               0 :         return status;
    1061                 : 
    1062               0 :     if (transform != NULL)
    1063               0 :         _cairo_analysis_surface_set_ctm (analysis_surface, transform);
    1064                 : 
    1065               0 :     status = _cairo_recording_surface_replay (&surface->base, analysis_surface);
    1066               0 :     _cairo_analysis_surface_get_bounding_box (analysis_surface, bbox);
    1067               0 :     cairo_surface_destroy (analysis_surface);
    1068                 : 
    1069               0 :     return status;
    1070                 : }
    1071                 : 
    1072                 : /**
    1073                 :  * cairo_recording_surface_ink_extents:
    1074                 :  * @surface: a #cairo_recording_surface_t
    1075                 :  * @x0: the x-coordinate of the top-left of the ink bounding box
    1076                 :  * @y0: the y-coordinate of the top-left of the ink bounding box
    1077                 :  * @width: the width of the ink bounding box
    1078                 :  * @height: the height of the ink bounding box
    1079                 :  *
    1080                 :  * Measures the extents of the operations stored within the recording-surface.
    1081                 :  * This is useful to compute the required size of an image surface (or
    1082                 :  * equivalent) into which to replay the full sequence of drawing operations.
    1083                 :  *
    1084                 :  * Since: 1.10
    1085                 :  **/
    1086                 : void
    1087               0 : cairo_recording_surface_ink_extents (cairo_surface_t *surface,
    1088                 :                                      double *x0,
    1089                 :                                      double *y0,
    1090                 :                                      double *width,
    1091                 :                                      double *height)
    1092                 : {
    1093                 :     cairo_status_t status;
    1094                 :     cairo_box_t bbox;
    1095                 : 
    1096               0 :     memset (&bbox, 0, sizeof (bbox));
    1097                 : 
    1098               0 :     if (! _cairo_surface_is_recording (surface)) {
    1099               0 :         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
    1100               0 :         goto DONE;
    1101                 :     }
    1102                 : 
    1103               0 :     status = _recording_surface_get_ink_bbox ((cairo_recording_surface_t *) surface,
    1104                 :                                          &bbox,
    1105                 :                                          NULL);
    1106               0 :     if (unlikely (status))
    1107               0 :         status = _cairo_surface_set_error (surface, status);
    1108                 : 
    1109                 : DONE:
    1110               0 :     if (x0)
    1111               0 :         *x0 = _cairo_fixed_to_double (bbox.p1.x);
    1112               0 :     if (y0)
    1113               0 :         *y0 = _cairo_fixed_to_double (bbox.p1.y);
    1114               0 :     if (width)
    1115               0 :         *width = _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x);
    1116               0 :     if (height)
    1117               0 :         *height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y);
    1118               0 : }
    1119                 : 
    1120                 : cairo_status_t
    1121               0 : _cairo_recording_surface_get_bbox (cairo_recording_surface_t *surface,
    1122                 :                                    cairo_box_t *bbox,
    1123                 :                                    const cairo_matrix_t *transform)
    1124                 : {
    1125               0 :     if (! surface->unbounded) {
    1126               0 :         _cairo_box_from_rectangle (bbox, &surface->extents);
    1127               0 :         if (transform != NULL)
    1128               0 :             _cairo_matrix_transform_bounding_box_fixed (transform, bbox, NULL);
    1129                 : 
    1130               0 :         return CAIRO_STATUS_SUCCESS;
    1131                 :     }
    1132                 : 
    1133               0 :     return _recording_surface_get_ink_bbox (surface, bbox, transform);
    1134                 : }

Generated by: LCOV version 1.7