Evas masking: Add some test cases
authorJean-Philippe Andre <jp.andre@samsung.com>
Tue, 6 Jan 2015 07:58:33 +0000 (16:58 +0900)
committerJean-Philippe Andre <jp.andre@samsung.com>
Wed, 7 Jan 2015 06:06:03 +0000 (15:06 +0900)
Here are only 3 very basic test cases.

One is a dumb set/get to check that image objects can
be passed as clippers.

The other one is a pixel verification test with extremely
basic data (NEAREST scaling and just rectangles). It also
compares text clipping and masking.

The last one performs a very basic verification that masks
of masks work.

src/Makefile_Evas.am
src/tests/evas/evas_suite.c
src/tests/evas/evas_suite.h
src/tests/evas/evas_test_mask.c [new file with mode: 0644]

index 4ff091c..1d8344f 100644 (file)
@@ -1896,6 +1896,7 @@ tests/evas/evas_test_render_engines.c \
 tests/evas/evas_test_filters.c \
 tests/evas/evas_test_image.c \
 tests/evas/evas_test_mesh.c \
+tests/evas/evas_test_mask.c \
 tests/evas/evas_tests_helpers.h \
 tests/evas/evas_suite.h
 
index baa8ab8..5d37325 100644 (file)
@@ -27,6 +27,7 @@ static const Evas_Test_Case etc[] = {
   { "Filters", evas_test_filters },
   { "Images", evas_test_image_object },
   { "Meshes", evas_test_mesh },
+  { "Masking", evas_test_mask },
   { NULL, NULL }
 };
 
index 4776508..645f758 100644 (file)
@@ -12,5 +12,6 @@ void evas_test_render_engines(TCase *tc);
 void evas_test_filters(TCase *tc);
 void evas_test_image_object(TCase *tc);
 void evas_test_mesh(TCase *tc);
+void evas_test_mask(TCase *tc);
 
 #endif /* _EVAS_SUITE_H */
diff --git a/src/tests/evas/evas_test_mask.c b/src/tests/evas/evas_test_mask.c
new file mode 100644 (file)
index 0000000..1f05512
--- /dev/null
@@ -0,0 +1,368 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef BUILD_ENGINE_BUFFER
+
+#include "evas_suite.h"
+#include "Evas.h"
+#include "Ecore_Evas.h"
+#include "evas_tests_helpers.h"
+
+#define TEST_FONT_NAME "DejaVuSans,UnDotum"
+#define TEST_FONT_SOURCE TESTS_SRC_DIR "/TestFont.eet"
+
+#define START_MASK_TEST(w, h) \
+   Ecore_Evas *ee; Evas *e; \
+   evas_init(); \
+   ecore_evas_init(); \
+   ee = ecore_evas_buffer_new(w, h); \
+   ecore_evas_show(ee); \
+   ecore_evas_manual_render_set(ee, EINA_TRUE); \
+   e = ecore_evas_get(ee); \
+   Eina_List *tofree = NULL; \
+   do {} while (0)
+
+#define END_MASK_TEST() do { \
+   Evas_Object *o; \
+   EINA_LIST_FREE(tofree, o) { evas_object_del(o); } \
+   ecore_evas_free(ee); \
+   ecore_evas_shutdown(); \
+   evas_shutdown(); \
+   } while (0)
+
+#define AUTODEL(o) do { tofree = eina_list_prepend(tofree, o); } while (0)
+
+static int
+_bgra_compare(unsigned int *data, unsigned int *ref, int w, int h)
+{
+   int i,j;
+   for (j = 0; j < h; j++)
+     {
+#if 0
+        printf("data: ");
+        for (i = 0; i < w; i++) printf("%#x ", data[i+j*w]);
+        printf("\nref:  ");
+        for (i = 0; i < w; i++) printf("%#x ", ref[i+j*w]);
+        printf("\n\n");
+#endif
+        for (i = 0; i < w; i++)
+          if (data[i+j*w] != ref[i+j*w])
+            {
+               printf("Pixel %d differ: %#x vs. %#x\n", i+j*w, data[i+j*w], ref[i+j*w]);
+               fflush(stdout);
+               return 1;
+            }
+     }
+   return 0;
+}
+
+// The usual useless unit test
+START_TEST(evas_mask_test_setget)
+{
+   Evas *e = _setup_evas();
+   Evas_Object *obj = NULL, *mask = NULL;
+
+   obj = evas_object_text_add(e);
+   fail_if(evas_object_clip_get(obj) != NULL);
+
+   mask = evas_object_image_filled_add(e);
+   evas_object_clip_set(obj, mask);
+   fail_if(evas_object_clip_get(obj) != mask);
+
+   evas_object_clip_unset(obj);
+   fail_if(evas_object_clip_get(obj) != NULL);
+
+   evas_object_del(mask);
+   evas_object_del(obj);
+
+   evas_free(e);
+   evas_shutdown();
+}
+END_TEST
+
+// This test is also very basic but will check the pixels
+START_TEST(evas_mask_test_compare_clip)
+{
+   Evas_Object *obj, *mask, *rect, *bg, *clip, *text;
+   unsigned int *data, *refdata[3];
+   const int W = 64;
+   const int H = 64;
+   int i, tw, th;
+
+   static unsigned int mask_data[] = {
+      0x00000000, 0x00000000, 0x00000000, 0x00000000,
+      0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+      0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+      0x00000000, 0x00000000, 0x00000000, 0x00000000,
+   };
+
+   static unsigned int ref_data[2][16] = {
+      // blue masked with alpha 0xFF over green bg
+      {
+         0xFF00FF00, 0xFF00FF00, 0xFF00FF00, 0xFF00FF00,
+         0xFF00FF00, 0xFF0000FF, 0xFF0000FF, 0xFF00FF00,
+         0xFF00FF00, 0xFF0000FF, 0xFF0000FF, 0xFF00FF00,
+         0xFF00FF00, 0xFF00FF00, 0xFF00FF00, 0xFF00FF00,
+      },
+      // blue masked with alpha 0x80 over green bg
+      {
+         0xFF00FF00, 0xFF00FF00, 0xFF00FF00, 0xFF00FF00,
+         0xFF00FF00, 0xFF007F80, 0xFF007F80, 0xFF00FF00,
+         0xFF00FF00, 0xFF007F80, 0xFF007F80, 0xFF00FF00,
+         0xFF00FF00, 0xFF00FF00, 0xFF00FF00, 0xFF00FF00,
+      }
+   };
+
+   START_MASK_TEST(W, H);
+   printf("Testing basic mask render... ");
+
+   // Create reference data -- scaled up images
+   obj = evas_object_image_filled_add(e);
+   evas_object_image_smooth_scale_set(obj, 0);
+   evas_object_image_size_set(obj, 4, 4);
+   evas_object_image_colorspace_set(obj, EVAS_COLORSPACE_ARGB8888);
+   evas_object_image_data_copy_set(obj, ref_data[0]);
+   evas_object_geometry_set(obj, 0, 0, W, H);
+   evas_object_show(obj);
+   AUTODEL(obj);
+
+   ecore_evas_manual_render(ee);
+   refdata[0] = calloc(W * H, 4);
+   memcpy(refdata[0], ecore_evas_buffer_pixels_get(ee), W * H * 4);
+
+   evas_object_image_data_copy_set(obj, ref_data[1]);
+   ecore_evas_manual_render(ee);
+   refdata[1] = calloc(W * H, 4);
+   memcpy(refdata[1], ecore_evas_buffer_pixels_get(ee), W * H * 4);
+
+   evas_object_hide(obj);
+
+   // Green background
+   bg = evas_object_rectangle_add(e);
+   evas_object_geometry_set(bg, 0, 0, W, H);
+   evas_object_color_set(bg, 0, 0xFF, 0, 0xFF);
+   evas_object_show(bg);
+   AUTODEL(bg);
+
+   // Blue rectangle
+   rect = evas_object_rectangle_add(e);
+   evas_object_geometry_set(rect, 0, 0, W, H);
+   evas_object_color_set(rect, 0, 0, 0xFF, 0xFF);
+   evas_object_show(rect);
+   AUTODEL(rect);
+
+   // Mask image
+   mask = evas_object_image_filled_add(e);
+   evas_object_image_smooth_scale_set(mask, 0);
+   evas_object_image_size_set(mask, 4, 4);
+   evas_object_image_colorspace_set(mask, EVAS_COLORSPACE_ARGB8888);
+   evas_object_image_data_copy_set(mask, mask_data);
+   evas_object_geometry_set(mask, 0, 0, W, H);
+   evas_object_clip_set(rect, mask);
+   evas_object_show(mask);
+   AUTODEL(mask);
+
+   // Compare dump data
+   data = calloc(W * H, 4);
+   ecore_evas_manual_render(ee);
+   memcpy(data, ecore_evas_buffer_pixels_get(ee), W * H * 4);
+   fail_if(_bgra_compare(data, refdata[0], W,  H) != 0);
+
+   // Try again with mask alpha = 0x80
+   evas_object_color_set(mask, 0x80, 0x80, 0x80, 0x80);
+   ecore_evas_manual_render(ee);
+   memcpy(data, ecore_evas_buffer_pixels_get(ee), W * H * 4);
+
+   evas_object_image_data_copy_set(obj, ref_data[1]);
+   evas_object_show(obj);
+   ecore_evas_manual_render(ee);
+   refdata[1] = calloc(W * H, 4);
+   memcpy(refdata[1], ecore_evas_buffer_pixels_get(ee), W * H * 4);
+   fail_if(_bgra_compare(data, refdata[1], W, H) != 0);
+
+   // Now try again with a clip instead - this verifies clip == mask
+   clip = evas_object_rectangle_add(e);
+   evas_object_geometry_set(clip, W / 4, H / 4, W / 2, H / 2);
+   evas_object_color_set(clip, 0xFF, 0xFF, 0xFF, 0xFF);
+   evas_object_clip_set(rect, clip);
+   evas_object_hide(mask);
+   evas_object_show(clip);
+
+   ecore_evas_manual_render(ee);
+   memcpy(data, ecore_evas_buffer_pixels_get(ee), W * H * 4);
+   fail_if(_bgra_compare(data, refdata[0], W, H));
+
+   evas_object_color_set(clip, 0x80, 0x80, 0x80, 0x80);
+   ecore_evas_manual_render(ee);
+   memcpy(data, ecore_evas_buffer_pixels_get(ee), W * H * 4);
+   fail_if(_bgra_compare(data, refdata[1], W, H));
+
+   // Reset objects
+   evas_object_hide(rect);
+   evas_object_hide(clip);
+   evas_object_hide(mask);
+
+   // Text masking test
+   text = evas_object_text_add(e);
+   evas_object_text_font_source_set(text, TEST_FONT_SOURCE);
+   evas_object_text_font_set(text, TEST_FONT_NAME, 20);
+   evas_object_text_text_set(text, "TEXT MASKING SHOULD CUT");
+   evas_object_color_set(text, 0xFF, 0xFF, 0xFF, 0xFF);
+   evas_object_geometry_get(text, NULL, NULL, &tw, &th);
+   evas_object_geometry_set(text, W/2 - tw/2, H/2 - th/2, tw, th);
+   evas_object_show(text);
+   evas_object_show(clip);
+   evas_object_color_set(clip, 0xFF, 0xFF, 0xFF, 0xFF);
+   evas_object_clip_set(text, clip);
+   ecore_evas_manual_render(ee);
+   refdata[2] = calloc(W * H, 4);
+   memcpy(refdata[2], ecore_evas_buffer_pixels_get(ee), W * H * 4);
+
+   evas_object_color_set(mask, 0xFF, 0xFF, 0xFF, 0xFF);
+   evas_object_clip_set(text, mask);
+   evas_object_hide(clip);
+   evas_object_show(mask);
+   ecore_evas_manual_render(ee);
+   memcpy(data, ecore_evas_buffer_pixels_get(ee), W * H * 4);
+
+   fail_if(_bgra_compare(data, refdata[2], W, H));
+
+   printf("PASSED!\n");
+   for (i = 0; i < 3; i++) free(refdata[i]);
+   free(data);
+   END_MASK_TEST();
+}
+END_TEST
+
+// This will simply check that a mask is recursively applied to children
+START_TEST(evas_mask_test_mask_of_mask)
+{
+   Evas_Object *bg, *tbl, *rect0, *mask0, *mask1, *obj;
+   unsigned int *data, *refdata;
+   const int W = 16;
+   const int H = 16;
+
+   // Note: This test isn't great as a mask will hijack the clipper
+   // set by the table to its children.
+
+   static unsigned int mask_data[3][16] =
+   {
+      // Table's mask
+      {
+         0x00000000, 0x00000000, 0x00000000, 0x00000000,
+         0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+         0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000,
+         0x00000000, 0x00000000, 0x00000000, 0x00000000,
+      },
+      // Rect's mask
+      {
+         0x00000000, 0x00000000, 0x00000000, 0x00000000,
+         0x00000000, 0x00000000, 0x00000000, 0x00000000,
+         0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+         0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF,
+      },
+      // Reference image with colors
+      {
+         0xFF00FF00, 0xFF00FF00, 0xFF00FF00, 0xFF00FF00,
+         0xFF00FF00, 0xFF00FF00, 0xFF00FF00, 0xFF00FF00,
+         0xFF00FF00, 0xFF00FF00, 0xFFFF00FF, 0xFF00FF00, // look here!
+         0xFF00FF00, 0xFF00FF00, 0xFF00FF00, 0xFF00FF00,
+      }
+   };
+
+   START_MASK_TEST(W, H);
+   printf("Testing basic masks of masks... ");
+
+   // Green background
+   bg = evas_object_rectangle_add(e);
+   evas_object_geometry_set(bg, 0, 0, W, H);
+   evas_object_color_set(bg, 0, 0xFF, 0, 0xFF);
+   evas_object_show(bg);
+   AUTODEL(bg);
+
+   // Table
+   tbl = evas_object_table_add(e);
+   evas_object_geometry_set(tbl, 0, 0, W, H);
+   evas_object_table_homogeneous_set(tbl, EVAS_OBJECT_TABLE_HOMOGENEOUS_TABLE);
+   evas_object_show(tbl);
+   AUTODEL(tbl);
+
+   // Table's mask
+   mask0 = evas_object_image_filled_add(e);
+   evas_object_image_smooth_scale_set(mask0, 0);
+   evas_object_image_size_set(mask0, 4, 4);
+   evas_object_image_colorspace_set(mask0, EVAS_COLORSPACE_ARGB8888);
+   evas_object_image_data_copy_set(mask0, mask_data[0]);
+   evas_object_geometry_set(mask0, 0, 0, W, H);
+   evas_object_show(mask0);
+   AUTODEL(mask0);
+
+   evas_object_clip_set(tbl, mask0);
+
+   // Rect is table's content
+   rect0 = evas_object_rectangle_add(e);
+   evas_object_color_set(rect0, 255, 0, 255, 255);
+   evas_object_show(rect0);
+
+   evas_object_size_hint_expand_set(rect0, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_fill_set(rect0, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_table_pack(tbl, rect0, 0, 0, 1, 1);
+
+   // mask1 is also table content
+   mask1 = evas_object_image_filled_add(e);
+   evas_object_image_smooth_scale_set(mask1, 0);
+   evas_object_image_size_set(mask1, 4, 4);
+   evas_object_image_colorspace_set(mask1, EVAS_COLORSPACE_ARGB8888);
+   evas_object_image_data_copy_set(mask1, mask_data[1]);
+   evas_object_show(mask1);
+
+   evas_object_size_hint_expand_set(mask1, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_fill_set(mask1, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_table_pack(tbl, mask1, 0, 0, 1, 1);
+
+   // BAAAAD: Hijack rect0's clipper
+   obj = evas_object_clip_get(rect0);
+   evas_object_clip_set(rect0, mask1);
+   if (!evas_object_clipees_has(obj))
+     evas_object_hide(obj);
+
+   // Screenshot mask of mask
+   data = calloc(W * H, 4);
+   ecore_evas_manual_render(ee);
+   memcpy(data, ecore_evas_buffer_pixels_get(ee), W * H * 4);
+
+   // Render reference image
+   obj = evas_object_image_filled_add(e);
+   evas_object_image_smooth_scale_set(obj, 0);
+   evas_object_image_size_set(obj, 4, 4);
+   evas_object_image_colorspace_set(obj, EVAS_COLORSPACE_ARGB8888);
+   evas_object_image_data_copy_set(obj, mask_data[2]);
+   evas_object_geometry_set(obj, 0, 0, W, H);
+   evas_object_show(obj);
+   AUTODEL(obj);
+
+   refdata = calloc(W * H, 4);
+   ecore_evas_manual_render(ee);
+   memcpy(refdata, ecore_evas_buffer_pixels_get(ee), W * H * 4);
+   fail_if(_bgra_compare(data, refdata, W, H) != 0);
+
+   printf("PASSED!\n");
+   free(refdata);
+   free(data);
+   END_MASK_TEST();
+}
+END_TEST
+
+// NOTE: Much more extensive tests are required. But they should
+// be based on "exactness" or a pixel similarity tool.
+// The GL engine is not tested at all. Even masking images is not tested...
+
+void evas_test_mask(TCase *tc)
+{
+   tcase_add_test(tc, evas_mask_test_setget);
+   tcase_add_test(tc, evas_mask_test_compare_clip);
+   tcase_add_test(tc, evas_mask_test_mask_of_mask);
+}
+
+#endif // BUILD_ENGINE_BUFFER