Compare commits

...

1 Commits

Author SHA1 Message Date
Matthias Clasen
c543854e24 Revise gsk_path_foreach
Make this struct-based.
2023-08-25 21:25:27 -04:00
8 changed files with 219 additions and 112 deletions

View File

@@ -104,20 +104,19 @@ gtk_path_transform_point (GskPathMeasure *measure,
}
static gboolean
gtk_path_transform_op (GskPathOperation op,
const graphene_point_t *pts,
gsize n_pts,
float weight,
gtk_path_transform_op (const graphene_point_t *start,
const graphene_point_t *end,
const GskPathControl *control,
gpointer data)
{
GtkPathTransform *transform = data;
switch (op)
switch (control->op)
{
case GSK_PATH_MOVE:
{
graphene_point_t res;
gtk_path_transform_point (transform->measure, &pts[0], &transform->offset, transform->scale, &res);
gtk_path_transform_point (transform->measure, end, &transform->offset, transform->scale, &res);
gsk_path_builder_move_to (transform->builder, res.x, res.y);
}
break;
@@ -125,7 +124,7 @@ gtk_path_transform_op (GskPathOperation op,
case GSK_PATH_LINE:
{
graphene_point_t res;
gtk_path_transform_point (transform->measure, &pts[1], &transform->offset, transform->scale, &res);
gtk_path_transform_point (transform->measure, end, &transform->offset, transform->scale, &res);
gsk_path_builder_line_to (transform->builder, res.x, res.y);
}
break;
@@ -133,8 +132,8 @@ gtk_path_transform_op (GskPathOperation op,
case GSK_PATH_QUAD:
{
graphene_point_t res[2];
gtk_path_transform_point (transform->measure, &pts[1], &transform->offset, transform->scale, &res[0]);
gtk_path_transform_point (transform->measure, &pts[2], &transform->offset, transform->scale, &res[1]);
gtk_path_transform_point (transform->measure, &control->quad.control, &transform->offset, transform->scale, &res[0]);
gtk_path_transform_point (transform->measure, end, &transform->offset, transform->scale, &res[1]);
gsk_path_builder_quad_to (transform->builder, res[0].x, res[0].y, res[1].x, res[1].y);
}
break;
@@ -142,9 +141,9 @@ gtk_path_transform_op (GskPathOperation op,
case GSK_PATH_CUBIC:
{
graphene_point_t res[3];
gtk_path_transform_point (transform->measure, &pts[1], &transform->offset, transform->scale, &res[0]);
gtk_path_transform_point (transform->measure, &pts[2], &transform->offset, transform->scale, &res[1]);
gtk_path_transform_point (transform->measure, &pts[3], &transform->offset, transform->scale, &res[2]);
gtk_path_transform_point (transform->measure, &control->cubic.control1, &transform->offset, transform->scale, &res[0]);
gtk_path_transform_point (transform->measure, &control->cubic.control2, &transform->offset, transform->scale, &res[1]);
gtk_path_transform_point (transform->measure, end, &transform->offset, transform->scale, &res[2]);
gsk_path_builder_cubic_to (transform->builder, res[0].x, res[0].y, res[1].x, res[1].y, res[2].x, res[2].y);
}
break;
@@ -152,9 +151,9 @@ gtk_path_transform_op (GskPathOperation op,
case GSK_PATH_CONIC:
{
graphene_point_t res[2];
gtk_path_transform_point (transform->measure, &pts[1], &transform->offset, transform->scale, &res[0]);
gtk_path_transform_point (transform->measure, &pts[3], &transform->offset, transform->scale, &res[1]);
gsk_path_builder_conic_to (transform->builder, res[0].x, res[0].y, res[1].x, res[1].y, weight);
gtk_path_transform_point (transform->measure, &control->conic.control, &transform->offset, transform->scale, &res[0]);
gtk_path_transform_point (transform->measure, end, &transform->offset, transform->scale, &res[1]);
gsk_path_builder_conic_to (transform->builder, res[0].x, res[0].y, res[1].x, res[1].y, control->conic.weight);
}
break;

View File

@@ -381,7 +381,10 @@ gsk_line_curve_decompose_curve (const GskCurve *curve,
{
const GskLineCurve *self = &curve->line;
return add_curve_func (GSK_PATH_LINE, self->points, 2, 0.f, user_data);
return add_curve_func (&self->points[0],
&self->points[1],
&(GskPathControl) { .op = GSK_PATH_LINE },
user_data);
}
static void
@@ -705,9 +708,10 @@ gsk_curve_add_line_cb (const graphene_point_t *from,
gpointer user_data)
{
AddLineData *data = user_data;
graphene_point_t p[2] = { *from, *to };
return data->add_curve (GSK_PATH_LINE, p, 2, 0.f, data->user_data);
return data->add_curve (from, to,
&(GskPathControl) { .op = GSK_PATH_LINE },
data->user_data);
}
static gboolean
@@ -720,13 +724,30 @@ gsk_quad_curve_decompose_curve (const GskCurve *curve,
const GskQuadCurve *self = &curve->quad;
if (flags & GSK_PATH_FOREACH_ALLOW_QUAD)
return add_curve_func (GSK_PATH_QUAD, self->points, 3, 0.f, user_data);
return add_curve_func (&self->points[0],
&self->points[2],
&(GskPathControl) {
.op = GSK_PATH_QUAD,
.quad = (GskQuadControl) {
.control = self->points[1],
},
},
user_data);
else if (flags & GSK_PATH_FOREACH_ALLOW_CUBIC)
{
GskCurve c;
gsk_curve_elevate (curve, &c);
return add_curve_func (GSK_PATH_CUBIC, c.cubic.points, 4, 0.f, user_data);
return add_curve_func (&c.cubic.points[0],
&c.cubic.points[3],
&(GskPathControl) {
.op = GSK_PATH_CUBIC,
.cubic = (GskCubicControl) {
.control1 = c.cubic.points[1],
.control2 = c.cubic.points[2],
},
},
user_data);
}
else
{
@@ -1180,7 +1201,16 @@ gsk_cubic_curve_decompose_curve (const GskCurve *curve,
const GskCubicCurve *self = &curve->cubic;
if (flags & GSK_PATH_FOREACH_ALLOW_CUBIC)
return add_curve_func (GSK_PATH_CUBIC, self->points, 4, 0.f, user_data);
return add_curve_func (&self->points[0],
&self->points[3],
&(GskPathControl) {
.op = GSK_PATH_CUBIC,
.cubic = (GskCubicControl) {
.control1 = self->points[1],
.control2 = self->points[2],
},
},
user_data);
/* FIXME: Quadratic or arc approximation */
return gsk_cubic_curve_decompose (curve,
@@ -1854,7 +1884,16 @@ gsk_conic_curve_decompose_or_add (const GskCurve *curve,
gpointer user_data)
{
if (gsk_conic_is_close_to_cubic (curve, cubic, tolerance))
return add_curve_func (GSK_PATH_CUBIC, cubic->cubic.points, 4, 0.f, user_data);
return add_curve_func (&cubic->cubic.points[0],
&cubic->cubic.points[3],
&(GskPathControl) {
.op = GSK_PATH_CUBIC,
.cubic = (GskCubicControl) {
.control1 = cubic->cubic.points[1],
.control2 = cubic->cubic.points[2],
},
},
user_data);
else
{
GskCurve c1, c2;
@@ -1881,13 +1920,16 @@ gsk_conic_curve_decompose_curve (const GskCurve *curve,
GskCurve c;
if (flags & GSK_PATH_FOREACH_ALLOW_CONIC)
return add_curve_func (GSK_PATH_CONIC,
(const graphene_point_t[3]) { self->points[0],
self->points[1],
self->points[3] },
3,
self->points[2].x,
user_data);
return add_curve_func (&self->points[0],
&self->points[3],
&(GskPathControl) {
.op = GSK_PATH_CONIC,
.conic = (GskConicControl) {
.control = self->points[1],
.weight = self->points[2].x
},
},
user_data);
if (flags & GSK_PATH_FOREACH_ALLOW_CUBIC)
{

View File

@@ -102,10 +102,9 @@ typedef gboolean (* GskCurveAddLineFunc) (const graphene_point_t *from,
GskCurveLineReason reason,
gpointer user_data);
typedef gboolean (* GskCurveAddCurveFunc) (GskPathOperation op,
const graphene_point_t *pts,
gsize n_pts,
float weight,
typedef gboolean (* GskCurveAddCurveFunc) (const graphene_point_t *start,
const graphene_point_t *end,
const GskPathControl *control,
gpointer user_data);
void gsk_curve_init (GskCurve *curve,

View File

@@ -231,16 +231,15 @@ gsk_path_to_string (GskPath *self)
}
static gboolean
gsk_path_to_cairo_add_op (GskPathOperation op,
const graphene_point_t *pts,
gsize n_pts,
float weight,
gsk_path_to_cairo_add_op (const graphene_point_t *start,
const graphene_point_t *end,
const GskPathControl *control,
gpointer cr)
{
switch (op)
switch (control->op)
{
case GSK_PATH_MOVE:
cairo_move_to (cr, pts[0].x, pts[0].y);
cairo_move_to (cr, end->x, end->y);
break;
case GSK_PATH_CLOSE:
@@ -248,11 +247,13 @@ gsk_path_to_cairo_add_op (GskPathOperation op,
break;
case GSK_PATH_LINE:
cairo_line_to (cr, pts[1].x, pts[1].y);
cairo_line_to (cr, end->x, end->y);
break;
case GSK_PATH_CUBIC:
cairo_curve_to (cr, pts[1].x, pts[1].y, pts[2].x, pts[2].y, pts[3].x, pts[3].y);
cairo_curve_to (cr, control->cubic.control1.x, control->cubic.control1.y,
control->cubic.control2.x, control->cubic.control2.y,
end->x, end->y);
break;
case GSK_PATH_QUAD:
@@ -668,64 +669,65 @@ gsk_path_foreach_trampoline_add_line (const graphene_point_t *from,
{
GskPathForeachTrampoline *trampoline = data;
return trampoline->func (GSK_PATH_LINE,
(graphene_point_t[2]) { *from, *to },
2,
0.f,
return trampoline->func (from, to,
&(GskPathControl) { GSK_PATH_LINE, },
trampoline->user_data);
}
static gboolean
gsk_path_foreach_trampoline_add_curve (GskPathOperation op,
const graphene_point_t *pts,
gsize n_pts,
float weight,
gsk_path_foreach_trampoline_add_curve (const graphene_point_t *start,
const graphene_point_t *end,
const GskPathControl *control,
gpointer data)
{
GskPathForeachTrampoline *trampoline = data;
return trampoline->func (op, pts, n_pts, weight, trampoline->user_data);
return trampoline->func (start, end, control, trampoline->user_data);
}
static gboolean
gsk_path_foreach_trampoline (GskPathOperation op,
const graphene_point_t *pts,
gsize n_pts,
float weight,
gsk_path_foreach_trampoline (const graphene_point_t *start,
const graphene_point_t *end,
const GskPathControl *control,
gpointer data)
{
GskPathForeachTrampoline *trampoline = data;
switch (op)
switch (control->op)
{
case GSK_PATH_MOVE:
case GSK_PATH_CLOSE:
case GSK_PATH_LINE:
return trampoline->func (op, pts, n_pts, weight, trampoline->user_data);
return trampoline->func (start, end, control, trampoline->user_data);
case GSK_PATH_QUAD:
{
GskCurve curve;
if (trampoline->flags & GSK_PATH_FOREACH_ALLOW_QUAD)
return trampoline->func (op, pts, n_pts, weight, trampoline->user_data);
return trampoline->func (start, end, control, trampoline->user_data);
else if (trampoline->flags & GSK_PATH_FOREACH_ALLOW_CUBIC)
{
return trampoline->func (GSK_PATH_CUBIC,
(graphene_point_t[4]) {
pts[0],
GRAPHENE_POINT_INIT ((pts[0].x + 2 * pts[1].x) / 3,
(pts[0].y + 2 * pts[1].y) / 3),
GRAPHENE_POINT_INIT ((pts[2].x + 2 * pts[1].x) / 3,
(pts[2].y + 2 * pts[1].y) / 3),
pts[2],
return trampoline->func (start,
end,
&(GskPathControl) {
.op = GSK_PATH_CUBIC,
.cubic = (GskCubicControl) {
.control1 = GRAPHENE_POINT_INIT ((start->x + 2 * control->quad.control.x) / 3,
(start->y + 2 * control->quad.control.y) / 3),
.control2 = GRAPHENE_POINT_INIT ((end->x + 2 * control->quad.control.x) / 3,
(end->y + 2 * control->quad.control.y) / 3),
},
},
4,
weight,
trampoline->user_data);
}
gsk_curve_init (&curve, gsk_pathop_encode (GSK_PATH_QUAD, pts));
gsk_curve_init (&curve, gsk_pathop_encode (GSK_PATH_QUAD,
(graphene_point_t[3]) {
*start,
control->quad.control,
*end,
} ));
return gsk_curve_decompose (&curve,
trampoline->tolerance,
gsk_path_foreach_trampoline_add_line,
@@ -737,9 +739,15 @@ gsk_path_foreach_trampoline (GskPathOperation op,
GskCurve curve;
if (trampoline->flags & GSK_PATH_FOREACH_ALLOW_CUBIC)
return trampoline->func (op, pts, n_pts, weight, trampoline->user_data);
return trampoline->func (start, end, control, trampoline->user_data);
gsk_curve_init (&curve, gsk_pathop_encode (GSK_PATH_CUBIC, pts));
gsk_curve_init (&curve, gsk_pathop_encode (GSK_PATH_CUBIC,
(const graphene_point_t[4]) {
*start,
control->cubic.control1,
control->cubic.control2,
*end,
}));
if (trampoline->flags & (GSK_PATH_FOREACH_ALLOW_QUAD|GSK_PATH_FOREACH_ALLOW_CONIC))
return gsk_curve_decompose_curve (&curve,
trampoline->flags,
@@ -758,9 +766,15 @@ gsk_path_foreach_trampoline (GskPathOperation op,
GskCurve curve;
if (trampoline->flags & GSK_PATH_FOREACH_ALLOW_CONIC)
return trampoline->func (op, pts, n_pts, weight, trampoline->user_data);
return trampoline->func (start, end, control, trampoline->user_data);
gsk_curve_init (&curve, gsk_pathop_encode (GSK_PATH_CONIC, (graphene_point_t[4]) { pts[0], pts[1], { weight, 0.f }, pts[2] } ));
gsk_curve_init (&curve, gsk_pathop_encode (GSK_PATH_CONIC,
(graphene_point_t[4]) {
*start,
control->conic.control,
{ control->conic.weight, 0.f },
*end
} ));
if (trampoline->flags & (GSK_PATH_FOREACH_ALLOW_QUAD|GSK_PATH_FOREACH_ALLOW_CUBIC))
return gsk_curve_decompose_curve (&curve,
trampoline->flags,

View File

@@ -53,21 +53,50 @@ typedef enum
GSK_PATH_FOREACH_ALLOW_CONIC = (1 << 2),
} GskPathForeachFlags;
typedef struct _GskQuadControl GskQuadControl;
struct _GskQuadControl
{
graphene_point_t control;
};
typedef struct _GskCubicControl GskCubicControl;
struct _GskCubicControl
{
graphene_point_t control1;
graphene_point_t control2;
};
typedef struct _GskConicControl GskConicControl;
struct _GskConicControl
{
graphene_point_t control;
float weight;
};
typedef struct _GskPathControl GskPathControl;
struct _GskPathControl
{
GskPathOperation op;
union {
GskQuadControl quad;
GskCubicControl cubic;
GskConicControl conic;
};
};
/**
* GskPathForeachFunc:
* @op: The operation
* @pts: The points of the operation
* @n_pts: The number of points
* @weight: The weight for conic curves, or unused if not a conic curve
* @start: The start point of the operation
* @end: The end point of the operation
* @control: The control data for the operation
* @user_data: The user data provided with the function
*
* Prototype of the callback to iterate through the operations of
* a path.
*
* For each operation, the callback is given the @op itself, the points
* that the operation is applied to in @pts, and a @weight for conic
* curves. The @n_pts argument is somewhat redundant, since the number
* of points can be inferred from the operation.
* For each operation, the callback is given the @op itself, the start-
* and endpoint, and the control data, depending on the kind of operation.
*
* Each contour of the path starts with a @GSK_PATH_MOVE operation.
* Closed contours end with a @GSK_PATH_CLOSE operation.
@@ -75,10 +104,9 @@ typedef enum
* Returns: %TRUE to continue iterating 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,
float weight,
typedef gboolean (* GskPathForeachFunc) (const graphene_point_t *start,
const graphene_point_t *end,
const GskPathControl *control,
gpointer user_data);
#define GSK_TYPE_PATH (gsk_path_get_type ())

View File

@@ -89,23 +89,50 @@ gsk_pathop_foreach (gskpathop pop,
switch (gsk_pathop_op (pop))
{
case GSK_PATH_MOVE:
return func (gsk_pathop_op (pop), gsk_pathop_points (pop), 1, 0, user_data);
return func (&GRAPHENE_POINT_INIT (0, 0),
&gsk_pathop_points (pop)[0],
&(GskPathControl) { .op = gsk_pathop_op (pop), },
user_data);
case GSK_PATH_CLOSE:
case GSK_PATH_LINE:
return func (gsk_pathop_op (pop), gsk_pathop_points (pop), 2, 0, user_data);
return func (&gsk_pathop_points (pop)[0],
&gsk_pathop_points (pop)[1],
&(GskPathControl) { .op = gsk_pathop_op (pop), },
user_data);
case GSK_PATH_QUAD:
return func (gsk_pathop_op (pop), gsk_pathop_points (pop), 3, 0, user_data);
return func (&gsk_pathop_points (pop)[0],
&gsk_pathop_points (pop)[2],
&(GskPathControl) {
.op = gsk_pathop_op (pop),
.quad = (GskQuadControl) { gsk_pathop_points (pop)[1] }
},
user_data);
case GSK_PATH_CUBIC:
return func (gsk_pathop_op (pop), gsk_pathop_points (pop), 4, 0, user_data);
return func (&gsk_pathop_points (pop)[0],
&gsk_pathop_points (pop)[3],
&(GskPathControl) {
.op = gsk_pathop_op (pop),
.cubic = (GskCubicControl) {
.control1 = gsk_pathop_points (pop)[1],
.control2 = gsk_pathop_points (pop)[2]
},
},
user_data);
case GSK_PATH_CONIC:
{
const graphene_point_t *pts = gsk_pathop_points (pop);
return func (gsk_pathop_op (pop), (graphene_point_t[3]) { pts[0], pts[1], pts[3] }, 3, pts[2].x, user_data);
}
return func (&gsk_pathop_points (pop)[0],
&gsk_pathop_points (pop)[3],
&(GskPathControl) {
.op = gsk_pathop_op (pop),
.conic = (GskConicControl) {
.control = gsk_pathop_points (pop)[1],
.weight = gsk_pathop_points (pop)[2].x
},
},
user_data);
default:
g_assert_not_reached ();

View File

@@ -25,18 +25,17 @@
#include <glib/gi18n-lib.h>
static gboolean
foreach_cb (GskPathOperation op,
const graphene_point_t *pts,
gsize n_pts,
float weight,
foreach_cb (const graphene_point_t *start,
const graphene_point_t *end,
const GskPathControl *control,
gpointer user_data)
{
GskPathBuilder *builder = user_data;
switch (op)
switch (control->op)
{
case GSK_PATH_MOVE:
gsk_path_builder_move_to (builder, pts[0].x, pts[0].y);
gsk_path_builder_move_to (builder, end->x, end->y);
break;
case GSK_PATH_CLOSE:
@@ -44,24 +43,24 @@ foreach_cb (GskPathOperation op,
break;
case GSK_PATH_LINE:
gsk_path_builder_line_to (builder, pts[1].x, pts[1].y);
gsk_path_builder_line_to (builder, end->x, end->y);
break;
case GSK_PATH_QUAD:
gsk_path_builder_quad_to (builder, pts[1].x, pts[1].y,
pts[2].x, pts[2].y);
gsk_path_builder_quad_to (builder, control->quad.control.x, control->quad.control.y,
end->x, end->y);
break;
case GSK_PATH_CUBIC:
gsk_path_builder_cubic_to (builder, pts[1].x, pts[1].y,
pts[2].x, pts[2].y,
pts[3].x, pts[3].y);
gsk_path_builder_cubic_to (builder, control->cubic.control1.x, control->cubic.control1.y,
control->cubic.control2.x, control->cubic.control2.y,
end->x, end->y);
break;
case GSK_PATH_CONIC:
gsk_path_builder_conic_to (builder, pts[1].x, pts[1].y,
pts[2].x, pts[2].y,
weight);
gsk_path_builder_conic_to (builder, control->conic.control.x, control->conic.control.y,
end->x, end->y,
control->conic.weight);
break;
default:

View File

@@ -35,17 +35,16 @@ typedef struct
} Statistics;
static gboolean
stats_cb (GskPathOperation op,
const graphene_point_t *pts,
gsize n_pts,
float weight,
stats_cb (const graphene_point_t *start,
const graphene_point_t *end,
const GskPathControl *control,
gpointer user_data)
{
Statistics *stats = user_data;
stats->ops++;
switch (op)
switch (control->op)
{
case GSK_PATH_MOVE:
stats->contours++;