#include <gtk/gtk.h>
#include <math.h>
#include <stdlib.h>
static void
hsv_to_rgb (GdkRGBA *rgba,
double h,
double s,
double v)
{
double hue, saturation, value;
double f, p, q, t;
rgba->alpha = 1 .0 ;
if ( s == 0 .0 )
{
rgba->red = v;
rgba->green = v;
rgba->blue = v; /* heh */
}
else
{
hue = h * 6 .0 ;
saturation = s;
value = v;
if (hue == 6 .0 )
hue = 0 .0 ;
f = hue - (int ) hue;
p = value * (1 .0 - saturation);
q = value * (1 .0 - saturation * f);
t = value * (1 .0 - saturation * (1 .0 - f));
switch ((int ) hue)
{
case 0 :
rgba->red = value;
rgba->green = t;
rgba->blue = p;
break ;
case 1 :
rgba->red = q;
rgba->green = value;
rgba->blue = p;
break ;
case 2 :
rgba->red = p;
rgba->green = value;
rgba->blue = t;
break ;
case 3 :
rgba->red = p;
rgba->green = q;
rgba->blue = value;
break ;
case 4 :
rgba->red = t;
rgba->green = p;
rgba->blue = value;
break ;
case 5 :
rgba->red = value;
rgba->green = p;
rgba->blue = q;
break ;
default :
g_assert_not_reached ();
}
}
}
static GskRenderNode *
rounded_borders (guint n)
{
GskRenderNode **nodes = g_newa (GskRenderNode *, n);
GskRenderNode *container;
GskRoundedRect outline;
float widths[4 ];
GdkRGBA colors[4 ];
guint i;
for (i = 0 ; i < n; i++)
{
outline.bounds.size.width = g_random_int_range (20 , 1000 );
outline.bounds.origin.x = g_random_int_range (0 , 1000 - outline.bounds.size.width);
outline.bounds.size.height = g_random_int_range (20 , 1000 );
outline.bounds.origin.y = g_random_int_range (0 , 1000 - outline.bounds.size.height);
outline.corner[0 ].width = outline.corner[0 ].height = 10 - (int ) sqrt (g_random_int_range (0 , 100 ));
outline.corner[1 ].width = outline.corner[1 ].height = 10 - (int ) sqrt (g_random_int_range (0 , 100 ));
outline.corner[2 ].width = outline.corner[2 ].height = 10 - (int ) sqrt (g_random_int_range (0 , 100 ));
outline.corner[3 ].width = outline.corner[3 ].height = 10 - (int ) sqrt (g_random_int_range (0 , 100 ));
widths[0 ] = widths[1 ] = widths[2 ] = widths[3 ] = g_random_int_range (0 , 5 );
hsv_to_rgb (&colors[0 ], g_random_double (), 1 .0 , 1 .0 );
colors[3 ] = colors[2 ] = colors[1 ] = colors[0 ];
nodes[i] = gsk_border_node_new (&outline, widths, colors);
}
container = gsk_container_node_new (nodes, n);
for (i = 0 ; i < n; i++)
gsk_render_node_unref (nodes[i]);
return container;
}
static GskRenderNode *
rounded_backgrounds (guint n)
{
GskRenderNode **nodes = g_newa (GskRenderNode *, n);
GskRenderNode *container, *texture;
GskRoundedRect outline;
GdkRGBA color;
guint i;
for (i = 0 ; i < n; i++)
{
outline.bounds.size.width = g_random_int_range (20 , 100 );
outline.bounds.origin.x = g_random_int_range (0 , 1000 - outline.bounds.size.width);
outline.bounds.size.height = g_random_int_range (20 , 100 );
outline.bounds.origin.y = g_random_int_range (0 , 1000 - outline.bounds.size.height);
outline.corner[0 ].width = outline.corner[0 ].height = 10 - (int ) sqrt (g_random_int_range (0 , 100 ));
outline.corner[1 ].width = outline.corner[1 ].height = 10 - (int ) sqrt (g_random_int_range (0 , 100 ));
outline.corner[2 ].width = outline.corner[2 ].height = 10 - (int ) sqrt (g_random_int_range (0 , 100 ));
outline.corner[3 ].width = outline.corner[3 ].height = 10 - (int ) sqrt (g_random_int_range (0 , 100 ));
hsv_to_rgb (&color, g_random_double (), g_random_double_range (0 .15 , 0 .4 ), g_random_double_range (0 .6 , 0 .85 ));
color.alpha = g_random_double_range (0 .5 , 0 .75 );
texture = gsk_color_node_new (&color, &outline.bounds);
nodes[i] = gsk_rounded_clip_node_new (texture, &outline);
}
container = gsk_container_node_new (nodes, n);
for (i = 0 ; i < n; i++)
gsk_render_node_unref (nodes[i]);
return container;
}
static GskRenderNode *
colors (guint n)
{
GskRenderNode **nodes = g_new (GskRenderNode *, 10 * n);
GskRenderNode *container;
graphene_rect_t bounds;
GdkRGBA color;
guint i;
for (i = 0 ; i < 10 * n; i++)
{
bounds.size.width = g_random_int_range (20 , 100 );
bounds.origin.x = g_random_int_range (0 , 1000 - bounds.size.width);
bounds.size.height = g_random_int_range (20 , 100 );
bounds.origin.y = g_random_int_range (0 , 1000 - bounds.size.height);
hsv_to_rgb (&color, g_random_double (), g_random_double_range (0 .15 , 0 .4 ), g_random_double_range (0 .6 , 0 .85 ));
color.alpha = g_random_double_range (0 .5 , 0 .75 );
nodes[i] = gsk_color_node_new (&color, &bounds);
}
container = gsk_container_node_new (nodes, 10 * n);
for (i = 0 ; i < 10 * n; i++)
gsk_render_node_unref (nodes[i]);
g_free (nodes);
return container;
}
static GskRenderNode *
clipped_colors (guint n)
{
GskRenderNode **nodes = g_newa (GskRenderNode *,n);
GskRenderNode *container;
graphene_rect_t bounds;
GdkRGBA color;
guint i;
for (i = 0 ; i < n; i++)
{
bounds.size.width = g_random_int_range (20 , 100 );
bounds.origin.x = g_random_int_range (0 , 1000 - bounds.size.width);
bounds.size.height = g_random_int_range (20 , 100 );
bounds.origin.y = g_random_int_range (0 , 1000 - bounds.size.height);
hsv_to_rgb (&color, g_random_double (), g_random_double_range (0 .15 , 0 .4 ), g_random_double_range (0 .6 , 0 .85 ));
color.alpha = g_random_double_range (0 .5 , 0 .75 );
nodes[i] = gsk_color_node_new (&color, &bounds);
}
container = gsk_container_node_new (nodes, n);
for (i = 0 ; i < n; i++)
gsk_render_node_unref (nodes[i]);
#define GRID_SIZE 4
for (i = 0 ; i < GRID_SIZE * GRID_SIZE; i++)
{
guint x = i % GRID_SIZE;
guint y = i / GRID_SIZE;
if ((x + y) % 2 )
continue ;
nodes[i / 2 ] = gsk_clip_node_new (container,
&GRAPHENE_RECT_INIT(
x * 1000 / GRID_SIZE, y * 1000 / GRID_SIZE,
1000 / GRID_SIZE, 1000 / GRID_SIZE
));
}
gsk_render_node_unref (container);
container = gsk_container_node_new (nodes, GRID_SIZE * GRID_SIZE / 2 );
for (i = 0 ; i < GRID_SIZE * GRID_SIZE / 2 ; i++)
gsk_render_node_unref (nodes[i]);
return container;
}
static int
compare_color_stops (gconstpointer a,
gconstpointer b,
gpointer user_data)
{
const GskColorStop *stopa = a;
const GskColorStop *stopb = b;
if (stopa->offset < stopb->offset)
return -1 ;
else if (stopa->offset > stopb->offset)
return 1 ;
else
return 0 ;
}
static GskRenderNode *
linear_gradient (guint n)
{
GskRenderNode **nodes = g_newa (GskRenderNode *, n);
GskRenderNode *container;
graphene_rect_t bounds;
GskColorStop stops[5 ];
graphene_point_t start, end;
guint i, j, n_stops;
for (i = 0 ; i < n; i++)
{
bounds.size.width = g_random_int_range (20 , 100 );
bounds.origin.x = g_random_int_range (0 , 1000 - bounds.size.width);
bounds.size.height = g_random_int_range (20 , 100 );
bounds.origin.y = g_random_int_range (0 , 1000 - bounds.size.height);
do {
start.x = g_random_double_range (- bounds.size.width / 4 , bounds.size.width / 4 );
if (start.x >= 0 )
start.x += bounds.origin.x;
else
start.x += bounds.origin.x + bounds.size.width;
start.y = g_random_double_range (- bounds.size.height / 4 , bounds.size.height / 4 );
if (start.y >= 0 )
start.y += bounds.origin.y;
else
start.y += bounds.origin.y + bounds.size.height;
end.x = g_random_double_range (- bounds.size.width / 4 , bounds.size.width / 4 );
if (end.x >= 0 )
end.x += bounds.origin.x;
else
end.x += bounds.origin.x + bounds.size.width;
end.y = g_random_double_range (- bounds.size.height / 4 , bounds.size.height / 4 );
if (end.y >= 0 )
end.y += bounds.origin.y;
else
end.y += bounds.origin.y + bounds.size.height;
} while (graphene_point_equal (&start, &end));
n_stops = g_random_int_range (2 , 5 );
for (j = 0 ; j < n_stops; j++)
{
if (j == 0 )
stops[j].offset = 0 ;
else if (j == n_stops - 1 )
stops[j].offset = 1 ;
else
stops[j].offset = g_random_double_range (0 , 1 );
hsv_to_rgb (&stops[j].color, g_random_double (), g_random_double_range (0 .15 , 0 .4 ), g_random_double_range (0 .6 , 0 .85 ));
stops[j].color.alpha = g_random_double_range (0 , 1 );
}
g_sort_array (stops, n_stops, sizeof (stops[0 ]), compare_color_stops, 0 );
if (g_random_boolean ())
nodes[i] = gsk_linear_gradient_node_new (&bounds, &start, &end, stops, n_stops);
else
nodes[i] = gsk_repeating_linear_gradient_node_new (&bounds, &start, &end, stops, n_stops);
}
container = gsk_container_node_new (nodes, n);
for (i = 0 ; i < n; i++)
gsk_render_node_unref (nodes[i]);
return container;
}
static GskRenderNode *
borders (guint n)
{
GskRenderNode **nodes = g_newa (GskRenderNode *, n);
GskRenderNode *container;
GskRoundedRect outline;
GdkRGBA colors[4 ];
float widths[4 ];
guint i, j;
for (i = 0 ; i < n; i++)
{
outline.bounds.size.width = g_random_int_range (20 , 100 );
outline.bounds.origin.x = g_random_int_range (0 , 1000 - outline.bounds.size.width);
outline.bounds.size.height = g_random_int_range (20 , 100 );
outline.bounds.origin.y = g_random_int_range (0 , 1000 - outline.bounds.size.height);
outline.corner[1 ].width = outline.corner[1 ].height = 10 - (int ) sqrt (g_random_int_range (0 , 100 ));
outline.corner[2 ].width = outline.corner[2 ].height = 10 - (int ) sqrt (g_random_int_range (0 , 100 ));
outline.corner[3 ].width = outline.corner[3 ].height = 10 - (int ) sqrt (g_random_int_range (0 , 100 ));
for (j = 0 ; j < 4 ; j++)
{
outline.corner[0 ].width = 10 - (int ) sqrt (g_random_int_range (0 , 100 ));
outline.corner[0 ].height = 10 - (int ) sqrt (g_random_int_range (0 , 100 ));
hsv_to_rgb (&colors[j], g_random_double (), 1 .0 , 0 .5 ); //g_random_double_range (0.15, 0.4), g_random_double_range (0.6, 0.85));
colors[j].alpha = 1 .0 ; //g_random_double_range (0.8, 1.0);
widths[j] = g_random_int_range (1 , 6 );
}
nodes[i] = gsk_border_node_new (&outline, widths, colors);
}
container = gsk_container_node_new (nodes, n);
for (i = 0 ; i < n; i++)
gsk_render_node_unref (nodes[i]);
return container;
}
const char *example =
"'Twas brillig, and the slithy toves\n"
"Did gyre and gimble in the wabe;\n"
"All mimsy were the borogoves,\n"
"And the mome raths outgrabe.\n"
"\n"
"'Beware the Jabberwock, my son!\n"
"The jaws that bite, the claws that catch!\n"
"Beware the Jubjub bird, and shun\n"
"The frumious Bandersnatch!'" ;
static GskRenderNode *
text (guint n)
{
GPtrArray *nodes;
GskRenderNode *container;
PangoFontDescription *desc;
PangoContext *context;
PangoLayout *layout;
GtkSettings *settings;
char *usr_dict_words;
char **words;
gsize n_words;
int dpi_int;
int i;
if (g_file_get_contents ("/usr/share/dict/words" , &usr_dict_words, NULL, NULL))
{
words = g_strsplit (usr_dict_words, "\n" , -1 );
g_free (usr_dict_words);
}
else
{
words = g_strsplit ("the quick brown fox jumps over the lazy dog" , " " , -1 );
}
n_words = g_strv_length (words);
context = pango_font_map_create_context (pango_cairo_font_map_get_default ());
nodes = g_ptr_array_new_with_free_func ((GDestroyNotify) gsk_render_node_unref);
settings = gtk_settings_get_default ();
g_object_get (settings, "gtk-xft-dpi" , &dpi_int, NULL);
if (dpi_int > 0 )
pango_cairo_context_set_resolution (context, dpi_int / 1024 .);
desc = pango_font_description_new ();
pango_font_description_set_family (desc, "Cantarell" );
layout = pango_layout_new (context);
for (i = 0 ; i < n; i++)
{
PangoFont *font;
PangoLayoutIter *iter;
PangoLayoutRun *run;
GdkRGBA color;
int x, y, width, height;
pango_layout_set_text (layout, words[g_random_int_range (0 , n_words)], -1 );
if (g_random_boolean ())
pango_font_description_set_style (desc, PANGO_STYLE_ITALIC);
else
pango_font_description_set_style (desc, PANGO_STYLE_NORMAL);
pango_font_description_set_weight (desc, 200 * g_random_int_range (1 , 5 ));
pango_font_description_set_size (desc, PANGO_SCALE * 4 * g_random_int_range (2 ,8 ));
font = pango_context_load_font (context, desc);
pango_layout_set_font_description (layout, desc);
pango_layout_get_pixel_size (layout, &width, &height);
x = width >= 1000 ? 0 : g_random_int_range (0 , 1000 - width);
y = height >= 1000 ? 0 : g_random_int_range (0 , 1000 - height);
hsv_to_rgb (&color, g_random_double (), g_random_double_range (0 .5 , 1 .0 ), g_random_double_range (0 .15 , 0 .75 ));
iter = pango_layout_get_iter (layout);
do
{
run = pango_layout_iter_get_run (iter);
if (run != NULL)
{
GskRenderNode *node;
node = gsk_text_node_new (font, run->glyphs, &color, &GRAPHENE_POINT_INIT (x, y));
if (node)
g_ptr_array_add (nodes, node);
}
}
while (pango_layout_iter_next_run (iter));
pango_layout_iter_free (iter);
g_object_unref (font);
}
pango_font_description_free (desc);
g_object_unref (layout);
container = gsk_container_node_new ((GskRenderNode **) nodes->pdata, nodes->len);
g_ptr_array_unref (nodes);
g_strfreev (words);
return container;
}
static GskRenderNode *
cairo_node (guint n)
{
GskRenderNode **nodes = g_newa (GskRenderNode *, n);
GskRenderNode *container;
graphene_rect_t bounds;
guint i;
for (i = 0 ; i < n; i++)
{
bounds.size.width = g_random_int_range (20 , 100 );
bounds.origin.x = g_random_int_range (0 , 1000 - bounds.size.width);
bounds.size.height = g_random_int_range (20 , 100 );
bounds.origin.y = g_random_int_range (0 , 1000 - bounds.size.height);
nodes [i] = gsk_cairo_node_new (&bounds);
}
container = gsk_container_node_new (nodes, n);
for (i = 0 ; i < n; i++)
gsk_render_node_unref (nodes[i]);
return container;
}
static GskRenderNode *
box_shadows (guint n)
{
GskRenderNode **nodes = g_newa (GskRenderNode *, n);
GskRenderNode *container;
int i, j;
GskRoundedRect outline;
GdkRGBA color;
float dx, dy;
float spread;
float blur;
for (i = 0 ; i < n; i++)
{
outline.bounds.size.width = g_random_int_range (20 , 100 );
outline.bounds.origin.x = g_random_int_range (0 , 1000 - outline.bounds.size.width);
outline.bounds.size.height = g_random_int_range (20 , 100 );
outline.bounds.origin.y = g_random_int_range (0 , 1000 - outline.bounds.size.height);
outline.corner[1 ].width = outline.corner[1 ].height = 10 - (int ) sqrt (g_random_int_range (0 , 100 ));
outline.corner[2 ].width = outline.corner[2 ].height = 10 - (int ) sqrt (g_random_int_range (0 , 100 ));
outline.corner[3 ].width = outline.corner[3 ].height = 10 - (int ) sqrt (g_random_int_range (0 , 100 ));
for (j = 0 ; j < 4 ; j++)
{
outline.corner[0 ].width = 10 - (int ) sqrt (g_random_int_range (0 , 100 ));
outline.corner[0 ].height = 10 - (int ) sqrt (g_random_int_range (0 , 100 ));
}
hsv_to_rgb (&color, g_random_double (), g_random_double_range (0 .15 , 0 .4 ), g_random_double_range (0 .6 , 0 .85 ));
dx = g_random_double_range (0 .0 , 5 .0 );
dy = g_random_double_range (0 .0 , 5 .0 );
spread = g_random_double_range (0 .0 , 10 .0 );
blur = g_random_double_range (0 .0 , 10 .0 );
if (g_random_boolean ())
nodes[i] = gsk_inset_shadow_node_new (&outline, &color, dx, dy, spread, blur);
else
nodes[i] = gsk_outset_shadow_node_new (&outline, &color, dx, dy, spread, blur);
}
container = gsk_container_node_new (nodes, n);
for (i = 0 ; i < n; i++)
gsk_render_node_unref (nodes[i]);
return container;
}
int
main (int argc, char **argv)
{
static const struct {
const char *name;
GskRenderNode * (* func) (guint n);
} functions[] = {
{ "cairo.node" , cairo_node },
{ "colors.node" , colors },
{ "clipped-colors.node" , clipped_colors },
{ "rounded-borders.node" , rounded_borders },
{ "rounded-backgrounds.node" , rounded_backgrounds },
{ "linear-gradient.node" , linear_gradient },
{ "borders.node" , borders },
{ "text.node" , text },
{ "box-shadows.node" , box_shadows },
};
GError *error = NULL;
GskRenderNode *node;
GPatternSpec *matcher;
const char *pattern;
guint i, n;
gtk_init ();
n = 100000 ;
pattern = "*" ;
if (argc > 1 )
{
if (argc > 2 )
pattern = argv[2 ];
n = atoi (argv[1 ]);
}
matcher = g_pattern_spec_new (pattern);
for (i = 0 ; i < G_N_ELEMENTS (functions); i++)
{
if (!g_pattern_spec_match_string (matcher, functions[i].name))
continue ;
node = functions[i].func (n);
if (!gsk_render_node_write_to_file (node, functions[i].name, &error))
{
g_print ("Error writing \" %s\": %s\n" , functions[i].name, error->message);
g_clear_error (&error);
return 1 ;
}
gsk_render_node_unref (node);
g_print ("Created test file \" %s\".\n" , functions[i].name);
}
g_pattern_spec_free (matcher);
return 0 ;
}
Messung V0.5 in Prozent C=98 H=90 G=94
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-07-02)
¤
*© Formatika GbR, Deutschland