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 © 2009 Intel Corporation
  4.  *
  5.  * This library is free software; you can redistribute it and/or
  6.  * modify it either under the terms of the GNU Lesser General Public
  7.  * License version 2.1 as published by the Free Software Foundation
  8.  * (the "LGPL") or, at your option, under the terms of the Mozilla
  9.  * Public License Version 1.1 (the "MPL"). If you do not alter this
  10.  * notice, a recipient may use your version of this file under either
  11.  * the MPL or the LGPL.
  12.  *
  13.  * You should have received a copy of the LGPL along with this library
  14.  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
  15.  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
  16.  * You should have received a copy of the MPL along with this library
  17.  * in the file COPYING-MPL-1.1
  18.  *
  19.  * The contents of this file are subject to the Mozilla Public License
  20.  * Version 1.1 (the "License"); you may not use this file except in
  21.  * compliance with the License. You may obtain a copy of the License at
  22.  * http://www.mozilla.org/MPL/
  23.  *
  24.  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
  25.  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
  26.  * the specific language governing rights and limitations.
  27.  *
  28.  * The Original Code is the cairo graphics library.
  29.  *
  30.  * The Initial Developer of the Original Code is Intel Corporation.
  31.  *
  32.  * Contributor(s):
  33.  *      Chris Wilson <chris@chris-wilson.co.uk>
  34.  */
  35.  
  36. #include "cairoint.h"
  37.  
  38. #include "cairo-error-private.h"
  39. #include "cairo-recording-surface-private.h"
  40. #include "cairo-surface-offset-private.h"
  41. #include "cairo-surface-subsurface-private.h"
  42.  
  43. static const cairo_surface_backend_t _cairo_surface_subsurface_backend;
  44.  
  45. static cairo_status_t
  46. _cairo_surface_subsurface_finish (void *abstract_surface)
  47. {
  48.     cairo_surface_subsurface_t *surface = abstract_surface;
  49.  
  50.     cairo_surface_destroy (surface->target);
  51.  
  52.     return CAIRO_STATUS_SUCCESS;
  53. }
  54.  
  55. static cairo_surface_t *
  56. _cairo_surface_subsurface_create_similar (void *other,
  57.                                           cairo_content_t content,
  58.                                           int width, int height)
  59. {
  60.     cairo_surface_subsurface_t *surface = other;
  61.     return surface->target->backend->create_similar (surface->target, content, width, height);
  62. }
  63.  
  64. static cairo_int_status_t
  65. _cairo_surface_subsurface_paint (void *abstract_surface,
  66.                                  cairo_operator_t op,
  67.                                  const cairo_pattern_t *source,
  68.                                  cairo_clip_t *clip)
  69. {
  70.     cairo_surface_subsurface_t *surface = abstract_surface;
  71.     cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
  72.     cairo_status_t status;
  73.     cairo_clip_t target_clip;
  74.  
  75.     _cairo_clip_init_copy (&target_clip, clip);
  76.     status = _cairo_clip_rectangle (&target_clip, &rect);
  77.     if (unlikely (status))
  78.         goto CLEANUP;
  79.  
  80.     status = _cairo_surface_offset_paint (surface->target,
  81.                                          -surface->extents.x, -surface->extents.y,
  82.                                           op, source, &target_clip);
  83.   CLEANUP:
  84.     _cairo_clip_fini (&target_clip);
  85.     return status;
  86. }
  87.  
  88. static cairo_int_status_t
  89. _cairo_surface_subsurface_mask (void *abstract_surface,
  90.                                 cairo_operator_t op,
  91.                                 const cairo_pattern_t *source,
  92.                                 const cairo_pattern_t *mask,
  93.                                 cairo_clip_t *clip)
  94. {
  95.     cairo_surface_subsurface_t *surface = abstract_surface;
  96.     cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
  97.     cairo_status_t status;
  98.     cairo_clip_t target_clip;
  99.  
  100.     _cairo_clip_init_copy (&target_clip, clip);
  101.     status = _cairo_clip_rectangle (&target_clip, &rect);
  102.     if (unlikely (status))
  103.         goto CLEANUP;
  104.  
  105.     status = _cairo_surface_offset_mask (surface->target,
  106.                                          -surface->extents.x, -surface->extents.y,
  107.                                          op, source, mask, &target_clip);
  108.   CLEANUP:
  109.     _cairo_clip_fini (&target_clip);
  110.     return status;
  111. }
  112.  
  113. static cairo_int_status_t
  114. _cairo_surface_subsurface_fill (void                    *abstract_surface,
  115.                                 cairo_operator_t         op,
  116.                                 const cairo_pattern_t   *source,
  117.                                 cairo_path_fixed_t      *path,
  118.                                 cairo_fill_rule_t        fill_rule,
  119.                                 double                   tolerance,
  120.                                 cairo_antialias_t        antialias,
  121.                                 cairo_clip_t            *clip)
  122. {
  123.     cairo_surface_subsurface_t *surface = abstract_surface;
  124.     cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
  125.     cairo_status_t status;
  126.     cairo_clip_t target_clip;
  127.  
  128.     _cairo_clip_init_copy (&target_clip, clip);
  129.     status = _cairo_clip_rectangle (&target_clip, &rect);
  130.     if (unlikely (status))
  131.         goto CLEANUP;
  132.  
  133.     status = _cairo_surface_offset_fill (surface->target,
  134.                                          -surface->extents.x, -surface->extents.y,
  135.                                          op, source, path, fill_rule, tolerance, antialias,
  136.                                          &target_clip);
  137.   CLEANUP:
  138.     _cairo_clip_fini (&target_clip);
  139.     return status;
  140. }
  141.  
  142. static cairo_int_status_t
  143. _cairo_surface_subsurface_stroke (void                          *abstract_surface,
  144.                                   cairo_operator_t               op,
  145.                                   const cairo_pattern_t         *source,
  146.                                   cairo_path_fixed_t            *path,
  147.                                   const cairo_stroke_style_t    *stroke_style,
  148.                                   const cairo_matrix_t          *ctm,
  149.                                   const cairo_matrix_t          *ctm_inverse,
  150.                                   double                         tolerance,
  151.                                   cairo_antialias_t              antialias,
  152.                                   cairo_clip_t                  *clip)
  153. {
  154.     cairo_surface_subsurface_t *surface = abstract_surface;
  155.     cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
  156.     cairo_status_t status;
  157.     cairo_clip_t target_clip;
  158.  
  159.     _cairo_clip_init_copy (&target_clip, clip);
  160.     status = _cairo_clip_rectangle (&target_clip, &rect);
  161.     if (unlikely (status))
  162.         goto CLEANUP;
  163.  
  164.     status = _cairo_surface_offset_stroke (surface->target,
  165.                                            -surface->extents.x, -surface->extents.y,
  166.                                            op, source, path, stroke_style, ctm, ctm_inverse,
  167.                                            tolerance, antialias,
  168.                                            &target_clip);
  169.   CLEANUP:
  170.     _cairo_clip_fini (&target_clip);
  171.     return status;
  172. }
  173.  
  174. static cairo_int_status_t
  175. _cairo_surface_subsurface_glyphs (void                  *abstract_surface,
  176.                                   cairo_operator_t       op,
  177.                                   const cairo_pattern_t *source,
  178.                                   cairo_glyph_t         *glyphs,
  179.                                   int                    num_glyphs,
  180.                                   cairo_scaled_font_t   *scaled_font,
  181.                                   cairo_clip_t          *clip,
  182.                                   int *remaining_glyphs)
  183. {
  184.     cairo_surface_subsurface_t *surface = abstract_surface;
  185.     cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
  186.     cairo_status_t status;
  187.     cairo_clip_t target_clip;
  188.  
  189.     _cairo_clip_init_copy (&target_clip, clip);
  190.     status = _cairo_clip_rectangle (&target_clip, &rect);
  191.     if (unlikely (status))
  192.         goto CLEANUP;
  193.  
  194.     status = _cairo_surface_offset_glyphs (surface->target,
  195.                                            -surface->extents.x, -surface->extents.y,
  196.                                            op, source,
  197.                                            scaled_font, glyphs, num_glyphs,
  198.                                            &target_clip);
  199.     *remaining_glyphs = 0;
  200.   CLEANUP:
  201.     _cairo_clip_fini (&target_clip);
  202.     return status;
  203. }
  204.  
  205. static cairo_status_t
  206. _cairo_surface_subsurface_flush (void *abstract_surface)
  207. {
  208.     cairo_surface_subsurface_t *surface = abstract_surface;
  209.     cairo_status_t status;
  210.  
  211.     status = CAIRO_STATUS_SUCCESS;
  212.     if (surface->target->backend->flush != NULL)
  213.         status = surface->target->backend->flush (surface->target);
  214.  
  215.     return status;
  216. }
  217.  
  218. static cairo_status_t
  219. _cairo_surface_subsurface_mark_dirty (void *abstract_surface,
  220.                                       int x, int y,
  221.                                       int width, int height)
  222. {
  223.     cairo_surface_subsurface_t *surface = abstract_surface;
  224.     cairo_status_t status;
  225.  
  226.     status = CAIRO_STATUS_SUCCESS;
  227.     if (surface->target->backend->mark_dirty_rectangle != NULL) {
  228.         cairo_rectangle_int_t rect, extents;
  229.  
  230.         rect.x = x;
  231.         rect.y = y;
  232.         rect.width  = width;
  233.         rect.height = height;
  234.  
  235.         extents.x = extents.y = 0;
  236.         extents.width  = surface->extents.width;
  237.         extents.height = surface->extents.height;
  238.  
  239.         if (_cairo_rectangle_intersect (&rect, &extents)) {
  240.             status = surface->target->backend->mark_dirty_rectangle (surface->target,
  241.                                                                      rect.x + surface->extents.x,
  242.                                                                      rect.y + surface->extents.y,
  243.                                                                      rect.width, rect.height);
  244.         }
  245.     }
  246.  
  247.     return status;
  248. }
  249.  
  250. static cairo_bool_t
  251. _cairo_surface_subsurface_get_extents (void *abstract_surface,
  252.                                        cairo_rectangle_int_t *extents)
  253. {
  254.     cairo_surface_subsurface_t *surface = abstract_surface;
  255.  
  256.     extents->x = 0;
  257.     extents->y = 0;
  258.     extents->width  = surface->extents.width;
  259.     extents->height = surface->extents.height;
  260.  
  261.     return TRUE;
  262. }
  263.  
  264. static void
  265. _cairo_surface_subsurface_get_font_options (void *abstract_surface,
  266.                                             cairo_font_options_t *options)
  267. {
  268.     cairo_surface_subsurface_t *surface = abstract_surface;
  269.  
  270.     if (surface->target->backend->get_font_options != NULL)
  271.         surface->target->backend->get_font_options (surface->target, options);
  272. }
  273.  
  274. struct extra {
  275.     cairo_image_surface_t *image;
  276.     void *image_extra;
  277. };
  278.  
  279. static void
  280. cairo_surface_paint_to_target (cairo_surface_t            *target,
  281.                                cairo_surface_subsurface_t *subsurface)
  282. {
  283.     cairo_t *cr;
  284.    
  285.     cr = cairo_create (target);
  286.  
  287.     cairo_set_source_surface (cr,
  288.                               subsurface->target,
  289.                               - subsurface->extents.x,
  290.                               - subsurface->extents.y);
  291.     cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
  292.     cairo_paint (cr);
  293.    
  294.     cairo_destroy (cr);
  295. }
  296.  
  297. static cairo_status_t
  298. _cairo_surface_subsurface_acquire_source_image (void                    *abstract_surface,
  299.                                                 cairo_image_surface_t  **image_out,
  300.                                                 void                   **extra_out)
  301. {
  302.     cairo_rectangle_int_t target_extents;
  303.     cairo_surface_subsurface_t *surface = abstract_surface;
  304.     cairo_image_surface_t *image;
  305.     cairo_status_t status;
  306.     struct extra *extra;
  307.     uint8_t *data;
  308.     cairo_bool_t ret;
  309.  
  310.     if (surface->target->type == CAIRO_SURFACE_TYPE_RECORDING) {
  311.         cairo_recording_surface_t *meta = (cairo_recording_surface_t *) surface->target;
  312.         cairo_surface_t *snapshot;
  313.  
  314.         snapshot = _cairo_surface_has_snapshot (&surface->base,
  315.                                                 &_cairo_image_surface_backend);
  316.         if (snapshot != NULL) {
  317.             *image_out = (cairo_image_surface_t *) cairo_surface_reference (snapshot);
  318.             *extra_out = NULL;
  319.             return CAIRO_STATUS_SUCCESS;
  320.         }
  321.  
  322.         if (! _cairo_surface_has_snapshot (&meta->base,
  323.                                            &_cairo_image_surface_backend))
  324.         {
  325.             image = (cairo_image_surface_t *)
  326.                 _cairo_image_surface_create_with_content (meta->content,
  327.                                                           surface->extents.width,
  328.                                                           surface->extents.height);
  329.             if (unlikely (image->base.status))
  330.                 return image->base.status;
  331.  
  332.             cairo_surface_paint_to_target (&image->base, surface);
  333.  
  334.             _cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
  335.  
  336.             *image_out = image;
  337.             *extra_out = NULL;
  338.             return CAIRO_STATUS_SUCCESS;
  339.         }
  340.     }
  341.  
  342.     extra = malloc (sizeof (struct extra));
  343.     if (unlikely (extra == NULL))
  344.         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
  345.  
  346.     status = _cairo_surface_acquire_source_image (surface->target, &extra->image, &extra->image_extra);
  347.     if (unlikely (status))
  348.         goto CLEANUP;
  349.  
  350.     ret = _cairo_surface_get_extents (&extra->image->base, &target_extents);
  351.     assert (ret);
  352.  
  353.     /* only copy if we need to perform sub-byte manipulation */
  354.     if (PIXMAN_FORMAT_BPP (extra->image->pixman_format) >= 8 &&
  355.         target_extents.x <= surface->extents.x &&
  356.         target_extents.y <= surface->extents.y &&
  357.         surface->extents.x + surface->extents.width <= target_extents.x + target_extents.width &&
  358.         surface->extents.y + surface->extents.height <= target_extents.y + target_extents.height) {
  359.  
  360.         assert ((PIXMAN_FORMAT_BPP (extra->image->pixman_format) % 8) == 0);
  361.  
  362.         data = extra->image->data + surface->extents.y * extra->image->stride;
  363.         data += PIXMAN_FORMAT_BPP (extra->image->pixman_format) / 8 * surface->extents.x;
  364.  
  365.         image = (cairo_image_surface_t *)
  366.             _cairo_image_surface_create_with_pixman_format (data,
  367.                                                             extra->image->pixman_format,
  368.                                                             surface->extents.width,
  369.                                                             surface->extents.height,
  370.                                                             extra->image->stride);
  371.         if (unlikely ((status = image->base.status)))
  372.             goto CLEANUP_IMAGE;
  373.  
  374.         image->base.is_clear = FALSE;
  375.     } else {
  376.         image = (cairo_image_surface_t *)
  377.             _cairo_image_surface_create_with_pixman_format (NULL,
  378.                                                             extra->image->pixman_format,
  379.                                                             surface->extents.width,
  380.                                                             surface->extents.height,
  381.                                                             0);
  382.         if (unlikely ((status = image->base.status)))
  383.             goto CLEANUP_IMAGE;
  384.  
  385.         cairo_surface_paint_to_target (&image->base, surface);
  386.     }
  387.  
  388.     *image_out = image;
  389.     *extra_out = extra;
  390.     return CAIRO_STATUS_SUCCESS;
  391.  
  392. CLEANUP_IMAGE:
  393.     _cairo_surface_release_source_image (surface->target, extra->image, extra->image_extra);
  394. CLEANUP:
  395.     free (extra);
  396.     return status;
  397. }
  398.  
  399. static void
  400. _cairo_surface_subsurface_release_source_image (void                   *abstract_surface,
  401.                                                 cairo_image_surface_t  *image,
  402.                                                 void                   *abstract_extra)
  403. {
  404.     cairo_surface_subsurface_t *surface = abstract_surface;
  405.  
  406.     if (abstract_extra != NULL) {
  407.         struct extra *extra = abstract_extra;
  408.  
  409.         _cairo_surface_release_source_image (surface->target, extra->image, extra->image_extra);
  410.         free (extra);
  411.     }
  412.  
  413.     cairo_surface_destroy (&image->base);
  414. }
  415.  
  416. static cairo_surface_t *
  417. _cairo_surface_subsurface_snapshot (void *abstract_surface)
  418. {
  419.     cairo_surface_subsurface_t *surface = abstract_surface;
  420.     cairo_surface_subsurface_t *snapshot;
  421.  
  422.     snapshot = malloc (sizeof (cairo_surface_subsurface_t));
  423.     if (unlikely (snapshot == NULL))
  424.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  425.  
  426.     _cairo_surface_init (&snapshot->base,
  427.                          &_cairo_surface_subsurface_backend,
  428.                          NULL, /* device */
  429.                          surface->target->content);
  430.     snapshot->target = _cairo_surface_snapshot (surface->target);
  431.     if (unlikely (snapshot->target->status)) {
  432.         cairo_status_t status;
  433.  
  434.         status = snapshot->target->status;
  435.         free (snapshot);
  436.         return _cairo_surface_create_in_error (status);
  437.     }
  438.  
  439.     snapshot->base.type = snapshot->target->type;
  440.     snapshot->extents = surface->extents;
  441.  
  442.     return &snapshot->base;
  443. }
  444.  
  445. static const cairo_surface_backend_t _cairo_surface_subsurface_backend = {
  446.     CAIRO_SURFACE_TYPE_SUBSURFACE,
  447.     _cairo_surface_subsurface_create_similar,
  448.     _cairo_surface_subsurface_finish,
  449.  
  450.     _cairo_surface_subsurface_acquire_source_image,
  451.     _cairo_surface_subsurface_release_source_image,
  452.     NULL, NULL, /* acquire, release dest */
  453.     NULL, /* clone similar */
  454.     NULL, /* composite */
  455.     NULL, /* fill rectangles */
  456.     NULL, /* composite trapezoids */
  457.     NULL, /* create span renderer */
  458.     NULL, /* check span renderer */
  459.     NULL, /* copy_page */
  460.     NULL, /* show_page */
  461.     _cairo_surface_subsurface_get_extents,
  462.     NULL, /* old_show_glyphs */
  463.     _cairo_surface_subsurface_get_font_options,
  464.     _cairo_surface_subsurface_flush,
  465.     _cairo_surface_subsurface_mark_dirty,
  466.     NULL, /* font_fini */
  467.     NULL, /* glyph_fini */
  468.  
  469.     _cairo_surface_subsurface_paint,
  470.     _cairo_surface_subsurface_mask,
  471.     _cairo_surface_subsurface_stroke,
  472.     _cairo_surface_subsurface_fill,
  473.     _cairo_surface_subsurface_glyphs,
  474.  
  475.     _cairo_surface_subsurface_snapshot,
  476. };
  477.  
  478. /**
  479.  * cairo_surface_create_for_rectangle:
  480.  * @target: an existing surface for which the sub-surface will point to
  481.  * @x: the x-origin of the sub-surface from the top-left of the target surface (in device-space units)
  482.  * @y: the y-origin of the sub-surface from the top-left of the target surface (in device-space units)
  483.  * @width: width of the sub-surface (in device-space units)
  484.  * @height: height of the sub-surface (in device-space units)
  485.  *
  486.  * Create a new surface that is a rectangle within the target surface.
  487.  * All operations drawn to this surface are then clipped and translated
  488.  * onto the target surface. Nothing drawn via this sub-surface outside of
  489.  * its bounds is drawn onto the target surface, making this a useful method
  490.  * for passing constrained child surfaces to library routines that draw
  491.  * directly onto the parent surface, i.e. with no further backend allocations,
  492.  * double buffering or copies.
  493.  *
  494.  * <note><para>The semantics of subsurfaces have not been finalized yet
  495.  * unless the rectangle is in full device units, is contained within
  496.  * the extents of the target surface, and the target or subsurface's
  497.  * device transforms are not changed.</para></note>
  498.  *
  499.  * Return value: a pointer to the newly allocated surface. The caller
  500.  * owns the surface and should call cairo_surface_destroy() when done
  501.  * with it.
  502.  *
  503.  * This function always returns a valid pointer, but it will return a
  504.  * pointer to a "nil" surface if @other is already in an error state
  505.  * or any other error occurs.
  506.  *
  507.  * Since: 1.10
  508.  **/
  509. cairo_surface_t *
  510. cairo_surface_create_for_rectangle (cairo_surface_t *target,
  511.                                     double x, double y,
  512.                                     double width, double height)
  513. {
  514.     cairo_surface_subsurface_t *surface;
  515.  
  516.     if (unlikely (target->status))
  517.         return _cairo_surface_create_in_error (target->status);
  518.     if (unlikely (target->finished))
  519.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
  520.  
  521.     surface = malloc (sizeof (cairo_surface_subsurface_t));
  522.     if (unlikely (surface == NULL))
  523.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  524.  
  525.     assert (_cairo_matrix_is_translation (&target->device_transform));
  526.     x += target->device_transform.x0;
  527.     y += target->device_transform.y0;
  528.  
  529.     _cairo_surface_init (&surface->base,
  530.                          &_cairo_surface_subsurface_backend,
  531.                          NULL, /* device */
  532.                          target->content);
  533.  
  534.     /* XXX forced integer alignment */
  535.     surface->extents.x = ceil (x);
  536.     surface->extents.y = ceil (y);
  537.     surface->extents.width = floor (x + width) - surface->extents.x;
  538.     surface->extents.height = floor (y + height) - surface->extents.y;
  539.  
  540.     if (target->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
  541.         /* Maintain subsurfaces as 1-depth */
  542.         cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) target;
  543.         surface->extents.x += sub->extents.x;
  544.         surface->extents.y += sub->extents.y;
  545.         target = sub->target;
  546.     }
  547.  
  548.     surface->target = cairo_surface_reference (target);
  549.  
  550.     return &surface->base;
  551. }
  552. /* XXX observe mark-dirty */
  553.