Replace nesting-only surface clipping with gstate contained serial-number tracked clipping sets that are loaded into the surface on demand just before each rendering operation. This permits multiple cairo_t contexts to reference a surface without regard to ordering of operations among the contexts.

Also in this patch is a change to the xlib surface that creates two separate Pictures, one for source and one for destination operands which separates the source clipping from destination clipping. Cairo now specifies that sources are never clipped by any clipping applied to them as destinations.
Move cairo_clip_t (renamed from cairo_clip_rec_t) from cairoint.h to cairo-gstate-private.h. Eliminate stack of clip state from surfaces. Add new surface clipping API.
Manage clip objects entirely within the gstate, loading the whole thing into the surface just before drawing.
Source surfaces need not have clipping modified as the surface interface now specifies that source surfaces are always unclipped.
Eliminate nested clipping contexts, leaving clip management entirely to the gstate. Create new clip API for the gstate which uses per-surface serial numbers to match gstate clipping against current surface clipping values.
Surfaces no longer track clipping regions at all, so the old _cairo_surface_get_clip_extents has been replaced with _cairo_surface_get_extents. For PDF/PS surfaces, this function is expected to return a rectangle covering the entire fixed point coordinate space to leave rendering unclipped by the surface.
Region clipping capability is now signalled by a non-NULL function pointer in set_clip_region.
Each surface now contains two Pictures, one for source and one for destination operands so that source operands are never clipped by destination clipping.
CAIRO_STATUS_BAD_NESTING removed
self-copy now passes (Xlib only, until libpixman changes land)
reviewed by: krh, otaylor, cworth
This commit is contained in:
Keith Packard 2005-05-26 11:35:44 +00:00
parent be903f4c22
commit 45a966f695
12 changed files with 546 additions and 405 deletions

View file

@ -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.

View file

@ -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;

View file

@ -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_clip (cairo_gstate_t *gstate)
{
cairo_surface_t *surface = gstate->surface;
if (!surface)
return CAIRO_STATUS_NULL_POINTER;
if (gstate->clip.serial == _cairo_surface_get_current_clip_serial (surface))
return CAIRO_STATUS_SUCCESS;
/* 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)
{
cairo_status_t status;
if (gstate->surface == surface)
return CAIRO_STATUS_SUCCESS;
if (surface) {
status = _cairo_surface_begin_reset_clip (surface);
if (!CAIRO_OK (status))
return status;
}
/* 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 (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);
}
if (CAIRO_OK (status))
status = _cairo_surface_set_clip_region (gstate->surface,
gstate->clip.region);
if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
if (!CAIRO_OK (status))
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;
}
/* Fall through as status == CAIRO_INT_STATUS_UNSUPPORTED
means that backend doesn't support clipping regions and
mask surface clipping should be used instead. */
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);
}
gstate->clip.serial = _cairo_surface_allocate_clip_serial (gstate->surface);
_cairo_traps_fini (&traps);
return status;
}
}
/* 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);

View file

@ -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,

View file

@ -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;
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 (region == surface->clip_region)
return CAIRO_STATUS_SUCCESS;
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);
}

View file

@ -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 */
};

View file

@ -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);
@ -432,6 +443,26 @@ _get_image_surface (cairo_xlib_surface_t *surface,
return CAIRO_STATUS_SUCCESS;
}
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)
{
@ -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,

View file

@ -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>";

View file

@ -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;
/**

View file

@ -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,
@ -1397,15 +1398,6 @@ cairo_private void
_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,
@ -1490,13 +1482,37 @@ _cairo_surface_clone_similar (cairo_surface_t *surface,
cairo_surface_t *src,
cairo_surface_t **clone_out);
cairo_private cairo_status_t
_cairo_surface_set_clip_region (cairo_surface_t *surface,
pixman_region16_t *region);
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_get_clip_extents (cairo_surface_t *surface,
cairo_rectangle_t *rectangle);
_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_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_extents (cairo_surface_t *surface,
cairo_rectangle_t *rectangle);
cairo_private cairo_status_t
_cairo_surface_show_glyphs (cairo_scaled_font_t *scaled_font,

View file

@ -93,7 +93,6 @@ rel-path-ref.png
XFAIL_TESTS = \
filter-nearest-offset \
pixman-rotate \
self-copy \
source-surface-scale-paint \
text-rotate

View file

@ -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);
}