summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);
}