[gtk/wip/otte/transform: 1/8] testsuite: Add a transforms test



commit 979e9bec27532c118f4ab7e30d7d59c85a321d5c
Author: Benjamin Otte <otte redhat com>
Date:   Sat Mar 2 04:39:46 2019 +0100

    testsuite: Add a transforms test
    
    In particular, check that to_matrix() and to_2d(), to_affine() and
    to_translate() return the same values.
    
    This also requires a recent Graphene version or the tests will fail.

 meson.build               |   2 +-
 testsuite/gtk/meson.build |   1 +
 testsuite/gtk/transform.c | 248 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 250 insertions(+), 1 deletion(-)
---
diff --git a/meson.build b/meson.build
index b4063c68d4..5ce18aaa0b 100644
--- a/meson.build
+++ b/meson.build
@@ -35,7 +35,7 @@ gdk_pixbuf_req     = '>= 2.30.0'
 introspection_req  = '>= 1.39.0'
 wayland_proto_req  = '>= 1.12'
 wayland_req        = '>= 1.14.91'
-graphene_req       = '>= 1.5.1'
+graphene_req       = '>= 1.8.5'
 epoxy_req          = '>= 1.4'
 cloudproviders_req = '>= 0.2.5'
 xkbcommon_req      = '>= 0.2.0'
