Line data Source code
1 : /* cairo - a vector graphics library with display and print output
2 : *
3 : * Copyright © 2002 University of Southern California
4 : * Copyright © 2005 Red Hat, Inc.
5 : * Copyright © 2009 Intel Corporation
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 University of Southern
33 : * California.
34 : *
35 : * Contributor(s):
36 : * Carl D. Worth <cworth@cworth.org>
37 : * Chris Wilson <chris@chris-wilson.co.uk>
38 : */
39 :
40 : #include "cairoint.h"
41 :
42 : #include "cairo-error-private.h"
43 : #include "cairo-surface-snapshot-private.h"
44 :
45 : static cairo_status_t
46 0 : _cairo_surface_snapshot_finish (void *abstract_surface)
47 : {
48 0 : cairo_surface_snapshot_t *surface = abstract_surface;
49 0 : cairo_status_t status = CAIRO_STATUS_SUCCESS;
50 :
51 0 : if (surface->clone != NULL) {
52 0 : cairo_surface_finish (surface->clone);
53 0 : status = surface->clone->status;
54 :
55 0 : cairo_surface_destroy (surface->clone);
56 : }
57 :
58 0 : return status;
59 : }
60 :
61 : static cairo_status_t
62 0 : _cairo_surface_snapshot_acquire_source_image (void *abstract_surface,
63 : cairo_image_surface_t **image_out,
64 : void **extra_out)
65 : {
66 0 : cairo_surface_snapshot_t *surface = abstract_surface;
67 :
68 0 : return _cairo_surface_acquire_source_image (surface->target, image_out, extra_out);
69 : }
70 :
71 : static void
72 0 : _cairo_surface_snapshot_release_source_image (void *abstract_surface,
73 : cairo_image_surface_t *image,
74 : void *extra)
75 : {
76 0 : cairo_surface_snapshot_t *surface = abstract_surface;
77 :
78 0 : _cairo_surface_release_source_image (surface->target, image, extra);
79 0 : }
80 :
81 : static cairo_bool_t
82 0 : _cairo_surface_snapshot_get_extents (void *abstract_surface,
83 : cairo_rectangle_int_t *extents)
84 : {
85 0 : cairo_surface_snapshot_t *surface = abstract_surface;
86 :
87 0 : return _cairo_surface_get_extents (surface->target, extents);
88 : }
89 :
90 : static const cairo_surface_backend_t _cairo_surface_snapshot_backend = {
91 : CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT,
92 :
93 : NULL, /* create similar */
94 : _cairo_surface_snapshot_finish,
95 :
96 : _cairo_surface_snapshot_acquire_source_image,
97 : _cairo_surface_snapshot_release_source_image,
98 : NULL, NULL, /* acquire, release dest */
99 : NULL, /* clone similar */
100 : NULL, /* composite */
101 : NULL, /* fill rectangles */
102 : NULL, /* composite trapezoids */
103 : NULL, /* create span renderer */
104 : NULL, /* check span renderer */
105 : NULL, /* copy_page */
106 : NULL, /* show_page */
107 : _cairo_surface_snapshot_get_extents,
108 : };
109 :
110 : static void
111 0 : _cairo_surface_snapshot_copy_on_write (cairo_surface_t *surface)
112 : {
113 0 : cairo_surface_snapshot_t *snapshot = (cairo_surface_snapshot_t *) surface;
114 : cairo_image_surface_t *image;
115 : cairo_image_surface_t *clone;
116 : void *extra;
117 : cairo_status_t status;
118 :
119 : /* We need to make an image copy of the original surface since the
120 : * snapshot may exceed the lifetime of the original device, i.e.
121 : * when we later need to use the snapshot the data may have already
122 : * been lost.
123 : */
124 :
125 0 : status = _cairo_surface_acquire_source_image (snapshot->target, &image, &extra);
126 0 : if (unlikely (status)) {
127 0 : snapshot->target = _cairo_surface_create_in_error (status);
128 0 : status = _cairo_surface_set_error (surface, status);
129 0 : return;
130 : }
131 :
132 0 : clone = (cairo_image_surface_t *)
133 0 : _cairo_image_surface_create_with_pixman_format (NULL,
134 0 : image->pixman_format,
135 0 : image->width,
136 0 : image->height,
137 : 0);
138 0 : if (likely (clone->base.status == CAIRO_STATUS_SUCCESS)) {
139 0 : if (clone->stride == image->stride) {
140 0 : memcpy (clone->data, image->data, image->stride * image->height);
141 : } else {
142 0 : pixman_image_composite32 (PIXMAN_OP_SRC,
143 0 : image->pixman_image, NULL, clone->pixman_image,
144 : 0, 0,
145 : 0, 0,
146 : 0, 0,
147 0 : image->width, image->height);
148 : }
149 0 : clone->base.is_clear = FALSE;
150 :
151 0 : snapshot->clone = &clone->base;
152 : } else {
153 0 : snapshot->clone = &clone->base;
154 0 : status = _cairo_surface_set_error (surface, clone->base.status);
155 : }
156 :
157 0 : _cairo_surface_release_source_image (snapshot->target, image, extra);
158 0 : snapshot->target = snapshot->clone;
159 0 : snapshot->base.type = snapshot->target->type;
160 : }
161 :
162 : /**
163 : * _cairo_surface_snapshot
164 : * @surface: a #cairo_surface_t
165 : *
166 : * Make an immutable reference to @surface. It is an error to call a
167 : * surface-modifying function on the result of this function. The
168 : * resulting 'snapshot' is a lazily copied-on-write surface i.e. it
169 : * remains a reference to the original surface until that surface is
170 : * written to again, at which time a copy is made of the original surface
171 : * and the snapshot then points to that instead. Multiple snapshots of the
172 : * same unmodified surface point to the same copy.
173 : *
174 : * The caller owns the return value and should call
175 : * cairo_surface_destroy() when finished with it. This function will not
176 : * return %NULL, but will return a nil surface instead.
177 : *
178 : * Return value: The snapshot surface. Note that the return surface
179 : * may not necessarily be of the same type as @surface.
180 : **/
181 : cairo_surface_t *
182 0 : _cairo_surface_snapshot (cairo_surface_t *surface)
183 : {
184 : cairo_surface_snapshot_t *snapshot;
185 : cairo_status_t status;
186 :
187 0 : if (unlikely (surface->status))
188 0 : return _cairo_surface_create_in_error (surface->status);
189 :
190 0 : if (surface->finished)
191 0 : return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
192 :
193 0 : if (surface->snapshot_of != NULL)
194 0 : return cairo_surface_reference (surface);
195 :
196 0 : if (surface->backend->snapshot != NULL) {
197 : cairo_surface_t *snap;
198 :
199 0 : snap = _cairo_surface_has_snapshot (surface, surface->backend);
200 0 : if (snap != NULL)
201 0 : return cairo_surface_reference (snap);
202 :
203 0 : snap = surface->backend->snapshot (surface);
204 0 : if (snap != NULL) {
205 0 : if (unlikely (snap->status))
206 0 : return snap;
207 :
208 0 : status = _cairo_surface_copy_mime_data (snap, surface);
209 0 : if (unlikely (status)) {
210 0 : cairo_surface_destroy (snap);
211 0 : return _cairo_surface_create_in_error (status);
212 : }
213 :
214 0 : snap->device_transform = surface->device_transform;
215 0 : snap->device_transform_inverse = surface->device_transform_inverse;
216 :
217 0 : cairo_surface_attach_snapshot (surface, snap, NULL);
218 :
219 0 : return snap;
220 : }
221 : }
222 :
223 0 : snapshot = (cairo_surface_snapshot_t *)
224 : _cairo_surface_has_snapshot (surface, &_cairo_surface_snapshot_backend);
225 0 : if (snapshot != NULL)
226 0 : return cairo_surface_reference (&snapshot->base);
227 :
228 0 : snapshot = malloc (sizeof (cairo_surface_snapshot_t));
229 0 : if (unlikely (snapshot == NULL))
230 0 : return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
231 :
232 0 : _cairo_surface_init (&snapshot->base,
233 : &_cairo_surface_snapshot_backend,
234 : NULL, /* device */
235 : surface->content);
236 0 : snapshot->base.type = surface->type;
237 :
238 0 : snapshot->target = surface;
239 0 : snapshot->clone = NULL;
240 :
241 0 : status = _cairo_surface_copy_mime_data (&snapshot->base, surface);
242 0 : if (unlikely (status)) {
243 0 : cairo_surface_destroy (&snapshot->base);
244 0 : return _cairo_surface_create_in_error (status);
245 : }
246 :
247 0 : snapshot->base.device_transform = surface->device_transform;
248 0 : snapshot->base.device_transform_inverse = surface->device_transform_inverse;
249 :
250 0 : cairo_surface_attach_snapshot (surface,
251 : &snapshot->base,
252 : _cairo_surface_snapshot_copy_on_write);
253 :
254 0 : return &snapshot->base;
255 : }
|