2bae01dbacfac7698ea2ce8126f313b4678af755
[framework/graphics/cairo.git] / src / cairo-surface-subsurface.c
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 <chris@chris-wilson.co.uk>
34  */
35
36 #include "cairoint.h"
37
38 #include "cairo-clip-inline.h"
39 #include "cairo-error-private.h"
40 #include "cairo-image-surface-private.h"
41 #include "cairo-recording-surface-private.h"
42 #include "cairo-surface-offset-private.h"
43 #include "cairo-surface-snapshot-private.h"
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);
54     cairo_surface_destroy (surface->snapshot);
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;
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_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     if (surface->target->backend->map_to_image == NULL)
95         return NULL;
96
97     target_extents.x = extents->x + surface->extents.x;
98     target_extents.y = extents->y + surface->extents.y;
99     target_extents.width  = extents->width;
100     target_extents.height = extents->height;
101
102     return surface->target->backend->map_to_image (surface->target,
103                                                    &target_extents);
104 }
105
106 static cairo_int_status_t
107 _cairo_surface_subsurface_unmap_image (void *abstract_surface,
108                                        cairo_image_surface_t *image)
109 {
110     cairo_surface_subsurface_t *surface = abstract_surface;
111
112     if (surface->target->backend->unmap_image == NULL)
113         return CAIRO_INT_STATUS_UNSUPPORTED;
114
115     return surface->target->backend->unmap_image (surface->target, image);
116 }
117
118 static cairo_int_status_t
119 _cairo_surface_subsurface_paint (void *abstract_surface,
120                                  cairo_operator_t op,
121                                  const cairo_pattern_t *source,
122                                  const cairo_clip_t *clip)
123 {
124     cairo_surface_subsurface_t *surface = abstract_surface;
125     cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
126     cairo_status_t status;
127     cairo_clip_t *target_clip;
128
129     target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect);
130     status = _cairo_surface_offset_paint (surface->target,
131                                          -surface->extents.x, -surface->extents.y,
132                                           op, source, target_clip);
133     _cairo_clip_destroy (target_clip);
134     return status;
135 }
136
137 static cairo_int_status_t
138 _cairo_surface_subsurface_mask (void *abstract_surface,
139                                 cairo_operator_t op,
140                                 const cairo_pattern_t *source,
141                                 const cairo_pattern_t *mask,
142                                 const cairo_clip_t *clip)
143 {
144     cairo_surface_subsurface_t *surface = abstract_surface;
145     cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
146     cairo_status_t status;
147     cairo_clip_t *target_clip;
148
149     target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect);
150     status = _cairo_surface_offset_mask (surface->target,
151                                          -surface->extents.x, -surface->extents.y,
152                                          op, source, mask, target_clip);
153     _cairo_clip_destroy (target_clip);
154     return status;
155 }
156
157 static cairo_int_status_t
158 _cairo_surface_subsurface_fill (void                    *abstract_surface,
159                                 cairo_operator_t         op,
160                                 const cairo_pattern_t   *source,
161                                 const cairo_path_fixed_t        *path,
162                                 cairo_fill_rule_t        fill_rule,
163                                 double                   tolerance,
164                                 cairo_antialias_t        antialias,
165                                 const cairo_clip_t              *clip)
166 {
167     cairo_surface_subsurface_t *surface = abstract_surface;
168     cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
169     cairo_status_t status;
170     cairo_clip_t *target_clip;
171
172     target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect);
173     status = _cairo_surface_offset_fill (surface->target,
174                                          -surface->extents.x, -surface->extents.y,
175                                          op, source, path, fill_rule, tolerance, antialias,
176                                          target_clip);
177     _cairo_clip_destroy (target_clip);
178     return status;
179 }
180
181 static cairo_int_status_t
182 _cairo_surface_subsurface_stroke (void                          *abstract_surface,
183                                   cairo_operator_t               op,
184                                   const cairo_pattern_t         *source,
185                                   const cairo_path_fixed_t              *path,
186                                   const cairo_stroke_style_t    *stroke_style,
187                                   const cairo_matrix_t          *ctm,
188                                   const cairo_matrix_t          *ctm_inverse,
189                                   double                         tolerance,
190                                   cairo_antialias_t              antialias,
191                                   const cairo_clip_t                    *clip)
192 {
193     cairo_surface_subsurface_t *surface = abstract_surface;
194     cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
195     cairo_status_t status;
196     cairo_clip_t *target_clip;
197
198     target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect);
199     status = _cairo_surface_offset_stroke (surface->target,
200                                            -surface->extents.x, -surface->extents.y,
201                                            op, source, path, stroke_style, ctm, ctm_inverse,
202                                            tolerance, antialias,
203                                            target_clip);
204     _cairo_clip_destroy (target_clip);
205     return status;
206 }
207
208 static cairo_int_status_t
209 _cairo_surface_subsurface_glyphs (void                  *abstract_surface,
210                                   cairo_operator_t       op,
211                                   const cairo_pattern_t *source,
212                                   cairo_glyph_t         *glyphs,
213                                   int                    num_glyphs,
214                                   cairo_scaled_font_t   *scaled_font,
215                                   const cairo_clip_t    *clip)
216 {
217     cairo_surface_subsurface_t *surface = abstract_surface;
218     cairo_rectangle_int_t rect = { 0, 0, surface->extents.width, surface->extents.height };
219     cairo_status_t status;
220     cairo_clip_t *target_clip;
221
222     target_clip = _cairo_clip_copy_intersect_rectangle (clip, &rect);
223     status = _cairo_surface_offset_glyphs (surface->target,
224                                            -surface->extents.x, -surface->extents.y,
225                                            op, source,
226                                            scaled_font, glyphs, num_glyphs,
227                                            target_clip);
228     _cairo_clip_destroy (target_clip);
229     return status;
230 }
231
232 static cairo_status_t
233 _cairo_surface_subsurface_flush (void *abstract_surface)
234 {
235     cairo_surface_subsurface_t *surface = abstract_surface;
236
237     cairo_surface_flush (surface->target);
238     return surface->target->status;
239 }
240
241 static cairo_status_t
242 _cairo_surface_subsurface_mark_dirty (void *abstract_surface,
243                                       int x, int y,
244                                       int width, int height)
245 {
246     cairo_surface_subsurface_t *surface = abstract_surface;
247     cairo_status_t status;
248
249     status = CAIRO_STATUS_SUCCESS;
250     if (surface->target->backend->mark_dirty_rectangle != NULL) {
251         cairo_rectangle_int_t rect, extents;
252
253         rect.x = x;
254         rect.y = y;
255         rect.width  = width;
256         rect.height = height;
257
258         extents.x = extents.y = 0;
259         extents.width  = surface->extents.width;
260         extents.height = surface->extents.height;
261
262         if (_cairo_rectangle_intersect (&rect, &extents)) {
263             status = surface->target->backend->mark_dirty_rectangle (surface->target,
264                                                                      rect.x + surface->extents.x,
265                                                                      rect.y + surface->extents.y,
266                                                                      rect.width, rect.height);
267         }
268     }
269
270     return status;
271 }
272
273 static cairo_bool_t
274 _cairo_surface_subsurface_get_extents (void *abstract_surface,
275                                        cairo_rectangle_int_t *extents)
276 {
277     cairo_surface_subsurface_t *surface = abstract_surface;
278
279     extents->x = 0;
280     extents->y = 0;
281     extents->width  = surface->extents.width;
282     extents->height = surface->extents.height;
283
284     return TRUE;
285 }
286
287 static void
288 _cairo_surface_subsurface_get_font_options (void *abstract_surface,
289                                             cairo_font_options_t *options)
290 {
291     cairo_surface_subsurface_t *surface = abstract_surface;
292
293     if (surface->target->backend->get_font_options != NULL)
294         surface->target->backend->get_font_options (surface->target, options);
295 }
296
297 static cairo_surface_t *
298 _cairo_surface_subsurface_source (void *abstract_surface,
299                                   cairo_rectangle_int_t *extents)
300 {
301     cairo_surface_subsurface_t *surface = abstract_surface;
302     cairo_surface_t *source;
303
304     source = _cairo_surface_get_source (surface->target, extents);
305     if (extents)
306         *extents = surface->extents;
307
308     return source;
309 }
310
311 static cairo_status_t
312 _cairo_surface_subsurface_acquire_source_image (void                    *abstract_surface,
313                                                 cairo_image_surface_t  **image_out,
314                                                 void                   **extra_out)
315 {
316     cairo_surface_subsurface_t *surface = abstract_surface;
317     cairo_surface_pattern_t pattern;
318     cairo_surface_t *image;
319     cairo_status_t status;
320
321     image = _cairo_image_surface_create_with_content (surface->base.content,
322                                                       surface->extents.width,
323                                                       surface->extents.height);
324     if (unlikely (image->status))
325         return image->status;
326
327     _cairo_pattern_init_for_surface (&pattern, surface->target);
328     cairo_matrix_init_translate (&pattern.base.matrix,
329                                  surface->extents.x,
330                                  surface->extents.y);
331     pattern.base.filter = CAIRO_FILTER_NEAREST;
332     status = _cairo_surface_paint (image,
333                                    CAIRO_OPERATOR_SOURCE,
334                                    &pattern.base, NULL);
335     _cairo_pattern_fini (&pattern.base);
336     if (unlikely (status)) {
337         cairo_surface_destroy (image);
338         return status;
339     }
340
341     *image_out = (cairo_image_surface_t *)image;
342     *extra_out = NULL;
343     return CAIRO_STATUS_SUCCESS;
344 }
345
346 static void
347 _cairo_surface_subsurface_release_source_image (void                   *abstract_surface,
348                                                 cairo_image_surface_t  *image,
349                                                 void                   *abstract_extra)
350 {
351     cairo_surface_destroy (&image->base);
352 }
353
354 static cairo_surface_t *
355 _cairo_surface_subsurface_snapshot (void *abstract_surface)
356 {
357     cairo_surface_subsurface_t *surface = abstract_surface;
358     cairo_surface_pattern_t pattern;
359     cairo_surface_t *clone;
360     cairo_status_t status;
361
362     TRACE ((stderr, "%s: target=%d\n", __FUNCTION__, surface->target->unique_id));
363
364     clone = _cairo_surface_create_similar_scratch (surface->target,
365                                                    surface->target->content,
366                                                    surface->extents.width,
367                                                    surface->extents.height);
368     if (unlikely (clone->status))
369         return clone;
370
371     _cairo_pattern_init_for_surface (&pattern, surface->target);
372     cairo_matrix_init_translate (&pattern.base.matrix,
373                                  surface->extents.x, surface->extents.y);
374     pattern.base.filter = CAIRO_FILTER_NEAREST;
375     status = _cairo_surface_paint (clone,
376                                    CAIRO_OPERATOR_SOURCE,
377                                    &pattern.base, NULL);
378     _cairo_pattern_fini (&pattern.base);
379
380     if (unlikely (status)) {
381         cairo_surface_destroy (clone);
382         clone = _cairo_surface_create_in_error (status);
383     }
384
385     return clone;
386 }
387
388 static cairo_t *
389 _cairo_surface_subsurface_create_context(void *target)
390 {
391     cairo_surface_subsurface_t *surface = target;
392     return surface->target->backend->create_context (&surface->base);
393 }
394
395 static const cairo_surface_backend_t _cairo_surface_subsurface_backend = {
396     CAIRO_SURFACE_TYPE_SUBSURFACE,
397     _cairo_surface_subsurface_finish,
398
399     _cairo_surface_subsurface_create_context,
400
401     _cairo_surface_subsurface_create_similar,
402     _cairo_surface_subsurface_create_similar_image,
403     _cairo_surface_subsurface_map_to_image,
404     _cairo_surface_subsurface_unmap_image,
405
406     _cairo_surface_subsurface_source,
407     _cairo_surface_subsurface_acquire_source_image,
408     _cairo_surface_subsurface_release_source_image,
409     _cairo_surface_subsurface_snapshot,
410
411     NULL, /* copy_page */
412     NULL, /* show_page */
413
414     _cairo_surface_subsurface_get_extents,
415     _cairo_surface_subsurface_get_font_options,
416
417     _cairo_surface_subsurface_flush,
418     _cairo_surface_subsurface_mark_dirty,
419
420     _cairo_surface_subsurface_paint,
421     _cairo_surface_subsurface_mask,
422     _cairo_surface_subsurface_stroke,
423     _cairo_surface_subsurface_fill,
424     NULL, /* fill/stroke */
425     _cairo_surface_subsurface_glyphs,
426 };
427
428 /**
429  * cairo_surface_create_for_rectangle:
430  * @target: an existing surface for which the sub-surface will point to
431  * @x: the x-origin of the sub-surface from the top-left of the target surface (in device-space units)
432  * @y: the y-origin of the sub-surface from the top-left of the target surface (in device-space units)
433  * @width: width of the sub-surface (in device-space units)
434  * @height: height of the sub-surface (in device-space units)
435  *
436  * Create a new surface that is a rectangle within the target surface.
437  * All operations drawn to this surface are then clipped and translated
438  * onto the target surface. Nothing drawn via this sub-surface outside of
439  * its bounds is drawn onto the target surface, making this a useful method
440  * for passing constrained child surfaces to library routines that draw
441  * directly onto the parent surface, i.e. with no further backend allocations,
442  * double buffering or copies.
443  *
444  * <note><para>The semantics of subsurfaces have not been finalized yet
445  * unless the rectangle is in full device units, is contained within
446  * the extents of the target surface, and the target or subsurface's
447  * device transforms are not changed.</para></note>
448  *
449  * Return value: a pointer to the newly allocated surface. The caller
450  * owns the surface and should call cairo_surface_destroy() when done
451  * with it.
452  *
453  * This function always returns a valid pointer, but it will return a
454  * pointer to a "nil" surface if @other is already in an error state
455  * or any other error occurs.
456  *
457  * Since: 1.10
458  **/
459 cairo_surface_t *
460 cairo_surface_create_for_rectangle (cairo_surface_t *target,
461                                     double x, double y,
462                                     double width, double height)
463 {
464     cairo_surface_subsurface_t *surface;
465
466     if (unlikely (width < 0 || height < 0))
467         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE));
468
469     if (unlikely (target->status))
470         return _cairo_surface_create_in_error (target->status);
471     if (unlikely (target->finished))
472         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
473
474     surface = malloc (sizeof (cairo_surface_subsurface_t));
475     if (unlikely (surface == NULL))
476         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
477
478     assert (_cairo_matrix_is_translation (&target->device_transform));
479     x += target->device_transform.x0;
480     y += target->device_transform.y0;
481
482     _cairo_surface_init (&surface->base,
483                          &_cairo_surface_subsurface_backend,
484                          NULL, /* device */
485                          target->content);
486
487     /* XXX forced integer alignment */
488     surface->extents.x = ceil (x);
489     surface->extents.y = ceil (y);
490     surface->extents.width = floor (x + width) - surface->extents.x;
491     surface->extents.height = floor (y + height) - surface->extents.y;
492     if ((surface->extents.width | surface->extents.height) < 0)
493         surface->extents.width = surface->extents.height = 0;
494
495     if (target->backend->type == CAIRO_SURFACE_TYPE_SUBSURFACE) {
496         /* Maintain subsurfaces as 1-depth */
497         cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) target;
498         surface->extents.x += sub->extents.x;
499         surface->extents.y += sub->extents.y;
500         target = sub->target;
501     }
502
503     surface->target = cairo_surface_reference (target);
504     surface->base.type = surface->target->type;
505
506     surface->snapshot = NULL;
507
508     return &surface->base;
509 }
510
511 cairo_surface_t *
512 _cairo_surface_create_for_rectangle_int (cairo_surface_t *target,
513                                          const cairo_rectangle_int_t *extents)
514 {
515     cairo_surface_subsurface_t *surface;
516
517     if (unlikely (target->status))
518         return _cairo_surface_create_in_error (target->status);
519     if (unlikely (target->finished))
520         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED));
521
522     assert (target->backend->type != CAIRO_SURFACE_TYPE_SUBSURFACE);
523
524     surface = malloc (sizeof (cairo_surface_subsurface_t));
525     if (unlikely (surface == NULL))
526         return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
527
528     assert (_cairo_matrix_is_translation (&target->device_transform));
529
530     _cairo_surface_init (&surface->base,
531                          &_cairo_surface_subsurface_backend,
532                          NULL, /* device */
533                          target->content);
534
535     surface->extents = *extents;
536     surface->extents.x += target->device_transform.x0;
537     surface->extents.y += target->device_transform.y0;
538
539     surface->target = cairo_surface_reference (target);
540     surface->base.type = surface->target->type;
541
542     surface->snapshot = NULL;
543
544     return &surface->base;
545 }
546 /* XXX observe mark-dirty */
547
548 static void
549 _cairo_surface_subsurface_detach_snapshot (cairo_surface_t *surface)
550 {
551     cairo_surface_subsurface_t *ss = (cairo_surface_subsurface_t *) surface;
552
553     TRACE ((stderr, "%s: target=%d\n", __FUNCTION__, ss->target->unique_id));
554
555     cairo_surface_destroy (ss->snapshot);
556     ss->snapshot = NULL;
557 }
558
559 void
560 _cairo_surface_subsurface_set_snapshot (cairo_surface_t *surface,
561                                         cairo_surface_t *snapshot)
562 {
563     cairo_surface_subsurface_t *ss = (cairo_surface_subsurface_t *) surface;
564
565     TRACE ((stderr, "%s: target=%d, snapshot=%d\n", __FUNCTION__,
566             ss->target->unique_id, snapshot->unique_id));
567
568     /* FIXME: attaching the subsurface as a snapshot to its target creates
569      * a reference cycle.  Let's make this call as a no-op until that bug
570      * is fixed.
571      */
572     return;
573
574     if (ss->snapshot)
575         _cairo_surface_detach_snapshot (ss->snapshot);
576
577     ss->snapshot = cairo_surface_reference (snapshot);
578
579     _cairo_surface_attach_snapshot (ss->target, &ss->base,
580                                     _cairo_surface_subsurface_detach_snapshot);
581 }