diff --git a/gsk/gskcontour.c b/gsk/gskcontour.c index 2791884515..fc30fbeb58 100644 --- a/gsk/gskcontour.c +++ b/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 */ diff --git a/gsk/gskcontourprivate.h b/gsk/gskcontourprivate.h index 2378fffe26..63e9161bc2 100644 --- a/gsk/gskcontourprivate.h +++ b/gsk/gskcontourprivate.h @@ -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, diff --git a/gsk/gskpath.c b/gsk/gskpath.c index 99797be3be..2ef92bba20 100644 --- a/gsk/gskpath.c +++ b/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)) { diff --git a/gsk/gskpathbuilder.c b/gsk/gskpathbuilder.c index 3622ba8544..7bd253ae16 100644 --- a/gsk/gskpathbuilder.c +++ b/gsk/gskpathbuilder.c @@ -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)); } /** diff --git a/testsuite/gsk/path-private.c b/testsuite/gsk/path-private.c index 3d2e3d74c4..c882b4ce7e 100644 --- a/testsuite/gsk/path-private.c +++ b/testsuite/gsk/path-private.c @@ -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 (); }