mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-12-26 13:41:07 +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;
|
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 */
|
/* {{{ Rounded Rectangle */
|
||||||
|
|
||||||
|
@ -36,6 +36,7 @@ GskContour * gsk_standard_contour_new (GskPathFlags
|
|||||||
|
|
||||||
GskContour * gsk_circle_contour_new (const graphene_point_t *center,
|
GskContour * gsk_circle_contour_new (const graphene_point_t *center,
|
||||||
float radius);
|
float radius);
|
||||||
|
GskContour * gsk_rect_contour_new (const graphene_rect_t *rect);
|
||||||
GskContour * gsk_rounded_rect_contour_new (const GskRoundedRect *rounded_rect);
|
GskContour * gsk_rounded_rect_contour_new (const GskRoundedRect *rounded_rect);
|
||||||
|
|
||||||
const char * gsk_contour_get_type_name (const GskContour *self);
|
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);
|
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
|
static gboolean
|
||||||
parse_circle (const char **p,
|
parse_circle (const char **p,
|
||||||
double *cx,
|
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_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_RIGHT] = GRAPHENE_SIZE_INIT (x5 - x6, y5 - y4);
|
||||||
rr->corner[GSK_CORNER_BOTTOM_LEFT] = GRAPHENE_SIZE_INIT (x7 - x8, y8 - y7);
|
rr->corner[GSK_CORNER_BOTTOM_LEFT] = GRAPHENE_SIZE_INIT (x7 - x8, y8 - y7);
|
||||||
|
|
||||||
|
skip_whitespace (p);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1195,35 +1227,47 @@ gsk_path_parse (const char *string)
|
|||||||
case 'M':
|
case 'M':
|
||||||
case 'm':
|
case 'm':
|
||||||
{
|
{
|
||||||
double x1, y1, r;
|
double x1, y1, w, h, r;
|
||||||
GskRoundedRect rr;
|
GskRoundedRect rr;
|
||||||
|
|
||||||
/* Look for special contours */
|
/* 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);
|
gsk_path_builder_add_circle (builder, &GRAPHENE_POINT_INIT (x1, y1), r);
|
||||||
|
|
||||||
x = x1 + r;
|
|
||||||
y = y1;
|
|
||||||
|
|
||||||
if (_strchr ("zZX", prev_cmd))
|
if (_strchr ("zZX", prev_cmd))
|
||||||
{
|
{
|
||||||
path_x = x;
|
path_x = x1 + r;
|
||||||
path_y = y;
|
path_y = y1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
x = x1 + r;
|
||||||
|
y = y1;
|
||||||
}
|
}
|
||||||
else if (parse_rounded_rect (&p, &rr))
|
else if (parse_rounded_rect (&p, &rr))
|
||||||
{
|
{
|
||||||
gsk_path_builder_add_rounded_rect (builder, &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))
|
if (_strchr ("zZX", prev_cmd))
|
||||||
{
|
{
|
||||||
path_x = x;
|
path_x = rr.bounds.origin.x + rr.corner[GSK_CORNER_TOP_LEFT].width;
|
||||||
path_y = y;
|
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))
|
else if (parse_coordinate_pair (&p, &x1, &y1))
|
||||||
{
|
{
|
||||||
@ -1232,6 +1276,7 @@ gsk_path_parse (const char *string)
|
|||||||
x1 += x;
|
x1 += x;
|
||||||
y1 += y;
|
y1 += y;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (repeat)
|
if (repeat)
|
||||||
gsk_path_builder_line_to (builder, x1, y1);
|
gsk_path_builder_line_to (builder, x1, y1);
|
||||||
else
|
else
|
||||||
@ -1243,6 +1288,7 @@ gsk_path_parse (const char *string)
|
|||||||
path_y = y1;
|
path_y = y1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
x = x1;
|
x = x1;
|
||||||
y = y1;
|
y = y1;
|
||||||
}
|
}
|
||||||
|
@ -460,20 +460,10 @@ void
|
|||||||
gsk_path_builder_add_rect (GskPathBuilder *self,
|
gsk_path_builder_add_rect (GskPathBuilder *self,
|
||||||
const graphene_rect_t *rect)
|
const graphene_rect_t *rect)
|
||||||
{
|
{
|
||||||
graphene_point_t current;
|
|
||||||
|
|
||||||
g_return_if_fail (self != NULL);
|
g_return_if_fail (self != NULL);
|
||||||
|
g_return_if_fail (rect != NULL);
|
||||||
|
|
||||||
current = self->current_point;
|
gsk_path_builder_add_contour (self, gsk_rect_contour_new (rect));
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -116,18 +116,14 @@ test_circle_winding (void)
|
|||||||
path1 = convert_to_standard_contour (path);
|
path1 = convert_to_standard_contour (path);
|
||||||
contour1 = gsk_path_get_contour (path1, 0);
|
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 ();
|
builder = gsk_path_builder_new ();
|
||||||
gsk_path_builder_add_reverse_path (builder, path);
|
gsk_path_builder_add_reverse_path (builder, path);
|
||||||
path2 = gsk_path_builder_free_to_path (builder);
|
path2 = gsk_path_builder_free_to_path (builder);
|
||||||
contour2 = gsk_path_get_contour (path2, 0);
|
contour2 = gsk_path_get_contour (path2, 0);
|
||||||
|
|
||||||
g_assert_true (gsk_contour_get_winding (contour, &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);
|
||||||
- gsk_contour_get_winding (contour2, &GRAPHENE_POINT_INIT (100, 100)));
|
g_assert_true (gsk_contour_get_winding (contour2, &GRAPHENE_POINT_INIT (100, 100)) == -1);
|
||||||
|
|
||||||
gsk_path_unref (path2);
|
gsk_path_unref (path2);
|
||||||
gsk_path_unref (path1);
|
gsk_path_unref (path1);
|
||||||
@ -189,22 +185,79 @@ test_rounded_rect_winding (void)
|
|||||||
path1 = convert_to_standard_contour (path);
|
path1 = convert_to_standard_contour (path);
|
||||||
contour1 = gsk_path_get_contour (path1, 0);
|
contour1 = gsk_path_get_contour (path1, 0);
|
||||||
|
|
||||||
g_assert_true (gsk_contour_get_winding (contour, &GRAPHENE_POINT_INIT (150, 150))
|
builder = gsk_path_builder_new ();
|
||||||
==
|
gsk_path_builder_add_reverse_path (builder, path);
|
||||||
gsk_contour_get_winding (contour1, &GRAPHENE_POINT_INIT (150, 150)));
|
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 ();
|
builder = gsk_path_builder_new ();
|
||||||
gsk_path_builder_add_reverse_path (builder, path);
|
gsk_path_builder_add_reverse_path (builder, path);
|
||||||
path2 = gsk_path_builder_free_to_path (builder);
|
path2 = gsk_path_builder_free_to_path (builder);
|
||||||
contour2 = gsk_path_get_contour (path2, 0);
|
contour2 = gsk_path_get_contour (path2, 0);
|
||||||
|
|
||||||
g_assert_true (gsk_contour_get_winding (contour, &GRAPHENE_POINT_INIT (150, 150))
|
path3 = convert_to_standard_contour (path2);
|
||||||
==
|
contour3 = gsk_path_get_contour (path3, 0);
|
||||||
- gsk_contour_get_winding (contour2, &GRAPHENE_POINT_INIT (150, 150)));
|
|
||||||
|
|
||||||
|
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 (path2);
|
||||||
gsk_path_unref (path1);
|
gsk_path_unref (path1);
|
||||||
gsk_path_unref (path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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/circle/winding", test_circle_winding);
|
||||||
g_test_add_func ("/path/rounded-rect/roundtrip", test_rounded_rect_roundtrip);
|
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/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 ();
|
return g_test_run ();
|
||||||
}
|
}
|
||||||
|
@ -323,7 +323,7 @@ test_rect_path (void)
|
|||||||
g_assert_true (gsk_path_is_closed (path));
|
g_assert_true (gsk_path_is_closed (path));
|
||||||
|
|
||||||
s = gsk_path_to_string (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_free (s);
|
||||||
|
|
||||||
g_assert_true (gsk_path_get_bounds (path, &bounds));
|
g_assert_true (gsk_path_get_bounds (path, &bounds));
|
||||||
@ -819,6 +819,42 @@ test_rounded_rect (void)
|
|||||||
gsk_path_unref (path);
|
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
|
static void
|
||||||
test_circle (void)
|
test_circle (void)
|
||||||
{
|
{
|
||||||
@ -883,7 +919,11 @@ test_circle (void)
|
|||||||
|
|
||||||
builder = gsk_path_builder_new ();
|
builder = gsk_path_builder_new ();
|
||||||
gsk_path_builder_add_path (builder, path);
|
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);
|
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));
|
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/rsvg-parse", test_rsvg_parse);
|
||||||
g_test_add_func ("/path/empty", test_empty_path);
|
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/foreach", test_foreach);
|
||||||
g_test_add_func ("/path/point", test_path_point);
|
g_test_add_func ("/path/point", test_path_point);
|
||||||
g_test_add_func ("/path/segments", test_path_segments);
|
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/builder/add", test_path_builder_add);
|
||||||
g_test_add_func ("/path/rotated-arc", test_rotated_arc);
|
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/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/circle", test_circle);
|
||||||
g_test_add_func ("/path/length", test_length);
|
g_test_add_func ("/path/length", test_length);
|
||||||
g_test_add_func ("/path/rect/segment", test_rect_segment);
|
g_test_add_func ("/path/rect/segment", test_rect_segment);
|
||||||
|
Loading…
Reference in New Issue
Block a user