[gtk/wip/otte/transform: 37/41] transform: Implement gsk_transform_invert()



commit fd91cf967f08ae634cb3ede1cdf029256cdc4145
Author: Benjamin Otte <otte redhat com>
Date:   Sun Mar 3 17:57:11 2019 +0100

    transform: Implement gsk_transform_invert()
    
    And use it.
    
    And test it.

 docs/reference/gsk/gsk4-sections.txt |   1 +
 gsk/gsktransform.c                   | 119 ++++++++++++++++++++++++++++++++++-
 gsk/gsktransform.h                   |   2 +
 gtk/gtkwidget.c                      |  16 ++++-
 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,
 };
 
@@ -1394,6 +1478,39 @@ gsk_transform_transform (GskTransform *next,
   return other->transform_class->apply (other, 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
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 9cceb2a51a..98779df25e 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 ();
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]