diff --git a/testsuite/gtk/meson.build b/testsuite/gtk/meson.build
index c02e4ab177..97e5f47fce 100644
--- a/testsuite/gtk/meson.build
+++ b/testsuite/gtk/meson.build
@@ -52,6 +52,7 @@ tests = [
   ['templates'],
   ['textbuffer'],
   ['textiter'],
+  ['transform'],
   ['treelistmodel'],
   ['treemodel', ['treemodel.c', 'liststore.c', 'treestore.c', 'filtermodel.c',
                  'modelrefcount.c', 'sortmodel.c', 'gtktreemodelrefcount.c']],
diff --git a/testsuite/gtk/transform.c b/testsuite/gtk/transform.c
new file mode 100644
index 0000000000..0d7a8ad9f1
--- /dev/null
+++ b/testsuite/gtk/transform.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright © 2019 Benjamin Otte
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Benjamin Otte <otte gnome org>
+ */
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+
+#define EPSILON (1.f / 1024 / 1024)
+
+/* macros stolen from graphene testsuite, so they get to keep their names */
+
+#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9))
+/* Use typeof on GCC */
+# define graphene_fuzzy_equals(n1,n2,epsilon) \
+  G_GNUC_EXTENSION({ \
+    __auto_type _n1 = (n1); \
+    __auto_type _n2 = (n2); \
+    __auto_type _epsilon = (epsilon); \
+    ((_n1 > _n2 ? (_n1 - _n2 ) : (_n2 - _n1)) <= _epsilon); \
+  })
+
+#else
+/* fallback for Visual Studio, typeof not supported */
+# define graphene_fuzzy_equals(n1,n2,epsilon) \
+  (((n1) > (n2) ? ((n1) - (n2)) : ((n2) - (n1))) <= (epsilon))
+
+#endif /* __GNUC__ */
+
+#define graphene_assert_fuzzy_matrix_cell_equal(row,col,n1,n2,epsilon) \
+  G_STMT_START { \
+    if (graphene_fuzzy_equals (n1, n2, epsilon)) ; else { \
+      char *s = g_strdup_printf ("[%d][%d]: " #n1 " == " #n2 " (+/- " #epsilon "): (%.7g == %.7g)", \
+                                 row, col, n1, n2); \
+      g_assertion_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, s); \
+      g_free (s); \
+    } \
+  } G_STMT_END
+
+#define graphene_assert_fuzzy_matrix_equal(m1,m2,epsilon) \
+  G_STMT_START { \
+    unsigned int __i, __j; \
+    float __m1[16], __m2[16]; \
+    graphene_matrix_to_float ((m1), __m1); \
+    graphene_matrix_to_float ((m2), __m2); \
+    for (__i = 0; __i < 4; __i++) { \
+      for (__j = 0; __j < 4; __j++) { \
+        unsigned int __idx = __i * 4 + __j; \
+        graphene_assert_fuzzy_matrix_cell_equal (__i, __j, __m1[__idx], __m2[__idx], epsilon); \
+      } \
+    } \
+  } G_STMT_END
+
+static struct {
+  GskTransformCategory category;
+} test_transforms[] = {
+  { GSK_TRANSFORM_CATEGORY_IDENTITY },
+  { GSK_TRANSFORM_CATEGORY_IDENTITY },
+  { GSK_TRANSFORM_CATEGORY_2D_TRANSLATE },
+  { GSK_TRANSFORM_CATEGORY_3D },
+  { GSK_TRANSFORM_CATEGORY_2D },
+  { GSK_TRANSFORM_CATEGORY_3D },
+  { GSK_TRANSFORM_CATEGORY_2D_AFFINE },
+  { GSK_TRANSFORM_CATEGORY_3D },
+};
+
+static GskTransform *
+apply_test_transform (GskTransform *transform,
+                      guint         i)
+{
+  switch (i)
+  {
+    case 0:
+      return transform ? transform : gsk_transform_new ();
+
+    case 1:
+      return gsk_transform_transform (transform, NULL);
+
+    case 2:
+      return gsk_transform_translate (transform, &GRAPHENE_POINT_INIT (3, 5));
+
+    case 3:
+      return gsk_transform_translate_3d (transform, &GRAPHENE_POINT3D_INIT (3, 5, 7));
+
+    case 4:
+      return gsk_transform_rotate (transform, 90);
+
+    case 5:
+      return gsk_transform_rotate_3d (transform, 90, graphene_vec3_y_axis ());
+
+    case 6:
+      return gsk_transform_scale (transform, 2, 3);
+
+    case 7:
+      return gsk_transform_scale_3d (transform, 2, 3, 5);
+
+    default:
+      g_assert_not_reached ();
+      return NULL;
+  }
+}
+
+static GskTransformCategory
+categorize_matrix (const graphene_matrix_t *matrix)
+{
+  if (!graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 0, 3), 0, EPSILON) ||
+      !graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 1, 3), 0, EPSILON) ||
+      !graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 2, 3), 0, EPSILON) ||
+      !graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 3, 3), 1, EPSILON))
+    return GSK_TRANSFORM_CATEGORY_ANY;
+
+  if (!graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 0, 2), 0, EPSILON) ||
+      !graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 1, 2), 0, EPSILON) ||
+      !graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 2, 2), 1, EPSILON) ||
+      !graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 3, 2), 0, EPSILON) ||
+      !graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 2, 0), 0, EPSILON) ||
+      !graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 2, 1), 0, EPSILON))
+    return GSK_TRANSFORM_CATEGORY_3D;
+
+  if (!graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 0, 1), 0, EPSILON) ||
+      !graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 1, 0), 0, EPSILON))
+    return GSK_TRANSFORM_CATEGORY_2D;
+
+  if (!graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 0, 0), 1, EPSILON) ||
+      !graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 1, 1), 1, EPSILON))
+    return GSK_TRANSFORM_CATEGORY_2D_AFFINE;
+
+  if (!graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 3, 0), 0, EPSILON) ||
+      !graphene_fuzzy_equals (graphene_matrix_get_value (matrix, 3, 1), 0, EPSILON))
+    return GSK_TRANSFORM_CATEGORY_2D_TRANSLATE;
+
+  return GSK_TRANSFORM_CATEGORY_IDENTITY;
+}
+
+static void
+check_conversions (GskTransform         *transform,
+                   GskTransformCategory  expected_category)
+{
+  graphene_matrix_t matrix, test;
+  float f[16] = { 1, 0, 0, 0,
+                  0, 1, 0, 0,
+                  0, 0, 1, 0,
+                  0, 0, 0, 1 };
+
+  g_assert_cmpint (gsk_transform_get_category (transform), ==, expected_category);
+  gsk_transform_to_matrix (transform, &matrix);
+  /* we don't insist on getting simplifications right.
+   * The matrix "scale(2) scale(0.5)" would be categorized as identity,
+   * but the transform might not do that.
+   */
+  g_assert_cmpint (gsk_transform_get_category (transform), <=, categorize_matrix (&matrix));
+
+  switch (expected_category)
+  {
+    case GSK_TRANSFORM_CATEGORY_UNKNOWN:
+    case GSK_TRANSFORM_CATEGORY_ANY:
+    case GSK_TRANSFORM_CATEGORY_3D:
+      break;
+
+    case GSK_TRANSFORM_CATEGORY_IDENTITY:
+    case GSK_TRANSFORM_CATEGORY_2D_TRANSLATE:
+      g_assert (gsk_transform_to_translate (transform,
+                                            &f[4 * 3 + 0], &f[4 * 3 + 1]));
+      graphene_matrix_init_from_float (&test, f);
+      graphene_assert_fuzzy_matrix_equal (&matrix, &test, EPSILON);
+      /* fallthrough */
+
+    case GSK_TRANSFORM_CATEGORY_2D_AFFINE:
+      g_assert (gsk_transform_to_affine (transform,
+                                         &f[4 * 0 + 0], &f[4 * 1 + 1],
+                                         &f[4 * 3 + 0], &f[4 * 3 + 1]));
+      graphene_matrix_init_from_float (&test, f);
+      graphene_assert_fuzzy_matrix_equal (&matrix, &test, EPSILON);
+      /* fallthrough */
+
+    case GSK_TRANSFORM_CATEGORY_2D:
+      g_assert (gsk_transform_to_2d (transform,
+                                     &f[4 * 0 + 0], &f[4 * 0 + 1],
+                                     &f[4 * 1 + 0], &f[4 * 1 + 1],
+                                     &f[4 * 3 + 0], &f[4 * 3 + 1]));
+      graphene_matrix_init_from_float (&test, f);
+      graphene_assert_fuzzy_matrix_equal (&matrix, &test, EPSILON);
+      break;
+   }
+}
+
+static void
+test_conversions_simple (void)
+{
+  GskTransform *transform;
+  guint i;
+
+  for (i = 0; i < G_N_ELEMENTS (test_transforms); i++)
+    {
+      transform = apply_test_transform (NULL, i);
+      check_conversions (transform, test_transforms[i].category);
+      gsk_transform_unref (transform);
+    }
+}
+
+static void
+test_conversions_transformed (void)
+{
+  GskTransform *transform;
+  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);
+              check_conversions (transform, MIN (test_transforms[i].category, MIN 
(test_transforms[j].category, test_transforms[k].category)));
+              gsk_transform_unref (transform);
+            }
+        }
+    }
+}
+
+int
+main (int   argc,
+      char *argv[])
+{
+  gtk_test_init (&argc, &argv, NULL);
+
+  g_test_add_func ("/transform/conversions/simple", test_conversions_simple);
+  g_test_add_func ("/transform/conversions/transformed", test_conversions_transformed);
+
+  return g_test_run ();
+}


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