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