diff --git a/gsk/gskcontour.c b/gsk/gskcontour.c index 76595e1145..359356d838 100644 --- a/gsk/gskcontour.c +++ b/gsk/gskcontour.c @@ -871,7 +871,7 @@ struct _GskStandardContour gsize n_ops; gsize n_points; graphene_point_t *points; - GskStandardOperation ops[]; + gskpathop ops[]; }; static gsize @@ -879,7 +879,7 @@ gsk_standard_contour_compute_size (gsize n_ops, gsize n_points) { return sizeof (GskStandardContour) - + sizeof (GskStandardOperation) * n_ops + + sizeof (gskpathop) * n_ops + sizeof (graphene_point_t) * n_points; } @@ -899,30 +899,11 @@ gsk_standard_contour_foreach (const GskContour *contour, { 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 (self->ops[i].op == GSK_PATH_CONIC) - { - graphene_point_t pts[3] = { self->points[self->ops[i].point], - self->points[self->ops[i].point + 1], - self->points[self->ops[i].point + 3] }; - float weight = self->points[self->ops[i].point + 2].x; - - if (!func (GSK_PATH_CONIC, pts, 3, weight, user_data)) - return FALSE; - } - else - { - if (!func (self->ops[i].op, &self->points[self->ops[i].point], n_points[self->ops[i].op], 0, user_data)) - return FALSE; - } + if (!gsk_pathop_foreach (self->ops[i], func, user_data)) + return FALSE; } return TRUE; @@ -945,9 +926,9 @@ gsk_standard_contour_print (const GskContour *contour, for (i = 0; i < self->n_ops; i ++) { - graphene_point_t *pt = &self->points[self->ops[i].point]; + const graphene_point_t *pt = gsk_pathop_points (self->ops[i]); - switch (self->ops[i].op) + switch (gsk_pathop_op (self->ops[i])) { case GSK_PATH_MOVE: g_string_append (string, "M "); @@ -1102,9 +1083,9 @@ gsk_standard_contour_init_measure (const GskContour *contour, for (i = 1; i < self->n_ops; i ++) { - graphene_point_t *pt = &self->points[self->ops[i].point]; + const graphene_point_t *pt = gsk_pathop_points (self->ops[i]); - switch (self->ops[i].op) + switch (gsk_pathop_op (self->ops[i])) { case GSK_PATH_MOVE: break; @@ -1184,8 +1165,8 @@ gsk_standard_contour_measure_get_point (GskStandardContour *self, { const graphene_point_t *pts; - pts = &self->points[self->ops[op].point]; - switch (self->ops[op].op) + pts = gsk_pathop_points (self->ops[op]); + switch (gsk_pathop_op (self->ops[op])) { case GSK_PATH_LINE: case GSK_PATH_CLOSE: @@ -1229,7 +1210,7 @@ gsk_standard_contour_get_point (const GskContour *contour, if (array->len == 0) { g_assert (distance == 0); - g_assert (self->ops[0].op == GSK_PATH_MOVE); + g_assert (gsk_pathop_op (self->ops[0]) == GSK_PATH_MOVE); if (pos) *pos = self->points[0]; if (tangent) @@ -1266,7 +1247,7 @@ gsk_standard_contour_get_closest_point (const GskContour *contour, gsize i; gboolean result = FALSE; - g_assert (self->ops[0].op == GSK_PATH_MOVE); + g_assert (gsk_pathop_op (self->ops[0]) == GSK_PATH_MOVE); last_point = self->points[0]; if (array->len == 0) @@ -1338,12 +1319,13 @@ gsk_standard_contour_get_closest_point (const GskContour *contour, } static void -gsk_standard_contour_init (GskContour *contour, - GskPathFlags flags, - const GskStandardOperation *ops, - gsize n_ops, +gsk_standard_contour_init (GskContour *contour, + GskPathFlags flags, const graphene_point_t *points, - gsize n_points); + gsize n_points, + const gskpathop *ops, + gsize n_ops, + ptrdiff_t offset); static void gsk_standard_contour_copy (const GskContour *contour, @@ -1351,7 +1333,7 @@ gsk_standard_contour_copy (const GskContour *contour, { const GskStandardContour *self = (const GskStandardContour *) contour; - gsk_standard_contour_init (dest, self->flags, self->ops, self->n_ops, self->points, self->n_points); + gsk_standard_contour_init (dest, self->flags, self->points, self->n_points, self->ops, self->n_ops, 0); } static void @@ -1400,12 +1382,12 @@ gsk_standard_contour_add_segment (const GskContour *contour, * taking care that first and last operation might be identical */ if (start_measure) { - switch (self->ops[start_measure->op].op) + switch (gsk_pathop_op (self->ops[start_measure->op])) { case GSK_PATH_CLOSE: case GSK_PATH_LINE: { - graphene_point_t *pts = &self->points[self->ops[start_measure->op].point]; + const graphene_point_t *pts = gsk_pathop_points (self->ops[start_measure->op]); graphene_point_t point; graphene_point_interpolate (&pts[0], &pts[1], start_progress, &point); @@ -1422,7 +1404,7 @@ gsk_standard_contour_add_segment (const GskContour *contour, case GSK_PATH_CURVE: { - graphene_point_t *pts = &self->points[self->ops[start_measure->op].point]; + const graphene_point_t *pts = gsk_pathop_points (self->ops[start_measure->op]); graphene_point_t curve[4], discard[4]; gsk_spline_split_cubic (pts, discard, curve, start_progress); @@ -1441,7 +1423,7 @@ gsk_standard_contour_add_segment (const GskContour *contour, case GSK_PATH_CONIC: { - graphene_point_t *pts = &self->points[self->ops[start_measure->op].point]; + const graphene_point_t *pts = gsk_pathop_points (self->ops[start_measure->op]); graphene_point_t curve[4], discard[4]; gsk_spline_split_conic (pts, discard, curve, start_progress); @@ -1470,9 +1452,9 @@ gsk_standard_contour_add_segment (const GskContour *contour, for (; i < (end_measure ? end_measure->op : self->n_ops); i++) { - graphene_point_t *pt = &self->points[self->ops[i].point]; + const graphene_point_t *pt = gsk_pathop_points (self->ops[i]); - switch (self->ops[i].op) + switch (gsk_pathop_op (self->ops[i])) { case GSK_PATH_MOVE: gsk_path_builder_move_to (builder, pt[0].x, pt[0].y); @@ -1500,12 +1482,12 @@ gsk_standard_contour_add_segment (const GskContour *contour, /* Add the last partial operation */ if (end_measure) { - switch (self->ops[end_measure->op].op) + switch (gsk_pathop_op (self->ops[end_measure->op])) { case GSK_PATH_CLOSE: case GSK_PATH_LINE: { - graphene_point_t *pts = &self->points[self->ops[end_measure->op].point]; + const graphene_point_t *pts = gsk_pathop_points (self->ops[end_measure->op]); graphene_point_t point; graphene_point_interpolate (&pts[0], &pts[1], end_progress, &point); @@ -1515,7 +1497,7 @@ gsk_standard_contour_add_segment (const GskContour *contour, case GSK_PATH_CURVE: { - graphene_point_t *pts = &self->points[self->ops[end_measure->op].point]; + const graphene_point_t *pts = gsk_pathop_points (self->ops[end_measure->op]); graphene_point_t curve[4], discard[4]; gsk_spline_split_cubic (pts, curve, discard, end_progress); @@ -1525,7 +1507,7 @@ gsk_standard_contour_add_segment (const GskContour *contour, case GSK_PATH_CONIC: { - graphene_point_t *pts = &self->points[self->ops[end_measure->op].point]; + const graphene_point_t *pts = gsk_pathop_points (self->ops[end_measure->op]); graphene_point_t curve[4], discard[4]; gsk_spline_split_conic (pts, curve, discard, end_progress); @@ -1637,37 +1619,47 @@ static const GskContourClass GSK_STANDARD_CONTOUR_CLASS = * see gsk_standard_contour_compute_size() */ static void -gsk_standard_contour_init (GskContour *contour, - GskPathFlags flags, - const GskStandardOperation *ops, - gsize n_ops, - const graphene_point_t *points, - gsize n_points) +gsk_standard_contour_init (GskContour *contour, + GskPathFlags flags, + const graphene_point_t *points, + gsize n_points, + const gskpathop *ops, + gsize n_ops, + gssize offset) + { GskStandardContour *self = (GskStandardContour *) contour; + gsize i; self->contour.klass = &GSK_STANDARD_CONTOUR_CLASS; self->flags = flags; self->n_ops = n_ops; - memcpy (self->ops, ops, sizeof (GskStandardOperation) * n_ops); self->n_points = n_points; self->points = (graphene_point_t *) &self->ops[n_ops]; memcpy (self->points, points, sizeof (graphene_point_t) * n_points); + + offset += self->points - points; + for (i = 0; i < n_ops; i++) + { + self->ops[i] = gsk_pathop_encode (gsk_pathop_op (ops[i]), + gsk_pathop_points (ops[i]) + offset); + } } GskContour * -gsk_standard_contour_new (GskPathFlags flags, - const GskStandardOperation *ops, - gsize n_ops, - const graphene_point_t *points, - gsize n_points) +gsk_standard_contour_new (GskPathFlags flags, + const graphene_point_t *points, + gsize n_points, + const gskpathop *ops, + gsize n_ops, + gssize offset) { GskContour *contour; contour = g_malloc0 (gsk_standard_contour_compute_size (n_ops, n_points)); - gsk_standard_contour_init (contour, flags, ops, n_ops, points, n_points); + gsk_standard_contour_init (contour, flags, points, n_points, ops, n_ops, offset); return contour; } diff --git a/gsk/gskcontourprivate.h b/gsk/gskcontourprivate.h index 13e54a8e5d..bce0689d17 100644 --- a/gsk/gskcontourprivate.h +++ b/gsk/gskcontourprivate.h @@ -23,6 +23,8 @@ #include +#include "gskpathopprivate.h" + G_BEGIN_DECLS typedef enum @@ -33,23 +35,17 @@ typedef enum typedef struct _GskContour GskContour; -typedef struct _GskStandardOperation GskStandardOperation; - -struct _GskStandardOperation { - GskPathOperation op; - gsize point; /* index into points array of the start point (last point of previous op) */ -}; - GskContour * gsk_rect_contour_new (const graphene_rect_t *rect); GskContour * gsk_circle_contour_new (const graphene_point_t *center, float radius, float start_angle, float end_angle); GskContour * gsk_standard_contour_new (GskPathFlags flags, - const GskStandardOperation *ops, + const graphene_point_t *points, + gsize n_points, + const gskpathop *ops, gsize n_ops, - const graphene_point_t *points, - gsize n_points); + gssize offset); void gsk_contour_copy (GskContour * dest, const GskContour *src); diff --git a/gsk/gskpathbuilder.c b/gsk/gskpathbuilder.c index a28898159f..c5e9533686 100644 --- a/gsk/gskpathbuilder.c +++ b/gsk/gskpathbuilder.c @@ -105,7 +105,7 @@ gsk_path_builder_new (void) builder = g_slice_new0 (GskPathBuilder); builder->ref_count = 1; - builder->ops = g_array_new (FALSE, FALSE, sizeof (GskStandardOperation)); + builder->ops = g_array_new (FALSE, FALSE, sizeof (gskpathop)); builder->points = g_array_new (FALSE, FALSE, sizeof (graphene_point_t)); /* Be explicit here */ @@ -137,6 +137,19 @@ gsk_path_builder_ref (GskPathBuilder *builder) return builder; } +/* We're cheating here. Out pathops are relative to the NULL pointer, + * so that we can not care about the points GArray reallocating itself + * until we create the contour. + * This does however mean that we need to not use gsk_pathop_get_points() + * without offsetting the returned pointer. + */ +static inline gskpathop +gsk_pathop_encode_index (GskPathOperation op, + gsize index) +{ + return gsk_pathop_encode (op, ((graphene_point_t *) NULL) + index); +} + static void gsk_path_builder_ensure_current (GskPathBuilder *builder) { @@ -144,7 +157,7 @@ gsk_path_builder_ensure_current (GskPathBuilder *builder) return; builder->flags = GSK_PATH_FLAT; - g_array_append_vals (builder->ops, &(GskStandardOperation) { GSK_PATH_MOVE, 0 }, 1); + g_array_append_vals (builder->ops, (gskpathop[1]) { gsk_pathop_encode_index (GSK_PATH_MOVE, 0) }, 1); g_array_append_val (builder->points, builder->current_point); } @@ -156,7 +169,7 @@ gsk_path_builder_append_current (GskPathBuilder *builder, { gsk_path_builder_ensure_current (builder); - g_array_append_vals (builder->ops, &(GskStandardOperation) { op, builder->points->len - 1 }, 1); + g_array_append_vals (builder->ops, (gskpathop[1]) { gsk_pathop_encode_index (op, builder->points->len - 1) }, 1); g_array_append_vals (builder->points, points, n_points); builder->current_point = points[n_points - 1]; @@ -171,10 +184,11 @@ gsk_path_builder_end_current (GskPathBuilder *builder) return; contour = gsk_standard_contour_new (builder->flags, - (GskStandardOperation *) builder->ops->data, - builder->ops->len, (graphene_point_t *) builder->points->data, - builder->points->len); + builder->points->len, + (gskpathop *) builder->ops->data, + builder->ops->len, + (graphene_point_t *) builder->points->data - (graphene_point_t *) NULL); g_array_set_size (builder->ops, 0); g_array_set_size (builder->points, 0); diff --git a/gsk/gskpathopprivate.h b/gsk/gskpathopprivate.h new file mode 100644 index 0000000000..864e97e2ea --- /dev/null +++ b/gsk/gskpathopprivate.h @@ -0,0 +1,178 @@ +/* + * Copyright © 2020 Benjamin Otte + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + * + * Authors: Benjamin Otte + */ + + +#ifndef __GSK_PATHOP_PRIVATE_H__ +#define __GSK_PATHOP_PRIVATE_H__ + +#include +#include + +G_BEGIN_DECLS + +typedef gpointer gskpathop; + +static inline +gskpathop gsk_pathop_encode (GskPathOperation op, + const graphene_point_t *pts); +static inline +const graphene_point_t *gsk_pathop_points (gskpathop pop); +static inline +GskPathOperation gsk_pathop_op (gskpathop pop); + +static inline +gboolean gsk_pathop_foreach (gskpathop pop, + GskPathForeachFunc func, + gpointer user_data); + +/* included inline so tests can use them */ +static inline +void gsk_path_builder_pathop_to (GskPathBuilder *builder, + gskpathop op); +static inline +void gsk_path_builder_pathop_reverse_to (GskPathBuilder *builder, + gskpathop op); + +/* IMPLEMENTATION */ + +#define GSK_PATHOP_OPERATION_MASK (0x7) + +static inline gskpathop +gsk_pathop_encode (GskPathOperation op, + const graphene_point_t *pts) +{ + /* g_assert (op & GSK_PATHOP_OPERATION_MASK == op); */ + + return GSIZE_TO_POINTER (GPOINTER_TO_SIZE (pts) | op); +} + +static inline const graphene_point_t * +gsk_pathop_points (gskpathop pop) +{ + return GSIZE_TO_POINTER (GPOINTER_TO_SIZE (pop) & ~GSK_PATHOP_OPERATION_MASK); +} + +static inline +GskPathOperation gsk_pathop_op (gskpathop pop) +{ + return GPOINTER_TO_SIZE (pop) & GSK_PATHOP_OPERATION_MASK; +} + +static inline gboolean +gsk_pathop_foreach (gskpathop pop, + GskPathForeachFunc func, + gpointer user_data) +{ + switch (gsk_pathop_op (pop)) + { + case GSK_PATH_MOVE: + return func (gsk_pathop_op (pop), gsk_pathop_points (pop), 1, 0, user_data); + + case GSK_PATH_CLOSE: + case GSK_PATH_LINE: + return func (gsk_pathop_op (pop), gsk_pathop_points (pop), 2, 0, user_data); + + case GSK_PATH_CURVE: + return func (gsk_pathop_op (pop), gsk_pathop_points (pop), 4, 0, 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); + } + + default: + g_assert_not_reached (); + return TRUE; + } +} + +static inline void +gsk_path_builder_pathop_to (GskPathBuilder *builder, + gskpathop op) +{ + const graphene_point_t *pts = gsk_pathop_points (op); + + switch (gsk_pathop_op (op)) + { + case GSK_PATH_MOVE: + gsk_path_builder_move_to (builder, pts[0].x, pts[0].y); + break; + + case GSK_PATH_CLOSE: + gsk_path_builder_close (builder); + 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, pts[2].x); + break; + + default: + g_assert_not_reached (); + break; + } +} + +static inline void +gsk_path_builder_pathop_reverse_to (GskPathBuilder *builder, + gskpathop op) +{ + const graphene_point_t *pts = gsk_pathop_points (op); + + switch (gsk_pathop_op (op)) + { + case GSK_PATH_MOVE: + gsk_path_builder_move_to (builder, pts[0].x, pts[0].y); + break; + + case GSK_PATH_CLOSE: + gsk_path_builder_line_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[2].x, pts[2].y, pts[1].x, pts[1].y, pts[0].x, pts[0].y); + break; + + case GSK_PATH_CONIC: + gsk_path_builder_conic_to (builder, pts[1].x, pts[1].y, pts[0].x, pts[0].y, pts[2].x); + break; + + default: + g_assert_not_reached (); + break; + } +} + + +G_END_DECLS + +#endif /* __GSK_PATHOP_PRIVATE_H__ */ +