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 33... | Line 33... | ||
33 | * Chris Wilson |
33 | * Chris Wilson |
34 | */ |
34 | */ |
Line 35... | Line 35... | ||
35 | 35 | ||
Line -... | Line 36... | ||
- | 36 | #include "cairoint.h" |
|
36 | #include "cairoint.h" |
37 | |
- | 38 | #include "cairo-clip-inline.h" |
|
37 | 39 | #include "cairo-error-private.h" |
|
38 | #include "cairo-error-private.h" |
40 | #include "cairo-image-surface-private.h" |
- | 41 | #include "cairo-recording-surface-private.h" |
|
39 | #include "cairo-recording-surface-private.h" |
42 | #include "cairo-surface-offset-private.h" |
Line 40... | Line 43... | ||
40 | #include "cairo-surface-offset-private.h" |
43 | #include "cairo-surface-snapshot-private.h" |
Line 41... | Line 44... | ||
41 | #include "cairo-surface-subsurface-private.h" |
44 | #include "cairo-surface-subsurface-private.h" |
42 | 45 | ||
43 | static const cairo_surface_backend_t _cairo_surface_subsurface_backend; |
46 | static const cairo_surface_backend_t _cairo_surface_subsurface_backend; |
44 | 47 | ||
Line 45... | Line 48... | ||
45 | static cairo_status_t |
48 | static cairo_status_t |
- | 49 | _cairo_surface_subsurface_finish (void *abstract_surface) |
|
Line 46... | Line 50... | ||
46 | _cairo_surface_subsurface_finish (void *abstract_surface) |
50 | { |
47 | { |
51 | cairo_surface_subsurface_t *surface = abstract_surface; |
Line 48... | Line 52... | ||
48 | cairo_surface_subsurface_t *surface = abstract_surface; |
52 | |
49 | 53 | cairo_surface_destroy (surface->target); |
|
50 | cairo_surface_destroy (surface->target); |
54 | cairo_surface_destroy (surface->snapshot); |
51 | 55 | ||
52 | return CAIRO_STATUS_SUCCESS; |
56 | return CAIRO_STATUS_SUCCESS; |
53 | } |
57 | } |
- | 58 | ||
- | 59 | static cairo_surface_t * |
|
- | 60 | _cairo_surface_subsurface_create_similar (void *other, |
|
- | 61 | cairo_content_t content, |
|
54 | 62 | int width, int height) |
|
55 | static cairo_surface_t * |
63 | { |
Line -... | Line 64... | ||
- | 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 | ||
56 | _cairo_surface_subsurface_create_similar (void *other, |
102 | static cairo_int_status_t |
57 | cairo_content_t content, |
103 | _cairo_surface_subsurface_unmap_image (void *abstract_surface, |
58 | int width, int height) |
104 | cairo_image_surface_t *image) |
59 | { |
105 | { |
60 | cairo_surface_subsurface_t *surface = other; |
106 | cairo_surface_subsurface_t *surface = abstract_surface; |
61 | return surface->target->backend->create_similar (surface->target, content, width, height); |
107 | return _cairo_surface_unmap_image (surface->target, image); |
62 | } |
108 | } |
63 | 109 | ||
64 | static cairo_int_status_t |
110 | static cairo_int_status_t |
65 | _cairo_surface_subsurface_paint (void *abstract_surface, |
111 | _cairo_surface_subsurface_paint (void *abstract_surface, |
66 | cairo_operator_t op, |
- | |
67 | const cairo_pattern_t *source, |
- | |
68 | cairo_clip_t *clip) |
- | |
69 | { |
- | |
70 | cairo_surface_subsurface_t *surface = abstract_surface; |
- | |
Line -... | Line 112... | ||
- | 112 | cairo_operator_t op, |
|
71 | cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; |
113 | const cairo_pattern_t *source, |
72 | cairo_status_t status; |
114 | const cairo_clip_t *clip) |
73 | cairo_clip_t target_clip; |
115 | { |
74 | - | ||
75 | _cairo_clip_init_copy (&target_clip, clip); |
116 | cairo_surface_subsurface_t *surface = abstract_surface; |
76 | status = _cairo_clip_rectangle (&target_clip, &rect); |
117 | cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; |
77 | if (unlikely (status)) |
118 | cairo_status_t status; |
Line 78... | Line 119... | ||
78 | goto CLEANUP; |
119 | cairo_clip_t *target_clip; |
79 | 120 | ||
80 | status = _cairo_surface_offset_paint (surface->target, |
121 | target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect); |
81 | -surface->extents.x, -surface->extents.y, |
122 | status = _cairo_surface_offset_paint (surface->target, |
82 | op, source, &target_clip); |
123 | -surface->extents.x, -surface->extents.y, |
83 | CLEANUP: |
124 | op, source, target_clip); |
84 | _cairo_clip_fini (&target_clip); |
125 | _cairo_clip_destroy (target_clip); |
85 | return status; |
126 | return status; |
86 | } |
127 | } |
87 | 128 | ||
88 | static cairo_int_status_t |
129 | static cairo_int_status_t |
89 | _cairo_surface_subsurface_mask (void *abstract_surface, |
- | |
90 | cairo_operator_t op, |
- | |
91 | const cairo_pattern_t *source, |
- | |
92 | const cairo_pattern_t *mask, |
- | |
93 | cairo_clip_t *clip) |
- | |
Line -... | Line 130... | ||
- | 130 | _cairo_surface_subsurface_mask (void *abstract_surface, |
|
94 | { |
131 | cairo_operator_t op, |
95 | cairo_surface_subsurface_t *surface = abstract_surface; |
132 | const cairo_pattern_t *source, |
96 | cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; |
133 | const cairo_pattern_t *mask, |
97 | cairo_status_t status; |
- | |
98 | cairo_clip_t target_clip; |
134 | const cairo_clip_t *clip) |
99 | 135 | { |
|
100 | _cairo_clip_init_copy (&target_clip, clip); |
136 | cairo_surface_subsurface_t *surface = abstract_surface; |
Line 101... | Line 137... | ||
101 | status = _cairo_clip_rectangle (&target_clip, &rect); |
137 | cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; |
102 | if (unlikely (status)) |
138 | cairo_status_t status; |
103 | goto CLEANUP; |
139 | cairo_clip_t *target_clip; |
104 | 140 | ||
105 | status = _cairo_surface_offset_mask (surface->target, |
141 | target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect); |
106 | -surface->extents.x, -surface->extents.y, |
142 | status = _cairo_surface_offset_mask (surface->target, |
107 | op, source, mask, &target_clip); |
143 | -surface->extents.x, -surface->extents.y, |
108 | CLEANUP: |
144 | op, source, mask, target_clip); |
109 | _cairo_clip_fini (&target_clip); |
145 | _cairo_clip_destroy (target_clip); |
110 | return status; |
146 | return status; |
111 | } |
147 | } |
112 | 148 | ||
113 | static cairo_int_status_t |
149 | static cairo_int_status_t |
114 | _cairo_surface_subsurface_fill (void *abstract_surface, |
150 | _cairo_surface_subsurface_fill (void *abstract_surface, |
115 | cairo_operator_t op, |
- | |
116 | const cairo_pattern_t *source, |
- | |
117 | cairo_path_fixed_t *path, |
- | |
118 | cairo_fill_rule_t fill_rule, |
- | |
119 | double tolerance, |
- | |
Line -... | Line 151... | ||
- | 151 | cairo_operator_t op, |
|
120 | cairo_antialias_t antialias, |
152 | const cairo_pattern_t *source, |
121 | cairo_clip_t *clip) |
153 | const cairo_path_fixed_t *path, |
122 | { |
154 | cairo_fill_rule_t fill_rule, |
123 | cairo_surface_subsurface_t *surface = abstract_surface; |
155 | double tolerance, |
124 | cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; |
- | |
125 | cairo_status_t status; |
156 | cairo_antialias_t antialias, |
126 | cairo_clip_t target_clip; |
157 | const cairo_clip_t *clip) |
127 | 158 | { |
|
Line 128... | Line 159... | ||
128 | _cairo_clip_init_copy (&target_clip, clip); |
159 | cairo_surface_subsurface_t *surface = abstract_surface; |
129 | status = _cairo_clip_rectangle (&target_clip, &rect); |
160 | cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; |
130 | if (unlikely (status)) |
161 | cairo_status_t status; |
131 | goto CLEANUP; |
162 | cairo_clip_t *target_clip; |
132 | 163 | ||
133 | status = _cairo_surface_offset_fill (surface->target, |
164 | target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect); |
134 | -surface->extents.x, -surface->extents.y, |
165 | status = _cairo_surface_offset_fill (surface->target, |
135 | op, source, path, fill_rule, tolerance, antialias, |
166 | -surface->extents.x, -surface->extents.y, |
136 | &target_clip); |
167 | op, source, path, fill_rule, tolerance, antialias, |
137 | CLEANUP: |
168 | target_clip); |
138 | _cairo_clip_fini (&target_clip); |
169 | _cairo_clip_destroy (target_clip); |
139 | return status; |
170 | return status; |
140 | } |
171 | } |
141 | 172 | ||
142 | static cairo_int_status_t |
173 | static cairo_int_status_t |
143 | _cairo_surface_subsurface_stroke (void *abstract_surface, |
174 | _cairo_surface_subsurface_stroke (void *abstract_surface, |
144 | cairo_operator_t op, |
- | |
145 | const cairo_pattern_t *source, |
- | |
146 | cairo_path_fixed_t *path, |
- | |
147 | const cairo_stroke_style_t *stroke_style, |
- | |
148 | const cairo_matrix_t *ctm, |
- | |
Line -... | Line 175... | ||
- | 175 | cairo_operator_t op, |
|
149 | const cairo_matrix_t *ctm_inverse, |
176 | const cairo_pattern_t *source, |
150 | double tolerance, |
177 | const cairo_path_fixed_t *path, |
151 | cairo_antialias_t antialias, |
178 | const cairo_stroke_style_t *stroke_style, |
152 | cairo_clip_t *clip) |
179 | const cairo_matrix_t *ctm, |
153 | { |
180 | const cairo_matrix_t *ctm_inverse, |
154 | cairo_surface_subsurface_t *surface = abstract_surface; |
- | |
155 | cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; |
181 | double tolerance, |
156 | cairo_status_t status; |
182 | cairo_antialias_t antialias, |
157 | cairo_clip_t target_clip; |
183 | const cairo_clip_t *clip) |
Line 158... | Line 184... | ||
158 | 184 | { |
|
159 | _cairo_clip_init_copy (&target_clip, clip); |
185 | cairo_surface_subsurface_t *surface = abstract_surface; |
160 | status = _cairo_clip_rectangle (&target_clip, &rect); |
186 | cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; |
161 | if (unlikely (status)) |
187 | cairo_status_t status; |
162 | goto CLEANUP; |
188 | cairo_clip_t *target_clip; |
163 | 189 | ||
164 | status = _cairo_surface_offset_stroke (surface->target, |
190 | target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect); |
165 | -surface->extents.x, -surface->extents.y, |
191 | status = _cairo_surface_offset_stroke (surface->target, |
166 | op, source, path, stroke_style, ctm, ctm_inverse, |
- | |
167 | tolerance, antialias, |
192 | -surface->extents.x, -surface->extents.y, |
168 | &target_clip); |
193 | op, source, path, stroke_style, ctm, ctm_inverse, |
169 | CLEANUP: |
194 | tolerance, antialias, |
170 | _cairo_clip_fini (&target_clip); |
195 | target_clip); |
171 | return status; |
196 | _cairo_clip_destroy (target_clip); |
172 | } |
- | |
173 | - | ||
174 | static cairo_int_status_t |
- | |
175 | _cairo_surface_subsurface_glyphs (void *abstract_surface, |
- | |
176 | cairo_operator_t op, |
- | |
Line -... | Line 197... | ||
- | 197 | return status; |
|
177 | const cairo_pattern_t *source, |
198 | } |
178 | cairo_glyph_t *glyphs, |
199 | |
179 | int num_glyphs, |
200 | static cairo_int_status_t |
180 | cairo_scaled_font_t *scaled_font, |
201 | _cairo_surface_subsurface_glyphs (void *abstract_surface, |
181 | cairo_clip_t *clip, |
202 | cairo_operator_t op, |
182 | int *remaining_glyphs) |
- | |
183 | { |
- | |
184 | cairo_surface_subsurface_t *surface = abstract_surface; |
203 | const cairo_pattern_t *source, |
185 | cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; |
204 | cairo_glyph_t *glyphs, |
186 | cairo_status_t status; |
205 | int num_glyphs, |
Line 187... | Line 206... | ||
187 | cairo_clip_t target_clip; |
206 | cairo_scaled_font_t *scaled_font, |
188 | 207 | const cairo_clip_t *clip) |
|
189 | _cairo_clip_init_copy (&target_clip, clip); |
208 | { |
190 | status = _cairo_clip_rectangle (&target_clip, &rect); |
209 | cairo_surface_subsurface_t *surface = abstract_surface; |
191 | if (unlikely (status)) |
- | |
192 | goto CLEANUP; |
- | |
193 | - | ||
194 | status = _cairo_surface_offset_glyphs (surface->target, |
- | |
195 | -surface->extents.x, -surface->extents.y, |
210 | cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; |
196 | op, source, |
- | |
197 | scaled_font, glyphs, num_glyphs, |
- | |
198 | &target_clip); |
211 | cairo_status_t status; |
Line 199... | Line 212... | ||
199 | *remaining_glyphs = 0; |
212 | cairo_clip_t *target_clip; |
200 | CLEANUP: |
213 | |
201 | _cairo_clip_fini (&target_clip); |
214 | target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect); |
Line 269... | Line 282... | ||
269 | 282 | ||
270 | if (surface->target->backend->get_font_options != NULL) |
283 | if (surface->target->backend->get_font_options != NULL) |
271 | surface->target->backend->get_font_options (surface->target, options); |
284 | surface->target->backend->get_font_options (surface->target, options); |
Line 272... | Line -... | ||
272 | } |
- | |
273 | 285 | } |
|
274 | struct extra { |
- | |
275 | cairo_image_surface_t *image; |
- | |
276 | void *image_extra; |
- | |
277 | }; |
- | |
278 | 286 | ||
279 | static void |
287 | static cairo_surface_t * |
280 | cairo_surface_paint_to_target (cairo_surface_t *target, |
288 | _cairo_surface_subsurface_source (void *abstract_surface, |
281 | cairo_surface_subsurface_t *subsurface) |
289 | cairo_rectangle_int_t *extents) |
282 | { |
- | |
283 | cairo_t *cr; |
290 | { |
Line 284... | Line -... | ||
284 | - | ||
285 | cr = cairo_create (target); |
291 | cairo_surface_subsurface_t *surface = abstract_surface; |
286 | 292 | cairo_surface_t *source; |
|
287 | cairo_set_source_surface (cr, |
293 | |
288 | subsurface->target, |
- | |
289 | - subsurface->extents.x, |
- | |
Line 290... | Line 294... | ||
290 | - subsurface->extents.y); |
294 | source = _cairo_surface_get_source (surface->target, extents); |
291 | cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); |
295 | if (extents) |
Line 292... | Line 296... | ||
292 | cairo_paint (cr); |
296 | *extents = surface->extents; |
293 | 297 | ||
294 | cairo_destroy (cr); |
298 | return source; |
295 | } |
299 | } |
296 | 300 | ||
297 | static cairo_status_t |
- | |
298 | _cairo_surface_subsurface_acquire_source_image (void *abstract_surface, |
301 | static cairo_status_t |
- | 302 | _cairo_surface_subsurface_acquire_source_image (void *abstract_surface, |
|
299 | cairo_image_surface_t **image_out, |
303 | cairo_image_surface_t **image_out, |
300 | void **extra_out) |
304 | void **extra_out) |
301 | { |
- | |
302 | cairo_rectangle_int_t target_extents; |
- | |
303 | cairo_surface_subsurface_t *surface = abstract_surface; |
- | |
304 | cairo_image_surface_t *image; |
- | |
305 | cairo_status_t status; |
- | |
306 | struct extra *extra; |
- | |
307 | uint8_t *data; |
- | |
308 | cairo_bool_t ret; |
- | |
309 | - | ||
310 | if (surface->target->type == CAIRO_SURFACE_TYPE_RECORDING) { |
- | |
311 | cairo_recording_surface_t *meta = (cairo_recording_surface_t *) surface->target; |
- | |
312 | cairo_surface_t *snapshot; |
- | |
313 | - | ||
314 | snapshot = _cairo_surface_has_snapshot (&surface->base, |
- | |
315 | &_cairo_image_surface_backend); |
- | |
Line 316... | Line -... | ||
316 | if (snapshot != NULL) { |
- | |
317 | *image_out = (cairo_image_surface_t *) cairo_surface_reference (snapshot); |
- | |
318 | *extra_out = NULL; |
- | |
319 | return CAIRO_STATUS_SUCCESS; |
- | |
320 | } |
305 | { |
321 | 306 | cairo_surface_subsurface_t *surface = abstract_surface; |
|
322 | if (! _cairo_surface_has_snapshot (&meta->base, |
307 | cairo_surface_pattern_t pattern; |
323 | &_cairo_image_surface_backend)) |
308 | cairo_surface_t *image; |
324 | { |
309 | cairo_status_t status; |
325 | image = (cairo_image_surface_t *) |
- | |
326 | _cairo_image_surface_create_with_content (meta->content, |
- | |
327 | surface->extents.width, |
- | |
328 | surface->extents.height); |
- | |
329 | if (unlikely (image->base.status)) |
- | |
330 | return image->base.status; |
- | |
331 | - | ||
332 | cairo_surface_paint_to_target (&image->base, surface); |
- | |
333 | - | ||
334 | _cairo_surface_attach_snapshot (&surface->base, &image->base, NULL); |
- | |
335 | - | ||
336 | *image_out = image; |
- | |
337 | *extra_out = NULL; |
- | |
338 | return CAIRO_STATUS_SUCCESS; |
- | |
339 | } |
- | |
340 | } |
- | |
341 | - | ||
342 | extra = malloc (sizeof (struct extra)); |
- | |
343 | if (unlikely (extra == NULL)) |
- | |
344 | return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
- | |
345 | - | ||
346 | status = _cairo_surface_acquire_source_image (surface->target, &extra->image, &extra->image_extra); |
- | |
347 | if (unlikely (status)) |
- | |
348 | goto CLEANUP; |
- | |
349 | - | ||
350 | ret = _cairo_surface_get_extents (&extra->image->base, &target_extents); |
- | |
351 | assert (ret); |
- | |
352 | - | ||
353 | /* only copy if we need to perform sub-byte manipulation */ |
- | |
354 | if (PIXMAN_FORMAT_BPP (extra->image->pixman_format) >= 8 && |
- | |
355 | target_extents.x <= surface->extents.x && |
- | |
356 | target_extents.y <= surface->extents.y && |
- | |
357 | surface->extents.x + surface->extents.width <= target_extents.x + target_extents.width && |
- | |
358 | surface->extents.y + surface->extents.height <= target_extents.y + target_extents.height) { |
- | |
359 | - | ||
360 | assert ((PIXMAN_FORMAT_BPP (extra->image->pixman_format) % 8) == 0); |
- | |
361 | - | ||
362 | data = extra->image->data + surface->extents.y * extra->image->stride; |
- | |
363 | data += PIXMAN_FORMAT_BPP (extra->image->pixman_format) / 8 * surface->extents.x; |
- | |
364 | - | ||
365 | image = (cairo_image_surface_t *) |
- | |
366 | _cairo_image_surface_create_with_pixman_format (data, |
- | |
367 | extra->image->pixman_format, |
- | |
368 | surface->extents.width, |
- | |
369 | surface->extents.height, |
- | |
370 | extra->image->stride); |
- | |
371 | if (unlikely ((status = image->base.status))) |
- | |
372 | goto CLEANUP_IMAGE; |
- | |
373 | - | ||
374 | image->base.is_clear = FALSE; |
- | |
375 | } else { |
- | |
376 | image = (cairo_image_surface_t *) |
- | |
377 | _cairo_image_surface_create_with_pixman_format (NULL, |
- | |
Line 378... | Line 310... | ||
378 | extra->image->pixman_format, |
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; |
|
379 | surface->extents.width, |
322 | status = _cairo_surface_paint (image, |
Line 380... | Line 323... | ||
380 | surface->extents.height, |
323 | CAIRO_OPERATOR_SOURCE, |
381 | 0); |
324 | &pattern.base, NULL); |
382 | if (unlikely ((status = image->base.status))) |
325 | _cairo_pattern_fini (&pattern.base); |
383 | goto CLEANUP_IMAGE; |
- | |
384 | - | ||
385 | cairo_surface_paint_to_target (&image->base, surface); |
- | |
386 | } |
- | |
387 | - | ||
388 | *image_out = image; |
- | |
389 | *extra_out = extra; |
326 | if (unlikely (status)) { |
Line 390... | Line 327... | ||
390 | return CAIRO_STATUS_SUCCESS; |
327 | cairo_surface_destroy (image); |
391 | 328 | return status; |
|
392 | CLEANUP_IMAGE: |
329 | } |
393 | _cairo_surface_release_source_image (surface->target, extra->image, extra->image_extra); |
330 | |
394 | CLEANUP: |
331 | *image_out = (cairo_image_surface_t *)image; |
395 | free (extra); |
- | |
396 | return status; |
- | |
397 | } |
- | |
398 | - | ||
399 | static void |
- | |
400 | _cairo_surface_subsurface_release_source_image (void *abstract_surface, |
- | |
401 | cairo_image_surface_t *image, |
- | |
402 | void *abstract_extra) |
- | |
403 | { |
- | |
404 | cairo_surface_subsurface_t *surface = abstract_surface; |
332 | *extra_out = NULL; |
405 | 333 | return CAIRO_STATUS_SUCCESS; |
|
Line 406... | Line 334... | ||
406 | if (abstract_extra != NULL) { |
334 | } |
407 | struct extra *extra = abstract_extra; |
335 | |
408 | 336 | static void |
|
409 | _cairo_surface_release_source_image (surface->target, extra->image, extra->image_extra); |
337 | _cairo_surface_subsurface_release_source_image (void *abstract_surface, |
410 | free (extra); |
338 | cairo_image_surface_t *image, |
- | 339 | void *abstract_extra) |
|
- | 340 | { |
|
Line 411... | Line 341... | ||
411 | } |
341 | cairo_surface_destroy (&image->base); |
412 | - | ||
413 | cairo_surface_destroy (&image->base); |
- | |
Line 414... | Line 342... | ||
414 | } |
342 | } |
415 | 343 | ||
416 | static cairo_surface_t * |
344 | static cairo_surface_t * |
417 | _cairo_surface_subsurface_snapshot (void *abstract_surface) |
345 | _cairo_surface_subsurface_snapshot (void *abstract_surface) |
418 | { |
- | |
419 | cairo_surface_subsurface_t *surface = abstract_surface; |
346 | { |
420 | cairo_surface_subsurface_t *snapshot; |
347 | cairo_surface_subsurface_t *surface = abstract_surface; |
Line -... | Line 348... | ||
- | 348 | cairo_surface_pattern_t pattern; |
|
- | 349 | cairo_surface_t *clone; |
|
- | 350 | cairo_status_t status; |
|
- | 351 | ||
421 | 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, |
|
422 | snapshot = malloc (sizeof (cairo_surface_subsurface_t)); |
357 | surface->extents.height); |
- | 358 | if (unlikely (clone->status)) |
|
423 | if (unlikely (snapshot == NULL)) |
359 | return clone; |
424 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); |
360 | |
Line 425... | Line -... | ||
425 | - | ||
426 | _cairo_surface_init (&snapshot->base, |
361 | _cairo_pattern_init_for_surface (&pattern, surface->target); |
- | 362 | cairo_matrix_init_translate (&pattern.base.matrix, |
|
Line -... | Line 363... | ||
- | 363 | surface->extents.x, surface->extents.y); |
|
- | 364 | pattern.base.filter = CAIRO_FILTER_NEAREST; |
|
- | 365 | status = _cairo_surface_paint (clone, |
|
427 | &_cairo_surface_subsurface_backend, |
366 | CAIRO_OPERATOR_SOURCE, |
- | 367 | &pattern.base, NULL); |
|
428 | NULL, /* device */ |
368 | _cairo_pattern_fini (&pattern.base); |
Line 429... | Line 369... | ||
429 | surface->target->content); |
369 | |
430 | snapshot->target = _cairo_surface_snapshot (surface->target); |
370 | if (unlikely (status)) { |
431 | if (unlikely (snapshot->target->status)) { |
- | |
432 | cairo_status_t status; |
371 | cairo_surface_destroy (clone); |
Line -... | Line 372... | ||
- | 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) |
|
433 | 380 | { |
|
434 | status = snapshot->target->status; |
381 | cairo_surface_subsurface_t *surface = target; |
435 | free (snapshot); |
- | |
436 | return _cairo_surface_create_in_error (status); |
- | |
437 | } |
- | |
438 | - | ||
439 | snapshot->base.type = snapshot->target->type; |
- | |
440 | snapshot->extents = surface->extents; |
382 | return surface->target->backend->create_context (&surface->base); |
441 | - | ||
- | 383 | } |
|
442 | return &snapshot->base; |
384 | |
443 | } |
385 | static const cairo_surface_backend_t _cairo_surface_subsurface_backend = { |
- | 386 | CAIRO_SURFACE_TYPE_SUBSURFACE, |
|
444 | 387 | _cairo_surface_subsurface_finish, |
|
445 | static const cairo_surface_backend_t _cairo_surface_subsurface_backend = { |
- | |
446 | CAIRO_SURFACE_TYPE_SUBSURFACE, |
388 | |
- | 389 | _cairo_surface_subsurface_create_context, |
|
447 | _cairo_surface_subsurface_create_similar, |
390 | |
448 | _cairo_surface_subsurface_finish, |
391 | _cairo_surface_subsurface_create_similar, |
449 | - | ||
450 | _cairo_surface_subsurface_acquire_source_image, |
- | |
Line 451... | Line 392... | ||
451 | _cairo_surface_subsurface_release_source_image, |
392 | _cairo_surface_subsurface_create_similar_image, |
452 | NULL, NULL, /* acquire, release dest */ |
393 | _cairo_surface_subsurface_map_to_image, |
453 | NULL, /* clone similar */ |
394 | _cairo_surface_subsurface_unmap_image, |
454 | NULL, /* composite */ |
395 | |
- | 396 | _cairo_surface_subsurface_source, |
|
455 | NULL, /* fill rectangles */ |
397 | _cairo_surface_subsurface_acquire_source_image, |
456 | NULL, /* composite trapezoids */ |
- | |
457 | NULL, /* create span renderer */ |
- | |
458 | NULL, /* check span renderer */ |
398 | _cairo_surface_subsurface_release_source_image, |
Line 459... | Line 399... | ||
459 | NULL, /* copy_page */ |
399 | _cairo_surface_subsurface_snapshot, |
460 | NULL, /* show_page */ |
400 | |
461 | _cairo_surface_subsurface_get_extents, |
401 | NULL, /* copy_page */ |
Line 511... | Line 451... | ||
511 | double x, double y, |
451 | double x, double y, |
512 | double width, double height) |
452 | double width, double height) |
513 | { |
453 | { |
514 | cairo_surface_subsurface_t *surface; |
454 | cairo_surface_subsurface_t *surface; |
Line -... | Line 455... | ||
- | 455 | ||
- | 456 | if (unlikely (width < 0 || height < 0)) |
|
- | 457 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); |
|
515 | 458 | ||
516 | if (unlikely (target->status)) |
459 | if (unlikely (target->status)) |
517 | return _cairo_surface_create_in_error (target->status); |
460 | return _cairo_surface_create_in_error (target->status); |
518 | if (unlikely (target->finished)) |
461 | if (unlikely (target->finished)) |
Line 534... | Line 477... | ||
534 | /* XXX forced integer alignment */ |
477 | /* XXX forced integer alignment */ |
535 | surface->extents.x = ceil (x); |
478 | surface->extents.x = ceil (x); |
536 | surface->extents.y = ceil (y); |
479 | surface->extents.y = ceil (y); |
537 | surface->extents.width = floor (x + width) - surface->extents.x; |
480 | surface->extents.width = floor (x + width) - surface->extents.x; |
538 | surface->extents.height = floor (y + height) - surface->extents.y; |
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; |
|
Line 539... | Line 484... | ||
539 | 484 | ||
540 | if (target->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { |
485 | if (target->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { |
541 | /* Maintain subsurfaces as 1-depth */ |
486 | /* Maintain subsurfaces as 1-depth */ |
542 | cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) target; |
487 | cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) target; |
543 | surface->extents.x += sub->extents.x; |
488 | surface->extents.x += sub->extents.x; |
544 | surface->extents.y += sub->extents.y; |
489 | surface->extents.y += sub->extents.y; |
545 | target = sub->target; |
490 | target = sub->target; |
Line 546... | Line 491... | ||
546 | } |
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; |
|
Line 547... | Line 531... | ||
547 | 531 | ||
548 | surface->target = cairo_surface_reference (target); |
532 | surface->snapshot = NULL; |
549 | 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 |