summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@redhat.com>2020-11-18 05:15:28 +0100
committerBenjamin Otte <otte@redhat.com>2020-11-19 22:41:37 +0100
commit4aca0358b40dd4666bab3280096d6e8b3f45dd9f (patch)
tree27a133af16574ca79df1318c95127285d9484d65
parentcf930d93e100b114e97dfc0ad98aff7e51e3d83b (diff)
downloadgtk+-4aca0358b40dd4666bab3280096d6e8b3f45dd9f.tar.gz
path: Add gsk_path_foreach()
-rw-r--r--gsk/gskenums.h22
-rw-r--r--gsk/gskpath.c102
-rw-r--r--gsk/gskpath.h23
-rw-r--r--gsk/gskpathprivate.h3
4 files changed, 142 insertions, 8 deletions
diff --git a/gsk/gskenums.h b/gsk/gskenums.h
index 98d5afd505..44e8854874 100644
--- a/gsk/gskenums.h
+++ b/gsk/gskenums.h
@@ -196,6 +196,28 @@ typedef enum {
} GskFillRule;
/**
+ * GskPathOperation:
+ * @GSK_PATH_MOVE: A move-to operation, with 1 point describing the
+ * target point.
+ * @GSK_PATH_LINE: A line-to operation, with 2 points describing the
+ * start and end point of a straight line.
+ * @GSK_PATH_CLOSE: A close operation ending the current contour with
+ * a line back to the starting point. Two points describe the start
+ * and end of the line.
+ * @GSK_PATH_CURVE: A curve-to operation describing a cubic bezier curve
+ * with 4 points describing the start point, the two control points
+ * and the end point of the curve.
+ *
+ * Path operations can be used to approximate a #GskPath.
+ **/
+typedef enum {
+ GSK_PATH_MOVE,
+ GSK_PATH_CLOSE,
+ GSK_PATH_LINE,
+ GSK_PATH_CURVE,
+} GskPathOperation;
+
+/**
* GskSerializationError:
* @GSK_SERIALIZATION_UNSUPPORTED_FORMAT: The format can not be
* identified
diff --git a/gsk/gskpath.c b/gsk/gskpath.c
index b69dd44fb8..c79ba541db 100644
--- a/gsk/gskpath.c
+++ b/gsk/gskpath.c
@@ -62,6 +62,10 @@ struct _GskContourClass
cairo_t *cr);
gboolean (* get_bounds) (const GskContour *contour,
graphene_rect_t *bounds);
+ gboolean (* foreach) (const GskContour *contour,
+ float tolerance,
+ GskPathForeachFunc func,
+ gpointer user_data);
gpointer (* init_measure) (const GskContour *contour,
float *out_length);
void (* free_measure) (const GskContour *contour,
@@ -157,6 +161,29 @@ gsk_rect_contour_get_bounds (const GskContour *contour,
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, user_data)
+ && func (GSK_PATH_LINE, &pts[0], 2, user_data)
+ && func (GSK_PATH_LINE, &pts[1], 2, user_data)
+ && func (GSK_PATH_LINE, &pts[2], 2, user_data)
+ && func (GSK_PATH_CLOSE, &pts[3], 2, user_data);
+}
+
static gpointer
gsk_rect_contour_init_measure (const GskContour *contour,
float *out_length)
@@ -258,6 +285,7 @@ static const GskContourClass GSK_RECT_CONTOUR_CLASS =
gsk_rect_contour_print,
gsk_rect_contour_to_cairo,
gsk_rect_contour_get_bounds,
+ gsk_rect_contour_foreach,
gsk_rect_contour_init_measure,
gsk_rect_contour_free_measure,
gsk_rect_contour_copy,
@@ -282,14 +310,6 @@ gsk_rect_contour_init (GskContour *contour,
/* STANDARD CONTOUR */
-typedef enum
-{
- GSK_PATH_MOVE,
- GSK_PATH_CLOSE,
- GSK_PATH_LINE,
- GSK_PATH_CURVE,
-} GskPathOperation;
-
typedef struct _GskStandardOperation GskStandardOperation;
struct _GskStandardOperation {
@@ -327,6 +347,30 @@ gsk_standard_contour_get_size (const GskContour *contour)
return gsk_standard_contour_compute_size (self->n_ops, self->n_points);
}
+static gboolean
+gsk_standard_contour_foreach (const GskContour *contour,
+ float tolerance,
+ GskPathForeachFunc func,
+ gpointer user_data)
+{
+ const GskStandardContour *self = (const GskStandardContour *) contour;
+ gsize i;
+ const gsize n_points[] = {
+ [GSK_PATH_MOVE] = 1,
+ [GSK_PATH_CLOSE] = 2,
+ [GSK_PATH_LINE] = 2,
+ [GSK_PATH_CURVE] = 4
+ };
+
+ for (i = 0; i < self->n_ops; i ++)
+ {
+ if (!func (self->ops[i].op, &self->points[self->ops[i].point], n_points[self->ops[i].op], user_data))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static GskPathFlags
gsk_standard_contour_get_flags (const GskContour *contour)
{
@@ -627,6 +671,7 @@ static const GskContourClass GSK_STANDARD_CONTOUR_CLASS =
gsk_standard_contour_print,
gsk_standard_contour_to_cairo,
gsk_standard_contour_get_bounds,
+ gsk_standard_contour_foreach,
gsk_standard_contour_init_measure,
gsk_standard_contour_free_measure,
gsk_standard_contour_copy,
@@ -682,6 +727,15 @@ gsk_contour_dup (const GskContour *src)
return copy;
}
+static gboolean
+gsk_contour_foreach (const GskContour *contour,
+ float tolerance,
+ GskPathForeachFunc func,
+ gpointer user_data)
+{
+ return contour->klass->foreach (contour, tolerance, func, user_data);
+}
+
gpointer
gsk_contour_init_measure (GskPath *path,
gsize i,
@@ -1013,6 +1067,38 @@ gsk_path_get_bounds (GskPath *self,
}
/**
+ * gsk_path_foreach:
+ * @self: a #GskPath
+ * @func: (scope call) (closure user_data): the function to call for operations
+ * @user_data: (nullable): user data passed to @func
+ *
+ * Calls @func for every operation of the path. Note that this only approximates
+ * @self, because paths can contain optimizations for various specialized contours.
+ *
+ * Returns: %FALSE if @func returned %FALSE, %TRUE otherwise.
+ **/
+gboolean
+gsk_path_foreach (GskPath *self,
+ GskPathForeachFunc func,
+ gpointer user_data)
+{
+ gsize i;
+
+ g_return_val_if_fail (self != NULL, FALSE);
+ g_return_val_if_fail (func, FALSE);
+
+ for (i = 0; i < self->n_contours; i++)
+ {
+ if (!gsk_contour_foreach (self->contours[i], GSK_PATH_TOLERANCE_DEFAULT, func, user_data))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* BUILDER */
+
+/**
* GskPathBuilder:
*
* A #GskPathBuilder struct is an opaque struct. It is meant to
diff --git a/gsk/gskpath.h b/gsk/gskpath.h
index 1be4ec189f..8011aba4eb 100644
--- a/gsk/gskpath.h
+++ b/gsk/gskpath.h
@@ -29,6 +29,24 @@
G_BEGIN_DECLS
+/**
+ * GskPathForeachFunc:
+ * @op: The operation to perform
+ * @pts: The points of the operation
+ * @n_pts: The number of points
+ * @user_data: The user data provided with the function
+ *
+ * Prototype of the callback to iterate throught the operations of
+ * a path.
+ *
+ * Returns: %TRUE to continue evaluating the path, %FALSE to
+ * immediately abort and not call the function again.
+ */
+typedef gboolean (* GskPathForeachFunc) (GskPathOperation op,
+ const graphene_point_t *pts,
+ gsize n_pts,
+ gpointer user_data);
+
#define GSK_TYPE_PATH (gsk_path_get_type ())
GDK_AVAILABLE_IN_ALL
@@ -61,6 +79,11 @@ GDK_AVAILABLE_IN_ALL
gboolean gsk_path_get_bounds (GskPath *path,
graphene_rect_t *bounds);
+GDK_AVAILABLE_IN_ALL
+gboolean gsk_path_foreach (GskPath *path,
+ GskPathForeachFunc func,
+ gpointer user_data);
+
#define GSK_TYPE_PATH_BUILDER (gsk_path_builder_get_type ())
typedef struct _GskPathBuilder GskPathBuilder;
diff --git a/gsk/gskpathprivate.h b/gsk/gskpathprivate.h
index 7238c44418..2e47ac465f 100644
--- a/gsk/gskpathprivate.h
+++ b/gsk/gskpathprivate.h
@@ -25,6 +25,9 @@
G_BEGIN_DECLS
+/* Same as Cairo, so looks like a good value. ¯\_(ツ)_/¯ */
+#define GSK_PATH_TOLERANCE_DEFAULT (0.1)
+
gsize gsk_path_get_n_contours (GskPath *path);
gpointer gsk_contour_init_measure (GskPath *path,