Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  compare-render.c

  Sprache: C
 

#include "config.h"
#include <string.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>
#include <stdlib.h>
#include "../reftests/reftest-compare.h"


static char *arg_output_dir = NULL;
static int arg_tolerance = 0;

extern void
replay_node (GskRenderNode *node, GtkSnapshot *snapshot);

static const char *
get_output_dir (void)
{
  static const char *output_dir = NULL;
  GError *error = NULL;
  GFile *file;

  if (output_dir)
    return output_dir;

  if (arg_output_dir)
    {
      GFile *arg_file = g_file_new_for_commandline_arg (arg_output_dir);
      const char *subdir;

      subdir = g_getenv ("TEST_OUTPUT_SUBDIR");
      if (subdir)
        {
          GFile *child = g_file_get_child (arg_file, subdir);
          g_object_unref (arg_file);
          arg_file = child;
        }

      output_dir = g_file_get_path (arg_file);
      g_object_unref (arg_file);
    }
  else
    {
      output_dir = g_get_tmp_dir ();
    }

  /* Just try to create the output directory.
   * If it already exists, that's exactly what we wanted to check,
   * so we can happily skip that error.
   */

  file = g_file_new_for_path (output_dir);
  if (!g_file_make_directory_with_parents (file, NULL, &error))
    {
      g_object_unref (file);

      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_EXISTS))
        {
          g_error ("Failed to create output dir: %s", error->message);
          g_error_free (error);
          return NULL;
        }
      g_error_free (error);
    }
  else
    g_object_unref (file);

  return output_dir;
}

static char *
file_replace_extension (const char *old_file,
                        const char *old_ext,
                        const char *new_ext)
{
  GString *file = g_string_new (NULL);

  if (g_str_has_suffix (old_file, old_ext))
    g_string_append_len (file, old_file, strlen (old_file) - strlen (old_ext));
  else
    g_string_append (file, old_file);

  g_string_append (file, new_ext);

  return g_string_free (file, FALSE);
}

static char *
get_output_file (const char *file,
                 const char *variant,
                 const char *orig_ext,
                 const char *new_ext)
{
  const char *dir;
  char *result, *base;
  char *name;

  dir = get_output_dir ();
  base = g_path_get_basename (file);
  if (variant)
    {
      char *s = file_replace_extension (base, orig_ext, "");
      name = g_strconcat (s, "-", variant, new_ext, NULL);
      g_free (s);
    }
  else
    {
      name = file_replace_extension (base, orig_ext, new_ext);
    }

  result = g_strconcat (dir, G_DIR_SEPARATOR_S, name, NULL);

  g_free (base);
  g_free (name);

  return result;
}

static void
save_image (GdkTexture *texture,
            const char *test_name,
            const char *variant_name,
            const char *extension)
{
  char *filename = get_output_file (test_name, variant_name, ".node", extension);
  gboolean result;

  g_print ("Storing test result image at %s\n", filename);
  result = gdk_texture_save_to_png (texture, filename);
  g_assert_true (result);
  g_free (filename);
}

static void
save_node (GskRenderNode *node,
           const char    *test_name,
           const char    *variant_name,
           const char    *extension)
{
  char *filename = get_output_file (test_name, variant_name, ".node", extension);
  GError *error = NULL;
  gboolean result;

  g_print ("Storing modified nodes at %s\n", filename);
  result = gsk_render_node_write_to_file (node, filename, &error);
  g_assert_no_error (error);
  g_assert_true (result);
  g_free (filename);
}

static void
deserialize_error_func (const GskParseLocation *start,
                        const GskParseLocation *end,
                        const GError           *error,
                        gpointer                user_data)
{
  GString *string = g_string_new ("<data>");

  g_string_append_printf (string, ":%zu:%zu",
                          start->lines + 1, start->line_chars + 1);
  if (start->lines != end->lines || start->line_chars != end->line_chars)
    {
      g_string_append (string, "-");
      if (start->lines != end->lines)
        g_string_append_printf (string, "%zu:", end->lines + 1);
      g_string_append_printf (string, "%zu", end->line_chars + 1);
    }

  if (error->domain == GTK_CSS_PARSER_WARNING)
    g_test_message ("Warning at %s: %s", string->str, error->message);
  else
    g_warning ("Error at %s: %s", string->str, error->message);

  g_string_free (string, TRUE);
}

