/*
* Copyright © 2020 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 <gtk/gtk.h>
#include "path-utils.h"
static GskPath *
create_random_degenerate_path (guint max_contours)
{
#define N_DEGENERATE_PATHS 15
GskPathBuilder *builder;
guint i;
builder = gsk_path_builder_new ();
switch (g_test_rand_int_range (0 , N_DEGENERATE_PATHS))
{
case 0 :
/* empty path */
break ;
case 1 :
/* a single point */
gsk_path_builder_move_to (builder,
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ));
break ;
case 2 :
/* N points */
for (i = 0 ; i < MIN (10 , max_contours); i++)
{
gsk_path_builder_move_to (builder,
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ));
}
break ;
case 3 :
/* 1 closed point */
gsk_path_builder_move_to (builder,
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ));
gsk_path_builder_close (builder);
break ;
case 4 :
/* the same point closed N times */
gsk_path_builder_move_to (builder,
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ));
for (i = 0 ; i < MIN (10 , max_contours); i++)
{
gsk_path_builder_close (builder);
}
break ;
case 5 :
/* a zero-width and zero-height rect */
gsk_path_builder_add_rect (builder,
&GRAPHENE_RECT_INIT (g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
0 , 0 ));
break ;
case 6 :
/* a zero-width rect */
gsk_path_builder_add_rect (builder,
&GRAPHENE_RECT_INIT (g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
0 ,
g_test_rand_double_range (-1000 , 1000 )));
break ;
case 7 :
/* a zero-height rect */
gsk_path_builder_add_rect (builder,
&GRAPHENE_RECT_INIT (g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
0 ));
break ;
case 8 :
/* a negative-size rect */
gsk_path_builder_add_rect (builder,
&GRAPHENE_RECT_INIT (g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 0 ),
g_test_rand_double_range (-1000 , 0 )));
break ;
case 9 :
/* an absolutely random rect */
gsk_path_builder_add_rect (builder,
&GRAPHENE_RECT_INIT (g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 )));
break ;
case 10 :
/* an absolutely random rect */
gsk_path_builder_add_rect (builder,
&GRAPHENE_RECT_INIT (g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 )));
break ;
case 11 :
/* an absolutely random circle */
gsk_path_builder_add_circle (builder,
&GRAPHENE_POINT_INIT (g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 )),
g_test_rand_double_range (1 , 1000 ));
break ;
case 12 :
/* circle with radius 0 */
gsk_path_builder_add_circle (builder,
&GRAPHENE_POINT_INIT (g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 )),
0 );
break ;
case 13 :
/* a zero-length line */
{
graphene_point_t point = GRAPHENE_POINT_INIT (g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ));
gsk_path_builder_move_to (builder, point.x, point.y);
gsk_path_builder_line_to (builder, point.x, point.y);
}
break ;
case 14 :
/* a cubic with start == end */
{
graphene_point_t point = GRAPHENE_POINT_INIT (g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ));
gsk_path_builder_move_to (builder, point.x, point.y);
gsk_path_builder_cubic_to (builder,
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
point.x, point.y);
}
break ;
case N_DEGENERATE_PATHS:
default :
g_assert_not_reached ();
}
return gsk_path_builder_free_to_path (builder);
}
static GskPath *
create_random_path (guint max_contours);
static void
add_shape_contour (GskPathBuilder *builder)
{
#define N_SHAPE_CONTOURS 3
switch (g_test_rand_int_range (0 , N_SHAPE_CONTOURS))
{
case 0 :
gsk_path_builder_add_rect (builder,
&GRAPHENE_RECT_INIT (g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (1 , 1000 ),
g_test_rand_double_range (1 , 1000 )));
break ;
case 1 :
gsk_path_builder_add_circle (builder,
&GRAPHENE_POINT_INIT (g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 )),
g_test_rand_double_range (1 , 1000 ));
break ;
case 2 :
{
GskPath *path = create_random_path (1 );
gsk_path_builder_add_path (builder, path);
gsk_path_unref (path);
}
break ;
case N_SHAPE_CONTOURS:
default :
g_assert_not_reached ();
break ;
}
}
static void
add_standard_contour (GskPathBuilder *builder)
{
guint i, n;
if (g_test_rand_bit ())
{
if (g_test_rand_bit ())
gsk_path_builder_move_to (builder,
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ));
else
gsk_path_builder_rel_move_to (builder,
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ));
}
/* that 20 is random, but should be enough to get some
* crazy self-intersecting shapes */
n = g_test_rand_int_range (1 , 20 );
for (i = 0 ; i < n; i++)
{
switch (g_test_rand_int_range (0 , 8 ))
{
case 0 :
gsk_path_builder_line_to (builder,
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ));
break ;
case 1 :
gsk_path_builder_rel_line_to (builder,
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ));
break ;
case 2 :
gsk_path_builder_quad_to (builder,
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ));
break ;
case 3 :
gsk_path_builder_rel_quad_to (builder,
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ));
break ;
case 4 :
gsk_path_builder_cubic_to (builder,
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ));
break ;
case 5 :
gsk_path_builder_rel_cubic_to (builder,
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ));
break ;
case 6 :
gsk_path_builder_conic_to (builder,
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (0 .2 , 20 ));
break ;
case 7 :
gsk_path_builder_rel_conic_to (builder,
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (-1000 , 1000 ),
g_test_rand_double_range (0 .2 , 20 ));
break ;
default :
g_assert_not_reached();
break ;
}
}
if (g_test_rand_bit ())
gsk_path_builder_close (builder);
}
static GskPath *
create_random_path (guint max_contours)
{
GskPathBuilder *builder;
guint i, n;
/* 5% chance for a weird shape */
if (!g_test_rand_int_range (0 , 20 ))
return create_random_degenerate_path (max_contours);
builder = gsk_path_builder_new ();
n = g_test_rand_int_range (1 , 10 );
n = MIN (n, max_contours);
for (i = 0 ; i < n; i++)
{
/* 2/3 of shapes are standard contours */
if (g_test_rand_int_range (0 , 3 ))
add_standard_contour (builder);
else
add_shape_contour (builder);
}
return gsk_path_builder_free_to_path (builder);
}
static void
test_create (void )
{
GskPath *path1, *path2, *built;
GskPathBuilder *builder;
guint i;
char *s;
GString *str;
for (i = 0 ; i < 1000 ; i++)
{
builder = gsk_path_builder_new ();
path1 = create_random_path (G_MAXUINT);
gsk_path_builder_add_path (builder, path1);
path2 = create_random_path (G_MAXUINT);
gsk_path_builder_add_path (builder, path2);
built = gsk_path_builder_free_to_path (builder);
str = g_string_new (NULL);
gsk_path_print (path1, str);
if (!gsk_path_is_empty (path1) && !gsk_path_is_empty (path2))
g_string_append_c (str, ' ' );
gsk_path_print (path2, str);
s = gsk_path_to_string (built);
g_assert_cmpstr (s, ==, str->str);
g_string_free (str, TRUE );
g_free (s);
gsk_path_unref (built);
gsk_path_unref (path2);
gsk_path_unref (path1);
}
}
static void
test_parse (void )
{
int i;
for (i = 0 ; i < 1000 ; i++)
{
GskPath *path1, *path2;
char *string1, *string2;
path1 = create_random_path (G_MAXUINT);
string1 = gsk_path_to_string (path1);
g_assert_nonnull (string1);
path2 = gsk_path_parse (string1);
g_assert_nonnull (path2);
string2 = gsk_path_to_string (path2);
g_assert_nonnull (string2);
assert_path_equal_with_epsilon (path1, path2, 1 .f / 1024 );
gsk_path_unref (path2);
gsk_path_unref (path1);
g_free (string2);
g_free (string1);
}
}
#define N_PATHS 3
static void
test_in_fill_union (void )
{
GskPath *path, *paths[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++)
{
paths[k] = create_random_path (G_MAXUINT);
gsk_path_builder_add_path (builder, paths[k]);
}
path = gsk_path_builder_free_to_path (builder);
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_in_fill (paths[k], &test, GSK_FILL_RULE_EVEN_ODD))
n_in_fill++;
}
in_fill = gsk_path_in_fill (path, &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_unref (path);
for (k = 0 ; k < N_PATHS; k++)
gsk_path_unref (paths[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,
float weight,
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_QUAD:
gsk_path_builder_quad_to (builders[0 ], pts[1 ].x, pts[1 ].y, pts[2 ].x, pts[2 ].y);
gsk_path_builder_quad_to (builders[1 ], pts[1 ].y, -pts[1 ].x, pts[2 ].y, -pts[2 ].x);
break ;
case GSK_PATH_CUBIC:
gsk_path_builder_cubic_to (builders[0 ], pts[1 ].x, pts[1 ].y, pts[2 ].x, pts[2 ].y, pts[3 ].x, pts[3 ].y);
gsk_path_builder_cubic_to (builders[1 ], pts[1 ].y, -pts[1 ].x, pts[2 ].y, -pts[2 ].x, pts[3 ].y, -pts[3 ].x);
break ;
case GSK_PATH_CONIC:
gsk_path_builder_conic_to (builders[0 ], pts[1 ].x, pts[1 ].y, pts[2 ].x, pts[2 ].y, weight);
gsk_path_builder_conic_to (builders[1 ], pts[1 ].y, -pts[1 ].x, pts[2 ].y, -pts[2 ].x, weight);
break ;
default :
g_assert_not_reached ();
return FALSE ;
}
return TRUE ;
}
static void
test_in_fill_rotated (void )
{
GskPath *path;
GskPathBuilder *builders[2 ];
GskPath *paths[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 ();
/* Use -1 here because we want all the flags, even future additions */
gsk_path_foreach (path, -1 , rotate_path_cb, builders);
gsk_path_unref (path);
paths[0 ] = gsk_path_builder_free_to_path (builders[0 ]);
paths[1 ] = gsk_path_builder_free_to_path (builders[1 ]);
for (j = 0 ; j < 100 ; j++)
{
GskFillRule fill_rule = g_test_rand_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_in_fill (paths[0 ], &GRAPHENE_POINT_INIT (x, y), fill_rule),
==,
gsk_path_in_fill (paths[1 ], &GRAPHENE_POINT_INIT (y, -x), fill_rule));
g_assert_cmpint (gsk_path_in_fill (paths[0 ], &GRAPHENE_POINT_INIT (y, x), fill_rule),
==,
gsk_path_in_fill (paths[1 ], &GRAPHENE_POINT_INIT (x, -y), fill_rule));
}
gsk_path_unref (paths[0 ]);
gsk_path_unref (paths[1 ]);
}
#undef N_FILL_RULES
}
static void
test_split (void )
{
GskPath *path, *path1, *path2;
GskPathMeasure *measure, *measure1, *measure2;
float length, length1, length2;
GskPathBuilder *builder;
float split, epsilon;
GskPathPoint point0, point1, point2;
float tolerance = 0 .5 ;
for (int i = 0 ; i < 100 ; i++)
{
if (g_test_verbose ())
g_test_message ("path %u" , i);
path = create_random_path (1 );
measure = gsk_path_measure_new_with_tolerance (path, tolerance);
length = gsk_path_measure_get_length (measure);
/* chosen high enough to stop the testsuite from failing */
epsilon = MAX (length / 250 , 1 .f / 1024 );
split = g_test_rand_double_range (0 , length);
if (!gsk_path_get_start_point (path, &point0) ||
!gsk_path_measure_get_point (measure, split, &point1) ||
!gsk_path_get_end_point (path, &point2))
{
gsk_path_unref (path);
gsk_path_measure_unref (measure);
continue ;
}
if (gsk_path_point_equal (&point0, &point1) ||
gsk_path_point_equal (&point1, &point2))
{
gsk_path_unref (path);
gsk_path_measure_unref (measure);
continue ;
}
g_assert_true (gsk_path_point_compare (&point0, &point1) < 0 );
g_assert_true (gsk_path_point_compare (&point1, &point2) < 0 );
builder = gsk_path_builder_new ();
gsk_path_builder_add_segment (builder, path, &point0, &point1);
path1 = gsk_path_builder_free_to_path (builder);
measure1 = gsk_path_measure_new_with_tolerance (path1, tolerance);
length1 = gsk_path_measure_get_length (measure1);
builder = gsk_path_builder_new ();
gsk_path_builder_add_segment (builder, path, &point1, &point2);
path2 = gsk_path_builder_free_to_path (builder);
measure2 = gsk_path_measure_new_with_tolerance (path2, tolerance);
length2 = gsk_path_measure_get_length (measure2);
g_assert_cmpfloat_with_epsilon (length, length1 + length2, epsilon);
gsk_path_unref (path2);
gsk_path_unref (path1);
gsk_path_unref (path);
gsk_path_measure_unref (measure2);
gsk_path_measure_unref (measure1);
gsk_path_measure_unref (measure);
}
}
static void
test_roundtrip (void )
{
GskPath *path;
GskPathMeasure *measure;
float length;
float split, epsilon;
GskPathPoint point;
float distance;
float tolerance = 0 .5 ;
for (int i = 0 ; i < 100 ; i++)
{
if (g_test_verbose ())
g_test_message ("path %u" , i);
path = create_random_path (1 );
measure = gsk_path_measure_new_with_tolerance (path, tolerance);
length = gsk_path_measure_get_length (measure);
/* chosen high enough to stop the testsuite from failing */
epsilon = MAX (length / 1000 , 1 .f / 1024 );
split = g_test_rand_double_range (0 , length);
if (!gsk_path_measure_get_point (measure, split, &point))
{
gsk_path_unref (path);
gsk_path_measure_unref (measure);
continue ;
}
distance = gsk_path_point_get_distance (&point, measure);
g_assert_cmpfloat_with_epsilon (split, distance, epsilon);
gsk_path_unref (path);
gsk_path_measure_unref (measure);
}
}
static void
test_segment (void )
{
GskPath *path, *path1, *path2, *path3;
GskPathMeasure *measure, *measure1, *measure2, *measure3;
GskPathPoint point0, point1, point2, point3;
float length, length1, length2, length3;
GskPathBuilder *builder;
float split1, split2, epsilon;
float tolerance = 0 .5 ;
for (int i = 0 ; i < 100 ; i++)
{
if (g_test_verbose ())
g_test_message ("path %u" , i);
path = create_random_path (G_MAXUINT);
measure = gsk_path_measure_new_with_tolerance (path, tolerance);
length = gsk_path_measure_get_length (measure);
/* We are accumulating both the split error and the roundtrip error
* here ( on both ends , for the middle segment ) . So we should expect
* the epsilon here to be at least 4 times the epsilon we can use
* in the split and roundtrip tests .
*/
epsilon = MAX (length / 200 , 1 .f / 1024 );
split1 = g_test_rand_double_range (0 , length);
split2 = g_test_rand_double_range (split1, length);
if (!gsk_path_get_start_point (path, &point0) ||
!gsk_path_measure_get_point (measure, split1, &point1) ||
!gsk_path_measure_get_point (measure, split2, &point2) ||
!gsk_path_get_end_point (path, &point3))
{
gsk_path_unref (path);
gsk_path_measure_unref (measure);
continue ;
}
if (gsk_path_point_equal (&point0, &point1) ||
gsk_path_point_equal (&point1, &point2) ||
gsk_path_point_equal (&point2, &point3))
{
gsk_path_unref (path);
gsk_path_measure_unref (measure);
continue ;
}
builder = gsk_path_builder_new ();
gsk_path_builder_add_segment (builder, path, &point0, &point1);
path1 = gsk_path_builder_free_to_path (builder);
measure1 = gsk_path_measure_new_with_tolerance (path1, tolerance);
length1 = gsk_path_measure_get_length (measure1);
builder = gsk_path_builder_new ();
gsk_path_builder_add_segment (builder, path, &point1, &point2);
path2 = gsk_path_builder_free_to_path (builder);
measure2 = gsk_path_measure_new_with_tolerance (path2, tolerance);
length2 = gsk_path_measure_get_length (measure2);
builder = gsk_path_builder_new ();
gsk_path_builder_add_segment (builder, path, &point2, &point3);
path3 = gsk_path_builder_free_to_path (builder);
measure3 = gsk_path_measure_new_with_tolerance (path3, tolerance);
length3 = gsk_path_measure_get_length (measure3);
g_assert_cmpfloat_with_epsilon (split1, length1, epsilon);
g_assert_cmpfloat_with_epsilon (split2, length1 + length2, epsilon);
g_assert_cmpfloat_with_epsilon (length, length1 + length2 + length3, epsilon);
gsk_path_unref (path3);
gsk_path_unref (path2);
gsk_path_unref (path1);
gsk_path_unref (path);
gsk_path_measure_unref (measure3);
gsk_path_measure_unref (measure2);
gsk_path_measure_unref (measure1);
gsk_path_measure_unref (measure);
}
}
static void
test_distance (void )
{
GskPath *path;
GskPathMeasure *measure;
GskPathPoint point = { .contour = 0 , .idx = 1 , .t = 1 };
float distance;
path = gsk_path_parse ("M 20 6.66666677e+30 C 20 60, 50 90, 100 60 C 150 30, 180 30, 180 60" );
measure = gsk_path_measure_new (path);
distance = gsk_path_point_get_distance (&point, measure);
/* We just need to get here */
if (g_test_verbose ())
g_test_message ("distance is %f" , distance);
gsk_path_measure_unref (measure);
gsk_path_unref (path);
}
static void
test_circle_bounds (void )
{
GskPathBuilder *builder;
GskPath *path;
graphene_rect_t bounds;
GskStroke *stroke;
gboolean ret;
builder = gsk_path_builder_new ();
gsk_path_builder_add_circle (builder, &GRAPHENE_POINT_INIT (10 , 10 ), 5 );
path = gsk_path_builder_free_to_path (builder);
ret = gsk_path_get_bounds (path, &bounds);
g_assert_true (ret);
g_assert_true (graphene_rect_equal (&bounds, &GRAPHENE_RECT_INIT (5 , 5 , 10 , 10 )));
stroke = gsk_stroke_new (2 );
ret = gsk_path_get_stroke_bounds (path, stroke, &bounds);
g_assert_true (ret);
g_assert_true (graphene_rect_equal (&bounds, &GRAPHENE_RECT_INIT (4 , 4 , 12 , 12 )));
gsk_stroke_free (stroke);
gsk_path_unref (path);
}
int
main (int argc,
char *argv[])
{
gtk_test_init (&argc, &argv, NULL);
g_test_add_func ("/path/create" , test_create);
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);
g_test_add_func ("/path/measure/split" , test_split);
g_test_add_func ("/path/measure/roundtrip" , test_roundtrip);
g_test_add_func ("/path/measure/segment" , test_segment);
g_test_add_func ("/path/measure/distance" , test_distance);
g_test_add_func ("/path/circle/bounds" , test_circle_bounds);
return g_test_run ();
}
Messung V0.5 in Prozent C=98 H=89 G=93
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-07-03)
¤
*© Formatika GbR, Deutschland