summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2005-05-26 11:35:44 +0000
committerKeith Packard <keithp@keithp.com>2005-05-26 11:35:44 +0000
commit45a966f69528c86dd6e3d4736805803b80de9f9b (patch)
treeaab7935e6367421d168dfda9bee057e6c2fca238
parentbe903f4c2232bfa8b48c1dca60ad5cf65f403c77 (diff)
Replace nesting-only surface clipping with gstate contained serial-number tracked clipping sets that are loaded into the surface on demand just before each rendering operation. This permits multiple cairo_t contexts to reference a surface without regard to ordering of operations among the contexts.
Also in this patch is a change to the xlib surface that creates two separate Pictures, one for source and one for destination operands which separates the source clipping from destination clipping. Cairo now specifies that sources are never clipped by any clipping applied to them as destinations. Move cairo_clip_t (renamed from cairo_clip_rec_t) from cairoint.h to cairo-gstate-private.h. Eliminate stack of clip state from surfaces. Add new surface clipping API. Manage clip objects entirely within the gstate, loading the whole thing into the surface just before drawing. Source surfaces need not have clipping modified as the surface interface now specifies that source surfaces are always unclipped. Eliminate nested clipping contexts, leaving clip management entirely to the gstate. Create new clip API for the gstate which uses per-surface serial numbers to match gstate clipping against current surface clipping values. Surfaces no longer track clipping regions at all, so the old _cairo_surface_get_clip_extents has been replaced with _cairo_surface_get_extents. For PDF/PS surfaces, this function is expected to return a rectangle covering the entire fixed point coordinate space to leave rendering unclipped by the surface. Region clipping capability is now signalled by a non-NULL function pointer in set_clip_region. Each surface now contains two Pictures, one for source and one for destination operands so that source operands are never clipped by destination clipping. CAIRO_STATUS_BAD_NESTING removed self-copy now passes (Xlib only, until libpixman changes land) reviewed by: krh, otaylor, cworth
-rw-r--r--ChangeLog95
-rw-r--r--src/cairo-gstate-private.h30
-rw-r--r--src/cairo-gstate.c286
-rw-r--r--src/cairo-pattern.c28
-rw-r--r--src/cairo-surface.c292
-rw-r--r--src/cairo-xcb-surface.c2
-rw-r--r--src/cairo-xlib-surface.c123
-rw-r--r--src/cairo.c2
-rw-r--r--src/cairo.h7
-rw-r--r--src/cairoint.h72
-rw-r--r--test/Makefile.am1
-rw-r--r--test/self-copy.c3
12 files changed, 541 insertions, 400 deletions
diff --git a/ChangeLog b/ChangeLog
index 0944e992b..a294738e4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,98 @@
+2005-05-26 Keith Packard <keithp@keithp.com>
+
+ reviewed by: krh, otaylor, cworth
+
+ Replace nesting-only surface clipping with gstate contained
+ serial-number tracked clipping sets that are loaded into the surface
+ on demand just before each rendering operation. This permits
+ multiple cairo_t contexts to reference a surface without
+ regard to ordering of operations among the contexts.
+
+ Also in this patch is a change to the xlib surface that
+ creates two separate Pictures, one for source and one for
+ destination operands which separates the source clipping
+ from destination clipping. Cairo now specifies that sources
+ are never clipped by any clipping applied to them as destinations.
+
+ * src/cairoint.h:
+ * src/cairo-gstate-private.h:
+ Move cairo_clip_t (renamed from cairo_clip_rec_t) from cairoint.h
+ to cairo-gstate-private.h. Eliminate stack of clip state
+ from surfaces. Add new surface clipping API.
+
+ * src/cairo-gstate.c: (_cairo_gstate_init),
+ (_cairo_gstate_init_copy), (_cairo_gstate_fini),
+ (_cairo_gstate_has_surface_clip), (_cairo_gstate_set_clip),
+ (_cairo_gstate_get_clip_extents),
+ (_cairo_gstate_set_target_surface), (_cairo_gstate_paint),
+ (_cairo_gstate_combine_clip_surface),
+ (_cairo_gstate_intersect_clip), (_get_mask_extents),
+ (_cairo_gstate_mask), (_cairo_gstate_stroke),
+ (_clip_and_compute_extents_arbitrary), (_composite_trap_region),
+ (_cairo_gstate_fill), (_cairo_gstate_reset_clip),
+ (_cairo_gstate_clip), (_cairo_gstate_show_glyphs):
+ Manage clip objects entirely within the gstate, loading
+ the whole thing into the surface just before drawing.
+
+ * src/cairo-pattern.c:
+ (_cairo_pattern_acquire_surface_for_gradient),
+ (_cairo_pattern_acquire_surface_for_solid),
+ (_cairo_pattern_acquire_surface_for_surface),
+ (_cairo_pattern_acquire_surface), (_cairo_pattern_release_surface):
+ Source surfaces need not have clipping modified as the
+ surface interface now specifies that source surfaces are always
+ unclipped.
+
+ * src/cairo-surface.c: (_cairo_surface_init),
+ (cairo_surface_finish), (_cairo_surface_clone_similar),
+ (_cairo_surface_get_current_clip_serial),
+ (_cairo_surface_allocate_clip_serial), (_cairo_surface_reset_clip),
+ (_cairo_surface_can_clip_region), (_cairo_surface_set_clip_region),
+ (_cairo_surface_can_clip_path), (_cairo_surface_clip_path),
+ (_cairo_surface_get_extents):
+ Eliminate nested clipping contexts, leaving clip management
+ entirely to the gstate. Create new clip API for the gstate
+ which uses per-surface serial numbers to match gstate clipping
+ against current surface clipping values.
+
+ Surfaces no longer track clipping regions at all, so the
+ old _cairo_surface_get_clip_extents has been replaced with
+ _cairo_surface_get_extents. For PDF/PS surfaces, this
+ function is expected to return a rectangle covering the
+ entire fixed point coordinate space to leave rendering
+ unclipped by the surface.
+
+ * src/cairo-xcb-surface.c:
+ Region clipping capability is now signalled by a non-NULL
+ function pointer in set_clip_region.
+
+ * src/cairo-xlib-surface.c: (_cairo_xlib_surface_finish),
+ (_cairo_xlib_surface_ensure_src_picture),
+ (_cairo_xlib_surface_ensure_dst_picture),
+ (_cairo_xlib_surface_set_matrix), (_cairo_xlib_surface_set_filter),
+ (_cairo_xlib_surface_set_repeat),
+ (_cairo_xlib_surface_set_attributes),
+ (_cairo_xlib_surface_composite),
+ (_cairo_xlib_surface_fill_rectangles),
+ (_cairo_xlib_surface_composite_trapezoids),
+ (_cairo_xlib_surface_set_clip_region),
+ (_cairo_xlib_surface_create_internal),
+ (_cairo_xlib_surface_show_glyphs32),
+ (_cairo_xlib_surface_show_glyphs16),
+ (_cairo_xlib_surface_show_glyphs8),
+ (_cairo_xlib_surface_show_glyphs):
+ Each surface now contains two Pictures, one for source
+ and one for destination operands so that source operands
+ are never clipped by destination clipping.
+
+ * src/cairo.h:
+ * src/cairo.c: (cairo_status_string):
+ CAIRO_STATUS_BAD_NESTING removed
+
+ * test/Makefile.am:
+ * test/self-copy.c: (main):
+ self-copy now passes (Xlib only, until libpixman changes land)
+
2005-05-26 Olivier Andrieu <oliv__a@users.sourceforg.net>
* src/cairo.c: trivial doc fixes.
diff --git a/src/cairo-gstate-private.h b/src/cairo-gstate-private.h
index eeb35b83e..03486ac9c 100644
--- a/src/cairo-gstate-private.h
+++ b/src/cairo-gstate-private.h
@@ -36,6 +36,33 @@
#ifndef CAIRO_GSTATE_PRIVATE_H
#define CAIRO_GSTATE_PRIVATE_H
+typedef struct _cairo_clip {
+ /*
+ * Mask-based clipping for cases where the backend
+ * clipping isn't sufficiently able.
+ *
+ * The rectangle here represents the
+ * portion of the destination surface that this
+ * clip surface maps to, it does not
+ * represent the extents of the clip region or
+ * clip paths
+ */
+ cairo_surface_t *surface;
+ cairo_rectangle_t surface_rect;
+ /*
+ * Surface clip serial number to store
+ * in the surface when this clip is set
+ */
+ unsigned int serial;
+ /*
+ * A clip region that can be placed in the surface
+ */
+ pixman_region16_t *region;
+ /*
+ * XXX add clip paths here
+ */
+} cairo_clip_t;
+
struct _cairo_gstate {
cairo_operator_t operator;
@@ -61,11 +88,10 @@ struct _cairo_gstate {
cairo_scaled_font_t *scaled_font; /* Specific to the current CTM */
cairo_surface_t *surface;
- int surface_level; /* Used to detect bad nested use */
cairo_pattern_t *source;
- cairo_clip_rec_t clip;
+ cairo_clip_t clip;
cairo_matrix_t font_matrix;
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index 45c729fc9..9878bef83 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -61,6 +61,9 @@ _cairo_gstate_ensure_font_face (cairo_gstate_t *gstate);
static void
_cairo_gstate_unset_font (cairo_gstate_t *gstate);
+static void
+_cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src);
+
cairo_gstate_t *
_cairo_gstate_create (cairo_surface_t *target)
{
@@ -110,10 +113,10 @@ _cairo_gstate_init (cairo_gstate_t *gstate,
CAIRO_GSTATE_DEFAULT_FONT_SIZE);
gstate->surface = NULL;
- gstate->surface_level = 0;
gstate->clip.region = NULL;
gstate->clip.surface = NULL;
+ gstate->clip.serial = 0;
gstate->source = _cairo_pattern_create_solid (CAIRO_COLOR_BLACK);
if (!gstate->source)
@@ -151,8 +154,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
memcpy (gstate->dash, other->dash, other->num_dashes * sizeof (double));
}
- if (other->clip.region)
- {
+ if (other->clip.region) {
gstate->clip.region = pixman_region_create ();
pixman_region_copy (gstate->clip.region, other->clip.region);
}
@@ -172,16 +174,8 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
if (status)
goto CLEANUP_FONT;
- status = _cairo_surface_begin (gstate->surface);
- if (status)
- goto CLEANUP_PEN;
- gstate->surface_level = gstate->surface->level;
-
return status;
- CLEANUP_PEN:
- _cairo_pen_fini (&gstate->pen_regular);
-
CLEANUP_FONT:
cairo_scaled_font_destroy (gstate->scaled_font);
gstate->scaled_font = NULL;
@@ -202,7 +196,6 @@ _cairo_gstate_fini (cairo_gstate_t *gstate)
cairo_scaled_font_destroy (gstate->scaled_font);
if (gstate->surface) {
- _cairo_surface_end (gstate->surface);
cairo_surface_destroy (gstate->surface);
gstate->surface = NULL;
}
@@ -214,6 +207,7 @@ _cairo_gstate_fini (cairo_gstate_t *gstate)
if (gstate->clip.region)
pixman_region_destroy (gstate->clip.region);
gstate->clip.region = NULL;
+ gstate->clip.serial = 0;
cairo_pattern_destroy (gstate->source);
@@ -333,26 +327,84 @@ _cairo_gstate_end_group (cairo_gstate_t *gstate)
}
*/
+static cairo_bool_t
+_cairo_gstate_has_surface_clip (cairo_gstate_t *gstate)
+{
+ /* check for path clipping here */
+
+ if (gstate->clip.region)
+ return 1;
+ return 0;
+}
+
static cairo_status_t
-_cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surface)
+_cairo_gstate_set_clip (cairo_gstate_t *gstate)
{
- cairo_status_t status;
+ cairo_surface_t *surface = gstate->surface;
- if (gstate->surface == surface)
+ if (!surface)
+ return CAIRO_STATUS_NULL_POINTER;
+ if (gstate->clip.serial == _cairo_surface_get_current_clip_serial (surface))
return CAIRO_STATUS_SUCCESS;
- if (surface) {
- status = _cairo_surface_begin_reset_clip (surface);
- if (!CAIRO_OK (status))
- return status;
+ /* check for path clipping here */
+
+ if (gstate->clip.region)
+ return _cairo_surface_set_clip_region (surface,
+ gstate->clip.region,
+ gstate->clip.serial);
+
+ return _cairo_surface_reset_clip (surface);
+}
+
+static cairo_status_t
+_cairo_gstate_get_clip_extents (cairo_gstate_t *gstate,
+ cairo_rectangle_t *rectangle)
+{
+ cairo_status_t status;
+
+ status = _cairo_surface_get_extents (gstate->surface, rectangle);
+ if (!CAIRO_OK(status))
+ return status;
+ /* check path extents here */
+
+ if (gstate->clip.region) {
+ pixman_box16_t *clip_box;
+ cairo_rectangle_t clip_rect;
+
+ /* get region extents as a box */
+ clip_box = pixman_region_extents (gstate->clip.region);
+ /* convert to a rectangle */
+ clip_rect.x = clip_box->x1;
+ clip_rect.width = clip_box->x2 - clip_box->x1;
+ clip_rect.y = clip_box->y1;
+ clip_rect.width = clip_box->y2 + clip_box->y1;
+ /* intersect with surface extents */
+ _cairo_rectangle_intersect (rectangle, &clip_rect);
}
+ if (gstate->clip.surface)
+ _cairo_rectangle_intersect (rectangle, &gstate->clip.surface_rect);
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+_cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surface)
+{
+ if (gstate->surface == surface)
+ return CAIRO_STATUS_SUCCESS;
+
+ /* allocate a new serial to represent our current state. Each
+ surface has its own set of serials */
+ gstate->clip.serial = 0;
+ if (surface && _cairo_gstate_has_surface_clip (gstate))
+ gstate->clip.serial = _cairo_surface_allocate_clip_serial (surface);
+
_cairo_gstate_unset_font (gstate);
- if (gstate->surface) {
- _cairo_surface_end (gstate->surface);
+ if (gstate->surface)
cairo_surface_destroy (gstate->surface);
- }
gstate->surface = surface;
@@ -360,12 +412,10 @@ _cairo_gstate_set_target_surface (cairo_gstate_t *gstate, cairo_surface_t *surfa
* (just like after cairo_create). This can be useful for forcing
* the old surface to be destroyed. */
if (surface == NULL) {
- gstate->surface_level = 0;
return CAIRO_STATUS_SUCCESS;
}
cairo_surface_reference (gstate->surface);
- gstate->surface_level = surface->level;
_cairo_gstate_identity_matrix (gstate);
@@ -733,10 +783,11 @@ _cairo_gstate_paint (cairo_gstate_t *gstate)
cairo_box_t box;
cairo_traps_t traps;
- if (gstate->surface->level != gstate->surface_level)
- return CAIRO_STATUS_BAD_NESTING;
-
- status = _cairo_surface_get_clip_extents (gstate->surface, &rectangle);
+ status = _cairo_gstate_set_clip (gstate);
+ if (!CAIRO_OK (status))
+ return status;
+
+ status = _cairo_gstate_get_clip_extents (gstate, &rectangle);
if (!CAIRO_OK (status))
return status;
@@ -778,8 +829,8 @@ _cairo_gstate_combine_clip_surface (cairo_gstate_t *gstate,
&pattern.base,
NULL,
intermediate,
- extents->x - gstate->clip.rect.x,
- extents->y - gstate->clip.rect.y,
+ extents->x - gstate->clip.surface_rect.x,
+ extents->y - gstate->clip.surface_rect.y,
0, 0,
0, 0,
extents->width, extents->height);
@@ -832,7 +883,7 @@ _cairo_gstate_intersect_clip (cairo_gstate_t *gstate,
pixman_region16_t *clip_rect;
cairo_status_t status;
- status = _region_new_from_rect (&gstate->clip.rect, &clip_rect);
+ status = _region_new_from_rect (&gstate->clip.surface_rect, &clip_rect);
if (!CAIRO_OK (status))
return status;
@@ -855,27 +906,12 @@ _get_mask_extents (cairo_gstate_t *gstate,
cairo_pattern_t *mask,
cairo_rectangle_t *extents)
{
- cairo_rectangle_t clip_rect;
- pixman_region16_t *clip_region;
- cairo_status_t status;
-
- status = _cairo_surface_get_clip_extents (gstate->surface, &clip_rect);
- if (!CAIRO_OK (status))
- return status;
-
- status = _region_new_from_rect (&clip_rect, &clip_region);
- if (!CAIRO_OK (status))
- return status;
-
- status = _cairo_gstate_intersect_clip (gstate, clip_region);
- if (!CAIRO_OK (status))
- return status;
-
- _region_rect_extents (clip_region, extents);
-
- pixman_region_destroy (clip_region);
-
- return CAIRO_STATUS_SUCCESS;
+ /*
+ * XXX should take mask extents into account, but
+ * that involves checking the transform... For now,
+ * be lazy and just use the destination extents
+ */
+ return _cairo_gstate_get_clip_extents (gstate, extents);
}
cairo_status_t
@@ -889,9 +925,10 @@ _cairo_gstate_mask (cairo_gstate_t *gstate,
cairo_status_t status;
int mask_x, mask_y;
- if (gstate->surface->level != gstate->surface_level)
- return CAIRO_STATUS_BAD_NESTING;
-
+ status = _cairo_gstate_set_clip (gstate);
+ if (!CAIRO_OK (status))
+ return status;
+
_get_mask_extents (gstate, mask, &extents);
if (gstate->clip.surface) {
@@ -960,12 +997,13 @@ _cairo_gstate_stroke (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
cairo_status_t status;
cairo_traps_t traps;
- if (gstate->surface->level != gstate->surface_level)
- return CAIRO_STATUS_BAD_NESTING;
-
if (gstate->line_width <= 0.0)
return CAIRO_STATUS_SUCCESS;
+ status = _cairo_gstate_set_clip (gstate);
+ if (!CAIRO_OK (status))
+ return status;
+
_cairo_pen_init (&gstate->pen_regular, gstate->line_width / 2.0, gstate);
_cairo_traps_init (&traps);
@@ -1122,7 +1160,7 @@ _clip_and_compute_extents_arbitrary (cairo_gstate_t *gstate,
}
if (gstate->clip.surface)
- _cairo_rectangle_intersect (extents, &gstate->clip.rect);
+ _cairo_rectangle_intersect (extents, &gstate->clip.surface_rect);
return CAIRO_STATUS_SUCCESS;
}
@@ -1137,16 +1175,25 @@ _composite_trap_region (cairo_gstate_t *gstate,
pixman_region16_t *trap_region,
cairo_rectangle_t *extents)
{
- cairo_status_t status, tmp_status;
+ cairo_status_t status;
cairo_pattern_union_t pattern;
cairo_pattern_union_t mask;
int num_rects = pixman_region_num_rects (trap_region);
+ unsigned int clip_serial;
if (num_rects == 0)
return CAIRO_STATUS_SUCCESS;
if (num_rects > 1) {
- status = _cairo_surface_set_clip_region (dst, trap_region);
+
+ status = _cairo_surface_can_clip_region (gstate->surface);
+ if (!CAIRO_OK (status))
+ return status;
+
+ clip_serial = _cairo_surface_allocate_clip_serial (gstate->surface);
+ status = _cairo_surface_set_clip_region (gstate->surface,
+ trap_region,
+ clip_serial);
if (!CAIRO_OK (status))
return status;
}
@@ -1162,8 +1209,8 @@ _composite_trap_region (cairo_gstate_t *gstate,
gstate->clip.surface ? &mask.base : NULL,
dst,
extents->x, extents->y,
- extents->x - (gstate->clip.surface ? gstate->clip.rect.x : 0),
- extents->y - (gstate->clip.surface ? gstate->clip.rect.y : 0),
+ extents->x - (gstate->clip.surface ? gstate->clip.surface_rect.x : 0),
+ extents->y - (gstate->clip.surface ? gstate->clip.surface_rect.y : 0),
extents->x, extents->y,
extents->width, extents->height);
@@ -1171,12 +1218,6 @@ _composite_trap_region (cairo_gstate_t *gstate,
if (gstate->clip.surface)
_cairo_pattern_fini (&mask.base);
- if (num_rects > 1) {
- tmp_status = _cairo_surface_set_clip_region (dst, gstate->clip.region);
- if (!CAIRO_OK (tmp_status))
- status = tmp_status;
- }
-
return status;
}
@@ -1431,8 +1472,9 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
cairo_status_t status;
cairo_traps_t traps;
- if (gstate->surface->level != gstate->surface_level)
- return CAIRO_STATUS_BAD_NESTING;
+ status = _cairo_gstate_set_clip (gstate);
+ if (!CAIRO_OK (status))
+ return status;
status = _cairo_surface_fill_path (gstate->operator,
gstate->source,
@@ -1574,9 +1616,6 @@ BAIL:
cairo_status_t
_cairo_gstate_reset_clip (cairo_gstate_t *gstate)
{
- if (gstate->surface->level != gstate->surface_level)
- return CAIRO_STATUS_BAD_NESTING;
-
/* destroy any existing clip-region artifacts */
if (gstate->clip.surface)
cairo_surface_destroy (gstate->clip.surface);
@@ -1585,12 +1624,8 @@ _cairo_gstate_reset_clip (cairo_gstate_t *gstate)
if (gstate->clip.region)
pixman_region_destroy (gstate->clip.region);
gstate->clip.region = NULL;
-
- /* reset the surface's clip to the whole surface */
- if (gstate->surface)
- _cairo_surface_set_clip_region (gstate->surface,
- gstate->clip.region);
-
+ gstate->clip.serial = 0;
+
return CAIRO_STATUS_SUCCESS;
}
@@ -1603,9 +1638,6 @@ _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
cairo_box_t extents;
pixman_region16_t *region;
- if (gstate->surface->level != gstate->surface_level)
- return CAIRO_STATUS_BAD_NESTING;
-
/* Fill the clip region as traps. */
_cairo_traps_init (&traps);
@@ -1615,63 +1647,62 @@ _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
return status;
}
- /* Check to see if we can represent these traps as a PixRegion. */
-
- status = _cairo_traps_extract_region (&traps, &region);
- if (!CAIRO_OK (status)) {
- _cairo_traps_fini (&traps);
- return status;
- }
+ status = _cairo_surface_can_clip_region (gstate->surface);
+
+ if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
+ if (!CAIRO_OK (status))
+ return status;
- if (region) {
- status = CAIRO_STATUS_SUCCESS;
+ /* Check to see if we can represent these traps as a PixRegion. */
+
+ status = _cairo_traps_extract_region (&traps, &region);
+ if (!CAIRO_OK (status)) {
+ _cairo_traps_fini (&traps);
+ return status;
+ }
- if (gstate->clip.region == NULL) {
- gstate->clip.region = region;
- } else {
- pixman_region16_t *intersection = pixman_region_create();
-
- if (pixman_region_intersect (intersection,
- gstate->clip.region, region)
- == PIXMAN_REGION_STATUS_SUCCESS) {
- pixman_region_destroy (gstate->clip.region);
- gstate->clip.region = intersection;
- } else {
- status = CAIRO_STATUS_NO_MEMORY;
+ if (region) {
+ status = CAIRO_STATUS_SUCCESS;
+
+ if (gstate->clip.region == NULL) {
+ gstate->clip.region = region;
+ } else {
+ pixman_region16_t *intersection = pixman_region_create();
+
+ if (pixman_region_intersect (intersection,
+ gstate->clip.region, region)
+ == PIXMAN_REGION_STATUS_SUCCESS) {
+ pixman_region_destroy (gstate->clip.region);
+ gstate->clip.region = intersection;
+ } else {
+ status = CAIRO_STATUS_NO_MEMORY;
+ }
+ pixman_region_destroy (region);
}
- pixman_region_destroy (region);
- }
+ gstate->clip.serial = _cairo_surface_allocate_clip_serial (gstate->surface);
- if (CAIRO_OK (status))
- status = _cairo_surface_set_clip_region (gstate->surface,
- gstate->clip.region);
-
- if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
_cairo_traps_fini (&traps);
+
return status;
}
-
- /* Fall through as status == CAIRO_INT_STATUS_UNSUPPORTED
- means that backend doesn't support clipping regions and
- mask surface clipping should be used instead. */
}
/* Otherwise represent the clip as a mask surface. */
if (gstate->clip.surface == NULL) {
_cairo_traps_extents (&traps, &extents);
- _cairo_box_round_to_rectangle (&extents, &gstate->clip.rect);
+ _cairo_box_round_to_rectangle (&extents, &gstate->clip.surface_rect);
gstate->clip.surface =
_cairo_surface_create_similar_solid (gstate->surface,
CAIRO_FORMAT_A8,
- gstate->clip.rect.width,
- gstate->clip.rect.height,
+ gstate->clip.surface_rect.width,
+ gstate->clip.surface_rect.height,
CAIRO_COLOR_WHITE);
if (gstate->clip.surface == NULL)
return CAIRO_STATUS_NO_MEMORY;
}
- translate_traps (&traps, -gstate->clip.rect.x, -gstate->clip.rect.y);
+ translate_traps (&traps, -gstate->clip.surface_rect.x, -gstate->clip.surface_rect.y);
_cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN,
@@ -1679,8 +1710,8 @@ _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
gstate->clip.surface,
0, 0,
0, 0,
- gstate->clip.rect.width,
- gstate->clip.rect.height,
+ gstate->clip.surface_rect.width,
+ gstate->clip.surface_rect.height,
traps.traps,
traps.num_traps);
@@ -1969,9 +2000,10 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
cairo_box_t bbox;
cairo_rectangle_t extents;
- if (gstate->surface->level != gstate->surface_level)
- return CAIRO_STATUS_BAD_NESTING;
-
+ status = _cairo_gstate_set_clip (gstate);
+ if (!CAIRO_OK (status))
+ return status;
+
status = _cairo_gstate_ensure_font (gstate);
if (status)
return status;
@@ -2001,7 +2033,7 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
cairo_surface_t *intermediate;
cairo_surface_pattern_t intermediate_pattern;
- _cairo_rectangle_intersect (&extents, &gstate->clip.rect);
+ _cairo_rectangle_intersect (&extents, &gstate->clip.surface_rect);
/* Shortcut if empty */
if (_cairo_rectangle_empty (&extents)) {
@@ -2048,8 +2080,8 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
&pattern.base,
NULL,
intermediate,
- extents.x - gstate->clip.rect.x,
- extents.y - gstate->clip.rect.y,
+ extents.x - gstate->clip.surface_rect.x,
+ extents.y - gstate->clip.surface_rect.y,
0, 0,
0, 0,
extents.width, extents.height);
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index 1746b6b2a..53a052d10 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -960,7 +960,6 @@ _cairo_pattern_acquire_surface_for_gradient (cairo_gradient_pattern_t *pattern,
attr->extend = repeat ? CAIRO_EXTEND_REPEAT : CAIRO_EXTEND_NONE;
attr->filter = CAIRO_FILTER_NEAREST;
attr->acquired = FALSE;
- attr->clip_saved = FALSE;
return status;
}
@@ -988,7 +987,6 @@ _cairo_pattern_acquire_surface_for_solid (cairo_solid_pattern_t *pattern,
attribs->extend = CAIRO_EXTEND_REPEAT;
attribs->filter = CAIRO_FILTER_NEAREST;
attribs->acquired = FALSE;
- attribs->clip_saved = FALSE;
return CAIRO_STATUS_SUCCESS;
}
@@ -1032,35 +1030,23 @@ _cairo_pattern_acquire_surface_for_surface (cairo_surface_pattern_t *pattern,
int tx, ty;
attr->acquired = FALSE;
- attr->clip_saved = FALSE;
if (_cairo_surface_is_image (dst))
{
cairo_image_surface_t *image;
- status = _cairo_surface_begin_reset_clip (pattern->surface);
- if (!CAIRO_OK (status))
- return status;
-
status = _cairo_surface_acquire_source_image (pattern->surface,
&image,
&attr->extra);
if (!CAIRO_OK (status))
return status;
- _cairo_surface_end (pattern->surface);
-
*out = &image->base;
attr->acquired = TRUE;
}
else
{
- status = _cairo_surface_begin_reset_clip (pattern->surface);
- if (!CAIRO_OK (status))
- return status;
-
status = _cairo_surface_clone_similar (dst, pattern->surface, out);
- _cairo_surface_end (pattern->surface);
}
attr->extend = pattern->base.extend;
@@ -1162,17 +1148,6 @@ _cairo_pattern_acquire_surface (cairo_pattern_t *pattern,
status = CAIRO_INT_STATUS_UNSUPPORTED;
}
-
- if (CAIRO_OK (status) && (*surface_out)->clip_region) {
- status = _cairo_surface_begin_reset_clip (*surface_out);
- if (!CAIRO_OK (status)) {
- _cairo_pattern_release_surface (dst, *surface_out, attributes);
- return status;
- }
-
- attributes->clip_saved = TRUE;
- }
-
return status;
}
@@ -1189,9 +1164,6 @@ _cairo_pattern_release_surface (cairo_surface_t *dst,
cairo_surface_t *surface,
cairo_surface_attributes_t *attributes)
{
- if (attributes->clip_saved)
- _cairo_surface_end (surface);
-
if (attributes->acquired)
{
_cairo_surface_release_source_image (dst,
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 0bcf80cf8..1242506b2 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -39,16 +39,6 @@
#include "cairoint.h"
-struct _cairo_surface_save {
- cairo_surface_save_t *next;
- pixman_region16_t *clip_region;
-};
-
-static cairo_status_t
-_cairo_surface_set_clip_region_internal (cairo_surface_t *surface,
- pixman_region16_t *region,
- cairo_bool_t copy_region,
- cairo_bool_t free_existing);
void
_cairo_surface_init (cairo_surface_t *surface,
@@ -68,110 +58,8 @@ _cairo_surface_init (cairo_surface_t *surface,
surface->device_x_offset = 0;
surface->device_y_offset = 0;
- surface->clip_region = NULL;
-
- surface->saves = NULL;
- surface->level = 0;
-}
-
-static cairo_status_t
-_cairo_surface_begin_internal (cairo_surface_t *surface,
- cairo_bool_t reset_clip)
-{
- cairo_surface_save_t *save;
-
- if (surface->finished)
- return CAIRO_STATUS_SURFACE_FINISHED;
-
- save = malloc (sizeof (cairo_surface_save_t));
- if (!save)
- return CAIRO_STATUS_NO_MEMORY;
-
- if (surface->clip_region) {
- if (reset_clip)
- {
- cairo_status_t status;
-
- save->clip_region = surface->clip_region;
- status = _cairo_surface_set_clip_region_internal (surface, NULL, FALSE, FALSE);
- if (!CAIRO_OK (status)) {
- free (save);
- return status;
- }
- }
- else
- {
- save->clip_region = pixman_region_create ();
- pixman_region_copy (save->clip_region, surface->clip_region);
- }
- } else {
- save->clip_region = NULL;
- }
-
- save->next = surface->saves;
- surface->saves = save;
- surface->level++;
-
- return CAIRO_STATUS_SUCCESS;
-}
-
-/**
- * _cairo_surface_begin:
- * @surface: a #cairo_surface_t
- *
- * Must be called before beginning to use the surface. State
- * of the surface like the clip region will be saved then restored
- * on the matching call _cairo_surface_end().
- */
-cairo_private cairo_status_t
-_cairo_surface_begin (cairo_surface_t *surface)
-{
- return _cairo_surface_begin_internal (surface, FALSE);
-}
-
-/**
- * _cairo_surface_begin_reset_clip:
- * @surface: a #cairo_surface_t
- *
- * Must be called before beginning to use the surface. State
- * of the surface like the clip region will be saved then restored
- * on the matching call _cairo_surface_end().
- *
- * After the state is saved, the clip region is cleared. This
- * combination of operations is a little artificial; the caller could
- * simply call _cairo_surface_set_clip_region (surface, NULL); after
- * _cairo_surface_save(). Combining the two saves a copy of the clip
- * region, and also simplifies error handling for the caller.
- **/
-cairo_private cairo_status_t
-_cairo_surface_begin_reset_clip (cairo_surface_t *surface)
-{
- return _cairo_surface_begin_internal (surface, TRUE);
-}
-
-/**
- * _cairo_surface_end:
- * @surface: a #cairo_surface_t
- *
- * Restores any state saved by _cairo_surface_begin()
- **/
-cairo_private cairo_status_t
-_cairo_surface_end (cairo_surface_t *surface)
-{
- cairo_surface_save_t *save;
- pixman_region16_t *clip_region;
-
- if (!surface->saves)
- return CAIRO_STATUS_BAD_NESTING;
-
- save = surface->saves;
- surface->saves = save->next;
- surface->level--;
-
- clip_region = save->clip_region;
- free (save);
-
- return _cairo_surface_set_clip_region_internal (surface, clip_region, FALSE, TRUE);
+ surface->next_clip_serial = 0;
+ surface->current_clip_serial = 0;
}
cairo_surface_t *
@@ -286,14 +174,6 @@ cairo_surface_finish (cairo_surface_t *surface)
if (surface->finished)
return CAIRO_STATUS_SURFACE_FINISHED;
- if (surface->saves)
- return CAIRO_STATUS_BAD_NESTING;
-
- if (surface->clip_region) {
- pixman_region_destroy (surface->clip_region);
- surface->clip_region = NULL;
- }
-
if (surface->backend->finish) {
status = surface->backend->finish (surface);
if (status)
@@ -521,7 +401,7 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
if (surface->backend->clone_similar) {
status = surface->backend->clone_similar (surface, src, clone_out);
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
- return status;
+ return status;
}
status = _cairo_surface_acquire_source_image (src, &image, &image_extra);
@@ -907,63 +787,153 @@ _cairo_surface_show_page (cairo_surface_t *surface)
return surface->backend->show_page (surface);
}
-static cairo_status_t
-_cairo_surface_set_clip_region_internal (cairo_surface_t *surface,
- pixman_region16_t *region,
- cairo_bool_t copy_region,
- cairo_bool_t free_existing)
+/**
+ * _cairo_surface_allocate_clip_serial:
+ * @surface: the #cairo_surface_t to return the serial number for
+ *
+ * Returns the serial number associated with the current
+ * clip in the surface. All gstate functions must
+ * verify that the correct clip is set in the surface before
+ * invoking any surface drawing function
+ */
+cairo_private unsigned int
+_cairo_surface_get_current_clip_serial (cairo_surface_t *surface)
{
+ return surface->current_clip_serial;
+}
+
+/**
+ * _cairo_surface_allocate_clip_serial:
+ * @surface: the #cairo_surface_t to allocate a serial number from
+ *
+ * Each surface has a separate set of clipping serial numbers,
+ * and this function allocates one from the specified surface.
+ * As zero is reserved for the special no-clipping case,
+ * this function will not return that.
+ */
+cairo_private unsigned int
+_cairo_surface_allocate_clip_serial (cairo_surface_t *surface)
+{
+ unsigned int serial;
+
+ if ((serial = ++(surface->next_clip_serial)) == 0)
+ serial = ++(surface->next_clip_serial);
+ return serial;
+}
+
+/**
+ * _cairo_surface_reset_clip:
+ * @surface: the #cairo_surface_t to reset the clip on
+ *
+ * This function sets the clipping for the surface to
+ * None, which is to say that drawing is entirely
+ * unclipped. It also sets the clip serial number
+ * to zero.
+ */
+cairo_private cairo_status_t
+_cairo_surface_reset_clip (cairo_surface_t *surface)
+{
+ cairo_status_t status;
+
if (surface->finished)
return CAIRO_STATUS_SURFACE_FINISHED;
-
- if (region == surface->clip_region)
- return CAIRO_STATUS_SUCCESS;
+ surface->current_clip_serial = 0;
+#if 0
+ if (surface->backend->clip_path) {
+ status = surface->backend->clip_path (surface, NULL);
+ if (!CAIRO_OK(status))
+ return status;
+ }
+#endif
+ if (surface->backend->set_clip_region != NULL) {
+ status = surface->backend->set_clip_region (surface, NULL);
+ if (!CAIRO_OK(status))
+ return status;
+ }
+ return CAIRO_STATUS_SUCCESS;
+}
+
+/**
+ * _cairo_surface_can_clip_region:
+ * @surface: the #cairo_surface_t to check for region clipping support
+ *
+ * This function checks whether the specified surface can
+ * support region-based clipping.
+ */
+cairo_private cairo_status_t
+_cairo_surface_can_clip_region (cairo_surface_t *surface)
+{
+ if (surface->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
if (surface->backend->set_clip_region == NULL)
return CAIRO_INT_STATUS_UNSUPPORTED;
+ return CAIRO_STATUS_SUCCESS;
+}
- if (surface->clip_region) {
- if (free_existing)
- pixman_region_destroy (surface->clip_region);
- surface->clip_region = NULL;
- }
-
- if (region) {
- if (copy_region) {
- surface->clip_region = pixman_region_create ();
- pixman_region_copy (surface->clip_region, region);
- } else
- surface->clip_region = region;
- }
+/**
+ * _cairo_surface_set_clip_region:
+ * @surface: the #cairo_surface_t to reset the clip on
+ * @region: the #pixman_region16_t to use for clipping
+ * @serial: the clip serial number associated with the region
+ *
+ * This function sets the clipping for the surface to
+ * the specified region and sets the surface clipping
+ * serial number to the associated serial number.
+ */
+cairo_private cairo_status_t
+_cairo_surface_set_clip_region (cairo_surface_t *surface,
+ pixman_region16_t *region,
+ unsigned int serial)
+{
+ if (surface->finished)
+ return CAIRO_STATUS_SURFACE_FINISHED;
+
+ assert (surface->backend->set_clip_region != NULL);
+ surface->current_clip_serial = serial;
return surface->backend->set_clip_region (surface, region);
}
-cairo_status_t
-_cairo_surface_set_clip_region (cairo_surface_t *surface,
- pixman_region16_t *region)
+#if 0
+/* new interfaces for path-based clipping */
+cairo_private cairo_status_t
+_cairo_surface_can_clip_path (cairo_surface_t *surface)
{
- return _cairo_surface_set_clip_region_internal (surface, region, TRUE, TRUE);
}
+cairo_private cairo_status_t
+_cairo_surface_clip_path (cairo_surface_t *surface,
+ cairo_path_fixed_t *path,
+ unsigned int serial)
+{
+ surface->current_clip_serial = clip_serial;
+ return surface->backend->clip_path (surface, path);
+}
+#endif
+
+/**
+ * _cairo_surface_get_extents:
+ * @surface: the #cairo_surface_t to fetch extents for
+ *
+ * This function returns a bounding box for the surface. The
+ * surface bounds are defined as a region beyond which no
+ * rendering will possibly be recorded, in otherwords,
+ * it is the maximum extent of potentially usable
+ * coordinates. For simple pixel-based surfaces,
+ * it can be a close bound on the retained pixel
+ * region. For virtual surfaces (PDF et al), it
+ * cannot and must extend to the reaches of the
+ * target system coordinate space.
+ */
+
cairo_status_t
-_cairo_surface_get_clip_extents (cairo_surface_t *surface,
- cairo_rectangle_t *rectangle)
+_cairo_surface_get_extents (cairo_surface_t *surface,
+ cairo_rectangle_t *rectangle)
{
if (surface->finished)
return CAIRO_STATUS_SURFACE_FINISHED;
- if (surface->clip_region) {
- pixman_box16_t *box = pixman_region_extents (surface->clip_region);
-
- rectangle->x = box->x1;
- rectangle->y = box->y1;
- rectangle->width = box->x2 - box->x1;
- rectangle->height = box->y2 - box->y1;
-
- return CAIRO_STATUS_SUCCESS;
- }
-
return surface->backend->get_extents (surface, rectangle);
}
diff --git a/src/cairo-xcb-surface.c b/src/cairo-xcb-surface.c
index 95568d608..633097331 100644
--- a/src/cairo-xcb-surface.c
+++ b/src/cairo-xcb-surface.c
@@ -1016,7 +1016,7 @@ static const cairo_surface_backend_t cairo_xcb_surface_backend = {
_cairo_xcb_surface_composite_trapezoids,
NULL, /* copy_page */
NULL, /* show_page */
- _cairo_xcb_surface_set_clip_region,
+ NULL, /* _cairo_xcb_surface_set_clip_region */
_cairo_xcb_surface_get_extents,
NULL /* show_glyphs */
};
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 41fb00c44..8b20ce2d6 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -46,7 +46,14 @@ typedef int (*cairo_xlib_error_func_t) (Display *display,
typedef struct _cairo_xlib_surface cairo_xlib_surface_t;
-static void _cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface);
+static void
+_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface);
+
+static void
+_cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t *surface);
+
+static void
+_cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t *surface);
/*
* Instead of taking two round trips for each blending request,
@@ -74,7 +81,8 @@ struct _cairo_xlib_surface {
int height;
int depth;
- Picture picture;
+ Picture dst_picture, src_picture;
+
XRenderPictFormat *format;
};
@@ -197,8 +205,11 @@ static cairo_status_t
_cairo_xlib_surface_finish (void *abstract_surface)
{
cairo_xlib_surface_t *surface = abstract_surface;
- if (surface->picture)
- XRenderFreePicture (surface->dpy, surface->picture);
+ if (surface->dst_picture)
+ XRenderFreePicture (surface->dpy, surface->dst_picture);
+
+ if (surface->src_picture)
+ XRenderFreePicture (surface->dpy, surface->src_picture);
if (surface->owns_pixmap)
XFreePixmap (surface->dpy, surface->drawable);
@@ -433,6 +444,26 @@ _get_image_surface (cairo_xlib_surface_t *surface,
}
static void
+_cairo_xlib_surface_ensure_src_picture (cairo_xlib_surface_t *surface)
+{
+ if (!surface->src_picture)
+ surface->src_picture = XRenderCreatePicture (surface->dpy,
+ surface->drawable,
+ surface->format,
+ 0, NULL);
+}
+
+static void
+_cairo_xlib_surface_ensure_dst_picture (cairo_xlib_surface_t *surface)
+{
+ if (!surface->dst_picture)
+ surface->dst_picture = XRenderCreatePicture (surface->dpy,
+ surface->drawable,
+ surface->format,
+ 0, NULL);
+}
+
+static void
_cairo_xlib_surface_ensure_gc (cairo_xlib_surface_t *surface)
{
XGCValues gcv;
@@ -588,7 +619,7 @@ _cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface,
{
XTransform xtransform;
- if (!surface->picture)
+ if (!surface->src_picture)
return CAIRO_STATUS_SUCCESS;
xtransform.matrix[0][0] = _cairo_fixed_from_double (matrix->xx);
@@ -617,7 +648,7 @@ _cairo_xlib_surface_set_matrix (cairo_xlib_surface_t *surface,
return CAIRO_INT_STATUS_UNSUPPORTED;
}
- XRenderSetPictureTransform (surface->dpy, surface->picture, &xtransform);
+ XRenderSetPictureTransform (surface->dpy, surface->src_picture, &xtransform);
return CAIRO_STATUS_SUCCESS;
}
@@ -628,7 +659,7 @@ _cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface,
{
char *render_filter;
- if (!surface->picture)
+ if (!surface->src_picture)
return CAIRO_STATUS_SUCCESS;
if (!CAIRO_SURFACE_RENDER_HAS_FILTERS (surface))
@@ -660,7 +691,7 @@ _cairo_xlib_surface_set_filter (cairo_xlib_surface_t *surface,
break;
}
- XRenderSetPictureFilter (surface->dpy, surface->picture,
+ XRenderSetPictureFilter (surface->dpy, surface->src_picture,
render_filter, NULL, 0);
return CAIRO_STATUS_SUCCESS;
@@ -672,13 +703,13 @@ _cairo_xlib_surface_set_repeat (cairo_xlib_surface_t *surface, int repeat)
XRenderPictureAttributes pa;
unsigned long mask;
- if (!surface->picture)
+ if (!surface->src_picture)
return CAIRO_STATUS_SUCCESS;
mask = CPRepeat;
pa.repeat = repeat;
- XRenderChangePicture (surface->dpy, surface->picture, mask, &pa);
+ XRenderChangePicture (surface->dpy, surface->src_picture, mask, &pa);
return CAIRO_STATUS_SUCCESS;
}
@@ -689,6 +720,8 @@ _cairo_xlib_surface_set_attributes (cairo_xlib_surface_t *surface,
{
cairo_int_status_t status;
+ _cairo_xlib_surface_ensure_src_picture (surface);
+
status = _cairo_xlib_surface_set_matrix (surface, &attributes->matrix);
if (status)
return status;
@@ -786,15 +819,17 @@ _cairo_xlib_surface_composite (cairo_operator_t operator,
return status;
status = _cairo_xlib_surface_set_attributes (src, &src_attr);
+
if (CAIRO_OK (status)) {
+ _cairo_xlib_surface_ensure_dst_picture (dst);
if (mask) {
status = _cairo_xlib_surface_set_attributes (mask, &mask_attr);
if (CAIRO_OK (status))
XRenderComposite (dst->dpy,
_render_operator (operator),
- src->picture,
- mask->picture,
- dst->picture,
+ src->src_picture,
+ mask->src_picture,
+ dst->dst_picture,
src_x + src_attr.x_offset,
src_y + src_attr.y_offset,
mask_x + mask_attr.x_offset,
@@ -804,9 +839,9 @@ _cairo_xlib_surface_composite (cairo_operator_t operator,
} else {
XRenderComposite (dst->dpy,
_render_operator (operator),
- src->picture,
+ src->src_picture,
0,
- dst->picture,
+ dst->dst_picture,
src_x + src_attr.x_offset,
src_y + src_attr.y_offset,
0, 0,
@@ -842,9 +877,10 @@ _cairo_xlib_surface_fill_rectangles (void *abstract_surface,
render_color.alpha = color->alpha_short;
/* XXX: This XRectangle cast is evil... it needs to go away somehow. */
+ _cairo_xlib_surface_ensure_dst_picture (surface);
XRenderFillRectangles (surface->dpy,
_render_operator (operator),
- surface->picture,
+ surface->dst_picture,
&render_color, (XRectangle *) rects, num_rects);
return CAIRO_STATUS_SUCCESS;
@@ -892,11 +928,12 @@ _cairo_xlib_surface_composite_trapezoids (cairo_operator_t operator,
render_src_y = src_y + render_reference_y - dst_y;
/* XXX: The XTrapezoid cast is evil and needs to go away somehow. */
+ _cairo_xlib_surface_ensure_dst_picture (dst);
status = _cairo_xlib_surface_set_attributes (src, &attributes);
if (CAIRO_OK (status))
XRenderCompositeTrapezoids (dst->dpy,
_render_operator (operator),
- src->picture, dst->picture,
+ src->src_picture, dst->dst_picture,
XRenderFindStandardFormat (dst->dpy, PictStandardA8),
render_src_x + attributes.x_offset,
render_src_y + attributes.y_offset,
@@ -917,10 +954,11 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface,
if (surface->gc)
XSetClipMask (surface->dpy, surface->gc, None);
- if (surface->picture) {
+ if (surface->format) {
XRenderPictureAttributes pa;
pa.clip_mask = None;
- XRenderChangePicture (surface->dpy, surface->picture,
+ _cairo_xlib_surface_ensure_dst_picture (surface);
+ XRenderChangePicture (surface->dpy, surface->dst_picture,
CPClipMask, &pa);
}
} else {
@@ -949,9 +987,11 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface,
if (surface->gc)
XSetClipRectangles(surface->dpy, surface->gc,
0, 0, rects, n_boxes, YXSorted);
- if (surface->picture)
- XRenderSetPictureClipRectangles (surface->dpy, surface->picture,
+ if (surface->format) {
+ _cairo_xlib_surface_ensure_dst_picture (surface);
+ XRenderSetPictureClipRectangles (surface->dpy, surface->dst_picture,
0, 0, rects, n_boxes);
+ }
if (rects)
free (rects);
@@ -1043,15 +1083,12 @@ _cairo_xlib_surface_create_internal (Display *dpy,
surface->gc = NULL;
surface->drawable = drawable;
surface->owns_pixmap = FALSE;
- surface->visual = visual;
- surface->format = format;
surface->use_pixmap = 0;
surface->width = width;
surface->height = height;
- surface->depth = depth;
if (format) {
- surface->depth = format->depth;
+ depth = format->depth;
} else if (visual) {
int i, j, k;
@@ -1061,10 +1098,10 @@ _cairo_xlib_surface_create_internal (Display *dpy,
for (i = 0; i < ScreenCount (dpy); i++) {
Screen *screen = ScreenOfDisplay (dpy, i);
for (j = 0; j < screen->ndepths; j++) {
- Depth *depth = &screen->depths[j];
- for (k = 0; k < depth->nvisuals; k++) {
- if (&depth->visuals[k] == visual) {
- surface->depth = depth->depth;
+ Depth *d = &screen->depths[j];
+ for (k = 0; k < d->nvisuals; k++) {
+ if (&d->visuals[k] == visual) {
+ depth = d->depth;
goto found;
}
}
@@ -1080,21 +1117,22 @@ _cairo_xlib_surface_create_internal (Display *dpy,
surface->render_minor = -1;
}
- surface->picture = None;
+ surface->dst_picture = None;
+ surface->src_picture = None;
if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface)) {
-
if (!format) {
if (visual) {
format = XRenderFindVisualFormat (dpy, visual);
} else if (depth == 1)
format = XRenderFindStandardFormat (dpy, PictStandardA1);
}
+ } else
+ format = NULL;
- if (format)
- surface->picture = XRenderCreatePicture (dpy, drawable,
- format, 0, NULL);
- }
+ surface->visual = visual;
+ surface->format = format;
+ surface->depth = depth;
return (cairo_surface_t *) surface;
}
@@ -1479,8 +1517,8 @@ _cairo_xlib_surface_show_glyphs32 (cairo_scaled_font_t *scaled_font,
XRenderCompositeText32 (self->dpy,
_render_operator (operator),
- src->picture,
- self->picture,
+ src->src_picture,
+ self->dst_picture,
g->a8_pict_format,
source_x, source_y,
0, 0,
@@ -1556,8 +1594,8 @@ _cairo_xlib_surface_show_glyphs16 (cairo_scaled_font_t *scaled_font,
XRenderCompositeText16 (self->dpy,
_render_operator (operator),
- src->picture,
- self->picture,
+ src->src_picture,
+ self->dst_picture,
g->a8_pict_format,
source_x, source_y,
0, 0,
@@ -1632,8 +1670,8 @@ _cairo_xlib_surface_show_glyphs8 (cairo_scaled_font_t *scaled_font,
XRenderCompositeText8 (self->dpy,
_render_operator (operator),
- src->picture,
- self->picture,
+ src->src_picture,
+ self->dst_picture,
g->a8_pict_format,
source_x, source_y,
0, 0,
@@ -1680,7 +1718,7 @@ _cairo_xlib_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
glyphset_cache_entry_t *stack_entries [N_STACK_BUF];
int i;
- if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (self))
+ if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE_TEXT (self) || !self->format)
return CAIRO_INT_STATUS_UNSUPPORTED;
status = _cairo_pattern_acquire_surface (pattern, &self->base,
@@ -1738,6 +1776,7 @@ _cairo_xlib_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
/* Call the appropriate sub-function. */
+ _cairo_xlib_surface_ensure_dst_picture (self);
if (elt_size == 8)
status = _cairo_xlib_surface_show_glyphs8 (scaled_font, operator, g, &key, src, self,
source_x + attributes.x_offset,
diff --git a/src/cairo.c b/src/cairo.c
index c6f46bff5..b70a248b6 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -2163,8 +2163,6 @@ cairo_status_string (cairo_t *cr)
return "the target surface has been finished";
case CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
return "the surface type is not appropriate for the operation";
- case CAIRO_STATUS_BAD_NESTING:
- return "drawing operations interleaved for two contexts for the same surface";
}
return "<unknown error status>";
diff --git a/src/cairo.h b/src/cairo.h
index 4cb3a023e..19d2afe01 100644
--- a/src/cairo.h
+++ b/src/cairo.h
@@ -130,6 +130,7 @@ typedef struct _cairo_user_data_key {
* @CAIRO_STATUS_NO_MEMORY:
* @CAIRO_STATUS_INVALID_RESTORE:
* @CAIRO_STATUS_INVALID_POP_GROUP:
+ * @CAIRO_STATUS_NO_CURRENT_POINT:
* @CAIRO_STATUS_INVALID_MATRIX:
* @CAIRO_STATUS_NO_TARGET_SURFACE:
* @CAIRO_STATUS_NULL_POINTER:
@@ -139,11 +140,6 @@ typedef struct _cairo_user_data_key {
* @CAIRO_STATUS_WRITE_ERROR:
* @CAIRO_STATUS_SURFACE_FINISHED:
* @CAIRO_STATUS_SURFACE_TYPE_MISMATCH:
- * @CAIRO_STATUS_BAD_NESTING: the same surface was used as the
- * target surface for two different cairo contexts at once,
- * and more drawing was done on the first context before the
- * surface was unset as the target for the second context.
- * See the documentation for cairo_create().
*
* #cairo_status_t is used to indicate errors that can occur when
* using Cairo. In some cases it is returned directly by functions.
@@ -165,7 +161,6 @@ typedef enum cairo_status {
CAIRO_STATUS_WRITE_ERROR,
CAIRO_STATUS_SURFACE_FINISHED,
CAIRO_STATUS_SURFACE_TYPE_MISMATCH,
- CAIRO_STATUS_BAD_NESTING
} cairo_status_t;
/**
diff --git a/src/cairoint.h b/src/cairoint.h
index 90d59b2cb..26fe3ecba 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -699,8 +699,6 @@ typedef struct _cairo_format_masks {
unsigned long blue_mask;
} cairo_format_masks_t;
-typedef struct _cairo_surface_save cairo_surface_save_t;
-
struct _cairo_surface {
const cairo_surface_backend_t *backend;
@@ -715,10 +713,21 @@ struct _cairo_surface {
double device_x_offset;
double device_y_offset;
- cairo_surface_save_t *saves; /* Stack of saved states from cairo_surface_begin/end() */
- int level; /* Number saved states */
-
- pixman_region16_t *clip_region;
+ /*
+ * Each time a clip region is modified, it gets the next value in this
+ * sequence. This means that clip regions for this surface are uniquely
+ * identified andupdates to the clip can be readily identified
+ */
+ unsigned int next_clip_serial;
+ /*
+ * The serial number of the current clip. This is set when
+ * the surface clipping is set. The gstate can then cheaply
+ * check whether the surface clipping is already correct before
+ * performing a rendering operation.
+ *
+ * The special value '0' is reserved for the unclipped case.
+ */
+ unsigned int current_clip_serial;
};
struct _cairo_image_surface {
@@ -840,7 +849,6 @@ typedef struct _cairo_surface_attributes {
int x_offset;
int y_offset;
cairo_bool_t acquired;
- cairo_bool_t clip_saved;
void *extra;
} cairo_surface_attributes_t;
@@ -880,13 +888,6 @@ typedef struct _cairo_traps {
#define CAIRO_GSTATE_MITER_LIMIT_DEFAULT 10.0
#define CAIRO_GSTATE_DEFAULT_FONT_SIZE 10.0
-/* Need a name distinct from the cairo_clip function */
-typedef struct _cairo_clip_rec {
- cairo_rectangle_t rect;
- pixman_region16_t *region;
- cairo_surface_t *surface;
-} cairo_clip_rec_t;
-
typedef struct _cairo_gstate cairo_gstate_t;
typedef struct _cairo_stroke_face {
@@ -1378,7 +1379,7 @@ _cairo_path_fixed_stroke_to_traps (cairo_path_fixed_t *path,
cairo_gstate_t *gstate,
cairo_traps_t *traps);
-/* cairo_surface.c */
+/* cairo-surface.c */
cairo_private cairo_surface_t *
_cairo_surface_create_similar_scratch (cairo_surface_t *other,
cairo_format_t format,
@@ -1398,15 +1399,6 @@ _cairo_surface_init (cairo_surface_t *surface,
const cairo_surface_backend_t *backend);
cairo_private cairo_status_t
-_cairo_surface_begin (cairo_surface_t *surface);
-
-cairo_private cairo_status_t
-_cairo_surface_begin_reset_clip (cairo_surface_t *surface);
-
-cairo_private cairo_status_t
-_cairo_surface_end (cairo_surface_t *surface);
-
-cairo_private cairo_status_t
_cairo_surface_fill_rectangle (cairo_surface_t *surface,
cairo_operator_t operator,
const cairo_color_t *color,
@@ -1490,13 +1482,37 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
cairo_surface_t *src,
cairo_surface_t **clone_out);
+cairo_private unsigned int
+_cairo_surface_get_current_clip_serial (cairo_surface_t *surface);
+
+cairo_private unsigned int
+_cairo_surface_allocate_clip_serial (cairo_surface_t *surface);
+
+cairo_private cairo_status_t
+_cairo_surface_reset_clip (cairo_surface_t *surface);
+
+cairo_private cairo_status_t
+_cairo_surface_can_clip_region (cairo_surface_t *surface);
+
+cairo_private cairo_status_t
+_cairo_surface_set_clip_region (cairo_surface_t *surface,
+ pixman_region16_t *region,
+ unsigned int serial);
+
+#if 0
+/* new interfaces for path-based clipping */
cairo_private cairo_status_t
-_cairo_surface_set_clip_region (cairo_surface_t *surface,
- pixman_region16_t *region);
+_cairo_surface_can_clip_path (cairo_surface_t *surface);
+
+cairo_private cairo_status_t
+_cairo_surface_clip_path (cairo_surface_t *surface,
+ cairo_path_fixed_t *path,
+ unsigned int serial);
+#endif
cairo_private cairo_status_t
-_cairo_surface_get_clip_extents (cairo_surface_t *surface,
- cairo_rectangle_t *rectangle);
+_cairo_surface_get_extents (cairo_surface_t *surface,
+ cairo_rectangle_t *rectangle);
cairo_private cairo_status_t
_cairo_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
diff --git a/test/Makefile.am b/test/Makefile.am
index 0ab593678..2550582a0 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -93,7 +93,6 @@ rel-path-ref.png
XFAIL_TESTS = \
filter-nearest-offset \
pixman-rotate \
-self-copy \
source-surface-scale-paint \
text-rotate
diff --git a/test/self-copy.c b/test/self-copy.c
index 3ad406ecc..5f4398b25 100644
--- a/test/self-copy.c
+++ b/test/self-copy.c
@@ -85,6 +85,5 @@ draw (cairo_t *cr, int width, int height)
int
main (void)
{
- return cairo_test_expect_failure (&test, draw,
- "copying from a surface to itself doesn't handle clipping properly");
+ return cairo_test (&test, draw);
}