diff options
author | Benjamin Otte <otte@redhat.com> | 2019-03-03 17:57:11 +0100 |
---|---|---|
committer | Benjamin Otte <otte@redhat.com> | 2019-03-04 23:41:51 +0100 |
commit | 3545abc7a1731a5714e5f541c6aa966a48e27ffe (patch) | |
tree | 982e63c54690f79ee35c8db85c8da61952b3967a | |
parent | 70b341139b48a7ee2bbb5bf6ba133fbe673fd2e5 (diff) | |
download | gtk+-3545abc7a1731a5714e5f541c6aa966a48e27ffe.tar.gz |
transform: Implement gsk_transform_invert()
And use it.
And test it.
-rw-r--r-- | docs/reference/gsk/gsk4-sections.txt | 1 | ||||
-rw-r--r-- | gsk/gsktransform.c | 119 | ||||
-rw-r--r-- | gsk/gsktransform.h | 2 | ||||
-rw-r--r-- | gtk/gtkwidget.c | 16 | ||||
-rw-r--r-- | testsuite/gtk/transform.c | 43 |
5 files changed, 176 insertions, 5 deletions
diff --git a/docs/reference/gsk/gsk4-sections.txt b/docs/reference/gsk/gsk4-sections.txt index f85ff189c4..980be45b99 100644 --- a/docs/reference/gsk/gsk4-sections.txt +++ b/docs/reference/gsk/gsk4-sections.txt @@ -163,6 +163,7 @@ gsk_transform_to_affine gsk_transform_to_translate <SUBSECTION> gsk_transform_transform +gsk_transform_invert gsk_transform_matrix gsk_transform_translate gsk_transform_translate_3d diff --git a/gsk/gsktransform.c b/gsk/gsktransform.c index a1e6da676e..767a275af8 100644 --- a/gsk/gsktransform.c +++ b/gsk/gsktransform.c @@ -75,6 +75,8 @@ struct _GskTransformClass GString *string); GskTransform * (* apply) (GskTransform *transform, GskTransform *apply_to); + GskTransform * (* invert) (GskTransform *transform, + GskTransform *next); /* both matrices have the same type */ gboolean (* equal) (GskTransform *first_transform, GskTransform *second_transform); @@ -178,7 +180,26 @@ static GskTransform * gsk_identity_transform_apply (GskTransform *transform, GskTransform *apply_to) { - return apply_to; + /* We do the following to make sure inverting a non-NULL transform + * will return a non-NULL transform. + */ + if (apply_to) + return apply_to; + else + return gsk_transform_new (); +} + +static GskTransform * +gsk_identity_transform_invert (GskTransform *transform, + GskTransform *next) +{ + /* We do the following to make sure inverting a non-NULL transform + * will return a non-NULL transform. + */ + if (next) + return next; + else + return gsk_transform_new (); } static gboolean @@ -200,6 +221,7 @@ static const GskTransformClass GSK_IDENTITY_TRANSFORM_CLASS = gsk_identity_transform_apply_translate, gsk_identity_transform_print, gsk_identity_transform_apply, + gsk_identity_transform_invert, gsk_identity_transform_equal, }; @@ -372,6 +394,24 @@ gsk_matrix_transform_apply (GskTransform *transform, self->category); } +static GskTransform * +gsk_matrix_transform_invert (GskTransform *transform, + GskTransform *next) +{ + GskMatrixTransform *self = (GskMatrixTransform *) transform; + graphene_matrix_t inverse; + + if (!graphene_matrix_inverse (&self->matrix, &inverse)) + { + gsk_transform_unref (next); + return NULL; + } + + return gsk_transform_matrix_with_category (next, + &inverse, + self->category); +} + static gboolean gsk_matrix_transform_equal (GskTransform *first_transform, GskTransform *second_transform) @@ -395,6 +435,7 @@ static const GskTransformClass GSK_TRANSFORM_TRANSFORM_CLASS = gsk_matrix_transform_apply_translate, gsk_matrix_transform_print, gsk_matrix_transform_apply, + gsk_matrix_transform_invert, gsk_matrix_transform_equal, }; @@ -526,6 +567,15 @@ gsk_translate_transform_apply (GskTransform *transform, return gsk_transform_translate_3d (apply_to, &self->point); } +static GskTransform * +gsk_translate_transform_invert (GskTransform *transform, + GskTransform *next) +{ + GskTranslateTransform *self = (GskTranslateTransform *) transform; + + return gsk_transform_translate_3d (next, &GRAPHENE_POINT3D_INIT (-self->point.x, -self->point.y, -self->point.z)); +} + static gboolean gsk_translate_transform_equal (GskTransform *first_transform, GskTransform *second_transform) @@ -570,6 +620,7 @@ static const GskTransformClass GSK_TRANSLATE_TRANSFORM_CLASS = gsk_translate_transform_apply_translate, gsk_translate_transform_print, gsk_translate_transform_apply, + gsk_translate_transform_invert, gsk_translate_transform_equal, }; @@ -710,6 +761,15 @@ gsk_rotate_transform_apply (GskTransform *transform, return gsk_transform_rotate (apply_to, self->angle); } +static GskTransform * +gsk_rotate_transform_invert (GskTransform *transform, + GskTransform *next) +{ + GskRotateTransform *self = (GskRotateTransform *) transform; + + return gsk_transform_rotate (next, - self->angle); +} + static gboolean gsk_rotate_transform_equal (GskTransform *first_transform, GskTransform *second_transform) @@ -743,6 +803,7 @@ static const GskTransformClass GSK_ROTATE_TRANSFORM_CLASS = gsk_rotate_transform_apply_translate, gsk_rotate_transform_print, gsk_rotate_transform_apply, + gsk_rotate_transform_invert, gsk_rotate_transform_equal, }; @@ -837,6 +898,15 @@ gsk_rotate3d_transform_apply (GskTransform *transform, return gsk_transform_rotate_3d (apply_to, self->angle, &self->axis); } +static GskTransform * +gsk_rotate3d_transform_invert (GskTransform *transform, + GskTransform *next) +{ + GskRotate3dTransform *self = (GskRotate3dTransform *) transform; + + return gsk_transform_rotate_3d (next, - self->angle, &self->axis); +} + static gboolean gsk_rotate3d_transform_equal (GskTransform *first_transform, GskTransform *second_transform) @@ -879,6 +949,7 @@ static const GskTransformClass GSK_ROTATE3D_TRANSFORM_CLASS = gsk_rotate3d_transform_apply_translate, gsk_rotate3d_transform_print, gsk_rotate3d_transform_apply, + gsk_rotate3d_transform_invert, gsk_rotate3d_transform_equal, }; @@ -1007,6 +1078,18 @@ gsk_scale_transform_apply (GskTransform *transform, return gsk_transform_scale_3d (apply_to, self->factor_x, self->factor_y, self->factor_z); } +static GskTransform * +gsk_scale_transform_invert (GskTransform *transform, + GskTransform *next) +{ + GskScaleTransform *self = (GskScaleTransform *) transform; + + return gsk_transform_scale_3d (next, + 1.f / self->factor_x, + 1.f / self->factor_y, + 1.f / self->factor_z); +} + static gboolean gsk_scale_transform_equal (GskTransform *first_transform, GskTransform *second_transform) @@ -1060,6 +1143,7 @@ static const GskTransformClass GSK_SCALE_TRANSFORM_CLASS = gsk_scale_transform_apply_translate, gsk_scale_transform_print, gsk_scale_transform_apply, + gsk_scale_transform_invert, gsk_scale_transform_equal, }; @@ -1395,6 +1479,39 @@ gsk_transform_transform (GskTransform *next, } /** + * gsk_transform_invert: + * @self: (allow-none) (transfer full): Transform to invert + * + * Inverts the given transform. + * + * If @self is not invertible, %NULL is returned. + * Note that inverting %NULL also returns %NULL, which is + * the correct inverse of %NULL. If you need to differentiate + * between those cases, you should check @self is not %NULL + * before calling this function. + * + * Returns: The inverted transform or %NULL if the transform + * cannot be inverted. + **/ +GskTransform * +gsk_transform_invert (GskTransform *self) +{ + GskTransform *result = NULL; + GskTransform *cur; + + for (cur = self; cur; cur = cur->next) + { + result = cur->transform_class->invert (cur, result); + if (result == NULL) + break; + } + + gsk_transform_unref (self); + + return result; +} + +/** * gsk_transform_equal: * @first: the first matrix * @second: the second matrix diff --git a/gsk/gsktransform.h b/gsk/gsktransform.h index 3696f6fab2..4a90b1308b 100644 --- a/gsk/gsktransform.h +++ b/gsk/gsktransform.h @@ -79,6 +79,8 @@ GDK_AVAILABLE_IN_ALL GskTransform * gsk_transform_transform (GskTransform *next, GskTransform *other); GDK_AVAILABLE_IN_ALL +GskTransform * gsk_transform_invert (GskTransform *self); +GDK_AVAILABLE_IN_ALL GskTransform * gsk_transform_matrix (GskTransform *next, const graphene_matrix_t *matrix); GDK_AVAILABLE_IN_ALL diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c index 1aac43184a..bdee0bf4dc 100644 --- a/gtk/gtkwidget.c +++ b/gtk/gtkwidget.c @@ -820,13 +820,23 @@ gtk_widget_real_pick (GtkWidget *widget, child = _gtk_widget_get_prev_sibling (child)) { GtkWidgetPrivate *priv = gtk_widget_get_instance_private (child); + GskTransform *transform; graphene_matrix_t inv; GtkWidget *picked; graphene_point3d_t p0, p1, res; - gsk_transform_to_matrix (priv->transform, &inv); - if (!graphene_matrix_inverse (&inv, &inv)) - continue; + if (priv->transform) + { + transform = gsk_transform_invert (gsk_transform_ref (priv->transform)); + if (transform == NULL) + continue; + } + else + { + transform = NULL; + } + gsk_transform_to_matrix (transform, &inv); + gsk_transform_unref (transform); graphene_point3d_init (&p0, x, y, 0); graphene_point3d_init (&p1, x, y, 1); graphene_matrix_transform_point3d (&inv, &p0, &p0); diff --git a/testsuite/gtk/transform.c b/testsuite/gtk/transform.c index 0d7a8ad9f1..0a71af4fd0 100644 --- a/testsuite/gtk/transform.c +++ b/testsuite/gtk/transform.c @@ -21,7 +21,7 @@ #include <gtk/gtk.h> -#define EPSILON (1.f / 1024 / 1024) +#define EPSILON (1.f / 1024 / 32) /* 2^-15 */ /* macros stolen from graphene testsuite, so they get to keep their names */ @@ -66,6 +66,14 @@ } \ } G_STMT_END +#define graphene_assert_fuzzy_transform_equal(t1,t2,epsilon) \ + G_STMT_START { \ + graphene_matrix_t __mat1, __mat2; \ + gsk_transform_to_matrix ((t1), &__mat1); \ + gsk_transform_to_matrix ((t2), &__mat2); \ + graphene_assert_fuzzy_matrix_equal (&__mat1, &__mat2, (epsilon)); \ + } G_STMT_END + static struct { GskTransformCategory category; } test_transforms[] = { @@ -235,6 +243,38 @@ test_conversions_transformed (void) } } +static void +test_invert (void) +{ + GskTransform *transform, *inverse, *identity; + guint i, j, k; + + for (i = 0; i < G_N_ELEMENTS (test_transforms); i++) + { + for (j = 0; j < G_N_ELEMENTS (test_transforms); j++) + { + for (k = 0; k < G_N_ELEMENTS (test_transforms); k++) + { + transform = apply_test_transform (NULL, i); + transform = apply_test_transform (transform, j); + transform = apply_test_transform (transform, k); + inverse = gsk_transform_invert (gsk_transform_ref (transform)); + g_assert (inverse != NULL || transform == NULL); + + identity = gsk_transform_transform (gsk_transform_ref (transform), inverse); + graphene_assert_fuzzy_transform_equal (identity, NULL, EPSILON); + gsk_transform_unref (identity); + + inverse = gsk_transform_invert (inverse); + graphene_assert_fuzzy_transform_equal (transform, inverse, EPSILON); + + gsk_transform_unref (transform); + gsk_transform_unref (inverse); + } + } + } +} + int main (int argc, char *argv[]) @@ -243,6 +283,7 @@ main (int argc, g_test_add_func ("/transform/conversions/simple", test_conversions_simple); g_test_add_func ("/transform/conversions/transformed", test_conversions_transformed); + g_test_add_func ("/transform/invert", test_invert); return g_test_run (); } |