[gtk/path-work-rebased: 974/1045] testsuite: Add tests for in_fill()




commit 6468ebadf4cc0f4b64bb88b30f594952d2d655d6
Author: Benjamin Otte <otte redhat com>
Date:   Mon Nov 30 04:22:06 2020 +0100

    testsuite: Add tests for in_fill()
    
    Add a test for measure_in_fill. Also test some
    special cases involving horizontal edges.

 testsuite/gsk/path-special-cases.c |  38 +++++++++
 testsuite/gsk/path.c               | 165 +++++++++++++++++++++++++++++++++++++
 2 files changed, 203 insertions(+)
---
diff --git a/testsuite/gsk/path-special-cases.c b/testsuite/gsk/path-special-cases.c
index 04a575ac1f..d4431419ff 100644
--- a/testsuite/gsk/path-special-cases.c
+++ b/testsuite/gsk/path-special-cases.c
@@ -306,6 +306,43 @@ test_serialize_custom_contours (void)
   gsk_path_unref (path1);
 }
 
+static void
+test_path_winding (void)
+{
+  struct {
+    const char *path;
+    graphene_point_t point;
+    gboolean result;
+  } tests[] = {
+    { "M 150 103 L 250 100 L 300 103 L 250 180 Z", GRAPHENE_POINT_INIT (175, 100), FALSE },
+    { "M 100 100 L 300 200 L 300 0 Z", GRAPHENE_POINT_INIT (250, 100), TRUE },
+    { "M 100 100 L 300 200 L 300 0 Z", GRAPHENE_POINT_INIT (400, 100), FALSE},
+    { "M 100 100  L 200 100 L 300 200 L 300 0 Z", GRAPHENE_POINT_INIT (50, 100), FALSE },
+    { "M 100 100  L 200 100 L 300 200 L 300 0 Z", GRAPHENE_POINT_INIT (150, 100), TRUE },
+    { "M 100 100  L 200 100 L 300 200 L 300 0 Z", GRAPHENE_POINT_INIT (250, 100), TRUE },
+    { "M 100 100  L 200 100 L 300 200 L 300 0 Z", GRAPHENE_POINT_INIT (400, 100), FALSE },
+    /* the following check that our elementary contours wind as expected.
+     * our rect contour is clockwise, our circle contour is counterclockwise
+     */
+    { "M100,100h100v100h-100z M200,150A50,50,0,1,0,100,150A50,50,0,1,0,200,150z", GRAPHENE_POINT_INIT 
(150,150), FALSE },
+  };
+  GskPath *path;
+  GskPathMeasure *measure;
+  gboolean res;
+
+  for (int i = 0; i < G_N_ELEMENTS (tests); i++)
+    {
+      path = gsk_path_parse (tests[i].path);
+      measure = gsk_path_measure_new (path);
+
+      res = gsk_path_measure_in_fill (measure, &tests[i].point, GSK_FILL_RULE_WINDING);
+      g_assert_true (res == tests[i].result);
+
+      gsk_path_measure_unref (measure);
+      gsk_path_unref (path);
+    }
+}
+
 int
 main (int   argc,
       char *argv[])
@@ -314,6 +351,7 @@ main (int   argc,
 
   g_test_add_func ("/path/rsvg-parse", test_rsvg_parse);
   g_test_add_func ("/path/serialize-custom-contours", test_serialize_custom_contours);
+  g_test_add_func ("/path/winding", test_path_winding);
 
   return g_test_run ();
 }
diff --git a/testsuite/gsk/path.c b/testsuite/gsk/path.c
index 3490981262..8cef3bc632 100644
--- a/testsuite/gsk/path.c
+++ b/testsuite/gsk/path.c
@@ -886,6 +886,169 @@ test_parse (void)
     }
 }
 
+#define N_PATHS 3
+static void
+test_in_fill_union (void)
+{
+  GskPath *path;
+  GskPathMeasure *measure, *measures[N_PATHS];
+  GskPathBuilder *builder;
+  guint i, j, k;
+
+  for (i = 0; i < 100; i++)
+    {
+      builder = gsk_path_builder_new ();
+      for (k = 0; k < N_PATHS; k++)
+        {
+          path = create_random_path (G_MAXUINT);
+          measures[k] = gsk_path_measure_new (path);
+          gsk_path_builder_add_path (builder, path);
+          gsk_path_unref (path);
+        }
+      path = gsk_path_builder_free_to_path (builder);
+      measure = gsk_path_measure_new (path);
+      gsk_path_unref (path);
+
+      for (j = 0; j < 100; j++)
+        {
+          graphene_point_t test = GRAPHENE_POINT_INIT (g_test_rand_double_range (-1000, 1000),
+                                                       g_test_rand_double_range (-1000, 1000));
+          GskFillRule fill_rule;
+
+          for (fill_rule = GSK_FILL_RULE_WINDING; fill_rule <= GSK_FILL_RULE_EVEN_ODD; fill_rule++)
+            {
+              guint n_in_fill = 0;
+              gboolean in_fill;
+
+              for (k = 0; k < N_PATHS; k++)
+                {
+                  if (gsk_path_measure_in_fill (measures[k], &test, GSK_FILL_RULE_EVEN_ODD))
+                    n_in_fill++;
+                }
+
+              in_fill = gsk_path_measure_in_fill (measure, &test, GSK_FILL_RULE_EVEN_ODD);
+
+              switch (fill_rule)
+              {
+                case GSK_FILL_RULE_WINDING:
+                  if (n_in_fill == 0)
+                    g_assert_false (in_fill);
+                  else if (n_in_fill == 1)
+                    g_assert_true (in_fill);
+                  /* else we can't say anything because the winding rule doesn't give enough info */
+                  break;
+
+                case GSK_FILL_RULE_EVEN_ODD:
+                  g_assert_cmpint (in_fill, ==, n_in_fill & 1);
+                  break;
+
+                default:
+                  g_assert_not_reached ();
+                  break;
+              }
+            }
+        }
+
+      gsk_path_measure_unref (measure);
+      for (k = 0; k < N_PATHS; k++)
+        {
+          gsk_path_measure_unref (measures[k]);
+        }
+    }
+}
+#undef N_PATHS
+
+/* This is somewhat sucky because using foreach breaks up the contours
+ * (like rects and circles) and replaces everything with the standard
+ * contour.
+ * But at least it extensively tests the standard contour.
+ */
+static gboolean
+rotate_path_cb (GskPathOperation        op,
+                const graphene_point_t *pts,
+                gsize                   n_pts,
+                gpointer                user_data)
+{
+  GskPathBuilder **builders = user_data;
+
+  switch (op)
+  {
+    case GSK_PATH_MOVE:
+      gsk_path_builder_move_to (builders[0], pts[0].x, pts[0].y);
+      gsk_path_builder_move_to (builders[1], pts[0].y, -pts[0].x);
+      break;
+
+    case GSK_PATH_CLOSE:
+      gsk_path_builder_close (builders[0]);
+      gsk_path_builder_close (builders[1]);
+      break;
+
+    case GSK_PATH_LINE:
+      gsk_path_builder_line_to (builders[0], pts[1].x, pts[1].y);
+      gsk_path_builder_line_to (builders[1], pts[1].y, -pts[1].x);
+      break;
+
+    case GSK_PATH_CURVE:
+      gsk_path_builder_curve_to (builders[0], pts[1].x, pts[1].y, pts[2].x, pts[2].y, pts[3].x, pts[3].y);
+      gsk_path_builder_curve_to (builders[1], pts[1].y, -pts[1].x, pts[2].y, -pts[2].x, pts[3].y, -pts[3].x);
+      break;
+
+    default:
+      g_assert_not_reached ();
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+static void
+test_in_fill_rotated (void)
+{
+  GskPath *path;
+  GskPathBuilder *builders[2];
+  GskPathMeasure *measures[2];
+  guint i, j;
+
+#define N_FILL_RULES 2
+  /* if this triggers, you added a new enum value to GskFillRule, so the define above needs
+   * an update */
+  g_assert_null (g_enum_get_value (g_type_class_ref (GSK_TYPE_FILL_RULE), N_FILL_RULES));
+
+  for (i = 0; i < 100; i++)
+    {
+      path = create_random_path (G_MAXUINT);
+      builders[0] = gsk_path_builder_new ();
+      builders[1] = gsk_path_builder_new ();
+      gsk_path_foreach (path, rotate_path_cb, builders);
+      gsk_path_unref (path);
+
+      path = gsk_path_builder_free_to_path (builders[0]);
+      measures[0] = gsk_path_measure_new (path);
+      gsk_path_unref (path);
+      path = gsk_path_builder_free_to_path (builders[1]);
+      measures[1] = gsk_path_measure_new (path);
+      gsk_path_unref (path);
+
+      for (j = 0; j < 100; j++)
+        {
+          GskFillRule fill_rule = g_random_int_range (0, N_FILL_RULES);
+          float x = g_test_rand_double_range (-1000, 1000);
+          float y = g_test_rand_double_range (-1000, 1000);
+  
+          g_assert_cmpint (gsk_path_measure_in_fill (measures[0], &GRAPHENE_POINT_INIT (x, y), fill_rule),
+                           ==,
+                           gsk_path_measure_in_fill (measures[1], &GRAPHENE_POINT_INIT (y, -x), fill_rule));
+          g_assert_cmpint (gsk_path_measure_in_fill (measures[0], &GRAPHENE_POINT_INIT (y, x), fill_rule),
+                           ==,
+                           gsk_path_measure_in_fill (measures[1], &GRAPHENE_POINT_INIT (x, -y), fill_rule));
+        }
+
+      gsk_path_measure_unref (measures[0]);
+      gsk_path_measure_unref (measures[1]);
+    }
+#undef N_FILL_RULES
+}
+
 int
 main (int   argc,
       char *argv[])
@@ -901,6 +1064,8 @@ main (int   argc,
   g_test_add_func ("/path/closest_point", test_closest_point);
   g_test_add_func ("/path/closest_point_for_point", test_closest_point_for_point);
   g_test_add_func ("/path/parse", test_parse);
+  g_test_add_func ("/path/in-fill-union", test_in_fill_union);
+  g_test_add_func ("/path/in-fill-rotated", test_in_fill_rotated);
 
   return g_test_run ();
 }


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