static GskRenderNode *
load_node_file (const char *node_file)
{
  GBytes *bytes;
  gsize len;
  char *contents;
  GError *error = NULL;
  GskRenderNode *node;

  if (!g_file_get_contents (node_file, &contents, &len, &error))
    {
      g_print ("Could not open node file: %s\n", error->message);
      g_clear_error (&error);
      return NULL;
    }

  bytes = g_bytes_new_take (contents, len);
  node = gsk_render_node_deserialize (bytes, deserialize_error_func, NULL);
  g_bytes_unref (bytes);

  g_assert_no_error (error);
  g_assert_nonnull (node);

  return node;
}

static void
make_random_clip (cairo_rectangle_int_t *int_clip,
                  int                    width,
                  int                    height)
{
  const char *clip = g_getenv ("OVERRIDE_CLIP");

  if (clip)
    {
      char **str = g_strsplit (clip, ",", -1);

      if (g_strv_length (str) == 4)
        {
          int_clip->width = CLAMP (atoi (str[2]), 1, width);
          int_clip->height = CLAMP (atoi (str[3]), 1, height);
          int_clip->x = CLAMP (atoi (str[0]), 0, width - int_clip->width);
          int_clip->y = CLAMP (atoi (str[1]), 0, height - int_clip->height);

          g_strfreev (str);
          return;
        }

      g_strfreev (str);
    }

  int_clip->width = g_test_rand_int_range (1, MIN (4096, width));
  int_clip->height = g_test_rand_int_range (1, MIN (4096, height));

  int_clip->x = g_test_rand_int_range (0, width - int_clip->width);
  int_clip->y = g_test_rand_int_range (0, height - int_clip->height);
}

static void
gsk_rect_from_cairo (graphene_rect_t              *rect,
                      const cairo_rectangle_int_t *int_rect)
{
  rect->origin.x = int_rect->x;
  rect->origin.y = int_rect->y;
  rect->size.width = int_rect->width;
  rect->size.height = int_rect->height;
}

static GskRenderNode *
flip_create_test (GskRenderNode *node,
                  gconstpointer  unused)
{
  GskRenderNode *result;
  GskTransform *transform;

  transform = gsk_transform_scale (NULL, -11);
  result = gsk_transform_node_new (node, transform);
  gsk_transform_unref (transform);

  return result;
}

static GdkTexture *
flip_create_reference (GskRenderer   *renderer,
                       GdkTexture    *texture,
                       gconstpointer  unused)
{
  GskRenderNode *texture_node, *transform_node;
  GdkTexture *result;
  GskTransform *transform;

  texture_node = gsk_texture_node_new (texture,
                                       &GRAPHENE_RECT_INIT (
                                         00,
                                         gdk_texture_get_width (texture),
                                         gdk_texture_get_height (texture)
                                       ));

  transform = gsk_transform_scale (NULL, -11);
  transform_node = gsk_transform_node_new (texture_node, transform);
  gsk_transform_unref (transform);

  result = gsk_renderer_render_texture (renderer, transform_node, NULL);

  gsk_render_node_unref (transform_node);
  gsk_render_node_unref (texture_node);

  return result;
}

static GskRenderNode *
repeat_create_test (GskRenderNode *node,
                    gconstpointer  unused)
{
  graphene_rect_t bounds, node_bounds;

  gsk_render_node_get_bounds (node, &node_bounds);

  node_bounds.size.width = ceil (node_bounds.size.width);
  node_bounds.size.height = ceil (node_bounds.size.height);

  bounds.size.width = MIN (10003 * node_bounds.size.width);
  bounds.size.height = MIN (10003 * node_bounds.size.height);
  bounds.origin.x = node_bounds.origin.x + floorf (node_bounds.size.width / 2);
  bounds.origin.y = node_bounds.origin.y + floorf (node_bounds.size.height / 2);

  return gsk_repeat_node_new (&bounds, node, &node_bounds);
}

static GdkTexture *
repeat_create_reference (GskRenderer   *renderer,
                         GdkTexture    *texture,
                         gconstpointer  unused)
{
  GskRenderNode *texture_nodes[16], *container_node, *reference_node;
  GdkTexture *result;
  int width, height;
  int i, j;

  width = gdk_texture_get_width (texture);
  height = gdk_texture_get_height (texture);

  for (i = 0; i < 4; i++)
    {
      for (j = 0; j < 4; j++)
        {
          texture_nodes[4 * j + i] = gsk_texture_node_new (texture,
                                                           &GRAPHENE_RECT_INIT (
                                                               i * width,
                                                               j * height,
                                                               width,
                                                               height
                                                           ));
        }
    }
  container_node = gsk_container_node_new (texture_nodes, G_N_ELEMENTS (texture_nodes));
  reference_node = gsk_clip_node_new (container_node,
                                      &GRAPHENE_RECT_INIT (
                                        width / 2,
                                        height / 2,
                                        MIN (10003 * width),
                                        MIN (10003 * height)
                                      ));
  result = gsk_renderer_render_texture (renderer, reference_node, NULL);

  for (i = 0; i < G_N_ELEMENTS (texture_nodes); i++)
    gsk_render_node_unref (texture_nodes[i]);
  gsk_render_node_unref (container_node);
  gsk_render_node_unref (reference_node);

  return result;
}

static GskRenderNode *
rotate_create_test (GskRenderNode *node,
                    gconstpointer  unused)
{
  GskRenderNode *result;
  GskTransform *transform;

  transform = gsk_transform_rotate (NULL, 90);
  result = gsk_transform_node_new (node, transform);
  gsk_transform_unref (transform);

  return result;
}

static GdkTexture *
rotate_create_reference (GskRenderer   *renderer,
                         GdkTexture    *texture,
                         gconstpointer  unused)
{
  GskRenderNode *texture_node, *transform_node;
  GdkTexture *result;
  GskTransform *transform;

  texture_node = gsk_texture_node_new (texture,
                                       &GRAPHENE_RECT_INIT (
                                         00,
                                         gdk_texture_get_width (texture),
                                         gdk_texture_get_height (texture)
                                       ));

  transform = gsk_transform_rotate (NULL, 90);
  transform_node = gsk_transform_node_new (texture_node, transform);
  gsk_transform_unref (transform);

  result = gsk_renderer_render_texture (renderer, transform_node, NULL);

  gsk_render_node_unref (transform_node);
  gsk_render_node_unref (texture_node);

  return result;
}

static GskRenderNode *
mask_create_test (GskRenderNode *node,
                  gconstpointer  unused)
{
  GskRenderNode *result, *nodes[2], *mask_node;
  graphene_rect_t bounds;

  gsk_render_node_get_bounds (node, &bounds);
  
  nodes[0] = gsk_color_node_new (&(GdkRGBA){ 0001},
                                 &GRAPHENE_RECT_INIT (bounds.origin.x, bounds.origin.y, 2525));
  if (bounds.size.width > 25 && bounds.size.height > 25)
    {
      nodes[1] = gsk_color_node_new (&(GdkRGBA){ 0001},
                                     &GRAPHENE_RECT_INIT (
                                         bounds.origin.x + 25,
                                         bounds.origin.y + 25,
                                         MIN (1000, bounds.size.width) - 25,
                                         MIN (1000, bounds.size.height) - 25));
      mask_node = gsk_container_node_new (nodes, G_N_ELEMENTS (nodes));
      gsk_render_node_unref (nodes[0]);
      gsk_render_node_unref (nodes[1]);
    }
  else
    {
      mask_node = nodes[0];
    }

  result = gsk_mask_node_new (node, mask_node, GSK_MASK_MODE_ALPHA);
  gsk_render_node_unref (mask_node);

  return result;
}

static GdkTexture *
mask_create_reference (GskRenderer   *renderer,
                       GdkTexture    *texture,
                       gconstpointer  unused)
{
  GskRenderNode *texture_node, *reference_node;
  GdkTexture *result;
  GskRenderNode *nodes[2];
  int width, height;

  width = gdk_texture_get_width (texture);
  height = gdk_texture_get_height (texture);
  texture_node = gsk_texture_node_new (texture,
                                       &GRAPHENE_RECT_INIT (00, width, height));
  nodes[0] = gsk_clip_node_new (texture_node,
                                &GRAPHENE_RECT_INIT (
                                    00,
                                    MIN (width, 25),
                                    MIN (height, 25)
                                ));
  if (width > 25 && height > 25)
    {
      nodes[1] = gsk_clip_node_new (texture_node,
                                    &GRAPHENE_RECT_INIT (
                                        2525,
                                        MIN (1000, width) - 25,
                                        MIN (1000, height) - 25
                                    ));
      reference_node = gsk_container_node_new (nodes, G_N_ELEMENTS (nodes));
      gsk_render_node_unref (nodes[0]);
      gsk_render_node_unref (nodes[1]);
    }
  else
    {
      reference_node = nodes[0];
    }
  result = gsk_renderer_render_texture (renderer, reference_node, NULL);

  gsk_render_node_unref (texture_node);
  gsk_render_node_unref (reference_node);

  return result;
}

static GskRenderNode *
replay_create_test (GskRenderNode *node,
                    gconstpointer  unused)
{
  GskRenderNode *result;
  graphene_rect_t node_bounds, result_bounds;
  GtkSnapshot *snapshot = gtk_snapshot_new ();

  replay_node (node, snapshot);
  result = gtk_snapshot_free_to_node (snapshot);
  /* If the whole render node tree got eliminated, make sure we have
     something to work with nevertheless.  */

  if (result == NULL)
    result = gsk_container_node_new (NULL, 0);

  gsk_render_node_get_bounds (node, &node_bounds);
  gsk_render_node_get_bounds (result, &result_bounds);
  /* Check that the node didn't grow.  */
  if (!graphene_rect_contains_rect (&node_bounds, &result_bounds))
    g_test_fail_printf ("Node bounds grew");

  return result;
}

static gpointer
clip_setup (GskRenderNode *node)
{
  cairo_rectangle_int_t *result;
  graphene_rect_t bounds;

  result = g_new (cairo_rectangle_int_t, 1);

  gsk_render_node_get_bounds (node, &bounds);
  if (bounds.size.width <= 1 || bounds.size.height <= 1)
    *result = (cairo_rectangle_int_t) { 0011 };
  else
    make_random_clip (result, ceil (bounds.size.width), ceil (bounds.size.height));

  g_print ("Node bounds %g %g %g %g\n",
           bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
  g_print ("Random clip rectangle %d %d %d %d\n",
           result->x, result->y, result->width, result->height);

  return result;
}

static GskRenderNode *
clip_create_test (GskRenderNode *node,
                  gconstpointer  data)
{
  const cairo_rectangle_int_t *int_clip = data;
  graphene_rect_t clip_rect, bounds;

  gsk_rect_from_cairo (&clip_rect, int_clip);
  gsk_render_node_get_bounds (node, &bounds);
  clip_rect.origin.x += bounds.origin.x;
  clip_rect.origin.y += bounds.origin.y;
  
  return gsk_clip_node_new (node, &clip_rect);
}

static GdkTexture *
clip_create_reference (GskRenderer   *renderer,
                       GdkTexture    *texture,
                       gconstpointer  data)
{
  const cairo_rectangle_int_t *int_clip = data;
  GskRenderNode *texture_node, *reference_node;
  graphene_rect_t texture_bounds, clip_rect;
  GdkTexture *result;

  gsk_rect_from_cairo (&clip_rect, int_clip);
  texture_bounds = GRAPHENE_RECT_INIT (0,
                                       0,
                                       gdk_texture_get_width (texture),
                                       gdk_texture_get_height (texture));

  texture_node = gsk_texture_node_new (texture, &texture_bounds);
  reference_node = gsk_clip_node_new (texture_node, &clip_rect);
  result = gsk_renderer_render_texture (renderer, reference_node, &texture_bounds);

  gsk_render_node_unref (reference_node);
  gsk_render_node_unref (texture_node);
  
  return result;
}

static GskRenderNode *
colorflip_create_test (GskRenderNode *node,
                       gconstpointer  unused)
{
  graphene_matrix_t matrix;

  graphene_matrix_init_from_float (&matrix,
                                   (const float []) { 0100,
                                                      1000,
                                                      0010,
                                                      0001 });

  return gsk_color_matrix_node_new (node, &matrix, graphene_vec4_zero ());
}

static GdkTexture *
colorflip_create_reference (GskRenderer   *renderer,
                            GdkTexture    *texture,
                            gconstpointer  unused)
{
  GskRenderNode *texture_node, *reference_node;
  GdkTexture *result;
  graphene_matrix_t matrix;

  texture_node = gsk_texture_node_new (texture,
                                       &GRAPHENE_RECT_INIT (
                                         00,
                                         gdk_texture_get_width (texture),
                                         gdk_texture_get_height (texture)
                                       ));

  graphene_matrix_init_from_float (&matrix,
                                   (const float []) { 0100,
                                                      1000,
                                                      0010,
                                                      0001 });
  reference_node = gsk_color_matrix_node_new (texture_node, &matrix, graphene_vec4_zero ());
  result = gsk_renderer_render_texture (renderer, reference_node, NULL);

  gsk_render_node_unref (texture_node);
  gsk_render_node_unref (reference_node);

  return result;
}

static gboolean
rect_shrink_to_int (graphene_rect_t *rect)
{
  float x1 = floor (rect->origin.x + rect->size.width);
  float y1 = floor (rect->origin.y + rect->size.height);

  rect->origin.x = ceil (rect->origin.x);
  rect->origin.y = ceil (rect->origin.y);
  rect->size.width = x1 - rect->origin.x;
  rect->size.height = y1 - rect->origin.y;

  return rect->size.width >=0 && rect->size.height >= 0;
}

static gpointer
opaque_setup (GskRenderNode *node)
{
  graphene_rect_t opaque;

  if (!gsk_render_node_get_opaque_rect (node, &opaque))
    {
      g_test_skip ("Node has no opaque rect");
      return NULL;
    }

  if (!rect_shrink_to_int (&opaque))
    {
      g_test_skip ("Opaque rect is too small, so it rounds to nothing.");
      return NULL;
    }

  return g_memdup2 (&opaque, sizeof (graphene_rect_t));
}

static GskRenderNode *
opaque_create_test (GskRenderNode *node,
                    gconstpointer  data)
{
  const graphene_rect_t *opaque = data;
  graphene_matrix_t matrix;
  GskRenderNode *clip, *result;

  /* clip to opaque region */
  clip = gsk_clip_node_new (node, opaque);

  /* Turn image to white, don't touch alpha */
  graphene_matrix_init_from_float (&matrix,
                                   (const float []) { 0,    0,    0,    0,
                                                      0,    0,    0,    0,
                                                      0,    0,    0,    0,
                                                      1.011.011.011 });
  result = gsk_color_matrix_node_new (clip, &matrix, graphene_vec4_zero ());

  gsk_render_node_unref (clip);

  return result;
}

static GdkTexture *
opaque_create_reference (GskRenderer   *renderer,
                         GdkTexture    *texture,
                         gconstpointer  user_data)
{
  const graphene_rect_t *rect = user_data;
  GBytes *bytes;
  guchar *data;
  gsize stride, size;
  GdkTexture *result;

  stride = ((gsize) rect->size.width + 3) & ~3;
  size = stride * rect->size.height;

  data = g_malloc (size);
  memset (data, 0xFF, size);
  bytes = g_bytes_new_take (data, size);

  result = gdk_memory_texture_new (rect->size.width,
                                   rect->size.height,
                                   GDK_MEMORY_A8,
                                   bytes,
                                   stride);

  g_bytes_unref (bytes);

  return result;
}

static GskRenderNode *
serialize_create_test (GskRenderNode *node,
                       gconstpointer  data)
{
  GskRenderNode *result;
  GBytes *bytes;

  bytes = gsk_render_node_serialize (node);
  result = gsk_render_node_deserialize (bytes, NULL, NULL);
  g_bytes_unref (bytes);

  return result;
}

typedef enum
{
  KEEP_BOUNDS = (1 << 0),
} TestFlags;

typedef struct _TestSetup TestSetup;
struct _TestSetup
{
  const char *name;
  const char *description;
  TestFlags flags;
  gpointer        (* setup)            (GskRenderNode *node);
  void            (* free)             (gpointer       data);
  GskRenderNode * (* create_test)      (GskRenderNode *node,
                                        gconstpointer  data);
  GdkTexture *    (* create_reference) (GskRenderer   *renderer,
                                        GdkTexture    *texture,
                                        gconstpointer  data);
};

static const TestSetup test_setups[] = {
  {
    .name = "plain",
    .description = "Run test as-is",
    .create_test = NULL,
    .create_reference = NULL,
  },
  {
    .name = "flip",
    .description = "Do flipped test",
    .create_test = flip_create_test,
    .create_reference = flip_create_reference,
  },
  {
    .name = "repeat",
    .description = "Do rotated test",
    .create_test = repeat_create_test,
    .create_reference = repeat_create_reference,
  },
  {
    .name = "rotate",
    .description = "Do repeated test",
    .create_test = rotate_create_test,
    .create_reference = rotate_create_reference,
  },
  {
    .name = "mask",
    .description = "Do masked test",
    .create_test = mask_create_test,
    .create_reference = mask_create_reference,
  },
  {
    .name = "replay",
    .description = "Do replay test",
    .flags = KEEP_BOUNDS,
    .create_test = replay_create_test,
    .create_reference = NULL,
  },
  {
    .name = "clip",
    .description = "Do clip test",
    .flags = KEEP_BOUNDS,
    .setup = clip_setup,
    .free = g_free,
    .create_test = clip_create_test,
    .create_reference = clip_create_reference,
  },
  {
    .name = "colorflip",
    .description = "Swap colors",
    .create_test = colorflip_create_test,
    .create_reference = colorflip_create_reference,
  },
  {
    .name = "opaque",
    .description = "Check the opaque rect",
    .setup = opaque_setup,
    .free = g_free,
    .create_test = opaque_create_test,
    .create_reference = opaque_create_reference,
  },
  {
    .name = "serialize",
    .description = "Serialize and deserialize",
    .create_test = serialize_create_test,
    .create_reference = NULL,
  },
};

static void
run_single_test (const TestSetup *setup,
                 const char      *file_name,
                 GskRenderer     *renderer,
                 GskRenderNode   *org_test,
                 GdkTexture      *org_reference)
{
  GskRenderNode *test;
  GdkTexture *reference, *rendered, *diff;
  graphene_rect_t test_bounds, *render_bounds;
  gpointer test_data;

  if (setup->flags & KEEP_BOUNDS)
    {
      gsk_render_node_get_bounds (org_test, &test_bounds);
      render_bounds = &test_bounds;
    }
  else
    render_bounds = NULL;

  if (setup->setup)
    {
      test_data = setup->setup (org_test);

      if (test_data == NULL && g_test_failed ())
        {
          /* Allow tests to fail/skip when setting up if
           * they return NULL */

          return;
        }
    }
  else
    test_data = NULL;

  if (setup->create_test)
    {
      test = setup->create_test (org_test, test_data);
    }
  else
    test = gsk_render_node_ref (org_test);

  rendered = gsk_renderer_render_texture (renderer, test, render_bounds);

  if (setup->create_reference)
    reference = setup->create_reference (renderer, org_reference, test_data);
  else
    reference = g_object_ref (org_reference);

  if (setup->free)
    setup->free (test_data);

  diff = reftest_compare_textures_with_tolerance (reference, rendered, arg_tolerance);
  if (diff)
    {
      g_test_fail ();
    }

  if (diff || g_test_verbose ())
    {
      save_node (test, file_name, setup->name, ".node");
      save_image (reference, file_name, setup->name, ".ref.png");
      save_image (rendered, file_name, setup->name, ".out.png");
      if (diff)
        save_image (diff, file_name, setup->name, ".diff.png");
    }

  g_clear_object (&diff);
  g_object_unref (rendered);
  g_object_unref (reference);
  gsk_render_node_unref (test);
}
                 
typedef struct _TestData TestData;

struct _TestData {
  char *node_file;
  char *png_file;
};

static void
test_data_free (TestData *test)
{
  g_free (test->node_file);
  g_free (test->png_file);

  g_free (test);
}

static gboolean test_enabled[G_N_ELEMENTS (test_setups)] = { FALSE, };

/*
 * Non-option arguments:
 *   1) .node file to compare
 *   2) .png file to compare the rendered .node file to
 */

static void
run_node_test (gconstpointer data)
{
  const TestData *test = data;
  GdkTexture *reference_texture = NULL;
  GskRenderer *renderer;
  GdkSurface *window;
  GskRenderNode *node;
  GError *error = NULL;
  gsize i;

  g_print ("Node file: '%s'\n", test->node_file);
  g_print ("PNG file: '%s'\n", test->png_file);

  window = gdk_surface_new_toplevel (gdk_display_get_default());
  renderer = gsk_renderer_new_for_surface (window);

  /* Load the render node from the given .node file */
  node = load_node_file (test->node_file);
  if (!node)
    {
      g_test_fail ();
      return;
    }

  /* Load the given reference png file */
  reference_texture = gdk_texture_new_from_filename (test->png_file, &error);
  if (reference_texture == NULL)
    {
      g_print ("Error loading reference surface: %s\n", error->message);
      g_clear_error (&error);
      g_test_fail ();
      return;
    }

  for (i = 0; i < G_N_ELEMENTS (test_setups); i++)
    {
      if (test_enabled[i])
        run_single_test (&test_setups[i], test->node_file, renderer, node, reference_texture);
    }

  g_object_unref (reference_texture);
  gsk_render_node_unref (node);
  gsk_renderer_unrealize (renderer);
  g_object_unref (renderer);
  gdk_surface_destroy (window);
}

int
main (int argc, char **argv)
{
  GOptionEntry options[] = {
    { "tolerance"'t'0, G_OPTION_ARG_INT, &arg_tolerance, "Tolerance to allow in comparisons""NUM" },
    { "output"00, G_OPTION_ARG_FILENAME, &arg_output_dir, "Directory to save image files to""DIR" },
    { test_setups[0].name, 00, G_OPTION_ARG_NONE, &test_enabled[0], test_setups[0].description, NULL },
    { test_setups[1].name, 00, G_OPTION_ARG_NONE, &test_enabled[1], test_setups[1].description, NULL },
    { test_setups[2].name, 00, G_OPTION_ARG_NONE, &test_enabled[2], test_setups[2].description, NULL },
    { test_setups[3].name, 00, G_OPTION_ARG_NONE, &test_enabled[3], test_setups[3].description, NULL },
    { test_setups[4].name, 00, G_OPTION_ARG_NONE, &test_enabled[4], test_setups[4].description, NULL },
    { test_setups[5].name, 00, G_OPTION_ARG_NONE, &test_enabled[5], test_setups[5].description, NULL },
    { test_setups[6].name, 00, G_OPTION_ARG_NONE, &test_enabled[6], test_setups[6].description, NULL },
    { test_setups[7].name, 00, G_OPTION_ARG_NONE, &test_enabled[7], test_setups[7].description, NULL },
    { test_setups[8].name, 00, G_OPTION_ARG_NONE, &test_enabled[8], test_setups[8].description, NULL },
    { test_setups[9].name, 00, G_OPTION_ARG_NONE, &test_enabled[9], test_setups[9].description, NULL },
    { NULL }
  };
  GOptionContext *context;
  GError *error = NULL;
  TestData *test;
  int result;
  gsize i;

  (g_test_init) (&argc, &argv, NULL);

  context = g_option_context_new ("NODE [REF] - run GSK node tests");
  g_option_context_add_main_entries (context, options, NULL);
  g_option_context_set_ignore_unknown_options (context, TRUE);

  if (!g_option_context_parse (context, &argc, &argv, &error))
    {
      g_error ("Option parsing failed: %s\n", error->message);
      return 1;
    }
  else if (argc != 3 && argc != 2)
    {
      char *help = g_option_context_get_help (context, TRUE, NULL);
      g_print ("%s", help);
      return 1;
    }

  g_option_context_free (context);

  for (i = 0; i < G_N_ELEMENTS (test_enabled); i++)
    {
      if (test_enabled[i])
        break;
    }
  if (i >= G_N_ELEMENTS (test_enabled))
    test_enabled[0] = TRUE;

  gtk_init ();

  test = g_new0 (TestData, 1);
  test->node_file = g_canonicalize_filename (argv[1], NULL);
  if (argc <= 2)
    test->png_file = file_replace_extension (test->node_file, ".node"".png");
  else
    test->png_file = g_canonicalize_filename (argv[2], NULL);

  g_test_add_vtable (test->node_file,
                     0,
                     test,
                     NULL,
                     (GTestFixtureFunc) run_node_test,
                     (GTestFixtureFunc) test_data_free);

  result = g_test_run ();

  return result;
}

Messung V0.5 in Prozent
C=100 H=90 G=95

¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet am  2026-07-02) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik