1 /* cairo - a vector graphics library with display and print output
3 * Copyright © 2009 Intel Corporation
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.
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
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/
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.
28 * The Original Code is the cairo graphics library.
30 * The Initial Developer of the Original Code is Intel Corporation.
33 * Chris Wilson <chris@chris-wilson.co.uk>
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"
46 static const cairo_surface_backend_t _cairo_surface_subsurface_backend
;
49 _cairo_surface_subsurface_finish (void *abstract_surface
)
51 cairo_surface_subsurface_t
*surface
= abstract_surface
;
53 cairo_surface_destroy (surface
->target
);
54 cairo_surface_destroy (surface
->snapshot
);
56 return CAIRO_STATUS_SUCCESS
;
59 static cairo_surface_t
*
60 _cairo_surface_subsurface_create_similar (void *other
,
61 cairo_content_t content
,
62 int width
, int height
)
64 cairo_surface_subsurface_t
*surface
= other
;
66 if (surface
->target
->backend
->create_similar
== NULL
)
69 return surface
->target
->backend
->create_similar (surface
->target
, content
, width
, height
);
72 static cairo_surface_t
*
73 _cairo_surface_subsurface_create_similar_image (void *other
,
74 cairo_format_t format
,
75 int width
, int height
)
77 cairo_surface_subsurface_t
*surface
= other
;
79 if (surface
->target
->backend
->create_similar_image
== NULL
)
82 return surface
->target
->backend
->create_similar_image (surface
->target
,
87 static cairo_image_surface_t
*
88 _cairo_surface_subsurface_map_to_image (void *abstract_surface
,
89 const cairo_rectangle_int_t
*extents
)
91 cairo_surface_subsurface_t
*surface
= abstract_surface
;
92 cairo_rectangle_int_t target_extents
;
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
;
99 return _cairo_surface_map_to_image (surface
->target
, &target_extents
);
102 static cairo_int_status_t
103 _cairo_surface_subsurface_unmap_image (void *abstract_surface
,
104 cairo_image_surface_t
*image
)
106 cairo_surface_subsurface_t
*surface
= abstract_surface
;
107 return _cairo_surface_unmap_image (surface
->target
, image
);
110 static cairo_int_status_t
111 _cairo_surface_subsurface_paint (void *abstract_surface
,
113 const cairo_pattern_t
*source
,
114 const cairo_clip_t
*clip
)
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
;
119 cairo_clip_t
*target_clip
;
121 target_clip
= _cairo_clip_copy_intersect_rectangle (clip
, &rect
);
122 status
= _cairo_surface_offset_paint (surface
->target
,
123 -surface
->extents
.x
, -surface
->extents
.y
,
124 op
, source
, target_clip
);
125 _cairo_clip_destroy (target_clip
);
129 static cairo_int_status_t
130 _cairo_surface_subsurface_mask (void *abstract_surface
,
132 const cairo_pattern_t
*source
,
133 const cairo_pattern_t
*mask
,
134 const cairo_clip_t
*clip
)
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
;
139 cairo_clip_t
*target_clip
;
141 target_clip
= _cairo_clip_copy_intersect_rectangle (clip
, &rect
);
142 status
= _cairo_surface_offset_mask (surface
->target
,
143 -surface
->extents
.x
, -surface
->extents
.y
,
144 op
, source
, mask
, target_clip
);
145 _cairo_clip_destroy (target_clip
);
149 static cairo_int_status_t
150 _cairo_surface_subsurface_fill (void *abstract_surface
,
152 const cairo_pattern_t
*source
,
153 const cairo_path_fixed_t
*path
,
154 cairo_fill_rule_t fill_rule
,
156 cairo_antialias_t antialias
,
157 const cairo_clip_t
*clip
)
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
;
162 cairo_clip_t
*target_clip
;
164 target_clip
= _cairo_clip_copy_intersect_rectangle (clip
, &rect
);
165 status
= _cairo_surface_offset_fill (surface
->target
,
166 -surface
->extents
.x
, -surface
->extents
.y
,
167 op
, source
, path
, fill_rule
, tolerance
, antialias
,
169 _cairo_clip_destroy (target_clip
);
173 static cairo_int_status_t
174 _cairo_surface_subsurface_stroke (void *abstract_surface
,
176 const cairo_pattern_t
*source
,
177 const cairo_path_fixed_t
*path
,
178 const cairo_stroke_style_t
*stroke_style
,
179 const cairo_matrix_t
*ctm
,
180 const cairo_matrix_t
*ctm_inverse
,
182 cairo_antialias_t antialias
,
183 const cairo_clip_t
*clip
)
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
;
188 cairo_clip_t
*target_clip
;
190 target_clip
= _cairo_clip_copy_intersect_rectangle (clip
, &rect
);
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
,
196 _cairo_clip_destroy (target_clip
);
200 static cairo_int_status_t
201 _cairo_surface_subsurface_glyphs (void *abstract_surface
,
203 const cairo_pattern_t
*source
,
204 cairo_glyph_t
*glyphs
,
206 cairo_scaled_font_t
*scaled_font
,
207 const cairo_clip_t
*clip
)
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
;
212 cairo_clip_t
*target_clip
;
214 target_clip
= _cairo_clip_copy_intersect_rectangle (clip
, &rect
);
215 status
= _cairo_surface_offset_glyphs (surface
->target
,
216 -surface
->extents
.x
, -surface
->extents
.y
,
218 scaled_font
, glyphs
, num_glyphs
,
220 _cairo_clip_destroy (target_clip
);
224 static cairo_status_t
225 _cairo_surface_subsurface_flush (void *abstract_surface
, unsigned flags
)
227 cairo_surface_subsurface_t
*surface
= abstract_surface
;
228 return _cairo_surface_flush (surface
->target
, flags
);
231 static cairo_status_t
232 _cairo_surface_subsurface_mark_dirty (void *abstract_surface
,
234 int width
, int height
)
236 cairo_surface_subsurface_t
*surface
= abstract_surface
;
237 cairo_status_t status
;
239 status
= CAIRO_STATUS_SUCCESS
;
240 if (surface
->target
->backend
->mark_dirty_rectangle
!= NULL
) {
241 cairo_rectangle_int_t rect
, extents
;
246 rect
.height
= height
;
248 extents
.x
= extents
.y
= 0;
249 extents
.width
= surface
->extents
.width
;
250 extents
.height
= surface
->extents
.height
;
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
);
264 _cairo_surface_subsurface_get_extents (void *abstract_surface
,
265 cairo_rectangle_int_t
*extents
)
267 cairo_surface_subsurface_t
*surface
= abstract_surface
;
271 extents
->width
= surface
->extents
.width
;
272 extents
->height
= surface
->extents
.height
;
278 _cairo_surface_subsurface_get_font_options (void *abstract_surface
,
279 cairo_font_options_t
*options
)
281 cairo_surface_subsurface_t
*surface
= abstract_surface
;
283 if (surface
->target
->backend
->get_font_options
!= NULL
)
284 surface
->target
->backend
->get_font_options (surface
->target
, options
);
287 static cairo_surface_t
*
288 _cairo_surface_subsurface_source (void *abstract_surface
,
289 cairo_rectangle_int_t
*extents
)
291 cairo_surface_subsurface_t
*surface
= abstract_surface
;
292 cairo_surface_t
*source
;
294 source
= _cairo_surface_get_source (surface
->target
, extents
);
296 *extents
= surface
->extents
;
301 static cairo_status_t
302 _cairo_surface_subsurface_acquire_source_image (void *abstract_surface
,
303 cairo_image_surface_t
**image_out
,
306 cairo_surface_subsurface_t
*surface
= abstract_surface
;
307 cairo_surface_pattern_t pattern
;
308 cairo_surface_t
*image
;
309 cairo_status_t status
;
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
;
317 _cairo_pattern_init_for_surface (&pattern
, surface
->target
);
318 cairo_matrix_init_translate (&pattern
.base
.matrix
,
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
);
331 *image_out
= (cairo_image_surface_t
*)image
;
333 return CAIRO_STATUS_SUCCESS
;
337 _cairo_surface_subsurface_release_source_image (void *abstract_surface
,
338 cairo_image_surface_t
*image
,
339 void *abstract_extra
)
341 cairo_surface_destroy (&image
->base
);
344 static cairo_surface_t
*
345 _cairo_surface_subsurface_snapshot (void *abstract_surface
)
347 cairo_surface_subsurface_t
*surface
= abstract_surface
;
348 cairo_surface_pattern_t pattern
;
349 cairo_surface_t
*clone
;
350 cairo_status_t status
;
352 TRACE ((stderr
, "%s: target=%d\n", __FUNCTION__
, surface
->target
->unique_id
));
354 clone
= _cairo_surface_create_scratch (surface
->target
,
355 surface
->target
->content
,
356 surface
->extents
.width
,
357 surface
->extents
.height
,
359 if (unlikely (clone
->status
))
362 _cairo_pattern_init_for_surface (&pattern
, surface
->target
);
363 cairo_matrix_init_translate (&pattern
.base
.matrix
,
364 surface
->extents
.x
, surface
->extents
.y
);
365 pattern
.base
.filter
= CAIRO_FILTER_NEAREST
;
366 status
= _cairo_surface_paint (clone
,
367 CAIRO_OPERATOR_SOURCE
,
368 &pattern
.base
, NULL
);
369 _cairo_pattern_fini (&pattern
.base
);
371 if (unlikely (status
)) {
372 cairo_surface_destroy (clone
);
373 clone
= _cairo_surface_create_in_error (status
);
380 _cairo_surface_subsurface_create_context(void *target
)
382 cairo_surface_subsurface_t
*surface
= target
;
383 return surface
->target
->backend
->create_context (&surface
->base
);
386 static const cairo_surface_backend_t _cairo_surface_subsurface_backend
= {
387 CAIRO_SURFACE_TYPE_SUBSURFACE
,
388 _cairo_surface_subsurface_finish
,
390 _cairo_surface_subsurface_create_context
,
392 _cairo_surface_subsurface_create_similar
,
393 _cairo_surface_subsurface_create_similar_image
,
394 _cairo_surface_subsurface_map_to_image
,
395 _cairo_surface_subsurface_unmap_image
,
397 _cairo_surface_subsurface_source
,
398 _cairo_surface_subsurface_acquire_source_image
,
399 _cairo_surface_subsurface_release_source_image
,
400 _cairo_surface_subsurface_snapshot
,
402 NULL
, /* copy_page */
403 NULL
, /* show_page */
405 _cairo_surface_subsurface_get_extents
,
406 _cairo_surface_subsurface_get_font_options
,
408 _cairo_surface_subsurface_flush
,
409 _cairo_surface_subsurface_mark_dirty
,
411 _cairo_surface_subsurface_paint
,
412 _cairo_surface_subsurface_mask
,
413 _cairo_surface_subsurface_stroke
,
414 _cairo_surface_subsurface_fill
,
415 NULL
, /* fill/stroke */
416 _cairo_surface_subsurface_glyphs
,
420 * cairo_surface_create_for_rectangle:
421 * @target: an existing surface for which the sub-surface will point to
422 * @x: the x-origin of the sub-surface from the top-left of the target surface (in device-space units)
423 * @y: the y-origin of the sub-surface from the top-left of the target surface (in device-space units)
424 * @width: width of the sub-surface (in device-space units)
425 * @height: height of the sub-surface (in device-space units)
427 * Create a new surface that is a rectangle within the target surface.
428 * All operations drawn to this surface are then clipped and translated
429 * onto the target surface. Nothing drawn via this sub-surface outside of
430 * its bounds is drawn onto the target surface, making this a useful method
431 * for passing constrained child surfaces to library routines that draw
432 * directly onto the parent surface, i.e. with no further backend allocations,
433 * double buffering or copies.
435 * <note><para>The semantics of subsurfaces have not been finalized yet
436 * unless the rectangle is in full device units, is contained within
437 * the extents of the target surface, and the target or subsurface's
438 * device transforms are not changed.</para></note>
440 * Return value: a pointer to the newly allocated surface. The caller
441 * owns the surface and should call cairo_surface_destroy() when done
444 * This function always returns a valid pointer, but it will return a
445 * pointer to a "nil" surface if @other is already in an error state
446 * or any other error occurs.
451 cairo_surface_create_for_rectangle (cairo_surface_t
*target
,
453 double width
, double height
)
455 cairo_surface_subsurface_t
*surface
;
457 if (unlikely (width
< 0 || height
< 0))
458 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_SIZE
));
460 if (unlikely (target
->status
))
461 return _cairo_surface_create_in_error (target
->status
);
462 if (unlikely (target
->finished
))
463 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_SURFACE_FINISHED
));
465 surface
= malloc (sizeof (cairo_surface_subsurface_t
));
466 if (unlikely (surface
== NULL
))
467 return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY
));
469 x
*= target
->device_transform
.xx
;
470 y
*= target
->device_transform
.yy
;
472 width
*= target
->device_transform
.xx
;
473 height
*= target
->device_transform
.yy
;
475 x
+= target
->device_transform
.x0
;
476 y
+= target
->device_transform
.y0
;
478 _cairo_surface_init (&surface
->base
,
479 &_cairo_surface_subsurface_backend
,
483 /* XXX forced integer alignment */
484 surface
->extents
.x
= ceil (x
);
485 surface
->extents
.y
= ceil (y
);
486 surface
->extents
.width
= floor (x
+ width
) - surface
->extents
.x
;
487 surface
->extents
.height
= floor (y
+ height
) - surface
->extents
.y
;
488 if ((surface
->extents
.width
| surface
->extents
.height
) < 0)
489 surface
->extents
.width
= surface
->extents
.height
= 0;
491 if (target
->backend
->type
== CAIRO_SURFACE_TYPE_SUBSURFACE
) {
492 /* Maintain subsurfaces as 1-depth */
493 cairo_surface_subsurface_t
*sub
= (cairo_surface_subsurface_t
*) target
;
494 surface
->extents
.x
+= sub
->extents
.x
;
495 surface
->extents
.y
+= sub
->extents
.y
;
496 target
= sub
->target
;
499 surface
->target
= cairo_surface_reference (target
);
500 surface
->base
.type
= surface
->target
->type
;
502 surface
->snapshot
= NULL
;
504 cairo_surface_set_device_scale (&surface
->base
,
505 target
->device_transform
.xx
,
506 target
->device_transform
.yy
);
508 return &surface
->base
;
512 _cairo_surface_create_for_rectangle_int (cairo_surface_t
*target
,
513 const cairo_rectangle_int_t
*extents
)
515 cairo_surface_subsurface_t
*surface
;
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
));
522 assert (target
->backend
->type
!= CAIRO_SURFACE_TYPE_SUBSURFACE
);
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
));
528 _cairo_surface_init (&surface
->base
,
529 &_cairo_surface_subsurface_backend
,
533 surface
->extents
= *extents
;
534 surface
->extents
.x
*= target
->device_transform
.xx
;
535 surface
->extents
.y
*= target
->device_transform
.yy
;
536 surface
->extents
.width
*= target
->device_transform
.xx
;
537 surface
->extents
.height
*= target
->device_transform
.yy
;
538 surface
->extents
.x
+= target
->device_transform
.x0
;
539 surface
->extents
.y
+= target
->device_transform
.y0
;
541 surface
->target
= cairo_surface_reference (target
);
542 surface
->base
.type
= surface
->target
->type
;
544 surface
->snapshot
= NULL
;
546 cairo_surface_set_device_scale (&surface
->base
,
547 target
->device_transform
.xx
,
548 target
->device_transform
.yy
);
550 return &surface
->base
;
552 /* XXX observe mark-dirty */
555 _cairo_surface_subsurface_detach_snapshot (cairo_surface_t
*surface
)
557 cairo_surface_subsurface_t
*ss
= (cairo_surface_subsurface_t
*) surface
;
559 TRACE ((stderr
, "%s: target=%d\n", __FUNCTION__
, ss
->target
->unique_id
));
561 cairo_surface_destroy (ss
->snapshot
);
566 _cairo_surface_subsurface_set_snapshot (cairo_surface_t
*surface
,
567 cairo_surface_t
*snapshot
)
569 cairo_surface_subsurface_t
*ss
= (cairo_surface_subsurface_t
*) surface
;
571 TRACE ((stderr
, "%s: target=%d, snapshot=%d\n", __FUNCTION__
,
572 ss
->target
->unique_id
, snapshot
->unique_id
));
574 /* FIXME: attaching the subsurface as a snapshot to its target creates
575 * a reference cycle. Let's make this call as a no-op until that bug
581 _cairo_surface_detach_snapshot (ss
->snapshot
);
583 ss
->snapshot
= cairo_surface_reference (snapshot
);
585 _cairo_surface_attach_snapshot (ss
->target
, &ss
->base
,
586 _cairo_surface_subsurface_detach_snapshot
);