summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2019-03-03 17:57:11 +0100
committerBenjamin Otte <otte@redhat.com>2019-03-04 23:41:51 +0100
commit3545abc7a1731a5714e5f541c6aa966a48e27ffe (patch)
tree982e63c54690f79ee35c8db85c8da61952b3967a
parent70b341139b48a7ee2bbb5bf6ba133fbe673fd2e5 (diff)
downloadgtk+-3545abc7a1731a5714e5f541c6aa966a48e27ffe.tar.gz
transform: Implement gsk_transform_invert()
And use it. And test it.
-rw-r--r--docs/reference/gsk/gsk4-sections.txt1
-rw-r--r--gsk/gsktransform.c119
-rw-r--r--gsk/gsktransform.h2
-rw-r--r--gtk/gtkwidget.c16
-rw-r--r--testsuite/gtk/transform.c43
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 ();
}