mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-25 21:21:21 +00:00
Add a rectangle contour
Add a contour that optimizes some things for rectangles. Also add rectangle detection to the path parser, and add tests similar to what we have for the other special contours.
This commit is contained in:
parent
ddd4855bbc
commit
0a28a5d53a
538
gsk/gskcontour.c
538
gsk/gskcontour.c
@ -1457,6 +1457,544 @@ gsk_circle_contour_new (const graphene_point_t *center,
|
||||
return (GskContour *) self;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
/* {{{ Rectangle */
|
||||
|
||||
typedef struct _GskRectContour GskRectContour;
|
||||
struct _GskRectContour
|
||||
{
|
||||
GskContour contour;
|
||||
|
||||
float x;
|
||||
float y;
|
||||
float width;
|
||||
float height;
|
||||
float length;
|
||||
};
|
||||
|
||||
static void
|
||||
gsk_rect_contour_copy (const GskContour *contour,
|
||||
GskContour *dest)
|
||||
{
|
||||
const GskRectContour *self = (const GskRectContour *) contour;
|
||||
GskRectContour *target = (GskRectContour *) dest;
|
||||
|
||||
*target = *self;
|
||||
}
|
||||
|
||||
static GskPathFlags
|
||||
gsk_rect_contour_get_flags (const GskContour *contour)
|
||||
{
|
||||
return GSK_PATH_FLAT | GSK_PATH_CLOSED;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_rect_contour_print (const GskContour *contour,
|
||||
GString *string)
|
||||
{
|
||||
const GskRectContour *self = (const GskRectContour *) contour;
|
||||
|
||||
_g_string_append_point (string, "M ", &GRAPHENE_POINT_INIT (self->x, self->y));
|
||||
_g_string_append_double (string, " h ", self->width);
|
||||
_g_string_append_double (string, " v ", self->height);
|
||||
_g_string_append_double (string, " h ", - self->width);
|
||||
g_string_append (string, " z");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_rect_contour_get_bounds (const GskContour *contour,
|
||||
GskBoundingBox *bounds)
|
||||
{
|
||||
const GskRectContour *self = (const GskRectContour *) contour;
|
||||
|
||||
gsk_bounding_box_init (bounds,
|
||||
&GRAPHENE_POINT_INIT (self->x, self->y),
|
||||
&GRAPHENE_POINT_INIT (self->x + self->width, self->y + self->height));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_rect_contour_get_stroke_bounds (const GskContour *contour,
|
||||
const GskStroke *stroke,
|
||||
GskBoundingBox *bounds)
|
||||
{
|
||||
const GskRectContour *self = (const GskRectContour *) contour;
|
||||
graphene_rect_t rect;
|
||||
|
||||
graphene_rect_init (&rect, self->x, self->y, self->width, self->height);
|
||||
graphene_rect_inset (&rect, - stroke->line_width / 2, - stroke->line_width / 2);
|
||||
gsk_bounding_box_init_from_rect (bounds, &rect);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_rect_contour_foreach (const GskContour *contour,
|
||||
float tolerance,
|
||||
GskPathForeachFunc func,
|
||||
gpointer user_data)
|
||||
{
|
||||
const GskRectContour *self = (const GskRectContour *) contour;
|
||||
graphene_point_t pts[] = {
|
||||
GRAPHENE_POINT_INIT (self->x, self->y),
|
||||
GRAPHENE_POINT_INIT (self->x + self->width, self->y),
|
||||
GRAPHENE_POINT_INIT (self->x + self->width, self->y + self->height),
|
||||
GRAPHENE_POINT_INIT (self->x, self->y + self->height),
|
||||
GRAPHENE_POINT_INIT (self->x, self->y)
|
||||
};
|
||||
|
||||
return func (GSK_PATH_MOVE, &pts[0], 1, 0.f, user_data) &&
|
||||
func (GSK_PATH_LINE, &pts[0], 2, 0.f, user_data) &&
|
||||
func (GSK_PATH_LINE, &pts[1], 2, 0.f, user_data) &&
|
||||
func (GSK_PATH_LINE, &pts[2], 2, 0.f, user_data) &&
|
||||
func (GSK_PATH_CLOSE, &pts[3], 2, 0.f, user_data);
|
||||
}
|
||||
|
||||
static GskContour *
|
||||
gsk_rect_contour_reverse (const GskContour *contour)
|
||||
{
|
||||
const GskRectContour *self = (const GskRectContour *) contour;
|
||||
|
||||
return gsk_rect_contour_new (&GRAPHENE_RECT_INIT (self->x + self->width,
|
||||
self->y,
|
||||
- self->width,
|
||||
self->height));
|
||||
}
|
||||
|
||||
static int
|
||||
gsk_rect_contour_get_winding (const GskContour *contour,
|
||||
const graphene_point_t *point)
|
||||
{
|
||||
const GskRectContour *self = (const GskRectContour *) contour;
|
||||
graphene_rect_t rect;
|
||||
|
||||
graphene_rect_init (&rect, self->x, self->y, self->width, self->height);
|
||||
|
||||
if (graphene_rect_contains_point (&rect, point))
|
||||
{
|
||||
if ((self->width < 0) != (self->height < 0))
|
||||
return -1;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gsize
|
||||
gsk_rect_contour_get_n_ops (const GskContour *contour)
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_rect_contour_closest_point (const GskRectContour *self,
|
||||
const graphene_point_t *point,
|
||||
float threshold,
|
||||
float *out_distance,
|
||||
float *out_offset)
|
||||
{
|
||||
graphene_point_t t, p;
|
||||
float distance;
|
||||
|
||||
/* offset coords to be relative to rectangle */
|
||||
t.x = point->x - self->x;
|
||||
t.y = point->y - self->y;
|
||||
|
||||
if (self->width)
|
||||
{
|
||||
/* do unit square math */
|
||||
t.x /= self->width;
|
||||
/* move point onto the square */
|
||||
t.x = CLAMP (t.x, 0.f, 1.f);
|
||||
}
|
||||
else
|
||||
t.x = 0.f;
|
||||
|
||||
if (self->height)
|
||||
{
|
||||
t.y /= self->height;
|
||||
t.y = CLAMP (t.y, 0.f, 1.f);
|
||||
}
|
||||
else
|
||||
t.y = 0.f;
|
||||
|
||||
if (t.x > 0 && t.x < 1 && t.y > 0 && t.y < 1)
|
||||
{
|
||||
float diff = MIN (t.x, 1.f - t.x) * fabsf (self->width) - MIN (t.y, 1.f - t.y) * fabsf (self->height);
|
||||
|
||||
if (diff < 0.f)
|
||||
t.x = ceilf (t.x - 0.5f); /* round 0.5 down */
|
||||
else if (diff > 0.f)
|
||||
t.y = roundf (t.y); /* round 0.5 up */
|
||||
else
|
||||
{
|
||||
/* at least 2 points match, return the first one in the stroke */
|
||||
if (t.y <= 1.f - t.y)
|
||||
t.y = 0.f;
|
||||
else if (1.f - t.x <= t.x)
|
||||
t.x = 1.f;
|
||||
else
|
||||
t.y = 1.f;
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't let -0 confuse us */
|
||||
t.x = fabsf (t.x);
|
||||
t.y = fabsf (t.y);
|
||||
|
||||
p = GRAPHENE_POINT_INIT (self->x + t.x * self->width,
|
||||
self->y + t.y * self->height);
|
||||
|
||||
distance = graphene_point_distance (point, &p, NULL, NULL);
|
||||
if (distance > threshold)
|
||||
return FALSE;
|
||||
|
||||
*out_distance = distance;
|
||||
|
||||
if (t.y == 0)
|
||||
*out_offset = t.x * fabsf (self->width);
|
||||
else if (t.y == 1)
|
||||
*out_offset = (2 - t.x) * fabsf (self->width) + fabsf (self->height);
|
||||
else if (t.x == 1)
|
||||
*out_offset = fabsf (self->width) + t.y * fabsf (self->height);
|
||||
else
|
||||
*out_offset = 2 * fabsf (self->width) + (2 - t.y) * fabsf (self->height);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_rect_contour_get_closest_point (const GskContour *contour,
|
||||
const graphene_point_t *point,
|
||||
float threshold,
|
||||
GskRealPathPoint *result,
|
||||
float *out_dist)
|
||||
{
|
||||
const GskRectContour *self = (const GskRectContour *) contour;
|
||||
float distance;
|
||||
|
||||
if (gsk_rect_contour_closest_point (self, point, threshold, out_dist, &distance))
|
||||
{
|
||||
result->idx = 1;
|
||||
result->t = distance / self->length;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
set_tangent (float xs,
|
||||
float ys,
|
||||
float xe,
|
||||
float ye,
|
||||
GskPathDirection direction,
|
||||
graphene_vec2_t *tangent)
|
||||
{
|
||||
if (direction == GSK_PATH_TO_START || direction == GSK_PATH_FROM_START)
|
||||
graphene_vec2_init (tangent, xs, ys);
|
||||
else
|
||||
graphene_vec2_init (tangent, xe, ye);
|
||||
|
||||
if (direction == GSK_PATH_TO_START || direction == GSK_PATH_FROM_END)
|
||||
graphene_vec2_negate (tangent, tangent);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_rect_contour_pos_tangent (const GskRectContour *self,
|
||||
float distance,
|
||||
GskPathDirection direction,
|
||||
graphene_point_t *pos,
|
||||
graphene_vec2_t *tangent)
|
||||
{
|
||||
if (distance == 0)
|
||||
{
|
||||
if (pos)
|
||||
*pos = GRAPHENE_POINT_INIT (self->x, self->y);
|
||||
|
||||
if (tangent)
|
||||
set_tangent (0.f, - copysignf (1.f, self->height),
|
||||
copysignf (1.f, self->width), 0.f,
|
||||
direction, tangent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (distance < fabsf (self->width))
|
||||
{
|
||||
if (pos)
|
||||
*pos = GRAPHENE_POINT_INIT (self->x + copysignf (distance, self->width), self->y);
|
||||
if (tangent)
|
||||
set_tangent (copysignf (1.f, self->width), 0.f,
|
||||
copysignf (1.f, self->width), 0.f,
|
||||
direction, tangent);
|
||||
return;
|
||||
}
|
||||
distance -= fabsf (self->width);
|
||||
|
||||
if (distance == 0)
|
||||
{
|
||||
if (pos)
|
||||
*pos = GRAPHENE_POINT_INIT (self->x + self->width, self->y);
|
||||
|
||||
if (tangent)
|
||||
set_tangent (copysignf (1.f, self->width), 0.f,
|
||||
0.f, copysignf (1.f, self->height),
|
||||
direction, tangent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (distance < fabsf (self->height))
|
||||
{
|
||||
if (pos)
|
||||
*pos = GRAPHENE_POINT_INIT (self->x + self->width, self->y + copysignf (distance, self->height));
|
||||
if (tangent)
|
||||
set_tangent (0.f, copysignf (1.f, self->height),
|
||||
0.f, copysignf (1.f, self->height),
|
||||
direction, tangent);
|
||||
return;
|
||||
}
|
||||
distance -= fabs (self->height);
|
||||
|
||||
if (distance == 0)
|
||||
{
|
||||
if (pos)
|
||||
*pos = GRAPHENE_POINT_INIT (self->x + self->width, self->y + self->height);
|
||||
|
||||
if (tangent)
|
||||
set_tangent (0.f, copysignf (1.f, self->height),
|
||||
- copysignf (1.f, self->width), 0.f,
|
||||
direction, tangent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (distance < fabsf (self->width))
|
||||
{
|
||||
if (pos)
|
||||
*pos = GRAPHENE_POINT_INIT (self->x + self->width - copysignf (distance, self->width), self->y + self->height);
|
||||
if (tangent)
|
||||
set_tangent (- copysignf (1.f, self->width), 0.f,
|
||||
- copysignf (1.f, self->width), 0.f,
|
||||
direction, tangent);
|
||||
return;
|
||||
}
|
||||
distance -= fabsf (self->width);
|
||||
|
||||
if (distance == 0)
|
||||
{
|
||||
if (pos)
|
||||
*pos = GRAPHENE_POINT_INIT (self->x, self->y + self->height);
|
||||
|
||||
if (tangent)
|
||||
set_tangent (- copysignf (1.f, self->width), 0.f,
|
||||
0.f, - copysignf (1.f, self->height),
|
||||
direction, tangent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (distance < fabsf (self->height))
|
||||
{
|
||||
if (pos)
|
||||
*pos = GRAPHENE_POINT_INIT (self->x, self->y + self->height - copysignf (distance, self->height));
|
||||
if (tangent)
|
||||
set_tangent (0.f, - copysignf (1.f, self->height),
|
||||
0.f, - copysignf (1.f, self->height),
|
||||
direction, tangent);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pos)
|
||||
*pos = GRAPHENE_POINT_INIT (self->x, self->y);
|
||||
|
||||
if (tangent)
|
||||
set_tangent (0.f, - copysignf (1.f, self->height),
|
||||
copysignf (1.f, self->width), 0.f,
|
||||
direction, tangent);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_rect_contour_get_position (const GskContour *contour,
|
||||
GskRealPathPoint *point,
|
||||
graphene_point_t *position)
|
||||
{
|
||||
const GskRectContour *self = (const GskRectContour *) contour;
|
||||
|
||||
gsk_rect_contour_pos_tangent (self, point->t * self->length, GSK_PATH_TO_END, position, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_rect_contour_get_tangent (const GskContour *contour,
|
||||
GskRealPathPoint *point,
|
||||
GskPathDirection direction,
|
||||
graphene_vec2_t *tangent)
|
||||
{
|
||||
const GskRectContour *self = (const GskRectContour *) contour;
|
||||
|
||||
gsk_rect_contour_pos_tangent (self, point->t * self->length, direction, NULL, tangent);
|
||||
}
|
||||
|
||||
static float
|
||||
gsk_rect_contour_get_curvature (const GskContour *contour,
|
||||
GskRealPathPoint *point,
|
||||
GskPathDirection direction,
|
||||
graphene_point_t *center)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_rect_contour_add_segment (const GskContour *contour,
|
||||
GskPathBuilder *builder,
|
||||
gboolean emit_move_to,
|
||||
GskRealPathPoint *start_point,
|
||||
GskRealPathPoint *end_point)
|
||||
{
|
||||
const GskRectContour *self = (const GskRectContour *) contour;
|
||||
float w = fabsf (self->width);
|
||||
float h = fabsf (self->height);
|
||||
float start = start_point->t * self->length;
|
||||
float end = end_point->t * self->length;
|
||||
|
||||
if (start < w)
|
||||
{
|
||||
if (emit_move_to)
|
||||
gsk_path_builder_move_to (builder, self->x + start * (w / self->width), self->y);
|
||||
if (end <= w)
|
||||
{
|
||||
gsk_path_builder_line_to (builder, self->x + end * (w / self->width), self->y);
|
||||
return;
|
||||
}
|
||||
gsk_path_builder_line_to (builder, self->x + self->width, self->y);
|
||||
}
|
||||
start -= w;
|
||||
end -= w;
|
||||
|
||||
if (start < h)
|
||||
{
|
||||
if (start >= 0 && emit_move_to)
|
||||
gsk_path_builder_move_to (builder, self->x + self->width, self->y + start * (h / self->height));
|
||||
if (end <= h)
|
||||
{
|
||||
gsk_path_builder_line_to (builder, self->x + self->width, self->y + end * (h / self->height));
|
||||
return;
|
||||
}
|
||||
gsk_path_builder_line_to (builder, self->x + self->width, self->y + self->height);
|
||||
}
|
||||
start -= h;
|
||||
end -= h;
|
||||
|
||||
if (start < w)
|
||||
{
|
||||
if (start >= 0 && emit_move_to)
|
||||
gsk_path_builder_move_to (builder, self->x + (w - start) * (w / self->width), self->y + self->height);
|
||||
if (end <= w)
|
||||
{
|
||||
gsk_path_builder_line_to (builder, self->x + (w - end) * (w / self->width), self->y + self->height);
|
||||
return;
|
||||
}
|
||||
gsk_path_builder_line_to (builder, self->x, self->y + self->height);
|
||||
}
|
||||
start -= w;
|
||||
end -= w;
|
||||
|
||||
if (start < h)
|
||||
{
|
||||
if (start >= 0 && emit_move_to)
|
||||
gsk_path_builder_move_to (builder, self->x, self->y + (h - start) * (h / self->height));
|
||||
if (end <= h)
|
||||
{
|
||||
gsk_path_builder_line_to (builder, self->x, self->y + (h - end) * (h / self->height));
|
||||
return;
|
||||
}
|
||||
gsk_path_builder_line_to (builder, self->x, self->y);
|
||||
}
|
||||
}
|
||||
|
||||
static gpointer
|
||||
gsk_rect_contour_init_measure (const GskContour *contour,
|
||||
float tolerance,
|
||||
float *out_length)
|
||||
{
|
||||
const GskRectContour *self = (const GskRectContour *) contour;
|
||||
|
||||
*out_length = self->length;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_rect_contour_free_measure (const GskContour *contour,
|
||||
gpointer data)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_rect_contour_get_point (const GskContour *contour,
|
||||
gpointer measure_data,
|
||||
float distance,
|
||||
GskRealPathPoint *result)
|
||||
{
|
||||
const GskRectContour *self = (const GskRectContour *) contour;
|
||||
|
||||
result->idx = 1;
|
||||
result->t = CLAMP (distance / self->length, 0, 1);
|
||||
}
|
||||
|
||||
static float
|
||||
gsk_rect_contour_get_distance (const GskContour *contour,
|
||||
GskRealPathPoint *point,
|
||||
gpointer measure_data)
|
||||
{
|
||||
const GskRectContour *self = (const GskRectContour *) contour;
|
||||
|
||||
return point->t * self->length;
|
||||
}
|
||||
|
||||
static const GskContourClass GSK_RECT_CONTOUR_CLASS =
|
||||
{
|
||||
sizeof (GskRectContour),
|
||||
"GskRectContour",
|
||||
gsk_rect_contour_copy,
|
||||
gsk_contour_get_size_default,
|
||||
gsk_rect_contour_get_flags,
|
||||
gsk_rect_contour_print,
|
||||
gsk_rect_contour_get_bounds,
|
||||
gsk_rect_contour_get_stroke_bounds,
|
||||
gsk_rect_contour_foreach,
|
||||
gsk_rect_contour_reverse,
|
||||
gsk_rect_contour_get_winding,
|
||||
gsk_rect_contour_get_n_ops,
|
||||
gsk_rect_contour_get_closest_point,
|
||||
gsk_rect_contour_get_position,
|
||||
gsk_rect_contour_get_tangent,
|
||||
gsk_rect_contour_get_curvature,
|
||||
gsk_rect_contour_add_segment,
|
||||
gsk_rect_contour_init_measure,
|
||||
gsk_rect_contour_free_measure,
|
||||
gsk_rect_contour_get_point,
|
||||
gsk_rect_contour_get_distance,
|
||||
};
|
||||
|
||||
GskContour *
|
||||
gsk_rect_contour_new (const graphene_rect_t *rect)
|
||||
{
|
||||
GskRectContour *self;
|
||||
|
||||
self = g_new0 (GskRectContour, 1);
|
||||
|
||||
self->contour.klass = &GSK_RECT_CONTOUR_CLASS;
|
||||
|
||||
self->x = rect->origin.x;
|
||||
self->y = rect->origin.y;
|
||||
self->width = rect->size.width;
|
||||
self->height = rect->size.height;
|
||||
self->length = 2 * (fabsf (self->width) + fabsf (self->height));
|
||||
|
||||
return (GskContour *) self;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
/* {{{ Rounded Rectangle */
|
||||
|
||||
|
@ -36,6 +36,7 @@ GskContour * gsk_standard_contour_new (GskPathFlags
|
||||
|
||||
GskContour * gsk_circle_contour_new (const graphene_point_t *center,
|
||||
float radius);
|
||||
GskContour * gsk_rect_contour_new (const graphene_rect_t *rect);
|
||||
GskContour * gsk_rounded_rect_contour_new (const GskRoundedRect *rounded_rect);
|
||||
|
||||
const char * gsk_contour_get_type_name (const GskContour *self);
|
||||
|
@ -995,6 +995,35 @@ is_line (double x0, double y0,
|
||||
NEAR (x0, x1) && NEAR (x0, x2) && NEAR (x0, x3);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_rectangle (const char **p,
|
||||
double *x,
|
||||
double *y,
|
||||
double *w,
|
||||
double *h)
|
||||
{
|
||||
const char *o = *p;
|
||||
double w2;
|
||||
|
||||
if (parse_coordinate_pair (p, x, y) &&
|
||||
parse_string (p, "h") &&
|
||||
parse_coordinate (p, w) &&
|
||||
parse_string (p, "v") &&
|
||||
parse_coordinate (p, h) &&
|
||||
parse_string (p, "h") &&
|
||||
parse_coordinate (p, &w2) &&
|
||||
parse_string (p, "z") &&
|
||||
NEAR (w2, -*w))
|
||||
{
|
||||
skip_whitespace (p);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
*p = o;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_circle (const char **p,
|
||||
double *cx,
|
||||
@ -1101,6 +1130,9 @@ parse_rounded_rect (const char **p,
|
||||
rr->corner[GSK_CORNER_TOP_RIGHT] = GRAPHENE_SIZE_INIT (x2 - x1, y3 - y2);
|
||||
rr->corner[GSK_CORNER_BOTTOM_RIGHT] = GRAPHENE_SIZE_INIT (x5 - x6, y5 - y4);
|
||||
rr->corner[GSK_CORNER_BOTTOM_LEFT] = GRAPHENE_SIZE_INIT (x7 - x8, y8 - y7);
|
||||
|
||||
skip_whitespace (p);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
@ -1195,35 +1227,47 @@ gsk_path_parse (const char *string)
|
||||
case 'M':
|
||||
case 'm':
|
||||
{
|
||||
double x1, y1, r;
|
||||
double x1, y1, w, h, r;
|
||||
GskRoundedRect rr;
|
||||
|
||||
/* Look for special contours */
|
||||
if (parse_circle (&p, &x1, &y1, &r))
|
||||
if (parse_rectangle (&p, &x1, &y1, &w, &h))
|
||||
{
|
||||
gsk_path_builder_add_rect (builder, &GRAPHENE_RECT_INIT (x1, y1, w, h));
|
||||
if (_strchr ("zZX", prev_cmd))
|
||||
{
|
||||
path_x = x1;
|
||||
path_y = y1;
|
||||
}
|
||||
|
||||
x = x1;
|
||||
y = y1;
|
||||
}
|
||||
else if (parse_circle (&p, &x1, &y1, &r))
|
||||
{
|
||||
gsk_path_builder_add_circle (builder, &GRAPHENE_POINT_INIT (x1, y1), r);
|
||||
|
||||
x = x1 + r;
|
||||
y = y1;
|
||||
|
||||
if (_strchr ("zZX", prev_cmd))
|
||||
{
|
||||
path_x = x;
|
||||
path_y = y;
|
||||
path_x = x1 + r;
|
||||
path_y = y1;
|
||||
}
|
||||
|
||||
x = x1 + r;
|
||||
y = y1;
|
||||
}
|
||||
else if (parse_rounded_rect (&p, &rr))
|
||||
{
|
||||
gsk_path_builder_add_rounded_rect (builder, &rr);
|
||||
|
||||
x = rr.bounds.origin.x + rr.corner[GSK_CORNER_TOP_LEFT].width;
|
||||
y = rr.bounds.origin.y;
|
||||
|
||||
if (_strchr ("zZX", prev_cmd))
|
||||
{
|
||||
path_x = x;
|
||||
path_y = y;
|
||||
path_x = rr.bounds.origin.x + rr.corner[GSK_CORNER_TOP_LEFT].width;
|
||||
path_y = rr.bounds.origin.y;
|
||||
}
|
||||
|
||||
x = rr.bounds.origin.x + rr.corner[GSK_CORNER_TOP_LEFT].width;
|
||||
y = rr.bounds.origin.y;
|
||||
}
|
||||
else if (parse_coordinate_pair (&p, &x1, &y1))
|
||||
{
|
||||
@ -1232,6 +1276,7 @@ gsk_path_parse (const char *string)
|
||||
x1 += x;
|
||||
y1 += y;
|
||||
}
|
||||
|
||||
if (repeat)
|
||||
gsk_path_builder_line_to (builder, x1, y1);
|
||||
else
|
||||
@ -1243,6 +1288,7 @@ gsk_path_parse (const char *string)
|
||||
path_y = y1;
|
||||
}
|
||||
}
|
||||
|
||||
x = x1;
|
||||
y = y1;
|
||||
}
|
||||
|
@ -460,20 +460,10 @@ void
|
||||
gsk_path_builder_add_rect (GskPathBuilder *self,
|
||||
const graphene_rect_t *rect)
|
||||
{
|
||||
graphene_point_t current;
|
||||
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (rect != NULL);
|
||||
|
||||
current = self->current_point;
|
||||
|
||||
gsk_path_builder_move_to (self, rect->origin.x, rect->origin.y);
|
||||
|
||||
gsk_path_builder_rel_line_to (self, rect->size.width, 0);
|
||||
gsk_path_builder_rel_line_to (self, 0, rect->size.height);
|
||||
gsk_path_builder_rel_line_to (self, - rect->size.width, 0);
|
||||
|
||||
gsk_path_builder_close (self);
|
||||
self->current_point = current;
|
||||
gsk_path_builder_add_contour (self, gsk_rect_contour_new (rect));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -116,18 +116,14 @@ test_circle_winding (void)
|
||||
path1 = convert_to_standard_contour (path);
|
||||
contour1 = gsk_path_get_contour (path1, 0);
|
||||
|
||||
g_assert_true (gsk_contour_get_winding (contour, &GRAPHENE_POINT_INIT (100, 100))
|
||||
==
|
||||
gsk_contour_get_winding (contour1, &GRAPHENE_POINT_INIT (100, 100)));
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
gsk_path_builder_add_reverse_path (builder, path);
|
||||
path2 = gsk_path_builder_free_to_path (builder);
|
||||
contour2 = gsk_path_get_contour (path2, 0);
|
||||
|
||||
g_assert_true (gsk_contour_get_winding (contour, &GRAPHENE_POINT_INIT (100, 100))
|
||||
==
|
||||
- gsk_contour_get_winding (contour2, &GRAPHENE_POINT_INIT (100, 100)));
|
||||
g_assert_true (gsk_contour_get_winding (contour, &GRAPHENE_POINT_INIT (100, 100)) == 1);
|
||||
g_assert_true (gsk_contour_get_winding (contour1, &GRAPHENE_POINT_INIT (100, 100)) == 1);
|
||||
g_assert_true (gsk_contour_get_winding (contour2, &GRAPHENE_POINT_INIT (100, 100)) == -1);
|
||||
|
||||
gsk_path_unref (path2);
|
||||
gsk_path_unref (path1);
|
||||
@ -189,22 +185,79 @@ test_rounded_rect_winding (void)
|
||||
path1 = convert_to_standard_contour (path);
|
||||
contour1 = gsk_path_get_contour (path1, 0);
|
||||
|
||||
g_assert_true (gsk_contour_get_winding (contour, &GRAPHENE_POINT_INIT (150, 150))
|
||||
==
|
||||
gsk_contour_get_winding (contour1, &GRAPHENE_POINT_INIT (150, 150)));
|
||||
builder = gsk_path_builder_new ();
|
||||
gsk_path_builder_add_reverse_path (builder, path);
|
||||
path2 = gsk_path_builder_free_to_path (builder);
|
||||
contour2 = gsk_path_get_contour (path2, 0);
|
||||
|
||||
g_assert_true (gsk_contour_get_winding (contour, &GRAPHENE_POINT_INIT (150, 150)) == 1);
|
||||
g_assert_true (gsk_contour_get_winding (contour1, &GRAPHENE_POINT_INIT (150, 150)) == 1);
|
||||
g_assert_true (gsk_contour_get_winding (contour2, &GRAPHENE_POINT_INIT (150, 150)) == -1);
|
||||
|
||||
gsk_path_unref (path2);
|
||||
gsk_path_unref (path1);
|
||||
}
|
||||
|
||||
static void
|
||||
test_rect_roundtrip (void)
|
||||
{
|
||||
graphene_rect_t rect;
|
||||
GskPathBuilder *builder;
|
||||
GskPath *path, *path2;
|
||||
const GskContour *contour;
|
||||
char *s;
|
||||
|
||||
rect = GRAPHENE_RECT_INIT (100, 100, 200, 150);
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
gsk_path_builder_add_rect (builder, &rect);
|
||||
path = gsk_path_builder_free_to_path (builder);
|
||||
contour = gsk_path_get_contour (path, 0);
|
||||
|
||||
g_assert_cmpstr (gsk_contour_get_type_name (contour), ==, "GskRectContour");
|
||||
|
||||
s = gsk_path_to_string (path);
|
||||
path2 = gsk_path_parse (s);
|
||||
contour = gsk_path_get_contour (path2, 0);
|
||||
|
||||
g_assert_cmpstr (gsk_contour_get_type_name (contour), ==, "GskRectContour");
|
||||
|
||||
g_free (s);
|
||||
gsk_path_unref (path2);
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
|
||||
static void
|
||||
test_rect_winding (void)
|
||||
{
|
||||
GskPathBuilder *builder;
|
||||
GskPath *path, *path1, *path2, *path3;
|
||||
const GskContour *contour, *contour1, *contour2, *contour3;
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
gsk_path_builder_add_rect (builder, &GRAPHENE_RECT_INIT (100, 100, 200, 150));
|
||||
path = gsk_path_builder_free_to_path (builder);
|
||||
contour = gsk_path_get_contour (path, 0);
|
||||
|
||||
path1 = convert_to_standard_contour (path);
|
||||
contour1 = gsk_path_get_contour (path1, 0);
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
gsk_path_builder_add_reverse_path (builder, path);
|
||||
path2 = gsk_path_builder_free_to_path (builder);
|
||||
contour2 = gsk_path_get_contour (path2, 0);
|
||||
|
||||
g_assert_true (gsk_contour_get_winding (contour, &GRAPHENE_POINT_INIT (150, 150))
|
||||
==
|
||||
- gsk_contour_get_winding (contour2, &GRAPHENE_POINT_INIT (150, 150)));
|
||||
path3 = convert_to_standard_contour (path2);
|
||||
contour3 = gsk_path_get_contour (path3, 0);
|
||||
|
||||
g_assert_true (gsk_contour_get_winding (contour, &GRAPHENE_POINT_INIT (150, 150)) == 1);
|
||||
g_assert_true (gsk_contour_get_winding (contour1, &GRAPHENE_POINT_INIT (150, 150)) == 1);
|
||||
g_assert_true (gsk_contour_get_winding (contour2, &GRAPHENE_POINT_INIT (150, 150)) == -1);
|
||||
g_assert_true (gsk_contour_get_winding (contour3, &GRAPHENE_POINT_INIT (150, 150)) == -1);
|
||||
|
||||
gsk_path_unref (path3);
|
||||
gsk_path_unref (path2);
|
||||
gsk_path_unref (path1);
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
|
||||
int
|
||||
@ -216,6 +269,8 @@ main (int argc, char *argv[])
|
||||
g_test_add_func ("/path/circle/winding", test_circle_winding);
|
||||
g_test_add_func ("/path/rounded-rect/roundtrip", test_rounded_rect_roundtrip);
|
||||
g_test_add_func ("/path/rounded-rect/winding", test_rounded_rect_winding);
|
||||
g_test_add_func ("/path/rect/roundtrip", test_rect_roundtrip);
|
||||
g_test_add_func ("/path/rect/winding", test_rect_winding);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
@ -323,7 +323,7 @@ test_rect_path (void)
|
||||
g_assert_true (gsk_path_is_closed (path));
|
||||
|
||||
s = gsk_path_to_string (path);
|
||||
g_assert_cmpstr (s, ==, "M 0 0 L 200 0 L 200 100 L 0 100 Z");
|
||||
g_assert_cmpstr (s, ==, "M 0 0 h 200 v 100 h -200 z");
|
||||
g_free (s);
|
||||
|
||||
g_assert_true (gsk_path_get_bounds (path, &bounds));
|
||||
@ -819,6 +819,42 @@ test_rounded_rect (void)
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
|
||||
static void
|
||||
test_rect (void)
|
||||
{
|
||||
graphene_rect_t rect;
|
||||
GskPathBuilder *builder;
|
||||
GskPath *path;
|
||||
GskPathPoint point;
|
||||
graphene_point_t p;
|
||||
|
||||
rect = GRAPHENE_RECT_INIT (10, 10, 100, 50);
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
|
||||
gsk_path_builder_add_rect (builder, &rect);
|
||||
|
||||
path = gsk_path_builder_free_to_path (builder);
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
p = GRAPHENE_POINT_INIT (g_test_rand_double_range (0, 200),
|
||||
g_test_rand_double_range (0, 200));
|
||||
|
||||
g_assert_true (graphene_rect_contains_point (&rect, &p) == gsk_path_in_fill (path, &p, GSK_FILL_RULE_WINDING));
|
||||
}
|
||||
|
||||
gsk_path_get_start_point (path, &point);
|
||||
gsk_path_point_get_position (&point, path, &p);
|
||||
g_assert_true (graphene_point_equal (&p, &GRAPHENE_POINT_INIT (10, 10)));
|
||||
|
||||
gsk_path_get_end_point (path, &point);
|
||||
gsk_path_point_get_position (&point, path, &p);
|
||||
g_assert_true (graphene_point_equal (&p, &GRAPHENE_POINT_INIT (10, 10)));
|
||||
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
|
||||
static void
|
||||
test_circle (void)
|
||||
{
|
||||
@ -883,7 +919,11 @@ test_circle (void)
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
gsk_path_builder_add_path (builder, path);
|
||||
gsk_path_builder_add_rect (builder, &GRAPHENE_RECT_INIT (-2, -2, 4, 4));
|
||||
gsk_path_builder_move_to (builder, -2, -2);
|
||||
gsk_path_builder_line_to (builder, 2, 0);
|
||||
gsk_path_builder_line_to (builder, 2, 2);
|
||||
gsk_path_builder_line_to (builder, -2, 2);
|
||||
gsk_path_builder_close (builder);
|
||||
path4 = gsk_path_builder_free_to_path (builder);
|
||||
|
||||
g_assert_true (gsk_path_in_fill (path4, &GRAPHENE_POINT_INIT (0, 0), GSK_FILL_RULE_WINDING));
|
||||
@ -1002,7 +1042,7 @@ main (int argc, char *argv[])
|
||||
|
||||
g_test_add_func ("/path/rsvg-parse", test_rsvg_parse);
|
||||
g_test_add_func ("/path/empty", test_empty_path);
|
||||
g_test_add_func ("/path/rect", test_rect_path);
|
||||
g_test_add_func ("/path/rect-path", test_rect_path);
|
||||
g_test_add_func ("/path/foreach", test_foreach);
|
||||
g_test_add_func ("/path/point", test_path_point);
|
||||
g_test_add_func ("/path/segments", test_path_segments);
|
||||
@ -1011,6 +1051,7 @@ main (int argc, char *argv[])
|
||||
g_test_add_func ("/path/builder/add", test_path_builder_add);
|
||||
g_test_add_func ("/path/rotated-arc", test_rotated_arc);
|
||||
g_test_add_func ("/path/rounded-rect", test_rounded_rect);
|
||||
g_test_add_func ("/path/rect", test_rect);
|
||||
g_test_add_func ("/path/circle", test_circle);
|
||||
g_test_add_func ("/path/length", test_length);
|
||||
g_test_add_func ("/path/rect/segment", test_rect_segment);
|
||||
|
Loading…
Reference in New Issue
Block a user