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 © 2009 Intel Corporation |
||
4 | * |
||
5 | * This library is free software; you can redistribute it and/or |
||
6 | * modify it either under the terms of the GNU Lesser General Public |
||
7 | * License version 2.1 as published by the Free Software Foundation |
||
8 | * (the "LGPL") or, at your option, under the terms of the Mozilla |
||
9 | * Public License Version 1.1 (the "MPL"). If you do not alter this |
||
10 | * notice, a recipient may use your version of this file under either |
||
11 | * the MPL or the LGPL. |
||
12 | * |
||
13 | * You should have received a copy of the LGPL along with this library |
||
14 | * in the file COPYING-LGPL-2.1; if not, write to the Free Software |
||
15 | * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA |
||
16 | * You should have received a copy of the MPL along with this library |
||
17 | * in the file COPYING-MPL-1.1 |
||
18 | * |
||
19 | * The contents of this file are subject to the Mozilla Public License |
||
20 | * Version 1.1 (the "License"); you may not use this file except in |
||
21 | * compliance with the License. You may obtain a copy of the License at |
||
22 | * http://www.mozilla.org/MPL/ |
||
23 | * |
||
24 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY |
||
25 | * OF ANY KIND, either express or implied. See the LGPL or the MPL for |
||
26 | * the specific language governing rights and limitations. |
||
27 | * |
||
28 | * The Original Code is the cairo graphics library. |
||
29 | * |
||
30 | * The Initial Developer of the Original Code is Intel Corporation. |
||
31 | * |
||
32 | * Contributor(s): |
||
33 | * Chris Wilson |
||
34 | */ |
||
35 | |||
36 | #include "cairoint.h" |
||
37 | |||
3959 | Serge | 38 | #include "cairo-clip-inline.h" |
1892 | serge | 39 | #include "cairo-error-private.h" |
3959 | Serge | 40 | #include "cairo-image-surface-private.h" |
1892 | serge | 41 | #include "cairo-recording-surface-private.h" |
42 | #include "cairo-surface-offset-private.h" |
||
3959 | Serge | 43 | #include "cairo-surface-snapshot-private.h" |
1892 | serge | 44 | #include "cairo-surface-subsurface-private.h" |
45 | |||
46 | static const cairo_surface_backend_t _cairo_surface_subsurface_backend; |
||
47 | |||
48 | static cairo_status_t |
||
49 | _cairo_surface_subsurface_finish (void *abstract_surface) |
||
50 | { |
||
51 | cairo_surface_subsurface_t *surface = abstract_surface; |
||
52 | |||
53 | cairo_surface_destroy (surface->target); |
||
3959 | Serge | 54 | cairo_surface_destroy (surface->snapshot); |
1892 | serge | 55 | |
56 | return CAIRO_STATUS_SUCCESS; |
||
57 | } |
||
58 | |||
59 | static cairo_surface_t * |
||
60 | _cairo_surface_subsurface_create_similar (void *other, |
||
61 | cairo_content_t content, |
||
62 | int width, int height) |
||
63 | { |
||
64 | cairo_surface_subsurface_t *surface = other; |
||
3959 | Serge | 65 | |
66 | if (surface->target->backend->create_similar == NULL) |
||
67 | return NULL; |
||
68 | |||
1892 | serge | 69 | return surface->target->backend->create_similar (surface->target, content, width, height); |
70 | } |
||
71 | |||
3959 | Serge | 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 | |||
1892 | serge | 102 | static cairo_int_status_t |
3959 | Serge | 103 | _cairo_surface_subsurface_unmap_image (void *abstract_surface, |
104 | cairo_image_surface_t *image) |
||
105 | { |
||
106 | cairo_surface_subsurface_t *surface = abstract_surface; |
||
107 | return _cairo_surface_unmap_image (surface->target, image); |
||
108 | } |
||
109 | |||
110 | static cairo_int_status_t |
||
1892 | serge | 111 | _cairo_surface_subsurface_paint (void *abstract_surface, |
112 | cairo_operator_t op, |
||
113 | const cairo_pattern_t *source, |
||
3959 | Serge | 114 | const cairo_clip_t *clip) |
1892 | serge | 115 | { |
116 | cairo_surface_subsurface_t *surface = abstract_surface; |
||
117 | cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; |
||
118 | cairo_status_t status; |
||
3959 | Serge | 119 | cairo_clip_t *target_clip; |
1892 | serge | 120 | |
3959 | Serge | 121 | target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect); |
1892 | serge | 122 | status = _cairo_surface_offset_paint (surface->target, |
123 | -surface->extents.x, -surface->extents.y, |
||
3959 | Serge | 124 | op, source, target_clip); |
125 | _cairo_clip_destroy (target_clip); |
||
1892 | serge | 126 | return status; |
127 | } |
||
128 | |||
129 | static cairo_int_status_t |
||
130 | _cairo_surface_subsurface_mask (void *abstract_surface, |
||
131 | cairo_operator_t op, |
||
132 | const cairo_pattern_t *source, |
||
133 | const cairo_pattern_t *mask, |
||
3959 | Serge | 134 | const cairo_clip_t *clip) |
1892 | serge | 135 | { |
136 | cairo_surface_subsurface_t *surface = abstract_surface; |
||
137 | cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; |
||
138 | cairo_status_t status; |
||
3959 | Serge | 139 | cairo_clip_t *target_clip; |
1892 | serge | 140 | |
3959 | Serge | 141 | target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect); |
1892 | serge | 142 | status = _cairo_surface_offset_mask (surface->target, |
143 | -surface->extents.x, -surface->extents.y, |
||
3959 | Serge | 144 | op, source, mask, target_clip); |
145 | _cairo_clip_destroy (target_clip); |
||
1892 | serge | 146 | return status; |
147 | } |
||
148 | |||
149 | static cairo_int_status_t |
||
150 | _cairo_surface_subsurface_fill (void *abstract_surface, |
||
151 | cairo_operator_t op, |
||
152 | const cairo_pattern_t *source, |
||
3959 | Serge | 153 | const cairo_path_fixed_t *path, |
1892 | serge | 154 | cairo_fill_rule_t fill_rule, |
155 | double tolerance, |
||
156 | cairo_antialias_t antialias, |
||
3959 | Serge | 157 | const cairo_clip_t *clip) |
1892 | serge | 158 | { |
159 | cairo_surface_subsurface_t *surface = abstract_surface; |
||
160 | cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; |
||
161 | cairo_status_t status; |
||
3959 | Serge | 162 | cairo_clip_t *target_clip; |
1892 | serge | 163 | |
3959 | Serge | 164 | target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect); |
1892 | serge | 165 | status = _cairo_surface_offset_fill (surface->target, |
166 | -surface->extents.x, -surface->extents.y, |
||
167 | op, source, path, fill_rule, tolerance, antialias, |
||
3959 | Serge | 168 | target_clip); |
169 | _cairo_clip_destroy (target_clip); |
||
1892 | serge | 170 | return status; |
171 | } |
||
172 | |||
173 | static cairo_int_status_t |
||
174 | _cairo_surface_subsurface_stroke (void *abstract_surface, |
||
175 | cairo_operator_t op, |
||
176 | const cairo_pattern_t *source, |
||
3959 | Serge | 177 | const cairo_path_fixed_t *path, |
1892 | serge | 178 | const cairo_stroke_style_t *stroke_style, |
179 | const cairo_matrix_t *ctm, |
||
180 | const cairo_matrix_t *ctm_inverse, |
||
181 | double tolerance, |
||
182 | cairo_antialias_t antialias, |
||
3959 | Serge | 183 | const cairo_clip_t *clip) |
1892 | serge | 184 | { |
185 | cairo_surface_subsurface_t *surface = abstract_surface; |
||
186 | cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; |
||
187 | cairo_status_t status; |
||
3959 | Serge | 188 | cairo_clip_t *target_clip; |
1892 | serge | 189 | |
3959 | Serge | 190 | target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect); |
1892 | serge | 191 | status = _cairo_surface_offset_stroke (surface->target, |
192 | -surface->extents.x, -surface->extents.y, |
||
193 | op, source, path, stroke_style, ctm, ctm_inverse, |
||
194 | tolerance, antialias, |
||
3959 | Serge | 195 | target_clip); |
196 | _cairo_clip_destroy (target_clip); |
||
1892 | serge | 197 | return status; |
198 | } |
||
199 | |||
200 | static cairo_int_status_t |
||
201 | _cairo_surface_subsurface_glyphs (void *abstract_surface, |
||
202 | cairo_operator_t op, |
||
203 | const cairo_pattern_t *source, |
||
204 | cairo_glyph_t *glyphs, |
||
205 | int num_glyphs, |
||
206 | cairo_scaled_font_t *scaled_font, |
||
3959 | Serge | 207 | const cairo_clip_t *clip) |
1892 | serge | 208 | { |
209 | cairo_surface_subsurface_t *surface = abstract_surface; |
||
210 | cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height }; |
||
211 | cairo_status_t status; |
||
3959 | Serge | 212 | cairo_clip_t *target_clip; |
1892 | serge | 213 | |
3959 | Serge | 214 | target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect); |
1892 | serge | 215 | status = _cairo_surface_offset_glyphs (surface->target, |
216 | -surface->extents.x, -surface->extents.y, |
||
217 | op, source, |
||
218 | scaled_font, glyphs, num_glyphs, |
||
3959 | Serge | 219 | target_clip); |
220 | _cairo_clip_destroy (target_clip); |
||
1892 | serge | 221 | return status; |
222 | } |
||
223 | |||
224 | static cairo_status_t |
||
3959 | Serge | 225 | _cairo_surface_subsurface_flush (void *abstract_surface, unsigned flags) |
1892 | serge | 226 | { |
227 | cairo_surface_subsurface_t *surface = abstract_surface; |
||
3959 | Serge | 228 | return _cairo_surface_flush (surface->target, flags); |
1892 | serge | 229 | } |
230 | |||
231 | static cairo_status_t |
||
232 | _cairo_surface_subsurface_mark_dirty (void *abstract_surface, |
||
233 | int x, int y, |
||
234 | int width, int height) |
||
235 | { |
||
236 | cairo_surface_subsurface_t *surface = abstract_surface; |
||
237 | cairo_status_t status; |
||
238 | |||
239 | status = CAIRO_STATUS_SUCCESS; |
||
240 | if (surface->target->backend->mark_dirty_rectangle != NULL) { |
||
241 | cairo_rectangle_int_t rect, extents; |
||
242 | |||
243 | rect.x = x; |
||
244 | rect.y = y; |
||
245 | rect.width = width; |
||
246 | rect.height = height; |
||
247 | |||
248 | extents.x = extents.y = 0; |
||
249 | extents.width = surface->extents.width; |
||
250 | extents.height = surface->extents.height; |
||
251 | |||
252 | if (_cairo_rectangle_intersect (&rect, &extents)) { |
||
253 | status = surface->target->backend->mark_dirty_rectangle (surface->target, |
||
254 | rect.x + surface->extents.x, |
||
255 | rect.y + surface->extents.y, |
||
256 | rect.width, rect.height); |
||
257 | } |
||
258 | } |
||
259 | |||
260 | return status; |
||
261 | } |
||
262 | |||
263 | static cairo_bool_t |
||
264 | _cairo_surface_subsurface_get_extents (void *abstract_surface, |
||
265 | cairo_rectangle_int_t *extents) |
||
266 | { |
||
267 | cairo_surface_subsurface_t *surface = abstract_surface; |
||
268 | |||
269 | extents->x = 0; |
||
270 | extents->y = 0; |
||
271 | extents->width = surface->extents.width; |
||
272 | extents->height = surface->extents.height; |
||
273 | |||
274 | return TRUE; |
||
275 | } |
||
276 | |||
277 | static void |
||
278 | _cairo_surface_subsurface_get_font_options (void *abstract_surface, |
||
279 | cairo_font_options_t *options) |
||
280 | { |
||
281 | cairo_surface_subsurface_t *surface = abstract_surface; |
||
282 | |||
283 | if (surface->target->backend->get_font_options != NULL) |
||
284 | surface->target->backend->get_font_options (surface->target, options); |
||
285 | } |
||
286 | |||
3959 | Serge | 287 | static cairo_surface_t * |
288 | _cairo_surface_subsurface_source (void *abstract_surface, |
||
289 | cairo_rectangle_int_t *extents) |
||
1892 | serge | 290 | { |
3959 | Serge | 291 | cairo_surface_subsurface_t *surface = abstract_surface; |
292 | cairo_surface_t *source; |
||
1892 | serge | 293 | |
3959 | Serge | 294 | source = _cairo_surface_get_source (surface->target, extents); |
295 | if (extents) |
||
296 | *extents = surface->extents; |
||
297 | |||
298 | return source; |
||
1892 | serge | 299 | } |
300 | |||
301 | static cairo_status_t |
||
302 | _cairo_surface_subsurface_acquire_source_image (void *abstract_surface, |
||
303 | cairo_image_surface_t **image_out, |
||
304 | void **extra_out) |
||
305 | { |
||
306 | cairo_surface_subsurface_t *surface = abstract_surface; |
||
3959 | Serge | 307 | cairo_surface_pattern_t pattern; |
308 | cairo_surface_t *image; |
||
1892 | serge | 309 | cairo_status_t status; |
310 | |||
3959 | Serge | 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; |
||
1892 | serge | 316 | |
3959 | Serge | 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; |
||
322 | status = _cairo_surface_paint (image, |
||
323 | CAIRO_OPERATOR_SOURCE, |
||
324 | &pattern.base, NULL); |
||
325 | _cairo_pattern_fini (&pattern.base); |
||
326 | if (unlikely (status)) { |
||
327 | cairo_surface_destroy (image); |
||
328 | return status; |
||
1892 | serge | 329 | } |
330 | |||
3959 | Serge | 331 | *image_out = (cairo_image_surface_t *)image; |
332 | *extra_out = NULL; |
||
1892 | serge | 333 | return CAIRO_STATUS_SUCCESS; |
334 | } |
||
335 | |||
336 | static void |
||
337 | _cairo_surface_subsurface_release_source_image (void *abstract_surface, |
||
338 | cairo_image_surface_t *image, |
||
339 | void *abstract_extra) |
||
340 | { |
||
341 | cairo_surface_destroy (&image->base); |
||
342 | } |
||
343 | |||
344 | static cairo_surface_t * |
||
345 | _cairo_surface_subsurface_snapshot (void *abstract_surface) |
||
346 | { |
||
347 | cairo_surface_subsurface_t *surface = abstract_surface; |
||
3959 | Serge | 348 | cairo_surface_pattern_t pattern; |
349 | cairo_surface_t *clone; |
||
350 | cairo_status_t status; |
||
1892 | serge | 351 | |
3959 | Serge | 352 | TRACE ((stderr, "%s: target=%d\n", __FUNCTION__, surface->target->unique_id)); |
1892 | serge | 353 | |
3959 | Serge | 354 | clone = _cairo_surface_create_similar_scratch (surface->target, |
355 | surface->target->content, |
||
356 | surface->extents.width, |
||
357 | surface->extents.height); |
||
358 | if (unlikely (clone->status)) |
||
359 | return clone; |
||
1892 | serge | 360 | |
3959 | Serge | 361 | _cairo_pattern_init_for_surface (&pattern, surface->target); |
362 | cairo_matrix_init_translate (&pattern.base.matrix, |
||
363 | surface->extents.x, surface->extents.y); |
||
364 | pattern.base.filter = CAIRO_FILTER_NEAREST; |
||
365 | status = _cairo_surface_paint (clone, |
||
366 | CAIRO_OPERATOR_SOURCE, |
||
367 | &pattern.base, NULL); |
||
368 | _cairo_pattern_fini (&pattern.base); |
||
369 | |||
370 | if (unlikely (status)) { |
||
371 | cairo_surface_destroy (clone); |
||
372 | clone = _cairo_surface_create_in_error (status); |
||
1892 | serge | 373 | } |
374 | |||
3959 | Serge | 375 | return clone; |
376 | } |
||
1892 | serge | 377 | |
3959 | Serge | 378 | static cairo_t * |
379 | _cairo_surface_subsurface_create_context(void *target) |
||
380 | { |
||
381 | cairo_surface_subsurface_t *surface = target; |
||
382 | return surface->target->backend->create_context (&surface->base); |
||
1892 | serge | 383 | } |
384 | |||
385 | static const cairo_surface_backend_t _cairo_surface_subsurface_backend = { |
||
386 | CAIRO_SURFACE_TYPE_SUBSURFACE, |
||
387 | _cairo_surface_subsurface_finish, |
||
388 | |||
3959 | Serge | 389 | _cairo_surface_subsurface_create_context, |
390 | |||
391 | _cairo_surface_subsurface_create_similar, |
||
392 | _cairo_surface_subsurface_create_similar_image, |
||
393 | _cairo_surface_subsurface_map_to_image, |
||
394 | _cairo_surface_subsurface_unmap_image, |
||
395 | |||
396 | _cairo_surface_subsurface_source, |
||
1892 | serge | 397 | _cairo_surface_subsurface_acquire_source_image, |
398 | _cairo_surface_subsurface_release_source_image, |
||
3959 | Serge | 399 | _cairo_surface_subsurface_snapshot, |
400 | |||
1892 | serge | 401 | NULL, /* copy_page */ |
402 | NULL, /* show_page */ |
||
3959 | Serge | 403 | |
1892 | serge | 404 | _cairo_surface_subsurface_get_extents, |
405 | _cairo_surface_subsurface_get_font_options, |
||
3959 | Serge | 406 | |
1892 | serge | 407 | _cairo_surface_subsurface_flush, |
408 | _cairo_surface_subsurface_mark_dirty, |
||
409 | |||
410 | _cairo_surface_subsurface_paint, |
||
411 | _cairo_surface_subsurface_mask, |
||
412 | _cairo_surface_subsurface_stroke, |
||
413 | _cairo_surface_subsurface_fill, |
||
3959 | Serge | 414 | NULL, /* fill/stroke */ |
1892 | serge | 415 | _cairo_surface_subsurface_glyphs, |
416 | }; |
||
417 | |||
418 | /** |
||
419 | * cairo_surface_create_for_rectangle: |
||
420 | * @target: an existing surface for which the sub-surface will point to |
||
421 | * @x: the x-origin of the sub-surface from the top-left of the target surface (in device-space units) |
||
422 | * @y: the y-origin of the sub-surface from the top-left of the target surface (in device-space units) |
||
423 | * @width: width of the sub-surface (in device-space units) |
||
424 | * @height: height of the sub-surface (in device-space units) |
||
425 | * |
||
426 | * Create a new surface that is a rectangle within the target surface. |
||
427 | * All operations drawn to this surface are then clipped and translated |
||
428 | * onto the target surface. Nothing drawn via this sub-surface outside of |
||
429 | * its bounds is drawn onto the target surface, making this a useful method |
||
430 | * for passing constrained child surfaces to library routines that draw |
||
431 | * directly onto the parent surface, i.e. with no further backend allocations, |
||
432 | * double buffering or copies. |
||
433 | * |
||
434 | * |
||
435 | * unless the rectangle is in full device units, is contained within |
||
436 | * the extents of the target surface, and the target or subsurface's |
||
437 | * device transforms are not changed. |
||
438 | * |
||
439 | * Return value: a pointer to the newly allocated surface. The caller |
||
440 | * owns the surface and should call cairo_surface_destroy() when done |
||
441 | * with it. |
||
442 | * |
||
443 | * This function always returns a valid pointer, but it will return a |
||
444 | * pointer to a "nil" surface if @other is already in an error state |
||
445 | * or any other error occurs. |
||
446 | * |
||
447 | * Since: 1.10 |
||
448 | **/ |
||
449 | cairo_surface_t * |
||
450 | cairo_surface_create_for_rectangle (cairo_surface_t *target, |
||
451 | double x, double y, |
||
452 | double width, double height) |
||
453 | { |
||
454 | cairo_surface_subsurface_t *surface; |
||
455 | |||
3959 | Serge | 456 | if (unlikely (width < 0 || height < 0)) |
457 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE)); |
||
458 | |||
1892 | serge | 459 | if (unlikely (target->status)) |
460 | return _cairo_surface_create_in_error (target->status); |
||
461 | if (unlikely (target->finished)) |
||
462 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED)); |
||
463 | |||
464 | surface = malloc (sizeof (cairo_surface_subsurface_t)); |
||
465 | if (unlikely (surface == NULL)) |
||
466 | return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); |
||
467 | |||
468 | assert (_cairo_matrix_is_translation (&target->device_transform)); |
||
469 | x += target->device_transform.x0; |
||
470 | y += target->device_transform.y0; |
||
471 | |||
472 | _cairo_surface_init (&surface->base, |
||
473 | &_cairo_surface_subsurface_backend, |
||
474 | NULL, /* device */ |
||
475 | target->content); |
||
476 | |||
477 | /* XXX forced integer alignment */ |
||
478 | surface->extents.x = ceil (x); |
||
479 | surface->extents.y = ceil (y); |
||
480 | surface->extents.width = floor (x + width) - surface->extents.x; |
||
481 | surface->extents.height = floor (y + height) - surface->extents.y; |
||
3959 | Serge | 482 | if ((surface->extents.width | surface->extents.height) < 0) |
483 | surface->extents.width = surface->extents.height = 0; |
||
1892 | serge | 484 | |
485 | if (target->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) { |
||
486 | /* Maintain subsurfaces as 1-depth */ |
||
487 | cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) target; |
||
488 | surface->extents.x += sub->extents.x; |
||
489 | surface->extents.y += sub->extents.y; |
||
490 | target = sub->target; |
||
491 | } |
||
492 | |||
493 | surface->target = cairo_surface_reference (target); |
||
3959 | Serge | 494 | surface->base.type = surface->target->type; |
1892 | serge | 495 | |
3959 | Serge | 496 | surface->snapshot = NULL; |
497 | |||
1892 | serge | 498 | return &surface->base; |
499 | } |
||
3959 | Serge | 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; |
||
531 | |||
532 | surface->snapshot = NULL; |
||
533 | |||
534 | return &surface->base; |
||
535 | } |
||
1892 | serge | 536 | /* XXX observe mark-dirty */ |
3959 | Serge | 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 | |||
569 | _cairo_surface_attach_snapshot (ss->target, &ss->base, |
||
570 | _cairo_surface_subsurface_detach_snapshot); |
||
571 | }>>> |