mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-05-08 20:48:03 +02:00
Fix up clip at pop_group time, to keep it in surface backend coordinates
We keep the clip in surface-backend coordinates always, so it needs fixing whenever we change the target surface out in the gstate. The only place this happens is in push_group, so fix it as part of gstate_redirect().
This commit is contained in:
parent
7fa3c6eee5
commit
fb7f7c2f27
4 changed files with 92 additions and 29 deletions
|
|
@ -87,6 +87,11 @@ _cairo_clip_fini (cairo_clip_t *clip);
|
|||
cairo_private void
|
||||
_cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other);
|
||||
|
||||
cairo_private void
|
||||
_cairo_clip_init_deep_copy (cairo_clip_t *clip,
|
||||
cairo_clip_t *other,
|
||||
cairo_surface_t *target);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_clip_reset (cairo_clip_t *clip);
|
||||
|
||||
|
|
|
|||
|
|
@ -234,8 +234,7 @@ _cairo_clip_intersect_path (cairo_clip_t *clip,
|
|||
cairo_path_fixed_t *path,
|
||||
cairo_fill_rule_t fill_rule,
|
||||
double tolerance,
|
||||
cairo_antialias_t antialias,
|
||||
cairo_surface_t *target)
|
||||
cairo_antialias_t antialias)
|
||||
{
|
||||
cairo_clip_path_t *clip_path;
|
||||
cairo_status_t status;
|
||||
|
|
@ -259,7 +258,6 @@ _cairo_clip_intersect_path (cairo_clip_t *clip,
|
|||
clip_path->antialias = antialias;
|
||||
clip_path->prev = clip->path;
|
||||
clip->path = clip_path;
|
||||
clip->serial = _cairo_surface_allocate_clip_serial (target);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
|
@ -447,10 +445,14 @@ _cairo_clip_clip (cairo_clip_t *clip,
|
|||
|
||||
status = _cairo_clip_intersect_path (clip,
|
||||
path, fill_rule, tolerance,
|
||||
antialias, target);
|
||||
antialias);
|
||||
if (status == CAIRO_STATUS_SUCCESS)
|
||||
clip->serial = _cairo_surface_allocate_clip_serial (target);
|
||||
|
||||
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
|
||||
return status;
|
||||
|
||||
|
||||
_cairo_traps_init (&traps);
|
||||
status = _cairo_path_fixed_fill_to_traps (path,
|
||||
fill_rule,
|
||||
|
|
@ -472,3 +474,70 @@ _cairo_clip_clip (cairo_clip_t *clip,
|
|||
|
||||
return status;
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_clip_translate (cairo_clip_t *clip,
|
||||
cairo_fixed_t tx,
|
||||
cairo_fixed_t ty)
|
||||
{
|
||||
if (clip->region) {
|
||||
pixman_region_translate (clip->region,
|
||||
_cairo_fixed_integer_part (tx),
|
||||
_cairo_fixed_integer_part (ty));
|
||||
}
|
||||
|
||||
if (clip->surface) {
|
||||
clip->surface_rect.x += _cairo_fixed_integer_part (tx);
|
||||
clip->surface_rect.y += _cairo_fixed_integer_part (ty);
|
||||
}
|
||||
|
||||
if (clip->path) {
|
||||
cairo_clip_path_t *clip_path = clip->path;
|
||||
while (clip_path) {
|
||||
_cairo_path_fixed_offset (&clip_path->path, tx, ty);
|
||||
clip_path = clip_path->prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_clip_path_reapply_clip_path (cairo_clip_t *clip,
|
||||
cairo_clip_path_t *clip_path)
|
||||
{
|
||||
if (clip_path->prev)
|
||||
_cairo_clip_path_reapply_clip_path (clip, clip_path->prev);
|
||||
|
||||
_cairo_clip_intersect_path (clip,
|
||||
&clip_path->path,
|
||||
clip_path->fill_rule,
|
||||
clip_path->tolerance,
|
||||
clip_path->antialias);
|
||||
}
|
||||
|
||||
void
|
||||
_cairo_clip_init_deep_copy (cairo_clip_t *clip,
|
||||
cairo_clip_t *other,
|
||||
cairo_surface_t *target)
|
||||
{
|
||||
_cairo_clip_init (clip, target);
|
||||
|
||||
if (other->mode != clip->mode) {
|
||||
/* We should reapply the original clip path in this case, and let
|
||||
* whatever the right handling is happen */
|
||||
} else {
|
||||
if (other->region) {
|
||||
clip->region = pixman_region_create ();
|
||||
pixman_region_copy (clip->region, other->region);
|
||||
}
|
||||
|
||||
if (other->surface) {
|
||||
_cairo_surface_clone_similar (target, clip->surface, &clip->surface);
|
||||
clip->surface_rect = other->surface_rect;
|
||||
}
|
||||
|
||||
if (other->path) {
|
||||
_cairo_clip_path_reapply_clip_path (clip, other->path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -303,30 +303,14 @@ _cairo_gstate_redirect_target (cairo_gstate_t *gstate, cairo_surface_t *child)
|
|||
* since its ref is now owned by gstate->parent_target */
|
||||
gstate->target = cairo_surface_reference (child);
|
||||
|
||||
/* Check that the new surface's clip mode is compatible */
|
||||
if (gstate->clip.mode != _cairo_surface_get_clip_mode (child)) {
|
||||
/* clip is not compatible; try to recreate it */
|
||||
/* XXX - saving the clip path always might be useful here,
|
||||
* so that we could recover non-CLIP_MODE_PATH clips */
|
||||
if (gstate->clip.mode == CAIRO_CLIP_MODE_PATH) {
|
||||
cairo_clip_t saved_clip = gstate->clip;
|
||||
_cairo_clip_fini (&gstate->clip);
|
||||
_cairo_clip_init_deep_copy (&gstate->clip, &gstate->next->clip, child);
|
||||
|
||||
_cairo_clip_init (&gstate->clip, child);
|
||||
|
||||
/* unwind the path and re-apply */
|
||||
_cairo_gstate_recursive_apply_clip_path (gstate, saved_clip.path);
|
||||
|
||||
_cairo_clip_fini (&saved_clip);
|
||||
} else {
|
||||
/* uh, not sure what to do here.. */
|
||||
_cairo_clip_fini (&gstate->clip);
|
||||
_cairo_clip_init (&gstate->clip, child);
|
||||
}
|
||||
} else {
|
||||
/* clip is compatible; allocate a new serial for the new surface. */
|
||||
if (gstate->clip.serial)
|
||||
gstate->clip.serial = _cairo_surface_allocate_clip_serial (child);
|
||||
}
|
||||
/* The clip is in surface backend coordinates for the previous target;
|
||||
* translate it into the child's backend coordinates. */
|
||||
_cairo_clip_translate (&gstate->clip,
|
||||
_cairo_fixed_from_double (child->device_x_offset - gstate->parent_target->device_x_offset),
|
||||
_cairo_fixed_from_double (child->device_y_offset - gstate->parent_target->device_y_offset));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -385,8 +385,13 @@ cairo_push_group_with_content (cairo_t *cr, cairo_content_t content)
|
|||
goto bail;
|
||||
|
||||
/* Set device offsets on the new surface so that logically it appears at
|
||||
* the same location on the parent surface. */
|
||||
cairo_surface_set_device_offset (group_surface, -extents.x, -extents.y);
|
||||
* the same location on the parent surface -- when we pop_group this,
|
||||
* the source pattern will get fixed up for the appropriate target surface
|
||||
* device offsets, so we want to set our own surface offsets from /that/,
|
||||
* and not from the device origin. */
|
||||
cairo_surface_set_device_offset (group_surface,
|
||||
cr->gstate->target->device_x_offset - extents.x,
|
||||
cr->gstate->target->device_y_offset - extents.y);
|
||||
|
||||
/* create a new gstate for the redirect */
|
||||
cairo_save (cr);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue