Subversion Repositories Kolibri OS

Rev

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

  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. 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.     recording_surface = malloc (sizeof (cairo_recording_surface_t));
  141.     if (unlikely (recording_surface == NULL))
  142.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  143.  
  144.     _cairo_surface_init (&recording_surface->base,
  145.                          &cairo_recording_surface_backend,
  146.                          NULL, /* device */
  147.                          content);
  148.  
  149.     recording_surface->content = content;
  150.  
  151.     recording_surface->unbounded = TRUE;
  152.     _cairo_clip_init (&recording_surface->clip);
  153.  
  154.     /* unbounded -> 'infinite' extents */
  155.     if (extents != NULL) {
  156.         recording_surface->extents_pixels = *extents;
  157.  
  158.         /* XXX check for overflow */
  159.         recording_surface->extents.x = floor (extents->x);
  160.         recording_surface->extents.y = floor (extents->y);
  161.         recording_surface->extents.width = ceil (extents->x + extents->width) - recording_surface->extents.x;
  162.         recording_surface->extents.height = ceil (extents->y + extents->height) - recording_surface->extents.y;
  163.  
  164.         status = _cairo_clip_rectangle (&recording_surface->clip,
  165.                                         &recording_surface->extents);
  166.         if (unlikely (status)) {
  167.             free (recording_surface);
  168.             return _cairo_surface_create_in_error (status);
  169.         }
  170.  
  171.         recording_surface->unbounded = FALSE;
  172.     }
  173.  
  174.     _cairo_array_init (&recording_surface->commands, sizeof (cairo_command_t *));
  175.  
  176.     recording_surface->replay_start_idx = 0;
  177.     recording_surface->base.is_clear = TRUE;
  178.  
  179.     return &recording_surface->base;
  180. }
  181. slim_hidden_def (cairo_recording_surface_create);
  182.  
  183. static cairo_surface_t *
  184. _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.     extents.x = extents.y = 0;
  191.     extents.width = width;
  192.     extents.height = height;
  193.     return cairo_recording_surface_create (content, &extents);
  194. }
  195.  
  196. static cairo_status_t
  197. _cairo_recording_surface_finish (void *abstract_surface)
  198. {
  199.     cairo_recording_surface_t *recording_surface = abstract_surface;
  200.     cairo_command_t **elements;
  201.     int i, num_elements;
  202.  
  203.     num_elements = recording_surface->commands.num_elements;
  204.     elements = _cairo_array_index (&recording_surface->commands, 0);
  205.     for (i = 0; i < num_elements; i++) {
  206.         cairo_command_t *command = elements[i];
  207.  
  208.         switch (command->header.type) {
  209.         case CAIRO_COMMAND_PAINT:
  210.             _cairo_pattern_fini (&command->paint.source.base);
  211.             break;
  212.  
  213.         case CAIRO_COMMAND_MASK:
  214.             _cairo_pattern_fini (&command->mask.source.base);
  215.             _cairo_pattern_fini (&command->mask.mask.base);
  216.             break;
  217.  
  218.         case CAIRO_COMMAND_STROKE:
  219.             _cairo_pattern_fini (&command->stroke.source.base);
  220.             _cairo_path_fixed_fini (&command->stroke.path);
  221.             _cairo_stroke_style_fini (&command->stroke.style);
  222.             break;
  223.  
  224.         case CAIRO_COMMAND_FILL:
  225.             _cairo_pattern_fini (&command->fill.source.base);
  226.             _cairo_path_fixed_fini (&command->fill.path);
  227.             break;
  228.  
  229.         case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
  230.             _cairo_pattern_fini (&command->show_text_glyphs.source.base);
  231.             free (command->show_text_glyphs.utf8);
  232.             free (command->show_text_glyphs.glyphs);
  233.             free (command->show_text_glyphs.clusters);
  234.             cairo_scaled_font_destroy (command->show_text_glyphs.scaled_font);
  235.             break;
  236.  
  237.         default:
  238.             ASSERT_NOT_REACHED;
  239.         }
  240.  
  241.         _cairo_clip_fini (&command->header.clip);
  242.         free (command);
  243.     }
  244.  
  245.     _cairo_array_fini (&recording_surface->commands);
  246.     _cairo_clip_fini (&recording_surface->clip);
  247.  
  248.     return CAIRO_STATUS_SUCCESS;
  249. }
  250.  
  251. static cairo_status_t
  252. _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.     cairo_recording_surface_t *surface = abstract_surface;
  258.     cairo_surface_t *image;
  259.  
  260.     image = _cairo_surface_has_snapshot (&surface->base,
  261.                                          &_cairo_image_surface_backend);
  262.     if (image != NULL) {
  263.         *image_out = (cairo_image_surface_t *) cairo_surface_reference (image);
  264.         *image_extra = NULL;
  265.         return CAIRO_STATUS_SUCCESS;
  266.     }
  267.  
  268.     image = _cairo_image_surface_create_with_content (surface->content,
  269.                                                       surface->extents.width,
  270.                                                       surface->extents.height);
  271.     if (unlikely (image->status))
  272.         return image->status;
  273.  
  274.     cairo_surface_set_device_offset (image,
  275.                                      -surface->extents.x,
  276.                                      -surface->extents.y);
  277.  
  278.     status = _cairo_recording_surface_replay (&surface->base, image);
  279.     if (unlikely (status)) {
  280.         cairo_surface_destroy (image);
  281.         return status;
  282.     }
  283.  
  284.     _cairo_surface_attach_snapshot (&surface->base, image, NULL);
  285.  
  286.     *image_out = (cairo_image_surface_t *) image;
  287.     *image_extra = NULL;
  288.     return CAIRO_STATUS_SUCCESS;
  289. }
  290.  
  291. static void
  292. _cairo_recording_surface_release_source_image (void                     *abstract_surface,
  293.                                                cairo_image_surface_t    *image,
  294.                                                void                     *image_extra)
  295. {
  296.     cairo_surface_destroy (&image->base);
  297. }
  298.  
  299. static cairo_status_t
  300. _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.     cairo_status_t status = CAIRO_STATUS_SUCCESS;
  307.  
  308.     command->type = type;
  309.     command->op = op;
  310.     command->region = CAIRO_RECORDING_REGION_ALL;
  311.     _cairo_clip_init_copy (&command->clip, clip);
  312.     if (recording_surface->clip.path != NULL)
  313.         status = _cairo_clip_apply_clip (&command->clip, &recording_surface->clip);
  314.  
  315.     return status;
  316. }
  317.  
  318. static cairo_int_status_t
  319. _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.     cairo_recording_surface_t *recording_surface = abstract_surface;
  326.     cairo_command_paint_t *command;
  327.  
  328.     command = malloc (sizeof (cairo_command_paint_t));
  329.     if (unlikely (command == NULL))
  330.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  331.  
  332.     status = _command_init (recording_surface,
  333.                             &command->header, CAIRO_COMMAND_PAINT, op, clip);
  334.     if (unlikely (status))
  335.         goto CLEANUP_COMMAND;
  336.  
  337.     status = _cairo_pattern_init_snapshot (&command->source.base, source);
  338.     if (unlikely (status))
  339.         goto CLEANUP_COMMAND;
  340.  
  341.     status = _cairo_array_append (&recording_surface->commands, &command);
  342.     if (unlikely (status))
  343.         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.     if (op == CAIRO_OPERATOR_CLEAR && clip == NULL)
  349.         recording_surface->replay_start_idx = recording_surface->commands.num_elements;
  350.  
  351.     return CAIRO_STATUS_SUCCESS;
  352.  
  353.   CLEANUP_SOURCE:
  354.     _cairo_pattern_fini (&command->source.base);
  355.   CLEANUP_COMMAND:
  356.     _cairo_clip_fini (&command->header.clip);
  357.     free (command);
  358.     return status;
  359. }
  360.  
  361. static cairo_int_status_t
  362. _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.     cairo_recording_surface_t *recording_surface = abstract_surface;
  370.     cairo_command_mask_t *command;
  371.  
  372.     command = malloc (sizeof (cairo_command_mask_t));
  373.     if (unlikely (command == NULL))
  374.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  375.  
  376.     status = _command_init (recording_surface,
  377.                             &command->header, CAIRO_COMMAND_MASK, op, clip);
  378.     if (unlikely (status))
  379.         goto CLEANUP_COMMAND;
  380.  
  381.     status = _cairo_pattern_init_snapshot (&command->source.base, source);
  382.     if (unlikely (status))
  383.         goto CLEANUP_COMMAND;
  384.  
  385.     status = _cairo_pattern_init_snapshot (&command->mask.base, mask);
  386.     if (unlikely (status))
  387.         goto CLEANUP_SOURCE;
  388.  
  389.     status = _cairo_array_append (&recording_surface->commands, &command);
  390.     if (unlikely (status))
  391.         goto CLEANUP_MASK;
  392.  
  393.     return CAIRO_STATUS_SUCCESS;
  394.  
  395.   CLEANUP_MASK:
  396.     _cairo_pattern_fini (&command->mask.base);
  397.   CLEANUP_SOURCE:
  398.     _cairo_pattern_fini (&command->source.base);
  399.   CLEANUP_COMMAND:
  400.     _cairo_clip_fini (&command->header.clip);
  401.     free (command);
  402.     return status;
  403. }
  404.  
  405. static cairo_int_status_t
  406. _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.     cairo_recording_surface_t *recording_surface = abstract_surface;
  419.     cairo_command_stroke_t *command;
  420.  
  421.     command = malloc (sizeof (cairo_command_stroke_t));
  422.     if (unlikely (command == NULL))
  423.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  424.  
  425.     status = _command_init (recording_surface,
  426.                             &command->header, CAIRO_COMMAND_STROKE, op, clip);
  427.     if (unlikely (status))
  428.         goto CLEANUP_COMMAND;
  429.  
  430.     status = _cairo_pattern_init_snapshot (&command->source.base, source);
  431.     if (unlikely (status))
  432.         goto CLEANUP_COMMAND;
  433.  
  434.     status = _cairo_path_fixed_init_copy (&command->path, path);
  435.     if (unlikely (status))
  436.         goto CLEANUP_SOURCE;
  437.  
  438.     status = _cairo_stroke_style_init_copy (&command->style, style);
  439.     if (unlikely (status))
  440.         goto CLEANUP_PATH;
  441.  
  442.     command->ctm = *ctm;
  443.     command->ctm_inverse = *ctm_inverse;
  444.     command->tolerance = tolerance;
  445.     command->antialias = antialias;
  446.  
  447.     status = _cairo_array_append (&recording_surface->commands, &command);
  448.     if (unlikely (status))
  449.         goto CLEANUP_STYLE;
  450.  
  451.     return CAIRO_STATUS_SUCCESS;
  452.  
  453.   CLEANUP_STYLE:
  454.     _cairo_stroke_style_fini (&command->style);
  455.   CLEANUP_PATH:
  456.     _cairo_path_fixed_fini (&command->path);
  457.   CLEANUP_SOURCE:
  458.     _cairo_pattern_fini (&command->source.base);
  459.   CLEANUP_COMMAND:
  460.     _cairo_clip_fini (&command->header.clip);
  461.     free (command);
  462.     return status;
  463. }
  464.  
  465. static cairo_int_status_t
  466. _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.     cairo_recording_surface_t *recording_surface = abstract_surface;
  477.     cairo_command_fill_t *command;
  478.  
  479.     command = malloc (sizeof (cairo_command_fill_t));
  480.     if (unlikely (command == NULL))
  481.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  482.  
  483.     status =_command_init (recording_surface,
  484.                            &command->header, CAIRO_COMMAND_FILL, op, clip);
  485.     if (unlikely (status))
  486.         goto CLEANUP_COMMAND;
  487.  
  488.     status = _cairo_pattern_init_snapshot (&command->source.base, source);
  489.     if (unlikely (status))
  490.         goto CLEANUP_COMMAND;
  491.  
  492.     status = _cairo_path_fixed_init_copy (&command->path, path);
  493.     if (unlikely (status))
  494.         goto CLEANUP_SOURCE;
  495.  
  496.     command->fill_rule = fill_rule;
  497.     command->tolerance = tolerance;
  498.     command->antialias = antialias;
  499.  
  500.     status = _cairo_array_append (&recording_surface->commands, &command);
  501.     if (unlikely (status))
  502.         goto CLEANUP_PATH;
  503.  
  504.     return CAIRO_STATUS_SUCCESS;
  505.  
  506.   CLEANUP_PATH:
  507.     _cairo_path_fixed_fini (&command->path);
  508.   CLEANUP_SOURCE:
  509.     _cairo_pattern_fini (&command->source.base);
  510.   CLEANUP_COMMAND:
  511.     _cairo_clip_fini (&command->header.clip);
  512.     free (command);
  513.     return status;
  514. }
  515.  
  516. static cairo_bool_t
  517. _cairo_recording_surface_has_show_text_glyphs (void *abstract_surface)
  518. {
  519.     return TRUE;
  520. }
  521.  
  522. static cairo_int_status_t
  523. _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.     cairo_recording_surface_t *recording_surface = abstract_surface;
  538.     cairo_command_show_text_glyphs_t *command;
  539.  
  540.     command = malloc (sizeof (cairo_command_show_text_glyphs_t));
  541.     if (unlikely (command == NULL))
  542.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  543.  
  544.     status = _command_init (recording_surface,
  545.                             &command->header, CAIRO_COMMAND_SHOW_TEXT_GLYPHS,
  546.                             op, clip);
  547.     if (unlikely (status))
  548.         goto CLEANUP_COMMAND;
  549.  
  550.     status = _cairo_pattern_init_snapshot (&command->source.base, source);
  551.     if (unlikely (status))
  552.         goto CLEANUP_COMMAND;
  553.  
  554.     command->utf8 = NULL;
  555.     command->utf8_len = utf8_len;
  556.     command->glyphs = NULL;
  557.     command->num_glyphs = num_glyphs;
  558.     command->clusters = NULL;
  559.     command->num_clusters = num_clusters;
  560.  
  561.     if (utf8_len) {
  562.         command->utf8 = malloc (utf8_len);
  563.         if (unlikely (command->utf8 == NULL)) {
  564.             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  565.             goto CLEANUP_ARRAYS;
  566.         }
  567.         memcpy (command->utf8, utf8, utf8_len);
  568.     }
  569.     if (num_glyphs) {
  570.         command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (glyphs[0]));
  571.         if (unlikely (command->glyphs == NULL)) {
  572.             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  573.             goto CLEANUP_ARRAYS;
  574.         }
  575.         memcpy (command->glyphs, glyphs, sizeof (glyphs[0]) * num_glyphs);
  576.     }
  577.     if (num_clusters) {
  578.         command->clusters = _cairo_malloc_ab (num_clusters, sizeof (clusters[0]));
  579.         if (unlikely (command->clusters == NULL)) {
  580.             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  581.             goto CLEANUP_ARRAYS;
  582.         }
  583.         memcpy (command->clusters, clusters, sizeof (clusters[0]) * num_clusters);
  584.     }
  585.  
  586.     command->cluster_flags = cluster_flags;
  587.  
  588.     command->scaled_font = cairo_scaled_font_reference (scaled_font);
  589.  
  590.     status = _cairo_array_append (&recording_surface->commands, &command);
  591.     if (unlikely (status))
  592.         goto CLEANUP_SCALED_FONT;
  593.  
  594.     return CAIRO_STATUS_SUCCESS;
  595.  
  596.   CLEANUP_SCALED_FONT:
  597.     cairo_scaled_font_destroy (command->scaled_font);
  598.   CLEANUP_ARRAYS:
  599.     free (command->utf8);
  600.     free (command->glyphs);
  601.     free (command->clusters);
  602.  
  603.     _cairo_pattern_fini (&command->source.base);
  604.   CLEANUP_COMMAND:
  605.     _cairo_clip_fini (&command->header.clip);
  606.     free (command);
  607.     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. _cairo_recording_surface_snapshot (void *abstract_other)
  625. {
  626.     cairo_recording_surface_t *other = abstract_other;
  627.     cairo_recording_surface_t *recording_surface;
  628.     cairo_status_t status;
  629.  
  630.     recording_surface = malloc (sizeof (cairo_recording_surface_t));
  631.     if (unlikely (recording_surface == NULL))
  632.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  633.  
  634.     _cairo_surface_init (&recording_surface->base,
  635.                          &cairo_recording_surface_backend,
  636.                          NULL, /* device */
  637.                          other->base.content);
  638.  
  639.     recording_surface->extents_pixels = other->extents_pixels;
  640.     recording_surface->extents = other->extents;
  641.     recording_surface->unbounded = other->unbounded;
  642.     recording_surface->content = other->content;
  643.  
  644.     _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.     recording_surface->replay_start_idx = 0;
  650.     recording_surface->base.is_clear = TRUE;
  651.  
  652.     _cairo_array_init (&recording_surface->commands, sizeof (cairo_command_t *));
  653.     status = _cairo_recording_surface_replay (&other->base, &recording_surface->base);
  654.     if (unlikely (status)) {
  655.         cairo_surface_destroy (&recording_surface->base);
  656.         return _cairo_surface_create_in_error (status);
  657.     }
  658.  
  659.     return &recording_surface->base;
  660. }
  661.  
  662. static cairo_bool_t
  663. _cairo_recording_surface_get_extents (void                  *abstract_surface,
  664.                                       cairo_rectangle_int_t *rectangle)
  665. {
  666.     cairo_recording_surface_t *surface = abstract_surface;
  667.  
  668.     if (surface->unbounded)
  669.         return FALSE;
  670.  
  671.     *rectangle = surface->extents;
  672.     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. _cairo_surface_is_recording (const cairo_surface_t *surface)
  685. {
  686.     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. _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.     if (surface->status)
  745.         return surface->status;
  746.  
  747.     recording_surface = (cairo_recording_surface_t *) surface;
  748.     status = CAIRO_STATUS_SUCCESS;
  749.  
  750.     num_elements = recording_surface->commands.num_elements;
  751.     elements = _cairo_array_index (&recording_surface->commands, 0);
  752.     for (i = recording_surface->replay_start_idx; i < num_elements; i++) {
  753.         cairo_command_t *command = elements[i];
  754.  
  755.         switch (command->header.type) {
  756.         case CAIRO_COMMAND_PAINT:
  757.         case CAIRO_COMMAND_MASK:
  758.             status = CAIRO_INT_STATUS_UNSUPPORTED;
  759.             break;
  760.  
  761.         case CAIRO_COMMAND_STROKE:
  762.         {
  763.             cairo_traps_t traps;
  764.  
  765.             _cairo_traps_init (&traps);
  766.  
  767.             /* XXX call cairo_stroke_to_path() when that is implemented */
  768.             status = _cairo_path_fixed_stroke_to_traps (&command->stroke.path,
  769.                                                         &command->stroke.style,
  770.                                                         &command->stroke.ctm,
  771.                                                         &command->stroke.ctm_inverse,
  772.                                                         command->stroke.tolerance,
  773.                                                         &traps);
  774.  
  775.             if (status == CAIRO_STATUS_SUCCESS)
  776.                 status = _cairo_traps_path (&traps, path);
  777.  
  778.             _cairo_traps_fini (&traps);
  779.             break;
  780.         }
  781.         case CAIRO_COMMAND_FILL:
  782.         {
  783.             status = _cairo_path_fixed_append (path,
  784.                                                &command->fill.path, CAIRO_DIRECTION_FORWARD,
  785.                                                0, 0);
  786.             break;
  787.         }
  788.         case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
  789.         {
  790.             status = _cairo_scaled_font_glyph_path (command->show_text_glyphs.scaled_font,
  791.                                                     command->show_text_glyphs.glyphs,
  792.                                                     command->show_text_glyphs.num_glyphs,
  793.                                                     path);
  794.             break;
  795.         }
  796.  
  797.         default:
  798.             ASSERT_NOT_REACHED;
  799.         }
  800.  
  801.         if (unlikely (status))
  802.             break;
  803.     }
  804.  
  805.     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. _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.     if (unlikely (surface->status))
  823.         return surface->status;
  824.  
  825.     if (unlikely (target->status))
  826.         return target->status;
  827.  
  828.     if (unlikely (surface->finished))
  829.         return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);
  830.  
  831.     if (surface->is_clear)
  832.         return CAIRO_STATUS_SUCCESS;
  833.  
  834.     assert (_cairo_surface_is_recording (surface));
  835.  
  836.     _cairo_surface_wrapper_init (&wrapper, target);
  837.     _cairo_surface_wrapper_set_extents (&wrapper, surface_extents);
  838.  
  839.     recording_surface = (cairo_recording_surface_t *) surface;
  840.     status = CAIRO_STATUS_SUCCESS;
  841.  
  842.     num_elements = recording_surface->commands.num_elements;
  843.     elements = _cairo_array_index (&recording_surface->commands, 0);
  844.  
  845.     for (i = recording_surface->replay_start_idx; i < num_elements; i++) {
  846.         cairo_command_t *command = elements[i];
  847.  
  848.         if (type == CAIRO_RECORDING_REPLAY && region != CAIRO_RECORDING_REGION_ALL) {
  849.             if (command->header.region != region)
  850.                 continue;
  851.         }
  852.  
  853.         switch (command->header.type) {
  854.         case CAIRO_COMMAND_PAINT:
  855.             status = _cairo_surface_wrapper_paint (&wrapper,
  856.                                                    command->header.op,
  857.                                                    &command->paint.source.base,
  858.                                                    _clip (command));
  859.             break;
  860.  
  861.         case CAIRO_COMMAND_MASK:
  862.             status = _cairo_surface_wrapper_mask (&wrapper,
  863.                                                   command->header.op,
  864.                                                   &command->mask.source.base,
  865.                                                   &command->mask.mask.base,
  866.                                                   _clip (command));
  867.             break;
  868.  
  869.         case CAIRO_COMMAND_STROKE:
  870.         {
  871.             status = _cairo_surface_wrapper_stroke (&wrapper,
  872.                                                     command->header.op,
  873.                                                     &command->stroke.source.base,
  874.                                                     &command->stroke.path,
  875.                                                     &command->stroke.style,
  876.                                                     &command->stroke.ctm,
  877.                                                     &command->stroke.ctm_inverse,
  878.                                                     command->stroke.tolerance,
  879.                                                     command->stroke.antialias,
  880.                                                     _clip (command));
  881.             break;
  882.         }
  883.         case CAIRO_COMMAND_FILL:
  884.         {
  885.             cairo_command_t *stroke_command;
  886.  
  887.             stroke_command = NULL;
  888.             if (type != CAIRO_RECORDING_CREATE_REGIONS && i < num_elements - 1)
  889.                 stroke_command = elements[i + 1];
  890.  
  891.             if (stroke_command != NULL &&
  892.                 type == CAIRO_RECORDING_REPLAY &&
  893.                 region != CAIRO_RECORDING_REGION_ALL)
  894.             {
  895.                 if (stroke_command->header.region != region)
  896.                     stroke_command = NULL;
  897.             }
  898.  
  899.             if (stroke_command != NULL &&
  900.                 stroke_command->header.type == CAIRO_COMMAND_STROKE &&
  901.                 _cairo_path_fixed_is_equal (&command->fill.path,
  902.                                             &stroke_command->stroke.path))
  903.             {
  904.                 status = _cairo_surface_wrapper_fill_stroke (&wrapper,
  905.                                                              command->header.op,
  906.                                                              &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.                                                              &stroke_command->stroke.source.base,
  913.                                                              &stroke_command->stroke.style,
  914.                                                              &stroke_command->stroke.ctm,
  915.                                                              &stroke_command->stroke.ctm_inverse,
  916.                                                              stroke_command->stroke.tolerance,
  917.                                                              stroke_command->stroke.antialias,
  918.                                                              _clip (command));
  919.                 i++;
  920.             }
  921.             else
  922.             {
  923.                 status = _cairo_surface_wrapper_fill (&wrapper,
  924.                                                       command->header.op,
  925.                                                       &command->fill.source.base,
  926.                                                       &command->fill.path,
  927.                                                       command->fill.fill_rule,
  928.                                                       command->fill.tolerance,
  929.                                                       command->fill.antialias,
  930.                                                       _clip (command));
  931.             }
  932.             break;
  933.         }
  934.         case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
  935.         {
  936.             cairo_glyph_t *glyphs = command->show_text_glyphs.glyphs;
  937.             cairo_glyph_t *glyphs_copy;
  938.             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.             glyphs_copy = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
  945.             if (unlikely (glyphs_copy == NULL)) {
  946.                 status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  947.                 break;
  948.             }
  949.  
  950.             memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
  951.  
  952.             status = _cairo_surface_wrapper_show_text_glyphs (&wrapper,
  953.                                                               command->header.op,
  954.                                                               &command->show_text_glyphs.source.base,
  955.                                                               command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len,
  956.                                                               glyphs_copy, num_glyphs,
  957.                                                               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.                                                               _clip (command));
  961.             free (glyphs_copy);
  962.             break;
  963.         }
  964.         default:
  965.             ASSERT_NOT_REACHED;
  966.         }
  967.  
  968.         if (type == CAIRO_RECORDING_CREATE_REGIONS) {
  969.             if (status == CAIRO_STATUS_SUCCESS) {
  970.                 command->header.region = CAIRO_RECORDING_REGION_NATIVE;
  971.             } else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) {
  972.                 command->header.region = CAIRO_RECORDING_REGION_IMAGE_FALLBACK;
  973.                 status = CAIRO_STATUS_SUCCESS;
  974.             } else {
  975.                 assert (_cairo_status_is_error (status));
  976.             }
  977.         }
  978.  
  979.         if (unlikely (status))
  980.             break;
  981.     }
  982.  
  983.     /* free up any caches */
  984.     for (i = recording_surface->replay_start_idx; i < num_elements; i++) {
  985.         cairo_command_t *command = elements[i];
  986.  
  987.         _cairo_clip_drop_cache (&command->header.clip);
  988.     }
  989.  
  990.     _cairo_surface_wrapper_fini (&wrapper);
  991.  
  992.     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. _cairo_recording_surface_replay (cairo_surface_t *surface,
  1009.                                  cairo_surface_t *target)
  1010. {
  1011.     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. _cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
  1025.                                                     cairo_surface_t *target)
  1026. {
  1027.     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. _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.     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. _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.     null_surface = _cairo_null_surface_create (surface->content);
  1055.     analysis_surface = _cairo_analysis_surface_create (null_surface);
  1056.     cairo_surface_destroy (null_surface);
  1057.  
  1058.     status = analysis_surface->status;
  1059.     if (unlikely (status))
  1060.         return status;
  1061.  
  1062.     if (transform != NULL)
  1063.         _cairo_analysis_surface_set_ctm (analysis_surface, transform);
  1064.  
  1065.     status = _cairo_recording_surface_replay (&surface->base, analysis_surface);
  1066.     _cairo_analysis_surface_get_bounding_box (analysis_surface, bbox);
  1067.     cairo_surface_destroy (analysis_surface);
  1068.  
  1069.     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. 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.     memset (&bbox, 0, sizeof (bbox));
  1097.  
  1098.     if (! _cairo_surface_is_recording (surface)) {
  1099.         _cairo_error_throw (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
  1100.         goto DONE;
  1101.     }
  1102.  
  1103.     status = _recording_surface_get_ink_bbox ((cairo_recording_surface_t *) surface,
  1104.                                          &bbox,
  1105.                                          NULL);
  1106.     if (unlikely (status))
  1107.         status = _cairo_surface_set_error (surface, status);
  1108.  
  1109. DONE:
  1110.     if (x0)
  1111.         *x0 = _cairo_fixed_to_double (bbox.p1.x);
  1112.     if (y0)
  1113.         *y0 = _cairo_fixed_to_double (bbox.p1.y);
  1114.     if (width)
  1115.         *width = _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x);
  1116.     if (height)
  1117.         *height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y);
  1118. }
  1119.  
  1120. cairo_status_t
  1121. _cairo_recording_surface_get_bbox (cairo_recording_surface_t *surface,
  1122.                                    cairo_box_t *bbox,
  1123.                                    const cairo_matrix_t *transform)
  1124. {
  1125.     if (! surface->unbounded) {
  1126.         _cairo_box_from_rectangle (bbox, &surface->extents);
  1127.         if (transform != NULL)
  1128.             _cairo_matrix_transform_bounding_box_fixed (transform, bbox, NULL);
  1129.  
  1130.         return CAIRO_STATUS_SUCCESS;
  1131.     }
  1132.  
  1133.     return _recording_surface_get_ink_bbox (surface, bbox, transform);
  1134. }
  1135.