diff --git a/gdk/gdkdihedral.c b/gdk/gdkdihedral.c index 74f5f8b280..f9286a9e61 100644 --- a/gdk/gdkdihedral.c +++ b/gdk/gdkdihedral.c @@ -59,3 +59,9 @@ gdk_dihedral_combine (GdkDihedral first, ((((first & 3) * (((second & 4) >> 1) + 1)) + second) & 3); } +GdkDihedral +gdk_dihedral_invert (GdkDihedral self) +{ + return ((4 - self) * (((self & 4) >> 1) + 1) & 3) | (self & 4); +} + diff --git a/gdk/gdkdihedralprivate.h b/gdk/gdkdihedralprivate.h index a754401fd5..699775d8c2 100644 --- a/gdk/gdkdihedralprivate.h +++ b/gdk/gdkdihedralprivate.h @@ -40,6 +40,7 @@ void gdk_dihedral_get_mat2 (GdkDihedral GdkDihedral gdk_dihedral_combine (GdkDihedral first, GdkDihedral second); +GdkDihedral gdk_dihedral_invert (GdkDihedral self); G_END_DECLS diff --git a/gsk/gpu/gskgpuclip.c b/gsk/gpu/gskgpuclip.c index da297969f7..6cf748bfea 100644 --- a/gsk/gpu/gskgpuclip.c +++ b/gsk/gpu/gskgpuclip.c @@ -168,12 +168,15 @@ gsk_gpu_clip_intersect_rounded_rect (GskGpuClip *dest, void gsk_gpu_clip_scale (GskGpuClip *dest, const GskGpuClip *src, + GdkDihedral dihedral, float scale_x, float scale_y) { + GskRoundedRect tmp; dest->type = src->type; + gsk_rounded_rect_dihedral (&tmp, &src->rect, dihedral); gsk_rounded_rect_scale_affine (&dest->rect, - &src->rect, + &tmp, 1.0f / scale_x, 1.0f / scale_y, 0, 0); } diff --git a/gsk/gpu/gskgpuclipprivate.h b/gsk/gpu/gskgpuclipprivate.h index a83957c1a0..01102d652e 100644 --- a/gsk/gpu/gskgpuclipprivate.h +++ b/gsk/gpu/gskgpuclipprivate.h @@ -6,6 +6,8 @@ #include #include +#include "gdk/gdkdihedralprivate.h" + G_BEGIN_DECLS typedef enum { @@ -51,12 +53,13 @@ gboolean gsk_gpu_clip_intersect_rect (GskGpuC gboolean gsk_gpu_clip_intersect_rounded_rect (GskGpuClip *dest, const GskGpuClip *src, const GskRoundedRect *rounded) G_GNUC_WARN_UNUSED_RESULT; -void gsk_gpu_clip_scale (GskGpuClip *dest, - const GskGpuClip *src, +void gsk_gpu_clip_scale (GskGpuClip *dest, + const GskGpuClip *src, + GdkDihedral dihedral, float scale_x, float scale_y); -gboolean gsk_gpu_clip_transform (GskGpuClip *dest, - const GskGpuClip *src, +gboolean gsk_gpu_clip_transform (GskGpuClip *dest, + const GskGpuClip *src, GskTransform *transform, const graphene_rect_t *viewport) G_GNUC_WARN_UNUSED_RESULT; diff --git a/gsk/gpu/gskgpunodeprocessor.c b/gsk/gpu/gskgpunodeprocessor.c index 8a9f4b4cee..6afb3561b8 100644 --- a/gsk/gpu/gskgpunodeprocessor.c +++ b/gsk/gpu/gskgpunodeprocessor.c @@ -1165,6 +1165,22 @@ gsk_gpu_node_processor_add_first_rounded_clip_node (GskGpuNodeProcessor gsk_rounded_clip_node_get_child (node)); } +static GskTransform * +gsk_transform_dihedral (GskTransform *transform, + GdkDihedral dihedral) +{ + int rotate = dihedral & 3; + int flip = dihedral & 4; + + if (flip) + transform = gsk_transform_scale (transform, -1.0, 1.0); + + if (rotate) + transform = gsk_transform_rotate (transform, rotate * 90.0f); + + return transform; +} + static void gsk_gpu_node_processor_add_transform_node (GskGpuNodeProcessor *self, GskRenderNode *node) @@ -1205,7 +1221,7 @@ gsk_gpu_node_processor_add_transform_node (GskGpuNodeProcessor *self, old_modelview = gsk_transform_ref (self->modelview); gsk_transform_to_affine (transform, &scale_x, &scale_y, &dx, &dy); - gsk_gpu_clip_scale (&self->clip, &old_clip, scale_x, scale_y); + gsk_gpu_clip_scale (&self->clip, &old_clip, GDK_DIHEDRAL_NORMAL, scale_x, scale_y); self->offset.x = (self->offset.x + dx) / scale_x; self->offset.y = (self->offset.y + dy) / scale_y; graphene_vec2_init (&self->scale, fabs (scale_x), fabs (scale_y)); @@ -1217,6 +1233,32 @@ gsk_gpu_node_processor_add_transform_node (GskGpuNodeProcessor *self, break; case GSK_FINE_TRANSFORM_CATEGORY_2D_DIHEDRAL: + { + GdkDihedral dihedral, inverted; + float xx, xy, yx, yy, dx, dy, scale_x, scale_y, old_scale_x, old_scale_y; + + gsk_gpu_clip_init_copy (&old_clip, &self->clip); + old_offset = self->offset; + old_scale = self->scale; + old_modelview = gsk_transform_ref (self->modelview); + + gsk_transform_to_dihedral (transform, &dihedral, &scale_x, &scale_y, &dx, &dy); + inverted = gdk_dihedral_invert (dihedral); + gdk_dihedral_get_mat2 (inverted, &xx, &xy, &yx, &yy); + gsk_gpu_clip_scale (&self->clip, &old_clip, inverted, scale_x, scale_y); + self->offset.x = (self->offset.x + dx) / scale_x; + self->offset.y = (self->offset.y + dy) / scale_y; + self->offset = GRAPHENE_POINT_INIT (xx * self->offset.x + xy * self->offset.y, + yx * self->offset.x + yy * self->offset.y); + old_scale_x = graphene_vec2_get_x (&old_scale); + old_scale_y = graphene_vec2_get_y (&old_scale); + graphene_vec2_init (&self->scale, + fabs (scale_x * (old_scale_x * xx + old_scale_y * yx)), + fabs (scale_y * (old_scale_x * xy + old_scale_y * yy))); + self->modelview = gsk_transform_dihedral (self->modelview, dihedral); + } + break; + case GSK_FINE_TRANSFORM_CATEGORY_2D: case GSK_FINE_TRANSFORM_CATEGORY_UNKNOWN: case GSK_FINE_TRANSFORM_CATEGORY_ANY: @@ -1350,7 +1392,7 @@ gsk_gpu_node_processor_add_first_transform_node (GskGpuNodeProcessor *se old_offset = self->offset; old_scale = self->scale; - gsk_gpu_clip_scale (&self->clip, &old_clip, scale_x, scale_y); + gsk_gpu_clip_scale (&self->clip, &old_clip, GDK_DIHEDRAL_NORMAL, scale_x, scale_y); self->offset.x = (self->offset.x + dx) / scale_x; self->offset.y = (self->offset.y + dy) / scale_y; graphene_vec2_init (&self->scale, fabs (scale_x), fabs (scale_y)); diff --git a/gsk/gskroundedrect.c b/gsk/gskroundedrect.c index 30cc177042..7306bb5d0f 100644 --- a/gsk/gskroundedrect.c +++ b/gsk/gskroundedrect.c @@ -321,6 +321,34 @@ gsk_rounded_rect_scale_affine (GskRoundedRect *dest, } } +void +gsk_rounded_rect_dihedral (GskRoundedRect *dest, + const GskRoundedRect *src, + GdkDihedral dihedral) +{ + guint flip = (dihedral & 2) + (dihedral >> 2); + guint i; + + gsk_rect_dihedral (&src->bounds, dihedral, &dest->bounds); + + if (dihedral & 1) + { + for (i = 0; i < 4; i++) + { + dest->corner[i].width = src->corner[((i + 1) & 3) ^ flip].width; + dest->corner[i].height = src->corner[((i + 1) & 3) ^ flip].height; + } + } + else + { + for (i = 0; i < 4; i++) + { + dest->corner[i].width = src->corner[i ^ flip].height; + dest->corner[i].height = src->corner[i ^ flip].width; + } + } +} + /* * gsk_rounded_rect_is_circular: * @self: the `GskRoundedRect` to check diff --git a/gsk/gskroundedrectprivate.h b/gsk/gskroundedrectprivate.h index 964e0edf84..e83e1aed1c 100644 --- a/gsk/gskroundedrectprivate.h +++ b/gsk/gskroundedrectprivate.h @@ -2,6 +2,8 @@ #include "gskroundedrect.h" +#include "gdk/gdkdihedralprivate.h" + #include G_BEGIN_DECLS @@ -34,12 +36,15 @@ G_STATIC_ASSERT (OPPOSITE_CORNER_Y (GSK_CORNER_BOTTOM_RIGHT) == GSK_CORNER_TOP_R }} -void gsk_rounded_rect_scale_affine (GskRoundedRect *dest, - const GskRoundedRect *src, - float scale_x, - float scale_y, - float dx, - float dy); +void gsk_rounded_rect_scale_affine (GskRoundedRect *dest, + const GskRoundedRect *src, + float scale_x, + float scale_y, + float dx, + float dy); +void gsk_rounded_rect_dihedral (GskRoundedRect *dest, + const GskRoundedRect *src, + GdkDihedral dihedral); gboolean gsk_rounded_rect_is_circular (const GskRoundedRect *self) G_GNUC_PURE;