/work/workdir/UnpackedTarball/cairo/src/cairo-surface-snapshot.c
Line | Count | Source (jump to first uncovered line) |
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-image-surface-private.h" |
44 | | #include "cairo-surface-snapshot-inline.h" |
45 | | |
46 | | static cairo_status_t |
47 | | _cairo_surface_snapshot_finish (void *abstract_surface) |
48 | 0 | { |
49 | 0 | cairo_surface_snapshot_t *surface = abstract_surface; |
50 | 0 | cairo_status_t status = CAIRO_STATUS_SUCCESS; |
51 | |
|
52 | 0 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
53 | |
|
54 | 0 | if (surface->clone != NULL) { |
55 | 0 | cairo_surface_finish (surface->clone); |
56 | 0 | status = surface->clone->status; |
57 | |
|
58 | 0 | cairo_surface_destroy (surface->clone); |
59 | 0 | } |
60 | |
|
61 | 0 | CAIRO_MUTEX_FINI (surface->mutex); |
62 | |
|
63 | 0 | return status; |
64 | 0 | } |
65 | | |
66 | | static cairo_status_t |
67 | | _cairo_surface_snapshot_flush (void *abstract_surface, unsigned flags) |
68 | 0 | { |
69 | 0 | cairo_surface_snapshot_t *surface = abstract_surface; |
70 | 0 | cairo_surface_t *target; |
71 | 0 | cairo_status_t status; |
72 | |
|
73 | 0 | target = _cairo_surface_snapshot_get_target (&surface->base); |
74 | 0 | status = target->status; |
75 | 0 | if (status == CAIRO_STATUS_SUCCESS) |
76 | 0 | status = _cairo_surface_flush (target, flags); |
77 | 0 | cairo_surface_destroy (target); |
78 | |
|
79 | 0 | return status; |
80 | 0 | } |
81 | | |
82 | | static cairo_surface_t * |
83 | | _cairo_surface_snapshot_source (void *abstract_surface, |
84 | | cairo_rectangle_int_t *extents) |
85 | 0 | { |
86 | 0 | cairo_surface_snapshot_t *surface = abstract_surface; |
87 | 0 | return _cairo_surface_get_source (surface->target, extents); /* XXX racy */ |
88 | 0 | } |
89 | | |
90 | | struct snapshot_extra { |
91 | | cairo_surface_t *target; |
92 | | void *extra; |
93 | | }; |
94 | | |
95 | | static cairo_status_t |
96 | | _cairo_surface_snapshot_acquire_source_image (void *abstract_surface, |
97 | | cairo_image_surface_t **image_out, |
98 | | void **extra_out) |
99 | 0 | { |
100 | 0 | cairo_surface_snapshot_t *surface = abstract_surface; |
101 | 0 | struct snapshot_extra *extra; |
102 | 0 | cairo_status_t status; |
103 | |
|
104 | 0 | extra = _cairo_malloc (sizeof (*extra)); |
105 | 0 | if (unlikely (extra == NULL)) { |
106 | 0 | *extra_out = NULL; |
107 | 0 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
108 | 0 | } |
109 | | |
110 | 0 | extra->target = _cairo_surface_snapshot_get_target (&surface->base); |
111 | 0 | status = _cairo_surface_acquire_source_image (extra->target, image_out, &extra->extra); |
112 | 0 | if (unlikely (status)) { |
113 | 0 | cairo_surface_destroy (extra->target); |
114 | 0 | free (extra); |
115 | 0 | extra = NULL; |
116 | 0 | } |
117 | |
|
118 | 0 | *extra_out = extra; |
119 | 0 | return status; |
120 | 0 | } |
121 | | |
122 | | static void |
123 | | _cairo_surface_snapshot_release_source_image (void *abstract_surface, |
124 | | cairo_image_surface_t *image, |
125 | | void *_extra) |
126 | 0 | { |
127 | 0 | struct snapshot_extra *extra = _extra; |
128 | |
|
129 | 0 | _cairo_surface_release_source_image (extra->target, image, extra->extra); |
130 | 0 | cairo_surface_destroy (extra->target); |
131 | 0 | free (extra); |
132 | 0 | } |
133 | | |
134 | | static cairo_bool_t |
135 | | _cairo_surface_snapshot_get_extents (void *abstract_surface, |
136 | | cairo_rectangle_int_t *extents) |
137 | 0 | { |
138 | 0 | cairo_surface_snapshot_t *surface = abstract_surface; |
139 | 0 | cairo_surface_t *target; |
140 | 0 | cairo_bool_t bounded; |
141 | |
|
142 | 0 | target = _cairo_surface_snapshot_get_target (&surface->base); |
143 | 0 | bounded = _cairo_surface_get_extents (target, extents); |
144 | 0 | cairo_surface_destroy (target); |
145 | |
|
146 | 0 | return bounded; |
147 | 0 | } |
148 | | |
149 | | static const cairo_surface_backend_t _cairo_surface_snapshot_backend = { |
150 | | CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT, |
151 | | _cairo_surface_snapshot_finish, |
152 | | NULL, |
153 | | |
154 | | NULL, /* create similar */ |
155 | | NULL, /* create similar image */ |
156 | | NULL, /* map to image */ |
157 | | NULL, /* unmap image */ |
158 | | |
159 | | _cairo_surface_snapshot_source, |
160 | | _cairo_surface_snapshot_acquire_source_image, |
161 | | _cairo_surface_snapshot_release_source_image, |
162 | | NULL, /* snapshot */ |
163 | | |
164 | | NULL, /* copy_page */ |
165 | | NULL, /* show_page */ |
166 | | |
167 | | _cairo_surface_snapshot_get_extents, |
168 | | NULL, /* get-font-options */ |
169 | | |
170 | | _cairo_surface_snapshot_flush, |
171 | | }; |
172 | | |
173 | | static void |
174 | | _cairo_surface_snapshot_copy_on_write (cairo_surface_t *surface) |
175 | 0 | { |
176 | 0 | cairo_surface_snapshot_t *snapshot = (cairo_surface_snapshot_t *) surface; |
177 | 0 | cairo_image_surface_t *image; |
178 | 0 | cairo_surface_t *clone; |
179 | 0 | void *extra; |
180 | 0 | cairo_status_t status; |
181 | |
|
182 | 0 | TRACE ((stderr, "%s: target=%d\n", |
183 | 0 | __FUNCTION__, snapshot->target->unique_id)); |
184 | | |
185 | | /* We need to make an image copy of the original surface since the |
186 | | * snapshot may exceed the lifetime of the original device, i.e. |
187 | | * when we later need to use the snapshot the data may have already |
188 | | * been lost. |
189 | | */ |
190 | |
|
191 | 0 | CAIRO_MUTEX_LOCK (snapshot->mutex); |
192 | |
|
193 | 0 | if (snapshot->target->backend->snapshot != NULL) { |
194 | 0 | clone = snapshot->target->backend->snapshot (snapshot->target); |
195 | 0 | if (clone != NULL) { |
196 | 0 | assert (clone->status || ! _cairo_surface_is_snapshot (clone)); |
197 | 0 | goto done; |
198 | 0 | } |
199 | 0 | } |
200 | | |
201 | | /* XXX copy to a similar surface, leave acquisition till later? |
202 | | * We should probably leave such decisions to the backend in case we |
203 | | * rely upon devices/connections like Xlib. |
204 | | */ |
205 | 0 | status = _cairo_surface_acquire_source_image (snapshot->target, &image, &extra); |
206 | 0 | if (unlikely (status)) { |
207 | 0 | snapshot->target = _cairo_surface_create_in_error (status); |
208 | 0 | status = _cairo_surface_set_error (surface, status); |
209 | 0 | goto unlock; |
210 | 0 | } |
211 | 0 | clone = image->base.backend->snapshot (&image->base); |
212 | 0 | _cairo_surface_release_source_image (snapshot->target, image, extra); |
213 | |
|
214 | 0 | done: |
215 | 0 | status = _cairo_surface_set_error (surface, clone->status); |
216 | 0 | snapshot->target = snapshot->clone = clone; |
217 | 0 | snapshot->base.type = clone->type; |
218 | 0 | unlock: |
219 | 0 | CAIRO_MUTEX_UNLOCK (snapshot->mutex); |
220 | 0 | } |
221 | | |
222 | | /** |
223 | | * _cairo_surface_snapshot: |
224 | | * @surface: a #cairo_surface_t |
225 | | * |
226 | | * Make an immutable reference to @surface. It is an error to call a |
227 | | * surface-modifying function on the result of this function. The |
228 | | * resulting 'snapshot' is a lazily copied-on-write surface i.e. it |
229 | | * remains a reference to the original surface until that surface is |
230 | | * written to again, at which time a copy is made of the original surface |
231 | | * and the snapshot then points to that instead. Multiple snapshots of the |
232 | | * same unmodified surface point to the same copy. |
233 | | * |
234 | | * The caller owns the return value and should call |
235 | | * cairo_surface_destroy() when finished with it. This function will not |
236 | | * return %NULL, but will return a nil surface instead. |
237 | | * |
238 | | * Return value: The snapshot surface. Note that the return surface |
239 | | * may not necessarily be of the same type as @surface. |
240 | | **/ |
241 | | cairo_surface_t * |
242 | | _cairo_surface_snapshot (cairo_surface_t *surface) |
243 | 0 | { |
244 | 0 | cairo_surface_snapshot_t *snapshot; |
245 | 0 | cairo_status_t status; |
246 | |
|
247 | 0 | TRACE ((stderr, "%s: target=%d\n", __FUNCTION__, surface->unique_id)); |
248 | |
|
249 | 0 | if (unlikely (surface->status)) |
250 | 0 | return _cairo_surface_create_in_error (surface->status); |
251 | | |
252 | 0 | if (unlikely (surface->finished)) |
253 | 0 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); |
254 | | |
255 | 0 | if (surface->snapshot_of != NULL) |
256 | 0 | return cairo_surface_reference (surface); |
257 | | |
258 | 0 | if (_cairo_surface_is_snapshot (surface)) |
259 | 0 | return cairo_surface_reference (surface); |
260 | | |
261 | 0 | snapshot = (cairo_surface_snapshot_t *) |
262 | 0 | _cairo_surface_has_snapshot (surface, &_cairo_surface_snapshot_backend); |
263 | 0 | if (snapshot != NULL) |
264 | 0 | return cairo_surface_reference (&snapshot->base); |
265 | | |
266 | 0 | snapshot = _cairo_malloc (sizeof (cairo_surface_snapshot_t)); |
267 | 0 | if (unlikely (snapshot == NULL)) |
268 | 0 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); |
269 | | |
270 | 0 | _cairo_surface_init (&snapshot->base, |
271 | 0 | &_cairo_surface_snapshot_backend, |
272 | 0 | NULL, /* device */ |
273 | 0 | surface->content, |
274 | 0 | surface->is_vector); |
275 | 0 | snapshot->base.type = surface->type; |
276 | |
|
277 | 0 | CAIRO_MUTEX_INIT (snapshot->mutex); |
278 | 0 | snapshot->target = surface; |
279 | 0 | snapshot->clone = NULL; |
280 | |
|
281 | 0 | status = _cairo_surface_copy_mime_data (&snapshot->base, surface); |
282 | 0 | if (unlikely (status)) { |
283 | 0 | cairo_surface_destroy (&snapshot->base); |
284 | 0 | return _cairo_surface_create_in_error (status); |
285 | 0 | } |
286 | | |
287 | 0 | snapshot->base.device_transform = surface->device_transform; |
288 | 0 | snapshot->base.device_transform_inverse = surface->device_transform_inverse; |
289 | |
|
290 | 0 | _cairo_surface_attach_snapshot (surface, |
291 | 0 | &snapshot->base, |
292 | 0 | _cairo_surface_snapshot_copy_on_write); |
293 | |
|
294 | 0 | return &snapshot->base; |
295 | 0 | } |