Rev 1892 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1892 | Rev 3959 | ||
---|---|---|---|
Line 38... | Line 38... | ||
38 | */ |
38 | */ |
Line 39... | Line 39... | ||
39 | 39 | ||
Line 40... | Line 40... | ||
40 | #include "cairoint.h" |
40 | #include "cairoint.h" |
- | 41 | ||
41 | 42 | #include "cairo-error-private.h" |
|
Line 42... | Line 43... | ||
42 | #include "cairo-error-private.h" |
43 | #include "cairo-image-surface-private.h" |
43 | #include "cairo-surface-snapshot-private.h" |
44 | #include "cairo-surface-snapshot-inline.h" |
44 | 45 | ||
45 | static cairo_status_t |
46 | static cairo_status_t |
46 | _cairo_surface_snapshot_finish (void *abstract_surface) |
47 | _cairo_surface_snapshot_finish (void *abstract_surface) |
Line -... | Line 48... | ||
- | 48 | { |
|
- | 49 | cairo_surface_snapshot_t *surface = abstract_surface; |
|
47 | { |
50 | cairo_status_t status = CAIRO_STATUS_SUCCESS; |
48 | cairo_surface_snapshot_t *surface = abstract_surface; |
51 | |
49 | cairo_status_t status = CAIRO_STATUS_SUCCESS; |
52 | TRACE ((stderr, "%s\n", __FUNCTION__)); |
Line 50... | Line 53... | ||
50 | 53 | ||
51 | if (surface->clone != NULL) { |
54 | if (surface->clone != NULL) { |
Line -... | Line 55... | ||
- | 55 | cairo_surface_finish (surface->clone); |
|
- | 56 | status = surface->clone->status; |
|
52 | cairo_surface_finish (surface->clone); |
57 | |
53 | status = surface->clone->status; |
58 | cairo_surface_destroy (surface->clone); |
Line 54... | Line 59... | ||
54 | 59 | } |
|
- | 60 | ||
- | 61 | CAIRO_MUTEX_FINI (surface->mutex); |
|
- | 62 | ||
- | 63 | return status; |
|
- | 64 | } |
|
- | 65 | ||
- | 66 | static cairo_status_t |
|
- | 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 | } |
|
55 | cairo_surface_destroy (surface->clone); |
87 | |
56 | } |
88 | struct snapshot_extra { |
57 | 89 | cairo_surface_t *target; |
|
58 | return status; |
90 | void *extra; |
59 | } |
91 | }; |
- | 92 | ||
- | 93 | static cairo_status_t |
|
- | 94 | _cairo_surface_snapshot_acquire_source_image (void *abstract_surface, |
|
- | 95 | cairo_image_surface_t **image_out, |
|
- | 96 | void **extra_out) |
|
- | 97 | { |
|
Line -... | Line 98... | ||
- | 98 | cairo_surface_snapshot_t *surface = abstract_surface; |
|
60 | 99 | struct snapshot_extra *extra; |
|
- | 100 | cairo_status_t status; |
|
- | 101 | ||
- | 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); |
|
61 | static cairo_status_t |
107 | status = _cairo_surface_acquire_source_image (extra->target, image_out, &extra->extra); |
Line 62... | Line 108... | ||
62 | _cairo_surface_snapshot_acquire_source_image (void *abstract_surface, |
108 | if (unlikely (status)) { |
63 | cairo_image_surface_t **image_out, |
109 | cairo_surface_destroy (extra->target); |
64 | void **extra_out) |
110 | free (extra); |
65 | { |
111 | } |
66 | cairo_surface_snapshot_t *surface = abstract_surface; |
112 | |
67 | 113 | *extra_out = extra; |
|
Line 68... | Line 114... | ||
68 | return _cairo_surface_acquire_source_image (surface->target, image_out, extra_out); |
114 | return status; |
- | 115 | } |
|
- | 116 | ||
69 | } |
117 | static void |
Line 70... | Line 118... | ||
70 | 118 | _cairo_surface_snapshot_release_source_image (void *abstract_surface, |
|
71 | static void |
119 | cairo_image_surface_t *image, |
72 | _cairo_surface_snapshot_release_source_image (void *abstract_surface, |
120 | void *_extra) |
73 | cairo_image_surface_t *image, |
121 | { |
74 | void *extra) |
122 | struct snapshot_extra *extra = _extra; |
- | 123 | ||
- | 124 | _cairo_surface_release_source_image (extra->target, image, extra->extra); |
|
- | 125 | cairo_surface_destroy (extra->target); |
|
- | 126 | free (extra); |
|
- | 127 | } |
|
- | 128 | ||
Line 75... | Line 129... | ||
75 | { |
129 | static cairo_bool_t |
76 | cairo_surface_snapshot_t *surface = abstract_surface; |
130 | _cairo_surface_snapshot_get_extents (void *abstract_surface, |
Line 77... | Line 131... | ||
77 | 131 | cairo_rectangle_int_t *extents) |
|
78 | _cairo_surface_release_source_image (surface->target, image, extra); |
132 | { |
- | 133 | cairo_surface_snapshot_t *surface = abstract_surface; |
|
- | 134 | cairo_surface_t *target; |
|
Line 79... | Line 135... | ||
79 | } |
135 | cairo_bool_t bounded; |
80 | 136 | ||
- | 137 | target = _cairo_surface_snapshot_get_target (&surface->base); |
|
- | 138 | bounded = _cairo_surface_get_extents (target, extents); |
|
Line -... | Line 139... | ||
- | 139 | cairo_surface_destroy (target); |
|
81 | static cairo_bool_t |
140 | |
82 | _cairo_surface_snapshot_get_extents (void *abstract_surface, |
141 | return bounded; |
83 | cairo_rectangle_int_t *extents) |
- | |
84 | { |
- | |
85 | cairo_surface_snapshot_t *surface = abstract_surface; |
142 | } |
86 | - | ||
87 | return _cairo_surface_get_extents (surface->target, extents); |
- | |
88 | } |
- | |
89 | - | ||
- | 143 | ||
90 | static const cairo_surface_backend_t _cairo_surface_snapshot_backend = { |
144 | static const cairo_surface_backend_t _cairo_surface_snapshot_backend = { |
91 | CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT, |
145 | CAIRO_INTERNAL_SURFACE_TYPE_SNAPSHOT, |
- | 146 | _cairo_surface_snapshot_finish, |
|
92 | 147 | NULL, |
|
- | 148 | ||
- | 149 | NULL, /* create similar */ |
|
- | 150 | NULL, /* create similar image */ |
|
93 | NULL, /* create similar */ |
151 | NULL, /* map to image */ |
Line 94... | Line 152... | ||
94 | _cairo_surface_snapshot_finish, |
152 | NULL, /* unmap image */ |
95 | 153 | ||
96 | _cairo_surface_snapshot_acquire_source_image, |
154 | _cairo_surface_snapshot_source, |
97 | _cairo_surface_snapshot_release_source_image, |
155 | _cairo_surface_snapshot_acquire_source_image, |
98 | NULL, NULL, /* acquire, release dest */ |
156 | _cairo_surface_snapshot_release_source_image, |
99 | NULL, /* clone similar */ |
157 | NULL, /* snapshot */ |
100 | NULL, /* composite */ |
158 | |
101 | NULL, /* fill rectangles */ |
159 | NULL, /* copy_page */ |
Line -... | Line 160... | ||
- | 160 | NULL, /* show_page */ |
|
- | 161 | ||
- | 162 | _cairo_surface_snapshot_get_extents, |
|
102 | NULL, /* composite trapezoids */ |
163 | NULL, /* get-font-options */ |
103 | NULL, /* create span renderer */ |
164 | |
104 | NULL, /* check span renderer */ |
165 | _cairo_surface_snapshot_flush, |
105 | NULL, /* copy_page */ |
166 | }; |
106 | NULL, /* show_page */ |
167 | |
Line -... | Line 168... | ||
- | 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; |
|
- | 173 | cairo_surface_t *clone; |
|
- | 174 | void *extra; |
|
- | 175 | cairo_status_t status; |
|
- | 176 | ||
- | 177 | TRACE ((stderr, "%s: target=%d\n", |
|
- | 178 | __FUNCTION__, snapshot->target->unique_id)); |
|
- | 179 | ||
- | 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. |
|
107 | _cairo_surface_snapshot_get_extents, |
182 | * when we later need to use the snapshot the data may have already |
108 | }; |
183 | * been lost. |
109 | 184 | */ |
|
110 | static void |
185 | |
111 | _cairo_surface_snapshot_copy_on_write (cairo_surface_t *surface) |
186 | CAIRO_MUTEX_LOCK (snapshot->mutex); |
112 | { |
- | |
113 | 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 | status = _cairo_surface_acquire_source_image (snapshot->target, &image, &extra); |
- | |
126 | if (unlikely (status)) { |
- | |
127 | snapshot->target = _cairo_surface_create_in_error (status); |
- | |
128 | status = _cairo_surface_set_error (surface, status); |
- | |
129 | return; |
- | |
130 | } |
- | |
131 | - | ||
132 | clone = (cairo_image_surface_t *) |
- | |
133 | _cairo_image_surface_create_with_pixman_format (NULL, |
- | |
134 | image->pixman_format, |
- | |
135 | image->width, |
- | |
136 | image->height, |
- | |
137 | 0); |
187 | |
138 | if (likely (clone->base.status == CAIRO_STATUS_SUCCESS)) { |
- | |
- | 188 | if (snapshot->target->backend->snapshot != NULL) { |
|
139 | if (clone->stride == image->stride) { |
189 | clone = snapshot->target->backend->snapshot (snapshot->target); |
- | 190 | if (clone != NULL) { |
|
- | 191 | assert (clone->status || ! _cairo_surface_is_snapshot (clone)); |
|
- | 192 | goto done; |
|
140 | memcpy (clone->data, image->data, image->stride * image->height); |
193 | } |
141 | } else { |
194 | } |
- | 195 | ||
- | 196 | /* XXX copy to a similar surface, leave acquisition till later? |
|
142 | pixman_image_composite32 (PIXMAN_OP_SRC, |
197 | * We should probably leave such decisions to the backend in case we |
Line 143... | Line 198... | ||
143 | image->pixman_image, NULL, clone->pixman_image, |
198 | * rely upon devices/connections like Xlib. |
144 | 0, 0, |
199 | */ |
145 | 0, 0, |
200 | status = _cairo_surface_acquire_source_image (snapshot->target, &image, &extra); |
146 | 0, 0, |
201 | if (unlikely (status)) { |
147 | image->width, image->height); |
202 | snapshot->target = _cairo_surface_create_in_error (status); |
148 | } |
203 | status = _cairo_surface_set_error (surface, status); |
149 | clone->base.is_clear = FALSE; |
204 | goto unlock; |
Line 182... | Line 237... | ||
182 | _cairo_surface_snapshot (cairo_surface_t *surface) |
237 | _cairo_surface_snapshot (cairo_surface_t *surface) |
183 | { |
238 | { |
184 | cairo_surface_snapshot_t *snapshot; |
239 | cairo_surface_snapshot_t *snapshot; |
185 | cairo_status_t status; |
240 | cairo_status_t status; |
Line -... | Line 241... | ||
- | 241 | ||
- | 242 | TRACE ((stderr, "%s: target=%d\n", __FUNCTION__, surface->unique_id)); |
|
186 | 243 | ||
187 | if (unlikely (surface->status)) |
244 | if (unlikely (surface->status)) |
Line 188... | Line 245... | ||
188 | return _cairo_surface_create_in_error (surface->status); |
245 | return _cairo_surface_create_in_error (surface->status); |
189 | 246 | ||
Line 190... | Line 247... | ||
190 | if (surface->finished) |
247 | if (unlikely (surface->finished)) |
191 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); |
248 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); |
Line 192... | Line -... | ||
192 | - | ||
193 | if (surface->snapshot_of != NULL) |
- | |
194 | return cairo_surface_reference (surface); |
- | |
195 | 249 | ||
196 | if (surface->backend->snapshot != NULL) { |
- | |
197 | cairo_surface_t *snap; |
250 | if (surface->snapshot_of != NULL) |
198 | - | ||
199 | snap = _cairo_surface_has_snapshot (surface, surface->backend); |
- | |
200 | if (snap != NULL) |
- | |
201 | return cairo_surface_reference (snap); |
- | |
202 | - | ||
203 | snap = surface->backend->snapshot (surface); |
- | |
204 | if (snap != NULL) { |
- | |
205 | if (unlikely (snap->status)) |
- | |
206 | return snap; |
- | |
207 | - | ||
208 | status = _cairo_surface_copy_mime_data (snap, surface); |
- | |
209 | if (unlikely (status)) { |
- | |
210 | cairo_surface_destroy (snap); |
- | |
211 | return _cairo_surface_create_in_error (status); |
- | |
212 | } |
- | |
213 | - | ||
214 | snap->device_transform = surface->device_transform; |
- | |
215 | snap->device_transform_inverse = surface->device_transform_inverse; |
- | |
216 | - | ||
217 | _cairo_surface_attach_snapshot (surface, snap, NULL); |
- | |
Line 218... | Line 251... | ||
218 | 251 | return cairo_surface_reference (surface); |
|
219 | return snap; |
252 | |
220 | } |
253 | if (_cairo_surface_is_snapshot (surface)) |
221 | } |
254 | return cairo_surface_reference (surface); |
Line 233... | Line 266... | ||
233 | &_cairo_surface_snapshot_backend, |
266 | &_cairo_surface_snapshot_backend, |
234 | NULL, /* device */ |
267 | NULL, /* device */ |
235 | surface->content); |
268 | surface->content); |
236 | snapshot->base.type = surface->type; |
269 | snapshot->base.type = surface->type; |
Line -... | Line 270... | ||
- | 270 | ||
237 | 271 | CAIRO_MUTEX_INIT (snapshot->mutex); |
|
238 | snapshot->target = surface; |
272 | snapshot->target = surface; |
Line 239... | Line 273... | ||
239 | snapshot->clone = NULL; |
273 | snapshot->clone = NULL; |
240 | 274 |