snapshot: Fix wrong nodes with transformed shadows

Test included.

The test is disabled for Cairo because the Cairo blurring code can't
deal with scaling, which makes things come out wrong for the test that
checks that we do the right thing with the blur radius when scaling.

Related: !6977
This commit is contained in:
Benjamin Otte 2024-03-06 20:46:06 +01:00
parent 8f8ece44a8
commit 53786841cc
4 changed files with 110 additions and 8 deletions

View File

@ -747,12 +747,18 @@ gtk_graphene_rect_scale_affine (const graphene_rect_t *rect,
graphene_rect_normalize (res); graphene_rect_normalize (res);
} }
typedef enum {
ENSURE_POSITIVE_SCALE = (1 << 0),
ENSURE_UNIFORM_SCALE = (1 << 1),
} GtkEnsureFlags;
static void static void
gtk_snapshot_ensure_affine (GtkSnapshot *snapshot, gtk_snapshot_ensure_affine_with_flags (GtkSnapshot *snapshot,
float *scale_x, GtkEnsureFlags flags,
float *scale_y, float *scale_x,
float *dx, float *scale_y,
float *dy) float *dx,
float *dy)
{ {
const GtkSnapshotState *state = gtk_snapshot_get_current_state (snapshot); const GtkSnapshotState *state = gtk_snapshot_get_current_state (snapshot);
@ -765,7 +771,8 @@ gtk_snapshot_ensure_affine (GtkSnapshot *snapshot,
else if (gsk_transform_get_category (state->transform) == GSK_TRANSFORM_CATEGORY_2D_AFFINE) else if (gsk_transform_get_category (state->transform) == GSK_TRANSFORM_CATEGORY_2D_AFFINE)
{ {
gsk_transform_to_affine (state->transform, scale_x, scale_y, dx, dy); gsk_transform_to_affine (state->transform, scale_x, scale_y, dx, dy);
if (*scale_x < 0.0 || *scale_y < 0.0) if (((flags & ENSURE_POSITIVE_SCALE) && (*scale_x < 0.0 || *scale_y < 0.0)) ||
((flags & ENSURE_UNIFORM_SCALE) && (*scale_x != *scale_y)))
{ {
gtk_snapshot_autopush_transform (snapshot); gtk_snapshot_autopush_transform (snapshot);
state = gtk_snapshot_get_current_state (snapshot); state = gtk_snapshot_get_current_state (snapshot);
@ -778,6 +785,19 @@ gtk_snapshot_ensure_affine (GtkSnapshot *snapshot,
} }
} }
static void
gtk_snapshot_ensure_affine (GtkSnapshot *snapshot,
float *scale_x,
float *scale_y,
float *dx,
float *dy)
{
gtk_snapshot_ensure_affine_with_flags (snapshot,
ENSURE_POSITIVE_SCALE,
scale_x, scale_y,
dx, dy);
}
static void static void
gtk_snapshot_ensure_translate (GtkSnapshot *snapshot, gtk_snapshot_ensure_translate (GtkSnapshot *snapshot,
float *dx, float *dx,
@ -1377,11 +1397,19 @@ gtk_snapshot_push_shadow (GtkSnapshot *snapshot,
const GskShadow *shadow, const GskShadow *shadow,
gsize n_shadows) gsize n_shadows)
{ {
const GtkSnapshotState *current_state = gtk_snapshot_get_current_state (snapshot);
GtkSnapshotState *state; GtkSnapshotState *state;
GskTransform *transform;
float scale_x, scale_y, dx, dy;
gsize i;
gtk_snapshot_ensure_affine_with_flags (snapshot,
ENSURE_POSITIVE_SCALE | ENSURE_UNIFORM_SCALE,
&scale_x, &scale_y,
&dx, &dy);
transform = gsk_transform_scale (gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (dx, dy)), scale_x, scale_y);
state = gtk_snapshot_push_state (snapshot, state = gtk_snapshot_push_state (snapshot,
current_state->transform, transform,
gtk_snapshot_collect_shadow, gtk_snapshot_collect_shadow,
gtk_snapshot_clear_shadow); gtk_snapshot_clear_shadow);
@ -1390,13 +1418,23 @@ gtk_snapshot_push_shadow (GtkSnapshot *snapshot,
{ {
state->data.shadow.shadows = NULL; state->data.shadow.shadows = NULL;
memcpy (&state->data.shadow.a_shadow, shadow, sizeof (GskShadow)); memcpy (&state->data.shadow.a_shadow, shadow, sizeof (GskShadow));
state->data.shadow.a_shadow.dx *= scale_x;
state->data.shadow.a_shadow.dy *= scale_y;
state->data.shadow.a_shadow.radius *= scale_x;
} }
else else
{ {
state->data.shadow.shadows = g_malloc (sizeof (GskShadow) * n_shadows); state->data.shadow.shadows = g_malloc (sizeof (GskShadow) * n_shadows);
memcpy (state->data.shadow.shadows, shadow, sizeof (GskShadow) * n_shadows); memcpy (state->data.shadow.shadows, shadow, sizeof (GskShadow) * n_shadows);
for (i = 0; i < n_shadows; i++)
{
state->data.shadow.shadows[i].dx *= scale_x;
state->data.shadow.shadows[i].dy *= scale_y;
state->data.shadow.shadows[i].radius *= scale_x;
}
} }
gsk_transform_unref (transform);
} }
static GskRenderNode * static GskRenderNode *

View File

@ -0,0 +1,63 @@
color {
bounds: -10 0 70 60;
color: white;
}
transform {
transform: scale(5);
child: shadow {
shadows: black 0 1;
child: color {
bounds: 0 0 10 1;
color: red;
}
}
}
transform {
transform: rotate(90);
child: shadow {
shadows: black 5 0;
child: color {
bounds: 20 -50 5 50;
color: lime;
}
}
}
clip {
clip: 0 40 50 10;
child: color-matrix "larry" {
matrix: matrix3d(1000, 0, 0, 0,
0, 1000, 0, 0,
0, 0, 1000, 0,
0, 0, 0, 1000);
child: transform {
transform: scale(5, 1);
child: shadow {
shadows: black 0 5 2;
child: color {
bounds: 0 40 10 5;
color: yellow;
}
}
}
}
}
/* This should be covered by the blur above */
clip {
clip: -10 45 5 5;
child: "larry";
}
clip {
clip: 55 45 5 5;
child: "larry";
}
/* This should not */
clip {
clip: 0 55 50 5;
child: "larry";
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B

View File

@ -149,6 +149,7 @@ compare_render_tests = [
'shadow-offset-clip', 'shadow-offset-clip',
'shadow-offset-to-outside-clip', 'shadow-offset-to-outside-clip',
'shadow-opacity', 'shadow-opacity',
'shadow-replay-nocairo',
'shrink-rounded-border', 'shrink-rounded-border',
'stroke', 'stroke',
'stroke-clipped-nogl', 'stroke-clipped-nogl',