[gtk/path-work-rebased: 69/71] Add GskRoundedRectContour
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/path-work-rebased: 69/71] Add GskRoundedRectContour
- Date: Fri, 8 Apr 2022 20:45:38 +0000 (UTC)
commit a88dbb820b0e0ecfcd37f4a8d8d780ea8ce9cc53
Author: Matthias Clasen <mclasen redhat com>
Date: Thu Apr 7 22:13:31 2022 -0400
Add GskRoundedRectContour
The main advantage here is that we can avoid
going through the stroker for the common case
of rounded rectangles.
gsk/gskcontour.c | 546 ++++++++++++++++++++++++++++++++++++++++++++----
gsk/gskcontourprivate.h | 1 +
gsk/gskpathbuilder.c | 53 +----
3 files changed, 515 insertions(+), 85 deletions(-)
---
diff --git a/gsk/gskcontour.c b/gsk/gskcontour.c
index 359a070153..945a1f4515 100644
--- a/gsk/gskcontour.c
+++ b/gsk/gskcontour.c
@@ -109,6 +109,8 @@ gsk_contour_get_size_default (const GskContour *contour)
return contour->klass->struct_size;
}
+/* {{{ Utilities */
+
static void
gsk_find_point_on_line (const graphene_point_t *a,
const graphene_point_t *b,
@@ -142,25 +144,6 @@ gsk_find_point_on_line (const graphene_point_t *a,
}
}
-/* {{{ Rectangle contour */
-
-typedef struct _GskRectContour GskRectContour;
-struct _GskRectContour
-{
- GskContour contour;
-
- float x;
- float y;
- float width;
- float height;
-};
-
-static GskPathFlags
-gsk_rect_contour_get_flags (const GskContour *contour)
-{
- return GSK_PATH_FLAT | GSK_PATH_CLOSED;
-}
-
static void
_g_string_append_double (GString *string,
double d)
@@ -180,6 +163,42 @@ _g_string_append_point (GString *string,
_g_string_append_double (string, pt->y);
}
+static gboolean
+stroke_is_simple (GskStroke *stroke)
+{
+ if (stroke->line_join == GSK_LINE_JOIN_ROUND ||
+ stroke->line_join == GSK_LINE_JOIN_BEVEL)
+ return FALSE;
+
+ if (stroke->miter_limit < 1.5)
+ return FALSE;
+
+ if (stroke->dash_length != 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+/* }}} */
+/* {{{ Rectangle contour */
+
+typedef struct _GskRectContour GskRectContour;
+struct _GskRectContour
+{
+ GskContour contour;
+
+ float x;
+ float y;
+ float width;
+ float height;
+};
+
+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)
@@ -516,22 +535,6 @@ gsk_rect_contour_get_stroke_bounds (const GskContour *contour,
return TRUE;
}
-static gboolean
-stroke_is_simple (GskStroke *stroke)
-{
- if (stroke->line_join == GSK_LINE_JOIN_ROUND ||
- stroke->line_join == GSK_LINE_JOIN_BEVEL)
- return FALSE;
-
- if (stroke->miter_limit < 1.5)
- return FALSE;
-
- if (stroke->dash_length != 0)
- return FALSE;
-
- return TRUE;
-}
-
static void
gsk_rect_contour_add_stroke (const GskContour *contour,
GskPathBuilder *builder,
@@ -1923,6 +1926,479 @@ gsk_standard_contour_new (GskPathFlags flags,
return contour;
}
+/* }}} */
+/* {{{ Rounded rectangle contour */
+
+typedef struct _GskRoundedRectContour GskRoundedRectContour;
+struct _GskRoundedRectContour
+{
+ GskContour contour;
+
+ GskRoundedRect rect;
+ gboolean ccw;
+};
+
+static GskPathFlags
+gsk_rounded_rect_contour_get_flags (const GskContour *contour)
+{
+ return GSK_PATH_CLOSED;
+}
+
+static inline 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_TOP_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 void
+gsk_rounded_rect_contour_print (const GskContour *contour,
+ GString *string)
+{
+ const GskRoundedRectContour *self = (const GskRoundedRectContour *) contour;
+ graphene_point_t pts[13];
+
+ get_rounded_rect_points (&self->rect, pts);
+
+#define APPEND_MOVE(p) \
+ g_string_append (string, "M "); \
+ _g_string_append_point (string, p);
+#define APPEND_LINE(p) \
+ g_string_append (string, " L "); \
+ _g_string_append_point (string, p);
+#define APPEND_CONIC(p1, p2) \
+ g_string_append (string, " O "); \
+ _g_string_append_point (string, p1); \
+ g_string_append (string, ", "); \
+ _g_string_append_point (string, p2); \
+ g_string_append (string, ", "); \
+ _g_string_append_double (string, M_SQRT1_2);
+#define APPEND_CLOSE g_string_append (string, " z");
+ 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
+
+ APPEND_MOVE (&pts[0]);
+ APPEND_CONIC (&pts[1], &pts[2]);
+ APPEND_LINE (&pts[3]);
+ APPEND_CONIC (&pts[4], &pts[5]);
+ APPEND_LINE (&pts[6]);
+ APPEND_CONIC (&pts[7], &pts[8]);
+ APPEND_LINE (&pts[9]);
+ APPEND_CONIC (&pts[10], &pts[11]);
+ APPEND_LINE (&pts[12]);
+ APPEND_CLOSE
+ }
+ else
+ {
+ APPEND_MOVE (&pts[0]);
+ APPEND_LINE (&pts[1]);
+ APPEND_CONIC (&pts[2], &pts[3]);
+ APPEND_LINE (&pts[4]);
+ APPEND_CONIC (&pts[5], &pts[6]);
+ APPEND_LINE (&pts[7]);
+ APPEND_CONIC (&pts[8], &pts[9]);
+ APPEND_LINE (&pts[10]);
+ APPEND_CONIC (&pts[11], &pts[12]);
+ APPEND_CLOSE;
+ }
+#undef APPEND_MOVE
+#undef APPEND_LINE
+#undef APPEND_CONIC
+#undef APPEND_CLOSE
+}
+
+static gboolean
+gsk_rounded_rect_contour_get_bounds (const GskContour *contour,
+ graphene_rect_t *rect)
+{
+ const GskRoundedRectContour *self = (const GskRoundedRectContour *) contour;
+
+ graphene_rect_init_from_rect (rect, &self->rect.bounds);
+
+ 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 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, user_data) &&
+ func (GSK_PATH_CONIC, &pts[0], 3, M_SQRT1_2, user_data) &&
+ func (GSK_PATH_LINE, &pts[2], 2, 0, user_data) &&
+ func (GSK_PATH_CONIC, &pts[3], 3, M_SQRT1_2, user_data) &&
+ func (GSK_PATH_LINE, &pts[5], 2, 0, user_data) &&
+ func (GSK_PATH_CONIC, &pts[6], 3, M_SQRT1_2, user_data) &&
+ func (GSK_PATH_LINE, &pts[8], 2, 0, user_data) &&
+ func (GSK_PATH_CONIC, &pts[9], 3, M_SQRT1_2, user_data) &&
+ func (GSK_PATH_LINE, &pts[11], 2, 0, user_data) &&
+ func (GSK_PATH_CLOSE, &pts[12], 2, 0, user_data);
+ }
+ else
+ {
+ return func (GSK_PATH_MOVE, &pts[0], 1, 0, user_data) &&
+ func (GSK_PATH_LINE, &pts[0], 2, 0, user_data) &&
+ func (GSK_PATH_CONIC, &pts[1], 3, M_SQRT1_2, user_data) &&
+ func (GSK_PATH_LINE, &pts[3], 2, 0, user_data) &&
+ func (GSK_PATH_CONIC, &pts[4], 3, M_SQRT1_2, user_data) &&
+ func (GSK_PATH_LINE, &pts[6], 2, 0, user_data) &&
+ func (GSK_PATH_CONIC, &pts[7], 3, M_SQRT1_2, user_data) &&
+ func (GSK_PATH_LINE, &pts[9], 2, 0, user_data) &&
+ func (GSK_PATH_CONIC, &pts[10], 3, M_SQRT1_2, user_data) &&
+ func (GSK_PATH_CLOSE, &pts[12], 2, 0, user_data);
+ }
+}
+
+typedef struct
+{
+ GskPath *path;
+ const GskContour *contour;
+ gpointer measure_data;
+} RoundedRectMeasureData;
+
+static gboolean
+add_cb (GskPathOperation op,
+ const graphene_point_t *pts,
+ gsize n_pts,
+ float weight,
+ gpointer user_data)
+{
+ GskPathBuilder *builder = user_data;
+ switch (op)
+ {
+ case GSK_PATH_MOVE:
+ gsk_path_builder_move_to (builder, pts[0].x, pts[0].y);
+ break;
+ case GSK_PATH_LINE:
+ gsk_path_builder_line_to (builder, pts[1].x, pts[1].y);
+ break;
+ case GSK_PATH_CURVE:
+ gsk_path_builder_curve_to (builder,
+ pts[1].x, pts[1].y,
+ pts[2].x, pts[2].y,
+ pts[3].x, pts[3].y);
+ break;
+ case GSK_PATH_CONIC:
+ gsk_path_builder_conic_to (builder,
+ pts[1].x, pts[1].y,
+ pts[3].x, pts[3].y,
+ weight);
+ break;
+ case GSK_PATH_CLOSE:
+ gsk_path_builder_close (builder);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ return TRUE;
+}
+
+static gpointer
+gsk_rounded_rect_contour_init_measure (const GskContour *contour,
+ float tolerance,
+ float *out_length)
+{
+ GskPathBuilder *builder;
+ RoundedRectMeasureData *data;
+
+ builder = gsk_path_builder_new ();
+
+ gsk_contour_foreach (contour, tolerance, add_cb, builder);
+
+ data = g_new (RoundedRectMeasureData, 1);
+ data->path = gsk_path_builder_free_to_path (builder);
+ data->contour = gsk_path_get_contour (data->path, 0);
+ data->measure_data = gsk_standard_contour_init_measure (data->contour, tolerance, out_length);
+
+ 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);
+ gsk_path_unref (data->path);
+ g_free (data);
+}
+
+static void
+gsk_rounded_rect_contour_get_point (const GskContour *contour,
+ gpointer measure_data,
+ float distance,
+ graphene_point_t *pos,
+ graphene_vec2_t *tangent)
+{
+ RoundedRectMeasureData *data = measure_data;
+
+ gsk_standard_contour_get_point (data->contour,
+ data->measure_data,
+ distance,
+ pos,
+ tangent);
+}
+
+static float
+gsk_rounded_rect_contour_get_curvature (const GskContour *contour,
+ gpointer measure_data,
+ float distance,
+ graphene_point_t *center)
+{
+ RoundedRectMeasureData *data = measure_data;
+
+ return gsk_standard_contour_get_curvature (data->contour,
+ data->measure_data,
+ distance,
+ center);
+}
+
+static gboolean
+gsk_rounded_rect_contour_get_closest_point (const GskContour *contour,
+ gpointer measure_data,
+ float tolerance,
+ const graphene_point_t *point,
+ float threshold,
+ float *out_distance,
+ graphene_point_t *out_pos,
+ float *out_offset,
+ graphene_vec2_t *out_tangent)
+{
+ RoundedRectMeasureData *data = measure_data;
+
+ return gsk_standard_contour_get_closest_point (data->contour,
+ data->measure_data,
+ tolerance,
+ point,
+ threshold,
+ out_distance,
+ out_pos,
+ out_offset,
+ out_tangent);
+}
+
+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 void
+gsk_rounded_rect_contour_add_segment (const GskContour *contour,
+ GskPathBuilder *builder,
+ gpointer measure_data,
+ gboolean emit_move_to,
+ float start,
+ float end)
+{
+ RoundedRectMeasureData *data = measure_data;
+
+ gsk_standard_contour_add_segment (data->contour,
+ builder,
+ data->measure_data,
+ emit_move_to,
+ start,
+ end);
+}
+
+static int
+gsk_rounded_rect_contour_get_winding (const GskContour *contour,
+ gpointer measure_data,
+ const graphene_point_t *point,
+ gboolean *on_edge)
+{
+ const GskRoundedRectContour *self = (const GskRoundedRectContour *) contour;
+
+ if (gsk_rounded_rect_contains_point (&self->rect, point))
+ return self->ccw ? 1 : -1;
+
+ return 0;
+}
+
+static gboolean
+gsk_rounded_rect_contour_get_stroke_bounds (const GskContour *contour,
+ const GskStroke *stroke,
+ graphene_rect_t *bounds)
+{
+ const GskRoundedRectContour *self = (const GskRoundedRectContour *) contour;
+
+ graphene_rect_init_from_rect (bounds, &self->rect.bounds);
+ graphene_rect_inset (bounds, - stroke->line_width / 2, - stroke->line_width / 2);
+
+ return TRUE;
+}
+
+static void
+gsk_rounded_rect_contour_add_stroke (const GskContour *contour,
+ GskPathBuilder *builder,
+ GskStroke *stroke)
+{
+ const GskRoundedRectContour *self = (const GskRoundedRectContour *) contour;
+
+ if (stroke_is_simple (stroke))
+ {
+ GskRoundedRect rect;
+ GskContour *c;
+
+ gsk_rounded_rect_init_copy (&rect, &self->rect);
+
+ gsk_rounded_rect_shrink (&rect,
+ stroke->line_width / 2,
+ stroke->line_width / 2,
+ stroke->line_width / 2,
+ stroke->line_width / 2);
+ c = gsk_rounded_rect_contour_new (&rect);
+ gsk_path_builder_add_contour (builder, c);
+
+ gsk_rounded_rect_init_copy (&rect, &self->rect);
+ gsk_rounded_rect_shrink (&rect,
+ - stroke->line_width / 2,
+ - stroke->line_width / 2,
+ - stroke->line_width / 2,
+ - stroke->line_width / 2);
+ c = gsk_rounded_rect_contour_new (&rect);
+ ((GskRoundedRectContour *)c)->ccw = TRUE;
+ gsk_path_builder_add_contour (builder, c);
+ }
+ else
+ gsk_contour_default_add_stroke (contour, builder, stroke);
+}
+
+static void
+gsk_rounded_rect_contour_offset (const GskContour *contour,
+ GskPathBuilder *builder,
+ float distance,
+ GskLineJoin line_join,
+ float miter_limit)
+{
+ const GskRoundedRectContour *self = (const GskRoundedRectContour *) contour;
+ GskRoundedRect rect;
+ GskContour *c;
+
+ gsk_rounded_rect_init_copy (&rect, &self->rect);
+ if (self->ccw)
+ distance = - distance;
+ gsk_rounded_rect_shrink (&rect, - distance, - distance, - distance, - distance);
+ c = gsk_rounded_rect_contour_new (&rect);
+ gsk_path_builder_add_contour (builder, c);
+}
+
+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 gboolean
+gsk_rounded_rect_contour_is_convex (const GskContour *contour)
+{
+ return TRUE;
+}
+
+static const GskContourClass GSK_ROUNDED_RECT_CONTOUR_CLASS =
+{
+ sizeof (GskRoundedRectContour),
+ "GskRoundedRectContour",
+ gsk_contour_get_size_default,
+ gsk_rounded_rect_contour_get_flags,
+ gsk_rounded_rect_contour_print,
+ gsk_rounded_rect_contour_get_bounds,
+ gsk_rounded_rect_contour_get_start_end,
+ gsk_rounded_rect_contour_foreach,
+ gsk_rounded_rect_contour_init_measure,
+ gsk_rounded_rect_contour_free_measure,
+ gsk_rounded_rect_contour_get_point,
+ gsk_rounded_rect_contour_get_curvature,
+ gsk_rounded_rect_contour_get_closest_point,
+ gsk_rounded_rect_contour_copy,
+ gsk_rounded_rect_contour_add_segment,
+ gsk_rounded_rect_contour_get_winding,
+ gsk_rounded_rect_contour_get_stroke_bounds,
+ gsk_rounded_rect_contour_add_stroke,
+ gsk_rounded_rect_contour_offset,
+ gsk_rounded_rect_contour_reverse,
+ gsk_rounded_rect_contour_is_convex,
+};
+
+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 cf5bf5493c..3a2be372d9 100644
--- a/gsk/gskcontourprivate.h
+++ b/gsk/gskcontourprivate.h
@@ -40,6 +40,7 @@ typedef enum
typedef struct _GskContour GskContour;
GskContour * gsk_rect_contour_new (const graphene_rect_t *rect);
+GskContour * gsk_rounded_rect_contour_new (const GskRoundedRect *rounded_rect);
GskContour * gsk_circle_contour_new (const graphene_point_t *center,
float radius,
float start_angle,
diff --git a/gsk/gskpathbuilder.c b/gsk/gskpathbuilder.c
index ff4c024398..d63a9ffdf6 100644
--- a/gsk/gskpathbuilder.c
+++ b/gsk/gskpathbuilder.c
@@ -367,60 +367,13 @@ void
gsk_path_builder_add_rounded_rect (GskPathBuilder *builder,
const GskRoundedRect *rect)
{
- const float weight = M_SQRT1_2;
+ GskContour *contour;
g_return_if_fail (builder != NULL);
g_return_if_fail (rect != NULL);
- gsk_path_builder_move_to (builder,
- rect->bounds.origin.x + rect->corner[GSK_CORNER_TOP_LEFT].width,
- rect->bounds.origin.y);
- /* top */
- gsk_path_builder_line_to (builder,
- rect->bounds.origin.x + rect->bounds.size.width -
rect->corner[GSK_CORNER_TOP_RIGHT].width,
- rect->bounds.origin.y);
- /* topright corner */
- gsk_path_builder_conic_to (builder,
- 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,
- weight);
- /* right */
- gsk_path_builder_line_to (builder,
- 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_conic_to (builder,
- 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,
- weight);
- /* bottom */
- gsk_path_builder_line_to (builder,
- rect->bounds.origin.x + rect->corner[GSK_CORNER_BOTTOM_LEFT].width,
- rect->bounds.origin.y + rect->bounds.size.height);
- /* bottomleft corner */
- gsk_path_builder_conic_to (builder,
- 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,
- weight);
- /* left */
- gsk_path_builder_line_to (builder,
- rect->bounds.origin.x,
- rect->bounds.origin.y + rect->corner[GSK_CORNER_TOP_LEFT].height);
- /* topleft corner */
- gsk_path_builder_conic_to (builder,
- rect->bounds.origin.x,
- rect->bounds.origin.y,
- rect->bounds.origin.x + rect->corner[GSK_CORNER_TOP_LEFT].width,
- rect->bounds.origin.y,
- weight);
- /* done */
- gsk_path_builder_close (builder);
+ contour = gsk_rounded_rect_contour_new (rect);
+ gsk_path_builder_add_contour (builder, contour);
}
/**
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]