Subversion Repositories Kolibri OS

Rev

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