Merge branch 'rounded-rect-contour' into 'main'
path: Add a rounded rect contour See merge request GNOME/gtk!6347
This commit is contained in:
385
gsk/gskcontour.c
385
gsk/gskcontour.c
@@ -1244,13 +1244,10 @@ gsk_circle_contour_get_winding (const GskContour *contour,
|
||||
{
|
||||
const GskCircleContour *self = (const GskCircleContour *) contour;
|
||||
|
||||
if (graphene_point_distance (point, &self->center, NULL, NULL) >= self->radius)
|
||||
return 0;
|
||||
if (graphene_point_distance (point, &self->center, NULL, NULL) <= self->radius)
|
||||
return self->ccw ? -1 : 1;
|
||||
|
||||
if (self->ccw)
|
||||
return -1;
|
||||
else
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gsize
|
||||
@@ -1500,6 +1497,382 @@ gsk_circle_contour_new (const graphene_point_t *center,
|
||||
return (GskContour *) self;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
/* {{{ Rounded Rectangle */
|
||||
|
||||
typedef struct _GskRoundedRectContour GskRoundedRectContour;
|
||||
struct _GskRoundedRectContour
|
||||
{
|
||||
GskContour contour;
|
||||
|
||||
GskRoundedRect rect;
|
||||
gboolean ccw;
|
||||
};
|
||||
|
||||
static void
|
||||
gsk_rounded_rect_contour_copy (const GskContour *contour,
|
||||
GskContour *dest)
|
||||
{
|
||||
const GskRoundedRectContour *self = (const GskRoundedRectContour *) contour;
|
||||
GskRoundedRectContour *target = (GskRoundedRectContour *) dest;
|
||||
|
||||
*target = *self;
|
||||
}
|
||||
|
||||
static GskPathFlags
|
||||
gsk_rounded_rect_contour_get_flags (const GskContour *contour)
|
||||
{
|
||||
return GSK_PATH_CLOSED;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_rounded_rect_contour_get_bounds (const GskContour *contour,
|
||||
GskBoundingBox *bounds)
|
||||
{
|
||||
const GskRoundedRectContour *self = (const GskRoundedRectContour *) contour;
|
||||
|
||||
gsk_bounding_box_init_from_rect (bounds, &self->rect.bounds);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_rounded_rect_contour_get_stroke_bounds (const GskContour *contour,
|
||||
const GskStroke *stroke,
|
||||
GskBoundingBox *bounds)
|
||||
{
|
||||
const GskRoundedRectContour *self = (const GskRoundedRectContour *) contour;
|
||||
GskBoundingBox b;
|
||||
|
||||
gsk_bounding_box_init_from_rect (&b, &self->rect.bounds);
|
||||
gsk_bounding_box_init (bounds,
|
||||
&GRAPHENE_POINT_INIT (b.min.x - stroke->line_width / 2,
|
||||
b.min.y - stroke->line_width / 2),
|
||||
&GRAPHENE_POINT_INIT (b.max.x + stroke->line_width / 2,
|
||||
b.max.y + stroke->line_width / 2));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_rounded_rect_contour_get_start_end (const GskContour *contour,
|
||||
graphene_point_t *start,
|
||||
graphene_point_t *end)
|
||||
{
|
||||
const GskRoundedRectContour *self = (const GskRoundedRectContour *) contour;
|
||||
|
||||
if (start)
|
||||
*start = GRAPHENE_POINT_INIT (self->rect.bounds.origin.x + self->rect.corner[GSK_CORNER_TOP_LEFT].width,
|
||||
self->rect.bounds.origin.y);
|
||||
|
||||
if (end)
|
||||
*end = GRAPHENE_POINT_INIT (self->rect.bounds.origin.x + self->rect.corner[GSK_CORNER_TOP_LEFT].width,
|
||||
self->rect.bounds.origin.y);
|
||||
}
|
||||
|
||||
static void
|
||||
get_rounded_rect_points (const GskRoundedRect *rect,
|
||||
graphene_point_t *pts)
|
||||
{
|
||||
pts[0] = GRAPHENE_POINT_INIT (rect->bounds.origin.x + rect->corner[GSK_CORNER_TOP_LEFT].width, rect->bounds.origin.y);
|
||||
pts[1] = GRAPHENE_POINT_INIT (rect->bounds.origin.x + rect->bounds.size.width - rect->corner[GSK_CORNER_TOP_RIGHT].width, rect->bounds.origin.y);
|
||||
pts[2] = GRAPHENE_POINT_INIT (rect->bounds.origin.x + rect->bounds.size.width, rect->bounds.origin.y);
|
||||
pts[3] = GRAPHENE_POINT_INIT (rect->bounds.origin.x + rect->bounds.size.width, rect->bounds.origin.y + rect->corner[GSK_CORNER_TOP_RIGHT].height);
|
||||
pts[4] = GRAPHENE_POINT_INIT (rect->bounds.origin.x + rect->bounds.size.width, rect->bounds.origin.y + rect->bounds.size.height - rect->corner[GSK_CORNER_BOTTOM_RIGHT].height);
|
||||
pts[5] = GRAPHENE_POINT_INIT (rect->bounds.origin.x + rect->bounds.size.width, rect->bounds.origin.y + rect->bounds.size.height);
|
||||
pts[6] = GRAPHENE_POINT_INIT (rect->bounds.origin.x + rect->bounds.size.width - rect->corner[GSK_CORNER_BOTTOM_RIGHT].width, rect->bounds.origin.y + rect->bounds.size.height);
|
||||
pts[7] = GRAPHENE_POINT_INIT (rect->bounds.origin.x + rect->corner[GSK_CORNER_BOTTOM_LEFT].width, rect->bounds.origin.y + rect->bounds.size.height);
|
||||
pts[8] = GRAPHENE_POINT_INIT (rect->bounds.origin.x, rect->bounds.origin.y + rect->bounds.size.height);
|
||||
pts[9] = GRAPHENE_POINT_INIT (rect->bounds.origin.x, rect->bounds.origin.y + rect->bounds.size.height - rect->corner[GSK_CORNER_BOTTOM_LEFT].height);
|
||||
pts[10] = GRAPHENE_POINT_INIT (rect->bounds.origin.x, rect->bounds.origin.y + rect->corner[GSK_CORNER_TOP_LEFT].height);
|
||||
pts[11] = GRAPHENE_POINT_INIT (rect->bounds.origin.x, rect->bounds.origin.y);
|
||||
pts[12] = GRAPHENE_POINT_INIT (rect->bounds.origin.x + rect->corner[GSK_CORNER_TOP_LEFT].width, rect->bounds.origin.y);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_rounded_rect_contour_foreach (const GskContour *contour,
|
||||
float tolerance,
|
||||
GskPathForeachFunc func,
|
||||
gpointer user_data)
|
||||
{
|
||||
const GskRoundedRectContour *self = (const GskRoundedRectContour *) contour;
|
||||
graphene_point_t pts[13];
|
||||
|
||||
get_rounded_rect_points (&self->rect, pts);
|
||||
if (self->ccw)
|
||||
{
|
||||
graphene_point_t p;
|
||||
#define SWAP(a,b,c) a = b; b = c; c = a;
|
||||
SWAP (p, pts[1], pts[11]);
|
||||
SWAP (p, pts[2], pts[10]);
|
||||
SWAP (p, pts[3], pts[9]);
|
||||
SWAP (p, pts[4], pts[8]);
|
||||
SWAP (p, pts[5], pts[7]);
|
||||
#undef SWAP
|
||||
|
||||
return func (GSK_PATH_MOVE, &pts[0], 1, 0.f, user_data) &&
|
||||
func (GSK_PATH_CONIC, &pts[0], 3, M_SQRT1_2, user_data) &&
|
||||
func (GSK_PATH_LINE, &pts[2], 2, 0.f, user_data) &&
|
||||
func (GSK_PATH_CONIC, &pts[3], 3, M_SQRT1_2, user_data) &&
|
||||
func (GSK_PATH_LINE, &pts[5], 2, 0.f, user_data) &&
|
||||
func (GSK_PATH_CONIC, &pts[6], 3, M_SQRT1_2, user_data) &&
|
||||
func (GSK_PATH_LINE, &pts[8], 2, 0.f, user_data) &&
|
||||
func (GSK_PATH_CONIC, &pts[9], 3, M_SQRT1_2, user_data) &&
|
||||
func (GSK_PATH_LINE, &pts[11], 2, 0.f, user_data) &&
|
||||
func (GSK_PATH_CLOSE, &pts[12], 2, 0.f, user_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
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_CONIC, &pts[1], 3, M_SQRT1_2, user_data) &&
|
||||
func (GSK_PATH_LINE, &pts[3], 2, 0.f, user_data) &&
|
||||
func (GSK_PATH_CONIC, &pts[4], 3, M_SQRT1_2, user_data) &&
|
||||
func (GSK_PATH_LINE, &pts[6], 2, 0.f, user_data) &&
|
||||
func (GSK_PATH_CONIC, &pts[7], 3, M_SQRT1_2, user_data) &&
|
||||
func (GSK_PATH_LINE, &pts[9], 2, 0.f, user_data) &&
|
||||
func (GSK_PATH_CONIC, &pts[10], 3, M_SQRT1_2, user_data) &&
|
||||
func (GSK_PATH_CLOSE, &pts[12], 2, 0.f, user_data);
|
||||
}
|
||||
}
|
||||
|
||||
static GskContour *
|
||||
gsk_rounded_rect_contour_reverse (const GskContour *contour)
|
||||
{
|
||||
const GskRoundedRectContour *self = (const GskRoundedRectContour *) contour;
|
||||
GskRoundedRectContour *copy;
|
||||
|
||||
copy = g_new0 (GskRoundedRectContour, 1);
|
||||
gsk_rounded_rect_contour_copy (contour, (GskContour *)copy);
|
||||
copy->ccw = !self->ccw;
|
||||
|
||||
return (GskContour *)copy;
|
||||
}
|
||||
|
||||
static int
|
||||
gsk_rounded_rect_contour_get_winding (const GskContour *contour,
|
||||
const graphene_point_t *point)
|
||||
{
|
||||
const GskRoundedRectContour *self = (const GskRoundedRectContour *) contour;
|
||||
|
||||
if (gsk_rounded_rect_contains_point (&self->rect, point))
|
||||
return self->ccw ? -1 : 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gsize
|
||||
gsk_rounded_rect_contour_get_n_ops (const GskContour *contour)
|
||||
{
|
||||
return 9;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_rounded_rect_contour_get_closest_point (const GskContour *contour,
|
||||
const graphene_point_t *point,
|
||||
float threshold,
|
||||
GskRealPathPoint *result,
|
||||
float *out_dist)
|
||||
{
|
||||
GskPath *path;
|
||||
const GskContour *std;
|
||||
gboolean ret;
|
||||
|
||||
path = convert_to_standard_contour (contour);
|
||||
std = gsk_path_get_contour (path, 0);
|
||||
ret = gsk_standard_contour_get_closest_point (std, point, threshold, result, out_dist);
|
||||
gsk_path_unref (path);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GskCurve *curve;
|
||||
unsigned int idx;
|
||||
unsigned int count;
|
||||
} InitCurveData;
|
||||
|
||||
static gboolean
|
||||
init_curve_cb (GskPathOperation op,
|
||||
const graphene_point_t *pts,
|
||||
gsize n_pts,
|
||||
float weight,
|
||||
gpointer user_data)
|
||||
{
|
||||
InitCurveData *data = user_data;
|
||||
|
||||
if (data->idx == data->count)
|
||||
{
|
||||
gsk_curve_init_foreach (data->curve, op, pts, n_pts, weight);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
data->count++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_rounded_rect_contour_init_curve (const GskContour *contour,
|
||||
unsigned int idx,
|
||||
GskCurve *curve)
|
||||
{
|
||||
InitCurveData data;
|
||||
|
||||
data.curve = curve;
|
||||
data.idx = idx;
|
||||
data.count = 0;
|
||||
|
||||
gsk_contour_foreach (contour, 0.5, init_curve_cb, &data);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_rounded_rect_contour_get_position (const GskContour *contour,
|
||||
GskRealPathPoint *point,
|
||||
graphene_point_t *position)
|
||||
{
|
||||
GskCurve curve;
|
||||
|
||||
gsk_rounded_rect_contour_init_curve (contour, point->idx, &curve);
|
||||
gsk_curve_get_point (&curve, point->t, position);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_rounded_rect_contour_get_tangent (const GskContour *contour,
|
||||
GskRealPathPoint *point,
|
||||
GskPathDirection direction,
|
||||
graphene_vec2_t *tangent)
|
||||
{
|
||||
GskCurve curve;
|
||||
|
||||
gsk_rounded_rect_contour_init_curve (contour, point->idx, &curve);
|
||||
gsk_curve_get_tangent (&curve, point->t, tangent);
|
||||
}
|
||||
|
||||
static float
|
||||
gsk_rounded_rect_contour_get_curvature (const GskContour *contour,
|
||||
GskRealPathPoint *point,
|
||||
GskPathDirection direction,
|
||||
graphene_point_t *center)
|
||||
{
|
||||
GskCurve curve;
|
||||
|
||||
gsk_rounded_rect_contour_init_curve (contour, point->idx, &curve);
|
||||
return gsk_curve_get_curvature (&curve, point->t, center);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_rounded_rect_contour_add_segment (const GskContour *contour,
|
||||
GskPathBuilder *builder,
|
||||
gboolean emit_move_to,
|
||||
GskRealPathPoint *start,
|
||||
GskRealPathPoint *end)
|
||||
{
|
||||
GskPath *path;
|
||||
const GskContour *std;
|
||||
|
||||
path = convert_to_standard_contour (contour);
|
||||
std = gsk_path_get_contour (path, 0);
|
||||
|
||||
gsk_standard_contour_add_segment (std, builder, emit_move_to, start, end);
|
||||
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const GskContour *contour;
|
||||
gpointer measure_data;
|
||||
} RoundedRectMeasureData;
|
||||
|
||||
static gpointer
|
||||
gsk_rounded_rect_contour_init_measure (const GskContour *contour,
|
||||
float tolerance,
|
||||
float *out_length)
|
||||
{
|
||||
RoundedRectMeasureData *data;
|
||||
GskPath *path;
|
||||
|
||||
path = convert_to_standard_contour (contour);
|
||||
data = g_new (RoundedRectMeasureData, 1);
|
||||
data->contour = gsk_contour_dup (gsk_path_get_contour (path, 0));
|
||||
data->measure_data = gsk_standard_contour_init_measure (data->contour, tolerance, out_length);
|
||||
gsk_path_unref (path);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_rounded_rect_contour_free_measure (const GskContour *contour,
|
||||
gpointer measure_data)
|
||||
{
|
||||
RoundedRectMeasureData *data = measure_data;
|
||||
|
||||
gsk_standard_contour_free_measure (data->contour, data->measure_data);
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_rounded_rect_contour_get_point (const GskContour *contour,
|
||||
gpointer measure_data,
|
||||
float distance,
|
||||
GskRealPathPoint *result)
|
||||
{
|
||||
RoundedRectMeasureData *data = measure_data;
|
||||
|
||||
gsk_standard_contour_get_point (data->contour, data->measure_data, distance, result);
|
||||
}
|
||||
|
||||
static float
|
||||
gsk_rounded_rect_contour_get_distance (const GskContour *contour,
|
||||
GskRealPathPoint *point,
|
||||
gpointer measure_data)
|
||||
{
|
||||
RoundedRectMeasureData *data = measure_data;
|
||||
|
||||
return gsk_standard_contour_get_distance (data->contour, point, data->measure_data);
|
||||
}
|
||||
|
||||
static const GskContourClass GSK_ROUNDED_RECT_CONTOUR_CLASS =
|
||||
{
|
||||
sizeof (GskRoundedRectContour),
|
||||
"GskRoundedRectContour",
|
||||
gsk_rounded_rect_contour_copy,
|
||||
gsk_contour_get_size_default,
|
||||
gsk_rounded_rect_contour_get_flags,
|
||||
gsk_contour_print_default,
|
||||
gsk_rounded_rect_contour_get_bounds,
|
||||
gsk_rounded_rect_contour_get_stroke_bounds,
|
||||
gsk_rounded_rect_contour_get_start_end,
|
||||
gsk_rounded_rect_contour_foreach,
|
||||
gsk_rounded_rect_contour_reverse,
|
||||
gsk_rounded_rect_contour_get_winding,
|
||||
gsk_rounded_rect_contour_get_n_ops,
|
||||
gsk_rounded_rect_contour_get_closest_point,
|
||||
gsk_rounded_rect_contour_get_position,
|
||||
gsk_rounded_rect_contour_get_tangent,
|
||||
gsk_rounded_rect_contour_get_curvature,
|
||||
gsk_rounded_rect_contour_add_segment,
|
||||
gsk_rounded_rect_contour_init_measure,
|
||||
gsk_rounded_rect_contour_free_measure,
|
||||
gsk_rounded_rect_contour_get_point,
|
||||
gsk_rounded_rect_contour_get_distance,
|
||||
};
|
||||
|
||||
GskContour *
|
||||
gsk_rounded_rect_contour_new (const GskRoundedRect *rect)
|
||||
{
|
||||
GskRoundedRectContour *self;
|
||||
|
||||
self = g_new0 (GskRoundedRectContour, 1);
|
||||
|
||||
self->contour.klass = &GSK_ROUNDED_RECT_CONTOUR_CLASS;
|
||||
|
||||
self->rect = *rect;
|
||||
|
||||
return (GskContour *) self;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
/* {{{ API */
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ GskContour * gsk_standard_contour_new (GskPathFlags
|
||||
|
||||
GskContour * gsk_circle_contour_new (const graphene_point_t *center,
|
||||
float radius);
|
||||
GskContour * gsk_rounded_rect_contour_new (const GskRoundedRect *rounded_rect);
|
||||
|
||||
const char * gsk_contour_get_type_name (const GskContour *self);
|
||||
void gsk_contour_copy (GskContour * dest,
|
||||
|
||||
131
gsk/gskpath.c
131
gsk/gskpath.c
@@ -964,6 +964,33 @@ parse_string (const char **p,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define NEAR(x, y) (fabs ((x) - (y)) < 0.001)
|
||||
|
||||
static gboolean
|
||||
is_rect (double x0, double y0,
|
||||
double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3)
|
||||
{
|
||||
return NEAR (x0, x3) && NEAR (x1, x2) &&
|
||||
NEAR (y0, y1) && NEAR (y2, y3) &&
|
||||
x0 < x1 && y1 < y2;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_line (double x0, double y0,
|
||||
double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3)
|
||||
{
|
||||
if (NEAR (y0, y3))
|
||||
return x0 <= x1 && x1 <= x2 && x2 <= x3 &&
|
||||
NEAR (y0, y1) && NEAR (y0, y2) && NEAR (y0, y3);
|
||||
else
|
||||
return y0 <= y1 && y1 <= y2 && y2 <= y3 &&
|
||||
NEAR (x0, x1) && NEAR (x0, x2) && NEAR (x0, x3);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_circle (const char **p,
|
||||
double *cx,
|
||||
@@ -998,16 +1025,12 @@ parse_circle (const char **p,
|
||||
xx = (x0 + x4) / 2;
|
||||
yy = (y2 + y6) / 2;
|
||||
|
||||
#define NEAR(x, y) (fabs ((x) - (y)) < 0.001)
|
||||
|
||||
if (NEAR (x0, x1) && NEAR (x0, x8) && NEAR (x0, x7) &&
|
||||
NEAR (x2, x6) && NEAR (x3, x4) && NEAR (x4, x5) &&
|
||||
NEAR (y5, y6) && NEAR (y6, y7) && NEAR (y4, y8) &&
|
||||
NEAR (y8, y0) && NEAR (y3, y2) && NEAR (y2, y1) &&
|
||||
NEAR (x2, xx) && NEAR (yy, y4) &&
|
||||
if (NEAR (x0, x8) && NEAR (y0, y8) &&
|
||||
is_rect (x5, y5, x7, y7, x1, y1, x3, y3) &&
|
||||
is_rect (x5, y5, x6, y6, xx, yy, x4, y4) &&
|
||||
is_rect (xx, yy, x0, y0, x1, y1, x2, y2) &&
|
||||
NEAR (w0, M_SQRT1_2) && NEAR (w1, M_SQRT1_2) &&
|
||||
NEAR (w2, M_SQRT1_2) && NEAR (w3, M_SQRT1_2) &&
|
||||
x1 > x2 && x2 > x3 && y3 > y4 && y4 > y5)
|
||||
NEAR (w2, M_SQRT1_2) && NEAR (w3, M_SQRT1_2))
|
||||
{
|
||||
*cx = xx;
|
||||
*cy = yy;
|
||||
@@ -1017,14 +1040,73 @@ parse_circle (const char **p,
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#undef NEAR
|
||||
}
|
||||
|
||||
*p = o;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_rounded_rect (const char **p,
|
||||
GskRoundedRect *rr)
|
||||
{
|
||||
const char *o = *p;
|
||||
double x0, y0, x1, y1, x2, y2, x3, y3;
|
||||
double x4, y4, x5, y5, x6, y6, x7, y7;
|
||||
double x8, y8, x9, y9, x10, y10, x11, y11;
|
||||
double x12, y12, w0, w1, w2, w3;
|
||||
|
||||
if (parse_coordinate_pair (p, &x0, &y0) &&
|
||||
parse_string (p, "L") &&
|
||||
parse_coordinate_pair (p, &x1, &y1) &&
|
||||
parse_string (p, "O") &&
|
||||
parse_coordinate_pair (p, &x2, &y2) &&
|
||||
parse_coordinate_pair (p, &x3, &y3) &&
|
||||
parse_nonnegative_number (p, &w0) &&
|
||||
parse_string (p, "L") &&
|
||||
parse_coordinate_pair (p, &x4, &y4) &&
|
||||
parse_string (p, "O") &&
|
||||
parse_coordinate_pair (p, &x5, &y5) &&
|
||||
parse_coordinate_pair (p, &x6, &y6) &&
|
||||
parse_nonnegative_number (p, &w1) &&
|
||||
parse_string (p, "L") &&
|
||||
parse_coordinate_pair (p, &x7, &y7) &&
|
||||
parse_string (p, "O") &&
|
||||
parse_coordinate_pair (p, &x8, &y8) &&
|
||||
parse_coordinate_pair (p, &x9, &y9) &&
|
||||
parse_nonnegative_number (p, &w2) &&
|
||||
parse_string (p, "L") &&
|
||||
parse_coordinate_pair (p, &x10, &y10) &&
|
||||
parse_string (p, "O") &&
|
||||
parse_coordinate_pair (p, &x11, &y11) &&
|
||||
parse_coordinate_pair (p, &x12, &y12) &&
|
||||
parse_nonnegative_number (p, &w3) &&
|
||||
parse_string (p, "Z"))
|
||||
{
|
||||
if (NEAR (x0, x12) && NEAR (y0, y12) &&
|
||||
is_rect (x11, y11, x2, y2, x5, y5, x8, y8) &&
|
||||
is_line (x11, y11, x0, y0, x1, y1, x2, y2) &&
|
||||
is_line (x2, y2, x3, y3, x4, y4, x5, y5) &&
|
||||
is_line (x8, y8, x7, y7, x6, y6, x5, y5) &&
|
||||
is_line (x11, y11, x10, y10, x9, y9, x8, y8) &&
|
||||
NEAR (w0, M_SQRT1_2) && NEAR (w1, M_SQRT1_2) &&
|
||||
NEAR (w2, M_SQRT1_2) && NEAR (w3, M_SQRT1_2))
|
||||
{
|
||||
rr->bounds = GRAPHENE_RECT_INIT (x11, y11, x5 - x11, y5 - y11);
|
||||
rr->corner[GSK_CORNER_TOP_LEFT] = GRAPHENE_SIZE_INIT (x12 - x11, y10 - y11);
|
||||
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);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
*p = o;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#undef NEAR
|
||||
|
||||
/**
|
||||
* gsk_path_parse:
|
||||
* @string: a string
|
||||
@@ -1110,17 +1192,34 @@ gsk_path_parse (const char *string)
|
||||
case 'm':
|
||||
{
|
||||
double x1, y1, r;
|
||||
GskRoundedRect rr;
|
||||
|
||||
/* Look for special contours */
|
||||
if (parse_circle (&p, &x1, &y1, &r))
|
||||
{
|
||||
gsk_path_builder_add_circle (builder, &GRAPHENE_POINT_INIT (x1, y1), r);
|
||||
if (_strchr ("zZX", prev_cmd))
|
||||
{
|
||||
path_x = x1 + r;
|
||||
path_y = y1;
|
||||
}
|
||||
|
||||
x = x1 + r;
|
||||
y = y1;
|
||||
|
||||
if (_strchr ("zZX", prev_cmd))
|
||||
{
|
||||
path_x = x;
|
||||
path_y = y;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
else if (parse_coordinate_pair (&p, &x1, &y1))
|
||||
{
|
||||
|
||||
@@ -488,59 +488,10 @@ void
|
||||
gsk_path_builder_add_rounded_rect (GskPathBuilder *self,
|
||||
const GskRoundedRect *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->bounds.origin.x + rect->corner[GSK_CORNER_TOP_LEFT].width,
|
||||
rect->bounds.origin.y);
|
||||
/* top */
|
||||
gsk_path_builder_line_to (self,
|
||||
rect->bounds.origin.x + rect->bounds.size.width - rect->corner[GSK_CORNER_TOP_RIGHT].width,
|
||||
rect->bounds.origin.y);
|
||||
/* topright corner */
|
||||
gsk_path_builder_arc_to (self,
|
||||
rect->bounds.origin.x + rect->bounds.size.width,
|
||||
rect->bounds.origin.y,
|
||||
rect->bounds.origin.x + rect->bounds.size.width,
|
||||
rect->bounds.origin.y + rect->corner[GSK_CORNER_TOP_RIGHT].height);
|
||||
/* right */
|
||||
gsk_path_builder_line_to (self,
|
||||
rect->bounds.origin.x + rect->bounds.size.width,
|
||||
rect->bounds.origin.y + rect->bounds.size.height - rect->corner[GSK_CORNER_BOTTOM_RIGHT].height);
|
||||
/* bottomright corner */
|
||||
gsk_path_builder_arc_to (self,
|
||||
rect->bounds.origin.x + rect->bounds.size.width,
|
||||
rect->bounds.origin.y + rect->bounds.size.height,
|
||||
rect->bounds.origin.x + rect->bounds.size.width - rect->corner[GSK_CORNER_BOTTOM_RIGHT].width,
|
||||
rect->bounds.origin.y + rect->bounds.size.height);
|
||||
/* bottom */
|
||||
gsk_path_builder_line_to (self,
|
||||
rect->bounds.origin.x + rect->corner[GSK_CORNER_BOTTOM_LEFT].width,
|
||||
rect->bounds.origin.y + rect->bounds.size.height);
|
||||
/* bottomleft corner */
|
||||
gsk_path_builder_arc_to (self,
|
||||
rect->bounds.origin.x,
|
||||
rect->bounds.origin.y + rect->bounds.size.height,
|
||||
rect->bounds.origin.x,
|
||||
rect->bounds.origin.y + rect->bounds.size.height - rect->corner[GSK_CORNER_BOTTOM_LEFT].height);
|
||||
/* left */
|
||||
gsk_path_builder_line_to (self,
|
||||
rect->bounds.origin.x,
|
||||
rect->bounds.origin.y + rect->corner[GSK_CORNER_TOP_LEFT].height);
|
||||
/* topleft corner */
|
||||
gsk_path_builder_arc_to (self,
|
||||
rect->bounds.origin.x,
|
||||
rect->bounds.origin.y,
|
||||
rect->bounds.origin.x + rect->corner[GSK_CORNER_TOP_LEFT].width,
|
||||
rect->bounds.origin.y);
|
||||
/* done */
|
||||
gsk_path_builder_close (self);
|
||||
self->current_point = current;
|
||||
gsk_path_builder_add_contour (self, gsk_rounded_rect_contour_new (rect));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -47,12 +47,46 @@ test_roundtrip_circle (void)
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
|
||||
static void
|
||||
test_roundtrip_rounded_rect (void)
|
||||
{
|
||||
GskRoundedRect rr;
|
||||
GskPathBuilder *builder;
|
||||
GskPath *path, *path2;
|
||||
const GskContour *contour;
|
||||
char *s;
|
||||
|
||||
rr.bounds = GRAPHENE_RECT_INIT (100, 100, 200, 150);
|
||||
rr.corner[GSK_CORNER_TOP_LEFT] = GRAPHENE_SIZE_INIT (10, 10);
|
||||
rr.corner[GSK_CORNER_TOP_RIGHT] = GRAPHENE_SIZE_INIT (20, 10);
|
||||
rr.corner[GSK_CORNER_BOTTOM_RIGHT] = GRAPHENE_SIZE_INIT (20, 0);
|
||||
rr.corner[GSK_CORNER_BOTTOM_LEFT] = GRAPHENE_SIZE_INIT (0, 0);
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
gsk_path_builder_add_rounded_rect (builder, &rr);
|
||||
path = gsk_path_builder_free_to_path (builder);
|
||||
contour = gsk_path_get_contour (path, 0);
|
||||
|
||||
g_assert_cmpstr (gsk_contour_get_type_name (contour), ==, "GskRoundedRectContour");
|
||||
|
||||
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), ==, "GskRoundedRectContour");
|
||||
|
||||
g_free (s);
|
||||
gsk_path_unref (path2);
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
gtk_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_test_add_func ("/path/roundtrip/circle", test_roundtrip_circle);
|
||||
g_test_add_func ("/path/roundtrip/rounded-rect", test_roundtrip_rounded_rect);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user