diff options
-rw-r--r-- | ChangeLog | 95 | ||||
-rw-r--r-- | src/cairo-gstate-private.h | 30 | ||||
-rw-r--r-- | src/cairo-gstate.c | 286 | ||||
-rw-r--r-- | src/cairo-pattern.c | 28 | ||||
-rw-r--r-- | src/cairo-surface.c | 292 | ||||
-rw-r--r-- | src/cairo-xcb-surface.c | 2 | ||||
-rw-r--r-- | src/cairo-xlib-surface.c | 123 | ||||
-rw-r--r-- | src/cairo.c | 2 | ||||
-rw-r--r-- | src/cairo.h | 7 | ||||
-rw-r--r-- | src/cairoint.h | 72 | ||||
-rw-r--r-- | test/Makefile.am | 1 | ||||
-rw-r--r-- | test/self-copy.c | 3 |
12 files changed, 541 insertions, 400 deletions
@@ -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, ®ion); - 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, ®ion); + 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); } |