Subversion Repositories Kolibri OS

Rev

Go to most recent revision | 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.  * Copyright © 2009 Chris Wilson
  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.  *      Chris Wilson <chris@chris-wilson.co.uk>
  36.  */
  37.  
  38. #include "cairoint.h"
  39.  
  40. #include "cairo-error-private.h"
  41. #include "cairo-surface-wrapper-private.h"
  42.  
  43. /* A collection of routines to facilitate surface wrapping */
  44.  
  45. static void
  46. _copy_transformed_pattern (cairo_pattern_t *pattern,
  47.                            const cairo_pattern_t *original,
  48.                            const cairo_matrix_t  *ctm_inverse)
  49. {
  50.     _cairo_pattern_init_static_copy (pattern, original);
  51.  
  52.     /* apply device_transform first so that it is transformed by ctm_inverse */
  53.     if (original->type == CAIRO_PATTERN_TYPE_SURFACE) {
  54.         cairo_surface_pattern_t *surface_pattern;
  55.         cairo_surface_t *surface;
  56.  
  57.         surface_pattern = (cairo_surface_pattern_t *) original;
  58.         surface = surface_pattern->surface;
  59.  
  60.         if (_cairo_surface_has_device_transform (surface))
  61.             _cairo_pattern_transform (pattern, &surface->device_transform);
  62.     }
  63.  
  64.     if (! _cairo_matrix_is_identity (ctm_inverse))
  65.         _cairo_pattern_transform (pattern, ctm_inverse);
  66. }
  67.  
  68. static inline cairo_bool_t
  69. _cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t *wrapper)
  70. {
  71.     return ! _cairo_matrix_is_identity (&wrapper->target->device_transform);
  72. }
  73.  
  74. static cairo_bool_t
  75. _cairo_surface_wrapper_needs_extents_transform (cairo_surface_wrapper_t *wrapper)
  76. {
  77.     return wrapper->has_extents && (wrapper->extents.x | wrapper->extents.y);
  78. }
  79.  
  80. cairo_status_t
  81. _cairo_surface_wrapper_acquire_source_image (cairo_surface_wrapper_t *wrapper,
  82.                                              cairo_image_surface_t  **image_out,
  83.                                              void                   **image_extra)
  84. {
  85.     if (unlikely (wrapper->target->status))
  86.         return wrapper->target->status;
  87.  
  88.     return _cairo_surface_acquire_source_image (wrapper->target,
  89.                                                 image_out, image_extra);
  90. }
  91.  
  92. void
  93. _cairo_surface_wrapper_release_source_image (cairo_surface_wrapper_t *wrapper,
  94.                                              cairo_image_surface_t  *image,
  95.                                              void                   *image_extra)
  96. {
  97.     _cairo_surface_release_source_image (wrapper->target, image, image_extra);
  98. }
  99.  
  100. cairo_status_t
  101. _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
  102.                               cairo_operator_t   op,
  103.                               const cairo_pattern_t *source,
  104.                               cairo_clip_t          *clip)
  105. {
  106.     cairo_status_t status;
  107.     cairo_clip_t clip_copy, *dev_clip = clip;
  108.     cairo_pattern_union_t source_copy;
  109.     cairo_clip_t target_clip;
  110.  
  111.     if (unlikely (wrapper->target->status))
  112.         return wrapper->target->status;
  113.  
  114.     if (wrapper->has_extents) {
  115.         _cairo_clip_init_copy (&target_clip, clip);
  116.         status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
  117.         if (unlikely (status))
  118.             goto FINISH;
  119.  
  120.         dev_clip = clip = &target_clip;
  121.     }
  122.  
  123.     if (clip && clip->all_clipped) {
  124.         status = CAIRO_STATUS_SUCCESS;
  125.         goto FINISH;
  126.     }
  127.  
  128.     if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
  129.         _cairo_surface_wrapper_needs_extents_transform (wrapper))
  130.     {
  131.         cairo_matrix_t m;
  132.  
  133.         cairo_matrix_init_identity (&m);
  134.  
  135.         if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
  136.             cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
  137.  
  138.         if (_cairo_surface_wrapper_needs_device_transform (wrapper))
  139.             cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
  140.  
  141.         if (clip != NULL) {
  142.             status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
  143.             if (unlikely (status))
  144.                 goto FINISH;
  145.  
  146.             dev_clip = &clip_copy;
  147.         }
  148.  
  149.         status = cairo_matrix_invert (&m);
  150.         assert (status == CAIRO_STATUS_SUCCESS);
  151.  
  152.         _copy_transformed_pattern (&source_copy.base, source, &m);
  153.         source = &source_copy.base;
  154.     }
  155.  
  156.     status = _cairo_surface_paint (wrapper->target, op, source, dev_clip);
  157.  
  158.   FINISH:
  159.     if (wrapper->has_extents)
  160.         _cairo_clip_reset (&target_clip);
  161.     if (dev_clip != clip)
  162.         _cairo_clip_reset (dev_clip);
  163.     return status;
  164. }
  165.  
  166. cairo_status_t
  167. _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
  168.                              cairo_operator_t    op,
  169.                              const cairo_pattern_t *source,
  170.                              const cairo_pattern_t *mask,
  171.                              cairo_clip_t           *clip)
  172. {
  173.     cairo_status_t status;
  174.     cairo_clip_t clip_copy, *dev_clip = clip;
  175.     cairo_pattern_union_t source_copy;
  176.     cairo_pattern_union_t mask_copy;
  177.     cairo_clip_t target_clip;
  178.  
  179.     if (unlikely (wrapper->target->status))
  180.         return wrapper->target->status;
  181.  
  182.     if (wrapper->has_extents) {
  183.         _cairo_clip_init_copy (&target_clip, clip);
  184.         status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
  185.         if (unlikely (status))
  186.             goto FINISH;
  187.  
  188.         dev_clip = clip = &target_clip;
  189.     }
  190.  
  191.     if (clip && clip->all_clipped) {
  192.         status = CAIRO_STATUS_SUCCESS;
  193.         goto FINISH;
  194.     }
  195.  
  196.     if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
  197.         _cairo_surface_wrapper_needs_extents_transform (wrapper))
  198.     {
  199.         cairo_matrix_t m;
  200.  
  201.         cairo_matrix_init_identity (&m);
  202.  
  203.         if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
  204.             cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
  205.  
  206.         if (_cairo_surface_wrapper_needs_device_transform (wrapper))
  207.             cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
  208.  
  209.         if (clip != NULL) {
  210.             status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
  211.             if (unlikely (status))
  212.                 goto FINISH;
  213.  
  214.             dev_clip = &clip_copy;
  215.         }
  216.  
  217.         status = cairo_matrix_invert (&m);
  218.         assert (status == CAIRO_STATUS_SUCCESS);
  219.  
  220.         _copy_transformed_pattern (&source_copy.base, source, &m);
  221.         source = &source_copy.base;
  222.  
  223.         _copy_transformed_pattern (&mask_copy.base, mask, &m);
  224.         mask = &mask_copy.base;
  225.     }
  226.  
  227.     status = _cairo_surface_mask (wrapper->target, op, source, mask, dev_clip);
  228.  
  229.   FINISH:
  230.     if (wrapper->has_extents)
  231.         _cairo_clip_reset (&target_clip);
  232.     if (dev_clip != clip)
  233.         _cairo_clip_reset (dev_clip);
  234.     return status;
  235. }
  236.  
  237. cairo_status_t
  238. _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
  239.                                cairo_operator_t          op,
  240.                                const cairo_pattern_t    *source,
  241.                                cairo_path_fixed_t       *path,
  242.                                const cairo_stroke_style_t       *stroke_style,
  243.                                const cairo_matrix_t             *ctm,
  244.                                const cairo_matrix_t             *ctm_inverse,
  245.                                double                    tolerance,
  246.                                cairo_antialias_t         antialias,
  247.                                cairo_clip_t             *clip)
  248. {
  249.     cairo_status_t status;
  250.     cairo_path_fixed_t path_copy, *dev_path = path;
  251.     cairo_clip_t clip_copy, *dev_clip = clip;
  252.     cairo_matrix_t dev_ctm = *ctm;
  253.     cairo_matrix_t dev_ctm_inverse = *ctm_inverse;
  254.     cairo_pattern_union_t source_copy;
  255.     cairo_clip_t target_clip;
  256.  
  257.     if (unlikely (wrapper->target->status))
  258.         return wrapper->target->status;
  259.  
  260.     if (wrapper->has_extents) {
  261.         _cairo_clip_init_copy (&target_clip, clip);
  262.         status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
  263.         if (unlikely (status))
  264.             goto FINISH;
  265.  
  266.         dev_clip = clip = &target_clip;
  267.     }
  268.  
  269.     if (clip && clip->all_clipped) {
  270.         status = CAIRO_STATUS_SUCCESS;
  271.         goto FINISH;
  272.     }
  273.  
  274.     if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
  275.         _cairo_surface_wrapper_needs_extents_transform (wrapper))
  276.     {
  277.         cairo_matrix_t m;
  278.  
  279.         cairo_matrix_init_identity (&m);
  280.  
  281.         if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
  282.             cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
  283.  
  284.         if (_cairo_surface_wrapper_needs_device_transform (wrapper))
  285.             cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
  286.  
  287.         status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
  288.         if (unlikely (status))
  289.             goto FINISH;
  290.  
  291.         _cairo_path_fixed_transform (&path_copy, &m);
  292.         dev_path = &path_copy;
  293.  
  294.         if (clip != NULL) {
  295.             status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
  296.             if (unlikely (status))
  297.                 goto FINISH;
  298.  
  299.             dev_clip = &clip_copy;
  300.         }
  301.  
  302.         cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
  303.  
  304.         status = cairo_matrix_invert (&m);
  305.         assert (status == CAIRO_STATUS_SUCCESS);
  306.  
  307.         cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
  308.  
  309.         _copy_transformed_pattern (&source_copy.base, source, &m);
  310.         source = &source_copy.base;
  311.     }
  312.     else
  313.     {
  314.         if (clip != NULL) {
  315.             dev_clip = &clip_copy;
  316.             _cairo_clip_init_copy (&clip_copy, clip);
  317.         }
  318.     }
  319.  
  320.     status = _cairo_surface_stroke (wrapper->target, op, source,
  321.                                     dev_path, stroke_style,
  322.                                     &dev_ctm, &dev_ctm_inverse,
  323.                                     tolerance, antialias,
  324.                                     dev_clip);
  325.  
  326.  FINISH:
  327.     if (dev_path != path)
  328.         _cairo_path_fixed_fini (dev_path);
  329.     if (wrapper->has_extents)
  330.         _cairo_clip_reset (&target_clip);
  331.     if (dev_clip != clip)
  332.         _cairo_clip_reset (dev_clip);
  333.     return status;
  334. }
  335.  
  336. cairo_status_t
  337. _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
  338.                                     cairo_operator_t         fill_op,
  339.                                     const cairo_pattern_t   *fill_source,
  340.                                     cairo_fill_rule_t        fill_rule,
  341.                                     double                   fill_tolerance,
  342.                                     cairo_antialias_t        fill_antialias,
  343.                                     cairo_path_fixed_t      *path,
  344.                                     cairo_operator_t         stroke_op,
  345.                                     const cairo_pattern_t   *stroke_source,
  346.                                     const cairo_stroke_style_t    *stroke_style,
  347.                                     const cairo_matrix_t            *stroke_ctm,
  348.                                     const cairo_matrix_t            *stroke_ctm_inverse,
  349.                                     double                   stroke_tolerance,
  350.                                     cairo_antialias_t        stroke_antialias,
  351.                                     cairo_clip_t            *clip)
  352. {
  353.     cairo_status_t status;
  354.     cairo_path_fixed_t path_copy, *dev_path = path;
  355.     cairo_clip_t clip_copy, *dev_clip = clip;
  356.     cairo_matrix_t dev_ctm = *stroke_ctm;
  357.     cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse;
  358.     cairo_pattern_union_t stroke_source_copy;
  359.     cairo_pattern_union_t fill_source_copy;
  360.     cairo_clip_t target_clip;
  361.  
  362.     if (unlikely (wrapper->target->status))
  363.         return wrapper->target->status;
  364.  
  365.     if (wrapper->has_extents) {
  366.         _cairo_clip_init_copy (&target_clip, clip);
  367.         status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
  368.         if (unlikely (status))
  369.             goto FINISH;
  370.  
  371.         dev_clip = clip = &target_clip;
  372.     }
  373.  
  374.     if (clip && clip->all_clipped) {
  375.         status = CAIRO_STATUS_SUCCESS;
  376.         goto FINISH;
  377.     }
  378.  
  379.     if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
  380.         _cairo_surface_wrapper_needs_extents_transform (wrapper))
  381.     {
  382.         cairo_matrix_t m;
  383.  
  384.         cairo_matrix_init_identity (&m);
  385.  
  386.         if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
  387.             cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
  388.  
  389.         if (_cairo_surface_wrapper_needs_device_transform (wrapper))
  390.             cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
  391.  
  392.         status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
  393.         if (unlikely (status))
  394.             goto FINISH;
  395.  
  396.         _cairo_path_fixed_transform (&path_copy, &m);
  397.         dev_path = &path_copy;
  398.  
  399.         if (clip != NULL) {
  400.             status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
  401.             if (unlikely (status))
  402.                 goto FINISH;
  403.  
  404.             dev_clip = &clip_copy;
  405.         }
  406.  
  407.         cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
  408.  
  409.         status = cairo_matrix_invert (&m);
  410.         assert (status == CAIRO_STATUS_SUCCESS);
  411.  
  412.         cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
  413.  
  414.         _copy_transformed_pattern (&stroke_source_copy.base, stroke_source, &m);
  415.         stroke_source = &stroke_source_copy.base;
  416.  
  417.         _copy_transformed_pattern (&fill_source_copy.base, fill_source, &m);
  418.         fill_source = &fill_source_copy.base;
  419.     }
  420.     else
  421.     {
  422.         if (clip != NULL) {
  423.             dev_clip = &clip_copy;
  424.             _cairo_clip_init_copy (&clip_copy, clip);
  425.         }
  426.     }
  427.  
  428.     status = _cairo_surface_fill_stroke (wrapper->target,
  429.                                          fill_op, fill_source, fill_rule,
  430.                                          fill_tolerance, fill_antialias,
  431.                                          dev_path,
  432.                                          stroke_op, stroke_source,
  433.                                          stroke_style,
  434.                                          &dev_ctm, &dev_ctm_inverse,
  435.                                          stroke_tolerance, stroke_antialias,
  436.                                          dev_clip);
  437.  
  438.   FINISH:
  439.     if (dev_path != path)
  440.         _cairo_path_fixed_fini (dev_path);
  441.     if (wrapper->has_extents)
  442.         _cairo_clip_reset (&target_clip);
  443.     if (dev_clip != clip)
  444.         _cairo_clip_reset (dev_clip);
  445.     return status;
  446. }
  447.  
  448. cairo_status_t
  449. _cairo_surface_wrapper_fill (cairo_surface_wrapper_t    *wrapper,
  450.                              cairo_operator_t    op,
  451.                              const cairo_pattern_t *source,
  452.                              cairo_path_fixed_t *path,
  453.                              cairo_fill_rule_t   fill_rule,
  454.                              double              tolerance,
  455.                              cairo_antialias_t   antialias,
  456.                              cairo_clip_t       *clip)
  457. {
  458.     cairo_status_t status;
  459.     cairo_path_fixed_t path_copy, *dev_path = path;
  460.     cairo_clip_t clip_copy, *dev_clip = clip;
  461.     cairo_pattern_union_t source_copy;
  462.     cairo_clip_t target_clip;
  463.  
  464.     if (unlikely (wrapper->target->status))
  465.         return wrapper->target->status;
  466.  
  467.     if (wrapper->has_extents) {
  468.         _cairo_clip_init_copy (&target_clip, clip);
  469.         status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
  470.         if (unlikely (status))
  471.             goto FINISH;
  472.  
  473.         dev_clip = clip = &target_clip;
  474.     }
  475.  
  476.     if (clip && clip->all_clipped) {
  477.         status = CAIRO_STATUS_SUCCESS;
  478.         goto FINISH;
  479.     }
  480.  
  481.     if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
  482.         _cairo_surface_wrapper_needs_extents_transform (wrapper))
  483.     {
  484.         cairo_matrix_t m;
  485.  
  486.         cairo_matrix_init_identity (&m);
  487.  
  488.         if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
  489.             cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
  490.  
  491.         if (_cairo_surface_wrapper_needs_device_transform (wrapper))
  492.             cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
  493.  
  494.         status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
  495.         if (unlikely (status))
  496.             goto FINISH;
  497.  
  498.         _cairo_path_fixed_transform (&path_copy, &m);
  499.         dev_path = &path_copy;
  500.  
  501.         if (clip != NULL) {
  502.             status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
  503.             if (unlikely (status))
  504.                 goto FINISH;
  505.  
  506.             dev_clip = &clip_copy;
  507.         }
  508.  
  509.         status = cairo_matrix_invert (&m);
  510.         assert (status == CAIRO_STATUS_SUCCESS);
  511.  
  512.         _copy_transformed_pattern (&source_copy.base, source, &m);
  513.         source = &source_copy.base;
  514.     }
  515.     else
  516.     {
  517.         if (clip != NULL) {
  518.             dev_clip = &clip_copy;
  519.             _cairo_clip_init_copy (&clip_copy, clip);
  520.         }
  521.     }
  522.  
  523.     status = _cairo_surface_fill (wrapper->target, op, source,
  524.                                   dev_path, fill_rule,
  525.                                   tolerance, antialias,
  526.                                   dev_clip);
  527.  
  528.  FINISH:
  529.     if (dev_path != path)
  530.         _cairo_path_fixed_fini (dev_path);
  531.     if (wrapper->has_extents)
  532.         _cairo_clip_reset (&target_clip);
  533.     if (dev_clip != clip)
  534.         _cairo_clip_reset (dev_clip);
  535.     return status;
  536. }
  537.  
  538. cairo_status_t
  539. _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
  540.                                          cairo_operator_t            op,
  541.                                          const cairo_pattern_t      *source,
  542.                                          const char                 *utf8,
  543.                                          int                         utf8_len,
  544.                                          cairo_glyph_t              *glyphs,
  545.                                          int                         num_glyphs,
  546.                                          const cairo_text_cluster_t *clusters,
  547.                                          int                         num_clusters,
  548.                                          cairo_text_cluster_flags_t  cluster_flags,
  549.                                          cairo_scaled_font_t        *scaled_font,
  550.                                          cairo_clip_t               *clip)
  551. {
  552.     cairo_status_t status;
  553.     cairo_clip_t clip_copy, *dev_clip = clip;
  554.     cairo_glyph_t *dev_glyphs = glyphs;
  555.     cairo_pattern_union_t source_copy;
  556.     cairo_clip_t target_clip;
  557.  
  558.     if (unlikely (wrapper->target->status))
  559.         return wrapper->target->status;
  560.  
  561.     if (glyphs == NULL || num_glyphs == 0)
  562.         return CAIRO_STATUS_SUCCESS;
  563.  
  564.     if (wrapper->has_extents) {
  565.         _cairo_clip_init_copy (&target_clip, clip);
  566.         status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
  567.         if (unlikely (status))
  568.             goto FINISH;
  569.  
  570.         dev_clip = clip = &target_clip;
  571.     }
  572.  
  573.     if (clip && clip->all_clipped) {
  574.         status = CAIRO_STATUS_SUCCESS;
  575.         goto FINISH;
  576.     }
  577.  
  578.     if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
  579.         _cairo_surface_wrapper_needs_extents_transform (wrapper))
  580.     {
  581.         cairo_matrix_t m;
  582.         int i;
  583.  
  584.         cairo_matrix_init_identity (&m);
  585.  
  586.         if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
  587.             cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
  588.  
  589.         if (_cairo_surface_wrapper_needs_device_transform (wrapper))
  590.             cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
  591.  
  592.         if (clip != NULL) {
  593.             status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
  594.             if (unlikely (status))
  595.                 goto FINISH;
  596.  
  597.             dev_clip = &clip_copy;
  598.         }
  599.  
  600.         dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
  601.         if (dev_glyphs == NULL) {
  602.             status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
  603.             goto FINISH;
  604.         }
  605.  
  606.         for (i = 0; i < num_glyphs; i++) {
  607.             dev_glyphs[i] = glyphs[i];
  608.             cairo_matrix_transform_point (&m, &dev_glyphs[i].x, &dev_glyphs[i].y);
  609.         }
  610.  
  611.         status = cairo_matrix_invert (&m);
  612.         assert (status == CAIRO_STATUS_SUCCESS);
  613.  
  614.         _copy_transformed_pattern (&source_copy.base, source, &m);
  615.         source = &source_copy.base;
  616.     }
  617.     else
  618.     {
  619.         if (clip != NULL) {
  620.             dev_clip = &clip_copy;
  621.             _cairo_clip_init_copy (&clip_copy, clip);
  622.         }
  623.     }
  624.  
  625.     status = _cairo_surface_show_text_glyphs (wrapper->target, op, source,
  626.                                               utf8, utf8_len,
  627.                                               dev_glyphs, num_glyphs,
  628.                                               clusters, num_clusters,
  629.                                               cluster_flags,
  630.                                               scaled_font,
  631.                                               dev_clip);
  632.  
  633.  FINISH:
  634.     if (dev_clip != clip)
  635.         _cairo_clip_reset (dev_clip);
  636.     if (wrapper->has_extents)
  637.         _cairo_clip_reset (&target_clip);
  638.     if (dev_glyphs != glyphs)
  639.         free (dev_glyphs);
  640.     return status;
  641. }
  642.  
  643. cairo_surface_t *
  644. _cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper,
  645.                                        cairo_content_t  content,
  646.                                        int              width,
  647.                                        int              height)
  648. {
  649.     return _cairo_surface_create_similar_scratch (wrapper->target,
  650.                                                   content, width, height);
  651. }
  652.  
  653. cairo_bool_t
  654. _cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t *wrapper,
  655.                                     cairo_rectangle_int_t   *extents)
  656. {
  657.     if (wrapper->has_extents) {
  658.         if (_cairo_surface_get_extents (wrapper->target, extents))
  659.             _cairo_rectangle_intersect (extents, &wrapper->extents);
  660.         else
  661.             *extents = wrapper->extents;
  662.  
  663.         return TRUE;
  664.     } else {
  665.         return _cairo_surface_get_extents (wrapper->target, extents);
  666.     }
  667. }
  668.  
  669. void
  670. _cairo_surface_wrapper_set_extents (cairo_surface_wrapper_t *wrapper,
  671.                                     const cairo_rectangle_int_t *extents)
  672. {
  673.     if (extents != NULL) {
  674.         wrapper->extents = *extents;
  675.         wrapper->has_extents = TRUE;
  676.     } else {
  677.         wrapper->has_extents = FALSE;
  678.     }
  679. }
  680.  
  681. void
  682. _cairo_surface_wrapper_get_font_options (cairo_surface_wrapper_t    *wrapper,
  683.                                          cairo_font_options_t       *options)
  684. {
  685.     cairo_surface_get_font_options (wrapper->target, options);
  686. }
  687.  
  688. cairo_surface_t *
  689. _cairo_surface_wrapper_snapshot (cairo_surface_wrapper_t *wrapper)
  690. {
  691.     return _cairo_surface_snapshot (wrapper->target);
  692. }
  693.  
  694. cairo_bool_t
  695. _cairo_surface_wrapper_has_show_text_glyphs (cairo_surface_wrapper_t *wrapper)
  696. {
  697.     return cairo_surface_has_show_text_glyphs (wrapper->target);
  698. }
  699.  
  700. void
  701. _cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
  702.                              cairo_surface_t *target)
  703. {
  704.     wrapper->target = cairo_surface_reference (target);
  705.     wrapper->has_extents = FALSE;
  706. }
  707.  
  708. void
  709. _cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper)
  710. {
  711.     cairo_surface_destroy (wrapper->target);
  712. }
  713.