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 © 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-clip-inline.h"
  39. #include "cairo-error-private.h"
  40. #include "cairo-image-surface-private.h"
  41. #include "cairo-recording-surface-private.h"
  42. #include "cairo-surface-offset-private.h"
  43. #include "cairo-surface-snapshot-private.h"
  44. #include "cairo-surface-subsurface-private.h"
  45.  
  46. static const cairo_surface_backend_t _cairo_surface_subsurface_backend;
  47.  
  48. static cairo_status_t
  49. _cairo_surface_subsurface_finish (void *abstract_surface)
  50. {
  51.     cairo_surface_subsurface_t *surface = abstract_surface;
  52.  
  53.     cairo_surface_destroy (surface->target);
  54.     cairo_surface_destroy (surface->snapshot);
  55.  
  56.     return CAIRO_STATUS_SUCCESS;
  57. }
  58.  
  59. static cairo_surface_t *
  60. _cairo_surface_subsurface_create_similar (void *other,
  61.                                           cairo_content_t content,
  62.                                           int width, int height)
  63. {
  64.     cairo_surface_subsurface_t *surface = other;
  65.  
  66.     if (surface->target->backend->create_similar == NULL)
  67.         return NULL;
  68.  
  69.     return surface->target->backend->create_similar (surface->target, content, width, height);
  70. }
  71.  
  72. static cairo_surface_t *
  73. _cairo_surface_subsurface_create_similar_image (void *other,
  74.                                                 cairo_format_t format,
  75.                                                 int width, int height)
  76. {
  77.     cairo_surface_subsurface_t *surface = other;
  78.  
  79.     if (surface->target->backend->create_similar_image == NULL)
  80.         return NULL;
  81.  
  82.     return surface->target->backend->create_similar_image (surface->target,
  83.                                                            format,
  84.                                                            width, height);
  85. }
  86.  
  87. static cairo_image_surface_t *
  88. _cairo_surface_subsurface_map_to_image (void *abstract_surface,
  89.                                         const cairo_rectangle_int_t *extents)
  90. {
  91.     cairo_surface_subsurface_t *surface = abstract_surface;
  92.     cairo_rectangle_int_t target_extents;
  93.  
  94.     target_extents.x = extents->x + surface->extents.x;
  95.     target_extents.y = extents->y + surface->extents.y;
  96.     target_extents.width  = extents->width;
  97.     target_extents.height = extents->height;
  98.  
  99.     return _cairo_surface_map_to_image (surface->target, &target_extents);
  100. }
  101.  
  102. static cairo_int_status_t
  103. _cairo_surface_subsurface_unmap_image (void *abstract_surface,
  104.                                        cairo_image_surface_t *image)
  105. {
  106.     cairo_surface_subsurface_t *surface = abstract_surface;
  107.     return _cairo_surface_unmap_image (surface->target, image);
  108. }
  109.  
  110. static cairo_int_status_t
  111. _cairo_surface_subsurface_paint (void *abstract_surface,
  112.                                  cairo_operator_t op,
  113.                                  const cairo_pattern_t *source,
  114.                                  const cairo_clip_t *clip)
  115. {
  116.     cairo_surface_subsurface_t *surface = abstract_surface;
  117.     cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
  118.     cairo_status_t status;
  119.     cairo_clip_t *target_clip;
  120.  
  121.     target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect);
  122.     status = _cairo_surface_offset_paint (surface->target,
  123.                                          -surface->extents.x, -surface->extents.y,
  124.                                           op, source, target_clip);
  125.     _cairo_clip_destroy (target_clip);
  126.     return status;
  127. }
  128.  
  129. static cairo_int_status_t
  130. _cairo_surface_subsurface_mask (void *abstract_surface,
  131.                                 cairo_operator_t op,
  132.                                 const cairo_pattern_t *source,
  133.                                 const cairo_pattern_t *mask,
  134.                                 const cairo_clip_t *clip)
  135. {
  136.     cairo_surface_subsurface_t *surface = abstract_surface;
  137.     cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
  138.     cairo_status_t status;
  139.     cairo_clip_t *target_clip;
  140.  
  141.     target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect);
  142.     status = _cairo_surface_offset_mask (surface->target,
  143.                                          -surface->extents.x, -surface->extents.y,
  144.                                          op, source, mask, target_clip);
  145.     _cairo_clip_destroy (target_clip);
  146.     return status;
  147. }
  148.  
  149. static cairo_int_status_t
  150. _cairo_surface_subsurface_fill (void                    *abstract_surface,
  151.                                 cairo_operator_t         op,
  152.                                 const cairo_pattern_t   *source,
  153.                                 const cairo_path_fixed_t        *path,
  154.                                 cairo_fill_rule_t        fill_rule,
  155.                                 double                   tolerance,
  156.                                 cairo_antialias_t        antialias,
  157.                                 const cairo_clip_t              *clip)
  158. {
  159.     cairo_surface_subsurface_t *surface = abstract_surface;
  160.     cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
  161.     cairo_status_t status;
  162.     cairo_clip_t *target_clip;
  163.  
  164.     target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect);
  165.     status = _cairo_surface_offset_fill (surface->target,
  166.                                          -surface->extents.x, -surface->extents.y,
  167.                                          op, source, path, fill_rule, tolerance, antialias,
  168.                                          target_clip);
  169.     _cairo_clip_destroy (target_clip);
  170.     return status;
  171. }
  172.  
  173. static cairo_int_status_t
  174. _cairo_surface_subsurface_stroke (void                          *abstract_surface,
  175.                                   cairo_operator_t               op,
  176.                                   const cairo_pattern_t         *source,
  177.                                   const cairo_path_fixed_t              *path,
  178.                                   const cairo_stroke_style_t    *stroke_style,
  179.                                   const cairo_matrix_t          *ctm,
  180.                                   const cairo_matrix_t          *ctm_inverse,
  181.                                   double                         tolerance,
  182.                                   cairo_antialias_t              antialias,
  183.                                   const cairo_clip_t                    *clip)
  184. {
  185.     cairo_surface_subsurface_t *surface = abstract_surface;
  186.     cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
  187.     cairo_status_t status;
  188.     cairo_clip_t *target_clip;
  189.  
  190.     target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect);
  191.     status = _cairo_surface_offset_stroke (surface->target,
  192.                                            -surface->extents.x, -surface->extents.y,
  193.                                            op, source, path, stroke_style, ctm, ctm_inverse,
  194.                                            tolerance, antialias,
  195.                                            target_clip);
  196.     _cairo_clip_destroy (target_clip);
  197.     return status;
  198. }
  199.  
  200. static cairo_int_status_t
  201. _cairo_surface_subsurface_glyphs (void                  *abstract_surface,
  202.                                   cairo_operator_t       op,
  203.                                   const cairo_pattern_t *source,
  204.                                   cairo_glyph_t         *glyphs,
  205.                                   int                    num_glyphs,
  206.                                   cairo_scaled_font_t   *scaled_font,
  207.                                   const cairo_clip_t    *clip)
  208. {
  209.     cairo_surface_subsurface_t *surface = abstract_surface;
  210.     cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
  211.     cairo_status_t status;
  212.     cairo_clip_t *target_clip;
  213.  
  214.     target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect);
  215.     status = _cairo_surface_offset_glyphs (surface->target,
  216.                                            -surface->extents.x, -surface->extents.y,
  217.                                            op, source,
  218.                                            scaled_font, glyphs, num_glyphs,
  219.                                            target_clip);
  220.     _cairo_clip_destroy (target_clip);
  221.     return status;
  222. }
  223.  
  224. static cairo_status_t
  225. _cairo_surface_subsurface_flush (void *abstract_surface, unsigned flags)
  226. {
  227.     cairo_surface_subsurface_t *surface = abstract_surface;
  228.     return _cairo_surface_flush (surface->target, flags);
  229. }
  230.  
  231. static cairo_status_t
  232. _cairo_surface_subsurface_mark_dirty (void *abstract_surface,
  233.                                       int x, int y,
  234.                                       int width, int height)
  235. {
  236.     cairo_surface_subsurface_t *surface = abstract_surface;
  237.     cairo_status_t status;
  238.  
  239.     status = CAIRO_STATUS_SUCCESS;
  240.     if (surface->target->backend->mark_dirty_rectangle != NULL) {
  241.         cairo_rectangle_int_t rect, extents;
  242.  
  243.         rect.x = x;
  244.         rect.y = y;
  245.         rect.width  = width;
  246.         rect.height = height;
  247.  
  248.         extents.x = extents.y = 0;
  249.         extents.width  = surface->extents.width;
  250.         extents.height = surface->extents.height;
  251.  
  252.         if (_cairo_rectangle_intersect (&rect, &extents)) {
  253.             status = surface->target->backend->mark_dirty_rectangle (surface->target,
  254.                                                                      rect.x + surface->extents.x,
  255.                                                                      rect.y + surface->extents.y,
  256.                                                                      rect.width, rect.height);
  257.         }
  258.     }
  259.  
  260.     return status;
  261. }
  262.  
  263. static cairo_bool_t
  264. _cairo_surface_subsurface_get_extents (void *abstract_surface,
  265.                                        cairo_rectangle_int_t *extents)
  266. {
  267.     cairo_surface_subsurface_t *surface = abstract_surface;
  268.  
  269.     extents->x = 0;
  270.     extents->y = 0;
  271.     extents->width  = surface->extents.width;
  272.     extents->height = surface->extents.height;
  273.  
  274.     return TRUE;
  275. }
  276.  
  277. static void
  278. _cairo_surface_subsurface_get_font_options (void *abstract_surface,
  279.                                             cairo_font_options_t *options)
  280. {
  281.     cairo_surface_subsurface_t *surface = abstract_surface;
  282.  
  283.     if (surface->target->backend->get_font_options != NULL)
  284.         surface->target->backend->get_font_options (surface->target, options);
  285. }
  286.  
  287. static cairo_surface_t *
  288. _cairo_surface_subsurface_source (void *abstract_surface,
  289.                                   cairo_rectangle_int_t *extents)
  290. {
  291.     cairo_surface_subsurface_t *surface = abstract_surface;
  292.     cairo_surface_t *source;
  293.  
  294.     source = _cairo_surface_get_source (surface->target, extents);
  295.     if (extents)
  296.         *extents = surface->extents;
  297.  
  298.     return source;
  299. }
  300.  
  301. static cairo_status_t
  302. _cairo_surface_subsurface_acquire_source_image (void                    *abstract_surface,
  303.                                                 cairo_image_surface_t  **image_out,
  304.                                                 void                   **extra_out)
  305. {
  306.     cairo_surface_subsurface_t *surface = abstract_surface;
  307.     cairo_surface_pattern_t pattern;
  308.     cairo_surface_t *image;
  309.     cairo_status_t status;
  310.  
  311.     image = _cairo_image_surface_create_with_content (surface->base.content,
  312.                                                       surface->extents.width,
  313.                                                       surface->extents.height);
  314.     if (unlikely (image->status))
  315.         return image->status;
  316.  
  317.     _cairo_pattern_init_for_surface (&pattern, surface->target);
  318.     cairo_matrix_init_translate (&pattern.base.matrix,
  319.                                  surface->extents.x,
  320.                                  surface->extents.y);
  321.     pattern.base.filter = CAIRO_FILTER_NEAREST;
  322.     status = _cairo_surface_paint (image,
  323.                                    CAIRO_OPERATOR_SOURCE,
  324.                                    &pattern.base, NULL);
  325.     _cairo_pattern_fini (&pattern.base);
  326.     if (unlikely (status)) {
  327.         cairo_surface_destroy (image);
  328.         return status;
  329.     }
  330.  
  331.     *image_out = (cairo_image_surface_t *)image;
  332.     *extra_out = NULL;
  333.     return CAIRO_STATUS_SUCCESS;
  334. }
  335.  
  336. static void
  337. _cairo_surface_subsurface_release_source_image (void                   *abstract_surface,
  338.                                                 cairo_image_surface_t  *image,
  339.                                                 void                   *abstract_extra)
  340. {
  341.     cairo_surface_destroy (&image->base);
  342. }
  343.  
  344. static cairo_surface_t *
  345. _cairo_surface_subsurface_snapshot (void *abstract_surface)
  346. {
  347.     cairo_surface_subsurface_t *surface = abstract_surface;
  348.     cairo_surface_pattern_t pattern;
  349.     cairo_surface_t *clone;
  350.     cairo_status_t status;
  351.  
  352.     TRACE ((stderr, "%s: target=%d\n", __FUNCTION__, surface->target->unique_id));
  353.  
  354.     clone = _cairo_surface_create_similar_scratch (surface->target,
  355.                                                    surface->target->content,
  356.                                                    surface->extents.width,
  357.                                                    surface->extents.height);
  358.     if (unlikely (clone->status))
  359.         return clone;
  360.  
  361.     _cairo_pattern_init_for_surface (&pattern, surface->target);
  362.     cairo_matrix_init_translate (&pattern.base.matrix,
  363.                                  surface->extents.x, surface->extents.y);
  364.     pattern.base.filter = CAIRO_FILTER_NEAREST;
  365.     status = _cairo_surface_paint (clone,
  366.                                    CAIRO_OPERATOR_SOURCE,
  367.                                    &pattern.base, NULL);
  368.     _cairo_pattern_fini (&pattern.base);
  369.  
  370.     if (unlikely (status)) {
  371.         cairo_surface_destroy (clone);
  372.         clone = _cairo_surface_create_in_error (status);
  373.     }
  374.  
  375.     return clone;
  376. }
  377.  
  378. static cairo_t *
  379. _cairo_surface_subsurface_create_context(void *target)
  380. {
  381.     cairo_surface_subsurface_t *surface = target;
  382.     return surface->target->backend->create_context (&surface->base);
  383. }
  384.  
  385. static const cairo_surface_backend_t _cairo_surface_subsurface_backend = {
  386.     CAIRO_SURFACE_TYPE_SUBSURFACE,
  387.     _cairo_surface_subsurface_finish,
  388.  
  389.     _cairo_surface_subsurface_create_context,
  390.  
  391.     _cairo_surface_subsurface_create_similar,
  392.     _cairo_surface_subsurface_create_similar_image,
  393.     _cairo_surface_subsurface_map_to_image,
  394.     _cairo_surface_subsurface_unmap_image,
  395.  
  396.     _cairo_surface_subsurface_source,
  397.     _cairo_surface_subsurface_acquire_source_image,
  398.     _cairo_surface_subsurface_release_source_image,
  399.     _cairo_surface_subsurface_snapshot,
  400.  
  401.     NULL, /* copy_page */
  402.     NULL, /* show_page */
  403.  
  404.     _cairo_surface_subsurface_get_extents,
  405.     _cairo_surface_subsurface_get_font_options,
  406.  
  407.     _cairo_surface_subsurface_flush,
  408.     _cairo_surface_subsurface_mark_dirty,
  409.  
  410.     _cairo_surface_subsurface_paint,
  411.     _cairo_surface_subsurface_mask,
  412.     _cairo_surface_subsurface_stroke,
  413.     _cairo_surface_subsurface_fill,
  414.     NULL, /* fill/stroke */
  415.     _cairo_surface_subsurface_glyphs,
  416. };
  417.  
  418. /**
  419.  * cairo_surface_create_for_rectangle:
  420.  * @target: an existing surface for which the sub-surface will point to
  421.  * @x: the x-origin of the sub-surface from the top-left of the target surface (in device-space units)
  422.  * @y: the y-origin of the sub-surface from the top-left of the target surface (in device-space units)
  423.  * @width: width of the sub-surface (in device-space units)
  424.  * @height: height of the sub-surface (in device-space units)
  425.  *
  426.  * Create a new surface that is a rectangle within the target surface.
  427.  * All operations drawn to this surface are then clipped and translated
  428.  * onto the target surface. Nothing drawn via this sub-surface outside of
  429.  * its bounds is drawn onto the target surface, making this a useful method
  430.  * for passing constrained child surfaces to library routines that draw
  431.  * directly onto the parent surface, i.e. with no further backend allocations,
  432.  * double buffering or copies.
  433.  *
  434.  * <note><para>The semantics of subsurfaces have not been finalized yet
  435.  * unless the rectangle is in full device units, is contained within
  436.  * the extents of the target surface, and the target or subsurface's
  437.  * device transforms are not changed.</para></note>
  438.  *
  439.  * Return value: a pointer to the newly allocated surface. The caller
  440.  * owns the surface and should call cairo_surface_destroy() when done
  441.  * with it.
  442.  *
  443.  * This function always returns a valid pointer, but it will return a
  444.  * pointer to a "nil" surface if @other is already in an error state
  445.  * or any other error occurs.
  446.  *
  447.  * Since: 1.10
  448.  **/
  449. cairo_surface_t *
  450. cairo_surface_create_for_rectangle (cairo_surface_t *target,
  451.                                     double x, double y,
  452.                                     double width, double height)
  453. {
  454.     cairo_surface_subsurface_t *surface;
  455.  
  456.     if (unlikely (width < 0 || height < 0))
  457.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
  458.  
  459.     if (unlikely (target->status))
  460.         return _cairo_surface_create_in_error (target->status);
  461.     if (unlikely (target->finished))
  462.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
  463.  
  464.     surface = malloc (sizeof (cairo_surface_subsurface_t));
  465.     if (unlikely (surface == NULL))
  466.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  467.  
  468.     assert (_cairo_matrix_is_translation (&target->device_transform));
  469.     x += target->device_transform.x0;
  470.     y += target->device_transform.y0;
  471.  
  472.     _cairo_surface_init (&surface->base,
  473.                          &_cairo_surface_subsurface_backend,
  474.                          NULL, /* device */
  475.                          target->content);
  476.  
  477.     /* XXX forced integer alignment */
  478.     surface->extents.x = ceil (x);
  479.     surface->extents.y = ceil (y);
  480.     surface->extents.width = floor (x + width) - surface->extents.x;
  481.     surface->extents.height = floor (y + height) - surface->extents.y;
  482.     if ((surface->extents.width | surface->extents.height) < 0)
  483.         surface->extents.width = surface->extents.height = 0;
  484.  
  485.     if (target->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
  486.         /* Maintain subsurfaces as 1-depth */
  487.         cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) target;
  488.         surface->extents.x += sub->extents.x;
  489.         surface->extents.y += sub->extents.y;
  490.         target = sub->target;
  491.     }
  492.  
  493.     surface->target = cairo_surface_reference (target);
  494.     surface->base.type = surface->target->type;
  495.  
  496.     surface->snapshot = NULL;
  497.  
  498.     return &surface->base;
  499. }
  500.  
  501. cairo_surface_t *
  502. _cairo_surface_create_for_rectangle_int (cairo_surface_t *target,
  503.                                          const cairo_rectangle_int_t *extents)
  504. {
  505.     cairo_surface_subsurface_t *surface;
  506.  
  507.     if (unlikely (target->status))
  508.         return _cairo_surface_create_in_error (target->status);
  509.     if (unlikely (target->finished))
  510.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
  511.  
  512.     assert (target->backend->type != CAIRO_SURFACE_TYPE_SUBSURFACE);
  513.  
  514.     surface = malloc (sizeof (cairo_surface_subsurface_t));
  515.     if (unlikely (surface == NULL))
  516.         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
  517.  
  518.     assert (_cairo_matrix_is_translation (&target->device_transform));
  519.  
  520.     _cairo_surface_init (&surface->base,
  521.                          &_cairo_surface_subsurface_backend,
  522.                          NULL, /* device */
  523.                          target->content);
  524.  
  525.     surface->extents = *extents;
  526.     surface->extents.x += target->device_transform.x0;
  527.     surface->extents.y += target->device_transform.y0;
  528.  
  529.     surface->target = cairo_surface_reference (target);
  530.     surface->base.type = surface->target->type;
  531.  
  532.     surface->snapshot = NULL;
  533.  
  534.     return &surface->base;
  535. }
  536. /* XXX observe mark-dirty */
  537.  
  538. static void
  539. _cairo_surface_subsurface_detach_snapshot (cairo_surface_t *surface)
  540. {
  541.     cairo_surface_subsurface_t *ss = (cairo_surface_subsurface_t *) surface;
  542.  
  543.     TRACE ((stderr, "%s: target=%d\n", __FUNCTION__, ss->target->unique_id));
  544.  
  545.     cairo_surface_destroy (ss->snapshot);
  546.     ss->snapshot = NULL;
  547. }
  548.  
  549. void
  550. _cairo_surface_subsurface_set_snapshot (cairo_surface_t *surface,
  551.                                         cairo_surface_t *snapshot)
  552. {
  553.     cairo_surface_subsurface_t *ss = (cairo_surface_subsurface_t *) surface;
  554.  
  555.     TRACE ((stderr, "%s: target=%d, snapshot=%d\n", __FUNCTION__,
  556.             ss->target->unique_id, snapshot->unique_id));
  557.  
  558.     /* FIXME: attaching the subsurface as a snapshot to its target creates
  559.      * a reference cycle.  Let's make this call as a no-op until that bug
  560.      * is fixed.
  561.      */
  562.     return;
  563.  
  564.     if (ss->snapshot)
  565.         _cairo_surface_detach_snapshot (ss->snapshot);
  566.  
  567.     ss->snapshot = cairo_surface_reference (snapshot);
  568.  
  569.     _cairo_surface_attach_snapshot (ss->target, &ss->base,
  570.                                     _cairo_surface_subsurface_detach_snapshot);
  571. }
  572.