Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /* cairo - a vector graphics library with display and print output
  2.  *
  3.  * Copyright © 2005 Red Hat, Inc
  4.  * Copyright © 2007 Adrian Johnson
  5.  *
  6.  * This library is free software; you can redistribute it and/or
  7.  * modify it either under the terms of the GNU Lesser General Public
  8.  * License version 2.1 as published by the Free Software Foundation
  9.  * (the "LGPL") or, at your option, under the terms of the Mozilla
  10.  * Public License Version 1.1 (the "MPL"). If you do not alter this
  11.  * notice, a recipient may use your version of this file under either
  12.  * the MPL or the LGPL.
  13.  *
  14.  * You should have received a copy of the LGPL along with this library
  15.  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
  16.  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
  17.  * You should have received a copy of the MPL along with this library
  18.  * in the file COPYING-MPL-1.1
  19.  *
  20.  * The contents of this file are subject to the Mozilla Public License
  21.  * Version 1.1 (the "License"); you may not use this file except in
  22.  * compliance with the License. You may obtain a copy of the License at
  23.  * http://www.mozilla.org/MPL/
  24.  *
  25.  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
  26.  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
  27.  * the specific language governing rights and limitations.
  28.  *
  29.  * The Original Code is the cairo graphics library.
  30.  *
  31.  * The Initial Developer of the Original Code is Red Hat, Inc.
  32.  *
  33.  * Contributor(s):
  34.  *      Carl Worth <cworth@cworth.org>
  35.  *      Keith Packard <keithp@keithp.com>
  36.  *      Adrian Johnson <ajohnson@redneon.com>
  37.  */
  38.  
  39. /* The paginated surface layer exists to provide as much code sharing
  40.  * as possible for the various paginated surface backends in cairo
  41.  * (PostScript, PDF, etc.). See cairo-paginated-private.h for
  42.  * more details on how it works and how to use it.
  43.  */
  44.  
  45. #include "cairoint.h"
  46.  
  47. #include "cairo-paginated-private.h"
  48. #include "cairo-paginated-surface-private.h"
  49. #include "cairo-recording-surface-private.h"
  50. #include "cairo-analysis-surface-private.h"
  51. #include "cairo-error-private.h"
  52.  
  53. static const cairo_surface_backend_t cairo_paginated_surface_backend;
  54.  
  55. static cairo_int_status_t
  56. _cairo_paginated_surface_show_page (void *abstract_surface);
  57.  
  58. static cairo_surface_t *
  59. _cairo_paginated_surface_create_similar (void                   *abstract_surface,
  60.                                          cairo_content_t         content,
  61.                                          int                     width,
  62.                                          int                     height)
  63. {
  64.     cairo_rectangle_t rect;
  65.     rect.x = rect.y = 0.;
  66.     rect.width = width;
  67.     rect.height = height;
  68.     return cairo_recording_surface_create (content, &rect);
  69. }
  70.  
  71. static cairo_surface_t *
  72. _create_recording_surface_for_target (cairo_surface_t *target,
  73.                                       cairo_content_t content)
  74. {
  75.     cairo_rectangle_int_t rect;
  76.  
  77.     if (_cairo_surface_get_extents (target, &rect)) {
  78.         cairo_rectangle_t recording_extents;
  79.  
  80.         recording_extents.x = rect.x;
  81.         recording_extents.y = rect.y;
  82.         recording_extents.width = rect.width;
  83.         recording_extents.height = rect.height;
  84.  
  85.         return cairo_recording_surface_create (content, &recording_extents);
  86.     } else {
  87.         return cairo_recording_surface_create (content, NULL);
  88.     }
  89. }
  90.  
  91. cairo_surface_t *
  92. _cairo_paginated_surface_create (cairo_surface_t                                *target,
  93.                                  cairo_content_t                                 content,
  94.                                  const cairo_paginated_surface_backend_t        *backend)
  95. {
  96.     cairo_paginated_surface_t *surface;
  97.     cairo_status_t status;
  98.  
  99.     surface = malloc (sizeof (cairo_paginated_surface_t));
  100.     if (unlikely (surface == NULL)) {
  101.         status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  102.         goto FAIL;
  103.     }
  104.  
  105.     _cairo_surface_init (&surface->base,
  106.                          &cairo_paginated_surface_backend,
  107.                          NULL, /* device */
  108.                          content);
  109.  
  110.     /* Override surface->base.type with target's type so we don't leak
  111.      * evidence of the paginated wrapper out to the user. */
  112.     surface->base.type = target->type;
  113.  
  114.     surface->target = cairo_surface_reference (target);
  115.  
  116.     surface->content = content;
  117.     surface->backend = backend;
  118.  
  119.     surface->recording_surface = _create_recording_surface_for_target (target, content);
  120.     status = surface->recording_surface->status;
  121.     if (unlikely (status))
  122.         goto FAIL_CLEANUP_SURFACE;
  123.  
  124.     surface->page_num = 1;
  125.     surface->base.is_clear = TRUE;
  126.  
  127.     return &surface->base;
  128.  
  129.   FAIL_CLEANUP_SURFACE:
  130.     cairo_surface_destroy (target);
  131.     free (surface);
  132.   FAIL:
  133.     return _cairo_surface_create_in_error (status);
  134. }
  135.  
  136. cairo_bool_t
  137. _cairo_surface_is_paginated (cairo_surface_t *surface)
  138. {
  139.     return surface->backend == &cairo_paginated_surface_backend;
  140. }
  141.  
  142. cairo_surface_t *
  143. _cairo_paginated_surface_get_target (cairo_surface_t *surface)
  144. {
  145.     cairo_paginated_surface_t *paginated_surface;
  146.  
  147.     assert (_cairo_surface_is_paginated (surface));
  148.  
  149.     paginated_surface = (cairo_paginated_surface_t *) surface;
  150.  
  151.     return paginated_surface->target;
  152. }
  153.  
  154. cairo_status_t
  155. _cairo_paginated_surface_set_size (cairo_surface_t      *surface,
  156.                                    int                   width,
  157.                                    int                   height)
  158. {
  159.     cairo_paginated_surface_t *paginated_surface;
  160.     cairo_status_t status;
  161.     cairo_rectangle_t recording_extents;
  162.  
  163.     assert (_cairo_surface_is_paginated (surface));
  164.  
  165.     paginated_surface = (cairo_paginated_surface_t *) surface;
  166.  
  167.     recording_extents.x = 0;
  168.     recording_extents.y = 0;
  169.     recording_extents.width = width;
  170.     recording_extents.height = height;
  171.  
  172.     cairo_surface_destroy (paginated_surface->recording_surface);
  173.     paginated_surface->recording_surface = cairo_recording_surface_create (paginated_surface->content,
  174.                                                                            &recording_extents);
  175.     status = paginated_surface->recording_surface->status;
  176.     if (unlikely (status))
  177.         return _cairo_surface_set_error (surface, status);
  178.  
  179.     return CAIRO_STATUS_SUCCESS;
  180. }
  181.  
  182. static cairo_status_t
  183. _cairo_paginated_surface_finish (void *abstract_surface)
  184. {
  185.     cairo_paginated_surface_t *surface = abstract_surface;
  186.     cairo_status_t status = CAIRO_STATUS_SUCCESS;
  187.  
  188.     if (! surface->base.is_clear || surface->page_num == 1) {
  189.         /* Bypass some of the sanity checking in cairo-surface.c, as we
  190.          * know that the surface is finished...
  191.          */
  192.         status = _cairo_paginated_surface_show_page (surface);
  193.     }
  194.  
  195.      /* XXX We want to propagate any errors from destroy(), but those are not
  196.       * returned via the api. So we need to explicitly finish the target,
  197.       * and check the status afterwards. However, we can only call finish()
  198.       * on the target, if we own it.
  199.       */
  200.     if (CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->target->ref_count) == 1)
  201.         cairo_surface_finish (surface->target);
  202.     if (status == CAIRO_STATUS_SUCCESS)
  203.         status = cairo_surface_status (surface->target);
  204.     cairo_surface_destroy (surface->target);
  205.  
  206.     cairo_surface_finish (surface->recording_surface);
  207.     if (status == CAIRO_STATUS_SUCCESS)
  208.         status = cairo_surface_status (surface->recording_surface);
  209.     cairo_surface_destroy (surface->recording_surface);
  210.  
  211.     return status;
  212. }
  213.  
  214. static cairo_surface_t *
  215. _cairo_paginated_surface_create_image_surface (void            *abstract_surface,
  216.                                                int              width,
  217.                                                int              height)
  218. {
  219.     cairo_paginated_surface_t *surface = abstract_surface;
  220.     cairo_surface_t *image;
  221.     cairo_font_options_t options;
  222.  
  223.     image = _cairo_image_surface_create_with_content (surface->content,
  224.                                                       width,
  225.                                                       height);
  226.  
  227.     cairo_surface_get_font_options (&surface->base, &options);
  228.     _cairo_surface_set_font_options (image, &options);
  229.  
  230.     return image;
  231. }
  232.  
  233. static cairo_status_t
  234. _cairo_paginated_surface_acquire_source_image (void            *abstract_surface,
  235.                                                cairo_image_surface_t **image_out,
  236.                                                void                **image_extra)
  237. {
  238.     cairo_paginated_surface_t *surface = abstract_surface;
  239.     cairo_bool_t is_bounded;
  240.     cairo_surface_t *image;
  241.     cairo_status_t status;
  242.     cairo_rectangle_int_t extents;
  243.  
  244.     is_bounded = _cairo_surface_get_extents (surface->target, &extents);
  245.     if (! is_bounded)
  246.         return CAIRO_INT_STATUS_UNSUPPORTED;
  247.  
  248.     image = _cairo_paginated_surface_create_image_surface (surface,
  249.                                                            extents.width,
  250.                                                            extents.height);
  251.  
  252.     status = _cairo_recording_surface_replay (surface->recording_surface, image);
  253.     if (unlikely (status)) {
  254.         cairo_surface_destroy (image);
  255.         return status;
  256.     }
  257.  
  258.     *image_out = (cairo_image_surface_t*) image;
  259.     *image_extra = NULL;
  260.  
  261.     return CAIRO_STATUS_SUCCESS;
  262. }
  263.  
  264. static void
  265. _cairo_paginated_surface_release_source_image (void       *abstract_surface,
  266.                                                cairo_image_surface_t *image,
  267.                                                void            *image_extra)
  268. {
  269.     cairo_surface_destroy (&image->base);
  270. }
  271.  
  272. static cairo_int_status_t
  273. _paint_fallback_image (cairo_paginated_surface_t *surface,
  274.                        cairo_rectangle_int_t     *rect)
  275. {
  276.     double x_scale = surface->base.x_fallback_resolution / surface->target->x_resolution;
  277.     double y_scale = surface->base.y_fallback_resolution / surface->target->y_resolution;
  278.     int x, y, width, height;
  279.     cairo_status_t status;
  280.     cairo_surface_t *image;
  281.     cairo_surface_pattern_t pattern;
  282.     cairo_clip_t clip;
  283.  
  284.     x = rect->x;
  285.     y = rect->y;
  286.     width = rect->width;
  287.     height = rect->height;
  288.     image = _cairo_paginated_surface_create_image_surface (surface,
  289.                                                            ceil (width  * x_scale),
  290.                                                            ceil (height * y_scale));
  291.     _cairo_surface_set_device_scale (image, x_scale, y_scale);
  292.     /* set_device_offset just sets the x0/y0 components of the matrix;
  293.      * so we have to do the scaling manually. */
  294.     cairo_surface_set_device_offset (image, -x*x_scale, -y*y_scale);
  295.  
  296.     status = _cairo_recording_surface_replay (surface->recording_surface, image);
  297.     if (unlikely (status))
  298.         goto CLEANUP_IMAGE;
  299.  
  300.     _cairo_pattern_init_for_surface (&pattern, image);
  301.     cairo_matrix_init (&pattern.base.matrix,
  302.                        x_scale, 0, 0, y_scale, -x*x_scale, -y*y_scale);
  303.     /* the fallback should be rendered at native resolution, so disable
  304.      * filtering (if possible) to avoid introducing potential artifacts. */
  305.     pattern.base.filter = CAIRO_FILTER_NEAREST;
  306.  
  307.     _cairo_clip_init (&clip);
  308.     status = _cairo_clip_rectangle (&clip, rect);
  309.     if (likely (status == CAIRO_STATUS_SUCCESS)) {
  310.         status = _cairo_surface_paint (surface->target,
  311.                                        CAIRO_OPERATOR_SOURCE,
  312.                                        &pattern.base, &clip);
  313.     }
  314.  
  315.     _cairo_clip_fini (&clip);
  316.     _cairo_pattern_fini (&pattern.base);
  317.  
  318. CLEANUP_IMAGE:
  319.     cairo_surface_destroy (image);
  320.  
  321.     return status;
  322. }
  323.  
  324. static cairo_int_status_t
  325. _paint_page (cairo_paginated_surface_t *surface)
  326. {
  327.     cairo_surface_t *analysis;
  328.     cairo_status_t status;
  329.     cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback;
  330.  
  331.     if (unlikely (surface->target->status))
  332.         return surface->target->status;
  333.  
  334.     analysis = _cairo_analysis_surface_create (surface->target);
  335.     if (unlikely (analysis->status))
  336.         return _cairo_surface_set_error (surface->target, analysis->status);
  337.  
  338.     surface->backend->set_paginated_mode (surface->target,
  339.                                           CAIRO_PAGINATED_MODE_ANALYZE);
  340.     status = _cairo_recording_surface_replay_and_create_regions (surface->recording_surface,
  341.                                                                  analysis);
  342.     if (status || analysis->status) {
  343.         if (status == CAIRO_STATUS_SUCCESS)
  344.             status = analysis->status;
  345.         goto FAIL;
  346.     }
  347.  
  348.      if (surface->backend->set_bounding_box) {
  349.          cairo_box_t bbox;
  350.  
  351.          _cairo_analysis_surface_get_bounding_box (analysis, &bbox);
  352.          status = surface->backend->set_bounding_box (surface->target, &bbox);
  353.          if (unlikely (status))
  354.              goto FAIL;
  355.      }
  356.  
  357.     if (surface->backend->set_fallback_images_required) {
  358.         cairo_bool_t has_fallbacks = _cairo_analysis_surface_has_unsupported (analysis);
  359.  
  360.         status = surface->backend->set_fallback_images_required (surface->target,
  361.                                                                  has_fallbacks);
  362.         if (unlikely (status))
  363.             goto FAIL;
  364.     }
  365.  
  366.     /* Finer grained fallbacks are currently only supported for some
  367.      * surface types */
  368.     if (surface->backend->supports_fine_grained_fallbacks != NULL &&
  369.         surface->backend->supports_fine_grained_fallbacks (surface->target))
  370.     {
  371.         has_supported = _cairo_analysis_surface_has_supported (analysis);
  372.         has_page_fallback = FALSE;
  373.         has_finegrained_fallback = _cairo_analysis_surface_has_unsupported (analysis);
  374.     }
  375.     else
  376.     {
  377.         if (_cairo_analysis_surface_has_unsupported (analysis)) {
  378.             has_supported = FALSE;
  379.             has_page_fallback = TRUE;
  380.         } else {
  381.             has_supported = TRUE;
  382.             has_page_fallback = FALSE;
  383.         }
  384.         has_finegrained_fallback = FALSE;
  385.     }
  386.  
  387.     if (has_supported) {
  388.         surface->backend->set_paginated_mode (surface->target,
  389.                                               CAIRO_PAGINATED_MODE_RENDER);
  390.  
  391.         status = _cairo_recording_surface_replay_region (surface->recording_surface,
  392.                                                          NULL,
  393.                                                          surface->target,
  394.                                                          CAIRO_RECORDING_REGION_NATIVE);
  395.         assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
  396.         if (unlikely (status))
  397.             goto FAIL;
  398.     }
  399.  
  400.     if (has_page_fallback) {
  401.         cairo_rectangle_int_t extents;
  402.         cairo_bool_t is_bounded;
  403.  
  404.         surface->backend->set_paginated_mode (surface->target,
  405.                                               CAIRO_PAGINATED_MODE_FALLBACK);
  406.  
  407.         is_bounded = _cairo_surface_get_extents (surface->target, &extents);
  408.         if (! is_bounded) {
  409.             status = CAIRO_INT_STATUS_UNSUPPORTED;
  410.             goto FAIL;
  411.         }
  412.  
  413.         status = _paint_fallback_image (surface, &extents);
  414.         if (unlikely (status))
  415.             goto FAIL;
  416.     }
  417.  
  418.     if (has_finegrained_fallback) {
  419.         cairo_region_t *region;
  420.         int num_rects, i;
  421.  
  422.         surface->backend->set_paginated_mode (surface->target,
  423.                                               CAIRO_PAGINATED_MODE_FALLBACK);
  424.  
  425.         region = _cairo_analysis_surface_get_unsupported (analysis);
  426.  
  427.         num_rects = cairo_region_num_rectangles (region);
  428.         for (i = 0; i < num_rects; i++) {
  429.             cairo_rectangle_int_t rect;
  430.  
  431.             cairo_region_get_rectangle (region, i, &rect);
  432.             status = _paint_fallback_image (surface, &rect);
  433.             if (unlikely (status))
  434.                 goto FAIL;
  435.         }
  436.     }
  437.  
  438.   FAIL:
  439.     cairo_surface_destroy (analysis);
  440.  
  441.     return _cairo_surface_set_error (surface->target, status);
  442. }
  443.  
  444. static cairo_status_t
  445. _start_page (cairo_paginated_surface_t *surface)
  446. {
  447.     if (surface->target->status)
  448.         return surface->target->status;
  449.  
  450.     if (! surface->backend->start_page)
  451.         return CAIRO_STATUS_SUCCESS;
  452.  
  453.     return _cairo_surface_set_error (surface->target,
  454.                                 surface->backend->start_page (surface->target));
  455. }
  456.  
  457. static cairo_int_status_t
  458. _cairo_paginated_surface_copy_page (void *abstract_surface)
  459. {
  460.     cairo_status_t status;
  461.     cairo_paginated_surface_t *surface = abstract_surface;
  462.  
  463.     status = _start_page (surface);
  464.     if (unlikely (status))
  465.         return status;
  466.  
  467.     status = _paint_page (surface);
  468.     if (unlikely (status))
  469.         return status;
  470.  
  471.     surface->page_num++;
  472.  
  473.     /* XXX: It might make sense to add some support here for calling
  474.      * cairo_surface_copy_page on the target surface. It would be an
  475.      * optimization for the output, but the interaction with image
  476.      * fallbacks gets tricky. For now, we just let the target see a
  477.      * show_page and we implement the copying by simply not destroying
  478.      * the recording-surface. */
  479.  
  480.     cairo_surface_show_page (surface->target);
  481.     return cairo_surface_status (surface->target);
  482. }
  483.  
  484. static cairo_int_status_t
  485. _cairo_paginated_surface_show_page (void *abstract_surface)
  486. {
  487.     cairo_status_t status;
  488.     cairo_paginated_surface_t *surface = abstract_surface;
  489.  
  490.     status = _start_page (surface);
  491.     if (unlikely (status))
  492.         return status;
  493.  
  494.     status = _paint_page (surface);
  495.     if (unlikely (status))
  496.         return status;
  497.  
  498.     cairo_surface_show_page (surface->target);
  499.     status = surface->target->status;
  500.     if (unlikely (status))
  501.         return status;
  502.  
  503.     status = surface->recording_surface->status;
  504.     if (unlikely (status))
  505.         return status;
  506.  
  507.     if (! surface->base.finished) {
  508.         cairo_surface_destroy (surface->recording_surface);
  509.  
  510.         surface->recording_surface = _create_recording_surface_for_target (surface->target,
  511.                                                                            surface->content);
  512.         status = surface->recording_surface->status;
  513.         if (unlikely (status))
  514.             return status;
  515.  
  516.         surface->page_num++;
  517.         surface->base.is_clear = TRUE;
  518.     }
  519.  
  520.     return CAIRO_STATUS_SUCCESS;
  521. }
  522.  
  523. static cairo_bool_t
  524. _cairo_paginated_surface_get_extents (void                    *abstract_surface,
  525.                                       cairo_rectangle_int_t   *rectangle)
  526. {
  527.     cairo_paginated_surface_t *surface = abstract_surface;
  528.  
  529.     return _cairo_surface_get_extents (surface->target, rectangle);
  530. }
  531.  
  532. static void
  533. _cairo_paginated_surface_get_font_options (void                  *abstract_surface,
  534.                                            cairo_font_options_t  *options)
  535. {
  536.     cairo_paginated_surface_t *surface = abstract_surface;
  537.  
  538.     cairo_surface_get_font_options (surface->target, options);
  539. }
  540.  
  541. static cairo_int_status_t
  542. _cairo_paginated_surface_paint (void                    *abstract_surface,
  543.                                 cairo_operator_t         op,
  544.                                 const cairo_pattern_t   *source,
  545.                                 cairo_clip_t            *clip)
  546. {
  547.     cairo_paginated_surface_t *surface = abstract_surface;
  548.  
  549.     return _cairo_surface_paint (surface->recording_surface, op, source, clip);
  550. }
  551.  
  552. static cairo_int_status_t
  553. _cairo_paginated_surface_mask (void             *abstract_surface,
  554.                                cairo_operator_t  op,
  555.                                const cairo_pattern_t    *source,
  556.                                const cairo_pattern_t    *mask,
  557.                                cairo_clip_t             *clip)
  558. {
  559.     cairo_paginated_surface_t *surface = abstract_surface;
  560.  
  561.     return _cairo_surface_mask (surface->recording_surface, op, source, mask, clip);
  562. }
  563.  
  564. static cairo_int_status_t
  565. _cairo_paginated_surface_stroke (void                   *abstract_surface,
  566.                                  cairo_operator_t        op,
  567.                                  const cairo_pattern_t  *source,
  568.                                  cairo_path_fixed_t     *path,
  569.                                  const cairo_stroke_style_t     *style,
  570.                                  const cairo_matrix_t           *ctm,
  571.                                  const cairo_matrix_t           *ctm_inverse,
  572.                                  double                  tolerance,
  573.                                  cairo_antialias_t       antialias,
  574.                                  cairo_clip_t           *clip)
  575. {
  576.     cairo_paginated_surface_t *surface = abstract_surface;
  577.  
  578.     return _cairo_surface_stroke (surface->recording_surface, op, source,
  579.                                   path, style,
  580.                                   ctm, ctm_inverse,
  581.                                   tolerance, antialias,
  582.                                   clip);
  583. }
  584.  
  585. static cairo_int_status_t
  586. _cairo_paginated_surface_fill (void                     *abstract_surface,
  587.                                cairo_operator_t          op,
  588.                                const cairo_pattern_t    *source,
  589.                                cairo_path_fixed_t       *path,
  590.                                cairo_fill_rule_t         fill_rule,
  591.                                double                    tolerance,
  592.                                cairo_antialias_t         antialias,
  593.                                cairo_clip_t             *clip)
  594. {
  595.     cairo_paginated_surface_t *surface = abstract_surface;
  596.  
  597.     return _cairo_surface_fill (surface->recording_surface, op, source,
  598.                                 path, fill_rule,
  599.                                 tolerance, antialias,
  600.                                 clip);
  601. }
  602.  
  603. static cairo_bool_t
  604. _cairo_paginated_surface_has_show_text_glyphs (void *abstract_surface)
  605. {
  606.     cairo_paginated_surface_t *surface = abstract_surface;
  607.  
  608.     return cairo_surface_has_show_text_glyphs (surface->target);
  609. }
  610.  
  611. static cairo_int_status_t
  612. _cairo_paginated_surface_show_text_glyphs (void                       *abstract_surface,
  613.                                            cairo_operator_t            op,
  614.                                            const cairo_pattern_t      *source,
  615.                                            const char                 *utf8,
  616.                                            int                         utf8_len,
  617.                                            cairo_glyph_t              *glyphs,
  618.                                            int                         num_glyphs,
  619.                                            const cairo_text_cluster_t *clusters,
  620.                                            int                         num_clusters,
  621.                                            cairo_text_cluster_flags_t  cluster_flags,
  622.                                            cairo_scaled_font_t        *scaled_font,
  623.                                            cairo_clip_t               *clip)
  624. {
  625.     cairo_paginated_surface_t *surface = abstract_surface;
  626.  
  627.     return _cairo_surface_show_text_glyphs (surface->recording_surface, op, source,
  628.                                             utf8, utf8_len,
  629.                                             glyphs, num_glyphs,
  630.                                             clusters, num_clusters,
  631.                                             cluster_flags,
  632.                                             scaled_font,
  633.                                             clip);
  634. }
  635.  
  636. static cairo_surface_t *
  637. _cairo_paginated_surface_snapshot (void *abstract_other)
  638. {
  639.     cairo_paginated_surface_t *other = abstract_other;
  640.  
  641.     return _cairo_surface_snapshot (other->recording_surface);
  642. }
  643.  
  644. static const cairo_surface_backend_t cairo_paginated_surface_backend = {
  645.     CAIRO_INTERNAL_SURFACE_TYPE_PAGINATED,
  646.     _cairo_paginated_surface_create_similar,
  647.     _cairo_paginated_surface_finish,
  648.     _cairo_paginated_surface_acquire_source_image,
  649.     _cairo_paginated_surface_release_source_image,
  650.     NULL, /* acquire_dest_image */
  651.     NULL, /* release_dest_image */
  652.     NULL, /* clone_similar */
  653.     NULL, /* composite */
  654.     NULL, /* fill_rectangles */
  655.     NULL, /* composite_trapezoids */
  656.     NULL, /* create_span_renderer */
  657.     NULL, /* check_span_renderer */
  658.     _cairo_paginated_surface_copy_page,
  659.     _cairo_paginated_surface_show_page,
  660.     _cairo_paginated_surface_get_extents,
  661.     NULL, /* old_show_glyphs */
  662.     _cairo_paginated_surface_get_font_options,
  663.     NULL, /* flush */
  664.     NULL, /* mark_dirty_rectangle */
  665.     NULL, /* scaled_font_fini */
  666.     NULL, /* scaled_glyph_fini */
  667.     _cairo_paginated_surface_paint,
  668.     _cairo_paginated_surface_mask,
  669.     _cairo_paginated_surface_stroke,
  670.     _cairo_paginated_surface_fill,
  671.     NULL, /* show_glyphs */
  672.     _cairo_paginated_surface_snapshot,
  673.     NULL, /* is_similar */
  674.     NULL, /* fill_stroke */
  675.     NULL, /* create_solid_pattern_surface */
  676.     NULL, /* can_repaint_solid_pattern_surface */
  677.     _cairo_paginated_surface_has_show_text_glyphs,
  678.     _cairo_paginated_surface_show_text_glyphs
  679. };
  680.