path: Split GskPathBuilder into its own file
... and add missing API docs.
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
#include <gsk/gskenums.h>
|
||||
#include <gsk/gskglshader.h>
|
||||
#include <gsk/gskpath.h>
|
||||
#include <gsk/gskpathbuilder.h>
|
||||
#include <gsk/gskpathmeasure.h>
|
||||
#include <gsk/gskrenderer.h>
|
||||
#include <gsk/gskrendernode.h>
|
||||
|
||||
630
gsk/gskpath.c
630
gsk/gskpath.c
@@ -21,13 +21,14 @@
|
||||
|
||||
#include "gskpathprivate.h"
|
||||
|
||||
#include "gskpathbuilder.h"
|
||||
#include "gsksplineprivate.h"
|
||||
|
||||
/**
|
||||
* SECTION:gskpath
|
||||
* @Title: Path
|
||||
* @Short_description: Lines and Curves
|
||||
* @See_also: #GskRenderNode
|
||||
* @See_also: #GskRenderNode, #GskPathBuilder
|
||||
*
|
||||
* This section describes the #GskPath structure that is used to
|
||||
* describe lines and curves that are more complex than simple rectangles.
|
||||
@@ -37,15 +38,6 @@
|
||||
* The #GskPathBuilder structure is meant to help in this endeavor.
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GSK_PATH_FLAT,
|
||||
GSK_PATH_CLOSED
|
||||
} GskPathFlags;
|
||||
|
||||
typedef struct _GskContour GskContour;
|
||||
typedef struct _GskContourClass GskContourClass;
|
||||
|
||||
struct _GskContour
|
||||
{
|
||||
const GskContourClass *klass;
|
||||
@@ -123,10 +115,6 @@ gsk_contour_get_size_default (const GskContour *contour)
|
||||
return contour->klass->struct_size;
|
||||
}
|
||||
|
||||
static GskContour *
|
||||
gsk_path_builder_add_contour_by_klass (GskPathBuilder *builder,
|
||||
const GskContourClass *klass);
|
||||
|
||||
static void
|
||||
gsk_find_point_on_line (const graphene_point_t *a,
|
||||
const graphene_point_t *b,
|
||||
@@ -492,20 +480,21 @@ static const GskContourClass GSK_RECT_CONTOUR_CLASS =
|
||||
gsk_rect_contour_add_segment
|
||||
};
|
||||
|
||||
static void
|
||||
gsk_rect_contour_init (GskContour *contour,
|
||||
float x,
|
||||
float y,
|
||||
float width,
|
||||
float height)
|
||||
GskContour *
|
||||
gsk_rect_contour_new (const graphene_rect_t *rect)
|
||||
{
|
||||
GskRectContour *self = (GskRectContour *) contour;
|
||||
GskRectContour *self;
|
||||
|
||||
self = g_new0 (GskRectContour, 1);
|
||||
|
||||
self->contour.klass = &GSK_RECT_CONTOUR_CLASS;
|
||||
self->x = x;
|
||||
self->y = y;
|
||||
self->width = width;
|
||||
self->height = height;
|
||||
|
||||
self->x = rect->origin.x;
|
||||
self->y = rect->origin.y;
|
||||
self->width = rect->size.width;
|
||||
self->height = rect->size.height;
|
||||
|
||||
return (GskContour *) self;
|
||||
}
|
||||
|
||||
/* CIRCLE CONTOUR */
|
||||
@@ -740,13 +729,6 @@ gsk_circle_contour_copy (const GskContour *contour,
|
||||
*target = *self;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_circle_contour_init (GskContour *contour,
|
||||
const graphene_point_t *center,
|
||||
float radius,
|
||||
float start_angle,
|
||||
float end_angle);
|
||||
|
||||
static void
|
||||
gsk_circle_contour_add_segment (const GskContour *contour,
|
||||
GskPathBuilder *builder,
|
||||
@@ -759,12 +741,10 @@ gsk_circle_contour_add_segment (const GskContour *contour,
|
||||
float length = self->radius * DEG_TO_RAD (delta);
|
||||
GskContour *segment;
|
||||
|
||||
segment = gsk_path_builder_add_contour_by_klass (builder, contour->klass);
|
||||
|
||||
gsk_circle_contour_init (segment,
|
||||
&self->center, self->radius,
|
||||
self->start_angle + start/length * delta,
|
||||
self->start_angle + end/length * delta);
|
||||
segment = gsk_circle_contour_new (&self->center, self->radius,
|
||||
self->start_angle + start/length * delta,
|
||||
self->start_angle + end/length * delta);
|
||||
gsk_path_builder_add_contour (builder, segment);
|
||||
}
|
||||
|
||||
static const GskContourClass GSK_CIRCLE_CONTOUR_CLASS =
|
||||
@@ -784,14 +764,17 @@ static const GskContourClass GSK_CIRCLE_CONTOUR_CLASS =
|
||||
gsk_circle_contour_add_segment
|
||||
};
|
||||
|
||||
static void
|
||||
gsk_circle_contour_init (GskContour *contour,
|
||||
const graphene_point_t *center,
|
||||
float radius,
|
||||
float start_angle,
|
||||
float end_angle)
|
||||
GskContour *
|
||||
gsk_circle_contour_new (const graphene_point_t *center,
|
||||
float radius,
|
||||
float start_angle,
|
||||
float end_angle)
|
||||
{
|
||||
GskCircleContour *self = (GskCircleContour *) contour;
|
||||
GskCircleContour *self;
|
||||
|
||||
self = g_new0 (GskCircleContour, 1);
|
||||
|
||||
self->contour.klass = &GSK_CIRCLE_CONTOUR_CLASS;
|
||||
|
||||
g_assert (fabs (start_angle - end_angle) <= 360);
|
||||
|
||||
@@ -800,17 +783,12 @@ gsk_circle_contour_init (GskContour *contour,
|
||||
self->radius = radius;
|
||||
self->start_angle = start_angle;
|
||||
self->end_angle = end_angle;
|
||||
|
||||
return (GskContour *) self;
|
||||
}
|
||||
|
||||
/* STANDARD CONTOUR */
|
||||
|
||||
typedef struct _GskStandardOperation GskStandardOperation;
|
||||
|
||||
struct _GskStandardOperation {
|
||||
GskPathOperation op;
|
||||
gsize point; /* index into points array of the start point (last point of previous op) */
|
||||
};
|
||||
|
||||
typedef struct _GskStandardContour GskStandardContour;
|
||||
struct _GskStandardContour
|
||||
{
|
||||
@@ -1430,12 +1408,12 @@ 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 GskStandardOperation *ops,
|
||||
gsize n_ops,
|
||||
const graphene_point_t *points,
|
||||
gsize n_points)
|
||||
{
|
||||
GskStandardContour *self = (GskStandardContour *) contour;
|
||||
|
||||
@@ -1449,6 +1427,22 @@ gsk_standard_contour_init (GskContour *contour,
|
||||
memcpy (self->points, points, sizeof (graphene_point_t) * n_points);
|
||||
}
|
||||
|
||||
GskContour *
|
||||
gsk_standard_contour_new (GskPathFlags flags,
|
||||
const GskStandardOperation *ops,
|
||||
gsize n_ops,
|
||||
const graphene_point_t *points,
|
||||
gsize n_points)
|
||||
{
|
||||
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);
|
||||
|
||||
return contour;
|
||||
}
|
||||
|
||||
/* CONTOUR */
|
||||
|
||||
static gsize
|
||||
@@ -1457,24 +1451,6 @@ gsk_contour_get_size (const GskContour *contour)
|
||||
return contour->klass->get_size (contour);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_contour_copy (GskContour *dest,
|
||||
const GskContour *src)
|
||||
{
|
||||
src->klass->copy (src, dest);
|
||||
}
|
||||
|
||||
static GskContour *
|
||||
gsk_contour_dup (const GskContour *src)
|
||||
{
|
||||
GskContour *copy;
|
||||
|
||||
copy = g_malloc0 (gsk_contour_get_size (src));
|
||||
gsk_contour_copy (copy, src);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_contour_foreach (const GskContour *contour,
|
||||
float tolerance,
|
||||
@@ -1543,18 +1519,78 @@ gsk_contour_get_closest_point (GskPath *path,
|
||||
out_tangent);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_contour_add_segment (const GskContour *self,
|
||||
GskPathBuilder *builder,
|
||||
gpointer measure_data,
|
||||
float start,
|
||||
float end)
|
||||
{
|
||||
self->klass->add_segment (self, builder, measure_data, start, end);
|
||||
}
|
||||
|
||||
static inline void
|
||||
gsk_contour_copy (GskContour *dest,
|
||||
const GskContour *src)
|
||||
{
|
||||
src->klass->copy (src, dest);
|
||||
}
|
||||
|
||||
GskContour *
|
||||
gsk_contour_dup (const GskContour *src)
|
||||
{
|
||||
GskContour *copy;
|
||||
|
||||
copy = g_malloc0 (gsk_contour_get_size (src));
|
||||
gsk_contour_copy (copy, src);
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
/* PATH */
|
||||
|
||||
static GskPath *
|
||||
gsk_path_alloc (gsize extra_size)
|
||||
GskPath *
|
||||
gsk_path_new_from_contours (const GSList *contours)
|
||||
{
|
||||
GskPath *self;
|
||||
GskPath *path;
|
||||
const GSList *l;
|
||||
gsize size;
|
||||
gsize n_contours;
|
||||
guint8 *contour_data;
|
||||
GskPathFlags flags;
|
||||
|
||||
self = g_malloc0 (sizeof (GskPath) + extra_size);
|
||||
self->ref_count = 1;
|
||||
self->n_contours = 0;
|
||||
flags = GSK_PATH_CLOSED | GSK_PATH_FLAT;
|
||||
size = 0;
|
||||
n_contours = 0;
|
||||
for (l = contours; l; l = l->next)
|
||||
{
|
||||
GskContour *contour = l->data;
|
||||
|
||||
return self;
|
||||
n_contours++;
|
||||
size += sizeof (GskContour *);
|
||||
size += gsk_contour_get_size (contour);
|
||||
flags &= contour->klass->get_flags (contour);
|
||||
}
|
||||
|
||||
path = g_malloc0 (sizeof (GskPath) + size);
|
||||
path->ref_count = 1;
|
||||
path->flags = flags;
|
||||
path->n_contours = n_contours;
|
||||
contour_data = (guint8 *) &path->contours[n_contours];
|
||||
n_contours = 0;
|
||||
|
||||
for (l = contours; l; l = l->next)
|
||||
{
|
||||
GskContour *contour = l->data;
|
||||
|
||||
path->contours[n_contours] = (GskContour *) contour_data;
|
||||
gsk_contour_copy ((GskContour *) contour_data, contour);
|
||||
size = gsk_contour_get_size (contour);
|
||||
contour_data += size;
|
||||
n_contours++;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1649,6 +1685,13 @@ gsk_path_unref (GskPath *self)
|
||||
g_free (self);
|
||||
}
|
||||
|
||||
const GskContour *
|
||||
gsk_path_get_contour (GskPath *path,
|
||||
gsize i)
|
||||
{
|
||||
return path->contours[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_print:
|
||||
* @self: a #GskPath
|
||||
@@ -1880,424 +1923,3 @@ gsk_path_foreach_with_tolerance (GskPath *self,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* BUILDER */
|
||||
|
||||
/**
|
||||
* GskPathBuilder:
|
||||
*
|
||||
* A #GskPathBuilder struct is an opaque struct. It is meant to
|
||||
* not be kept around and only be used to create new #GskPath
|
||||
* objects.
|
||||
*/
|
||||
|
||||
struct _GskPathBuilder
|
||||
{
|
||||
int ref_count;
|
||||
|
||||
GSList *contours; /* (reverse) list of already recorded contours */
|
||||
|
||||
GskPathFlags flags; /* flags for the current path */
|
||||
GArray *ops; /* operations for current contour - size == 0 means no current contour */
|
||||
GArray *points; /* points for the operations */
|
||||
};
|
||||
|
||||
G_DEFINE_BOXED_TYPE (GskPathBuilder,
|
||||
gsk_path_builder,
|
||||
gsk_path_builder_ref,
|
||||
gsk_path_builder_unref)
|
||||
|
||||
|
||||
void
|
||||
gsk_path_builder_add_contour (GskPathBuilder *builder,
|
||||
GskPath *path,
|
||||
gsize i)
|
||||
{
|
||||
GskContour *copy;
|
||||
|
||||
copy = gsk_contour_dup (path->contours[i]);
|
||||
builder->contours = g_slist_prepend (builder->contours, copy);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_path_builder_add_contour_segment (GskPathBuilder *builder,
|
||||
GskPath *path,
|
||||
gsize i,
|
||||
gpointer measure_data,
|
||||
float start,
|
||||
float end)
|
||||
{
|
||||
const GskContour *self = path->contours[i];
|
||||
|
||||
self->klass->add_segment (self, builder, measure_data, start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_builder_new:
|
||||
*
|
||||
* Create a new #GskPathBuilder object. The resulting builder
|
||||
* would create an empty #GskPath. Use addition functions to add
|
||||
* types to it.
|
||||
*
|
||||
* Returns: a new #GskPathBuilder
|
||||
**/
|
||||
GskPathBuilder *
|
||||
gsk_path_builder_new (void)
|
||||
{
|
||||
GskPathBuilder *builder;
|
||||
|
||||
builder = g_slice_new0 (GskPathBuilder);
|
||||
builder->ref_count = 1;
|
||||
|
||||
builder->ops = g_array_new (FALSE, FALSE, sizeof (GskStandardOperation));
|
||||
builder->points = g_array_new (FALSE, FALSE, sizeof (graphene_point_t));
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_builder_ref:
|
||||
* @builder: a #GskPathBuilder
|
||||
*
|
||||
* Acquires a reference on the given @builder.
|
||||
*
|
||||
* This function is intended primarily for bindings. #GskPathBuilder objects
|
||||
* should not be kept around.
|
||||
*
|
||||
* Returns: (transfer none): the given #GskPathBuilder with
|
||||
* its reference count increased
|
||||
*/
|
||||
GskPathBuilder *
|
||||
gsk_path_builder_ref (GskPathBuilder *builder)
|
||||
{
|
||||
g_return_val_if_fail (builder != NULL, NULL);
|
||||
g_return_val_if_fail (builder->ref_count > 0, NULL);
|
||||
|
||||
builder->ref_count += 1;
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_path_builder_append_current (GskPathBuilder *builder,
|
||||
GskPathOperation op,
|
||||
gsize n_points,
|
||||
const graphene_point_t *points)
|
||||
{
|
||||
g_assert (builder->ops->len > 0);
|
||||
g_assert (builder->points->len > 0);
|
||||
g_assert (n_points > 0);
|
||||
|
||||
g_array_append_vals (builder->ops, &(GskStandardOperation) { op, builder->points->len - 1 }, 1);
|
||||
g_array_append_vals (builder->points, points, n_points);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_path_builder_end_current (GskPathBuilder *builder)
|
||||
{
|
||||
GskContour *contour;
|
||||
|
||||
if (builder->ops->len == 0)
|
||||
return;
|
||||
|
||||
contour = g_malloc0 (gsk_standard_contour_compute_size (builder->ops->len, builder->points->len));
|
||||
gsk_standard_contour_init (contour,
|
||||
0,
|
||||
(GskStandardOperation *) builder->ops->data,
|
||||
builder->ops->len,
|
||||
(graphene_point_t *) builder->points->data,
|
||||
builder->points->len);
|
||||
builder->contours = g_slist_prepend (builder->contours, contour);
|
||||
|
||||
g_array_set_size (builder->ops, 0);
|
||||
g_array_set_size (builder->points, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_path_builder_clear (GskPathBuilder *builder)
|
||||
{
|
||||
gsk_path_builder_end_current (builder);
|
||||
|
||||
g_slist_free_full (builder->contours, g_free);
|
||||
builder->contours = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_builder_unref:
|
||||
* @builder: a #GskPathBuilder
|
||||
*
|
||||
* Releases a reference on the given @builder.
|
||||
*/
|
||||
void
|
||||
gsk_path_builder_unref (GskPathBuilder *builder)
|
||||
{
|
||||
g_return_if_fail (builder != NULL);
|
||||
g_return_if_fail (builder->ref_count > 0);
|
||||
|
||||
builder->ref_count -= 1;
|
||||
|
||||
if (builder->ref_count > 0)
|
||||
return;
|
||||
|
||||
gsk_path_builder_clear (builder);
|
||||
g_array_unref (builder->ops);
|
||||
g_array_unref (builder->points);
|
||||
g_slice_free (GskPathBuilder, builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_builder_free_to_path: (skip)
|
||||
* @builder: a #GskPathBuilder
|
||||
*
|
||||
* Creates a new #GskPath from the current state of the
|
||||
* given @builder, and frees the @builder instance.
|
||||
*
|
||||
* Returns: (transfer full): the newly created #GskPath
|
||||
* with all the contours added to @builder
|
||||
*/
|
||||
GskPath *
|
||||
gsk_path_builder_free_to_path (GskPathBuilder *builder)
|
||||
{
|
||||
GskPath *res;
|
||||
|
||||
g_return_val_if_fail (builder != NULL, NULL);
|
||||
|
||||
res = gsk_path_builder_to_path (builder);
|
||||
|
||||
gsk_path_builder_unref (builder);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_builder_to_path:
|
||||
* @builder: a #GskPathBuilder
|
||||
*
|
||||
* Creates a new #GskPath from the given @builder.
|
||||
*
|
||||
* The given #GskPathBuilder is reset once this function returns;
|
||||
* you cannot call this function multiple times on the same @builder instance.
|
||||
*
|
||||
* This function is intended primarily for bindings. C code should use
|
||||
* gsk_path_builder_free_to_path().
|
||||
*
|
||||
* Returns: (transfer full): the newly created #GskPath
|
||||
* with all the contours added to @builder
|
||||
*/
|
||||
GskPath *
|
||||
gsk_path_builder_to_path (GskPathBuilder *builder)
|
||||
{
|
||||
GskPath *path;
|
||||
GSList *l;
|
||||
gsize size;
|
||||
gsize n_contours;
|
||||
guint8 *contour_data;
|
||||
GskPathFlags flags;
|
||||
|
||||
g_return_val_if_fail (builder != NULL, NULL);
|
||||
|
||||
gsk_path_builder_end_current (builder);
|
||||
|
||||
builder->contours = g_slist_reverse (builder->contours);
|
||||
flags = GSK_PATH_CLOSED | GSK_PATH_FLAT;
|
||||
size = 0;
|
||||
n_contours = 0;
|
||||
for (l = builder->contours; l; l = l->next)
|
||||
{
|
||||
GskContour *contour = l->data;
|
||||
|
||||
n_contours++;
|
||||
size += sizeof (GskContour *);
|
||||
size += gsk_contour_get_size (contour);
|
||||
flags &= contour->klass->get_flags (contour);
|
||||
}
|
||||
|
||||
path = gsk_path_alloc (size);
|
||||
path->flags = flags;
|
||||
path->n_contours = n_contours;
|
||||
contour_data = (guint8 *) &path->contours[n_contours];
|
||||
n_contours = 0;
|
||||
|
||||
for (l = builder->contours; l; l = l->next)
|
||||
{
|
||||
GskContour *contour = l->data;
|
||||
|
||||
path->contours[n_contours] = (GskContour *) contour_data;
|
||||
gsk_contour_copy ((GskContour *) contour_data, contour);
|
||||
size = gsk_contour_get_size (contour);
|
||||
contour_data += size;
|
||||
n_contours++;
|
||||
}
|
||||
|
||||
gsk_path_builder_clear (builder);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_builder_add_path:
|
||||
* @builder: a #GskPathBuilder
|
||||
* @path: (transfer none): the path to append
|
||||
*
|
||||
* Appends all of @path to @builder.
|
||||
**/
|
||||
void
|
||||
gsk_path_builder_add_path (GskPathBuilder *builder,
|
||||
GskPath *path)
|
||||
{
|
||||
gsize i;
|
||||
|
||||
g_return_if_fail (builder != NULL);
|
||||
g_return_if_fail (path != NULL);
|
||||
|
||||
for (i = 0; i < path->n_contours; i++)
|
||||
{
|
||||
gsk_path_builder_add_contour (builder, path, i);
|
||||
}
|
||||
}
|
||||
|
||||
static GskContour *
|
||||
gsk_path_builder_add_contour_by_klass (GskPathBuilder *builder,
|
||||
const GskContourClass *klass)
|
||||
{
|
||||
GskContour *contour;
|
||||
|
||||
gsk_path_builder_end_current (builder);
|
||||
|
||||
contour = g_malloc0 (klass->struct_size);
|
||||
builder->contours = g_slist_prepend (builder->contours, contour);
|
||||
|
||||
return contour;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_builder_add_rect:
|
||||
* @builder: A #GskPathBuilder
|
||||
* @rect: The rectangle to create a path for
|
||||
*
|
||||
* Creates a path representing the given rectangle.
|
||||
*
|
||||
* If the width or height of the rectangle is negative, the start
|
||||
* point will be on the right or bottom, respectively.
|
||||
*
|
||||
* If the the width or height are 0, the path will be a closed
|
||||
* horizontal or vertical line. If both are 0, it'll be a closed dot.
|
||||
*
|
||||
* Returns: a new #GskPath representing a rectangle
|
||||
**/
|
||||
void
|
||||
gsk_path_builder_add_rect (GskPathBuilder *builder,
|
||||
const graphene_rect_t *rect)
|
||||
{
|
||||
GskContour *contour;
|
||||
|
||||
g_return_if_fail (builder != NULL);
|
||||
|
||||
contour = gsk_path_builder_add_contour_by_klass (builder, &GSK_RECT_CONTOUR_CLASS);
|
||||
gsk_rect_contour_init (contour,
|
||||
rect->origin.x, rect->origin.y,
|
||||
rect->size.width, rect->size.height);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_builder_add_circle:
|
||||
* @builder: a #GskPathBuilder
|
||||
* @center: the center of the circle
|
||||
* @radius: the radius of the circle
|
||||
*
|
||||
* Adds a circle with the @center and @radius.
|
||||
**/
|
||||
void
|
||||
gsk_path_builder_add_circle (GskPathBuilder *builder,
|
||||
const graphene_point_t *center,
|
||||
float radius)
|
||||
{
|
||||
GskContour *contour;
|
||||
|
||||
g_return_if_fail (builder != NULL);
|
||||
g_return_if_fail (center != NULL);
|
||||
g_return_if_fail (radius > 0);
|
||||
|
||||
contour = gsk_path_builder_add_contour_by_klass (builder, &GSK_CIRCLE_CONTOUR_CLASS);
|
||||
gsk_circle_contour_init (contour, center, radius, 0, 360);
|
||||
}
|
||||
|
||||
void
|
||||
gsk_path_builder_move_to (GskPathBuilder *builder,
|
||||
float x,
|
||||
float y)
|
||||
{
|
||||
g_return_if_fail (builder != NULL);
|
||||
|
||||
gsk_path_builder_end_current (builder);
|
||||
|
||||
builder->flags = GSK_PATH_FLAT;
|
||||
g_array_append_vals (builder->ops, &(GskStandardOperation) { GSK_PATH_MOVE, 0 }, 1);
|
||||
g_array_append_val (builder->points, GRAPHENE_POINT_INIT(x, y));
|
||||
}
|
||||
|
||||
void
|
||||
gsk_path_builder_line_to (GskPathBuilder *builder,
|
||||
float x,
|
||||
float y)
|
||||
{
|
||||
g_return_if_fail (builder != NULL);
|
||||
|
||||
if (builder->ops->len == 0)
|
||||
{
|
||||
gsk_path_builder_move_to (builder, x, y);
|
||||
return;
|
||||
}
|
||||
|
||||
/* skip the line if it goes to the same point */
|
||||
if (graphene_point_equal (&g_array_index (builder->points, graphene_point_t, builder->points->len - 1),
|
||||
&GRAPHENE_POINT_INIT (x, y)))
|
||||
return;
|
||||
|
||||
gsk_path_builder_append_current (builder,
|
||||
GSK_PATH_LINE,
|
||||
1, (graphene_point_t[1]) {
|
||||
GRAPHENE_POINT_INIT (x, y)
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
gsk_path_builder_curve_to (GskPathBuilder *builder,
|
||||
float x1,
|
||||
float y1,
|
||||
float x2,
|
||||
float y2,
|
||||
float x3,
|
||||
float y3)
|
||||
{
|
||||
g_return_if_fail (builder != NULL);
|
||||
|
||||
if (builder->ops->len == 0)
|
||||
gsk_path_builder_move_to (builder, x1, y1);
|
||||
|
||||
builder->flags ^= ~GSK_PATH_FLAT;
|
||||
gsk_path_builder_append_current (builder,
|
||||
GSK_PATH_CURVE,
|
||||
3, (graphene_point_t[3]) {
|
||||
GRAPHENE_POINT_INIT (x1, y1),
|
||||
GRAPHENE_POINT_INIT (x2, y2),
|
||||
GRAPHENE_POINT_INIT (x3, y3)
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
gsk_path_builder_close (GskPathBuilder *builder)
|
||||
{
|
||||
g_return_if_fail (builder != NULL);
|
||||
|
||||
if (builder->ops->len == 0)
|
||||
return;
|
||||
|
||||
builder->flags |= GSK_PATH_CLOSED;
|
||||
gsk_path_builder_append_current (builder,
|
||||
GSK_PATH_CLOSE,
|
||||
1, (graphene_point_t[1]) {
|
||||
g_array_index (builder->points, graphene_point_t, 0)
|
||||
});
|
||||
|
||||
gsk_path_builder_end_current (builder);
|
||||
}
|
||||
|
||||
|
||||
@@ -79,54 +79,6 @@ gboolean gsk_path_foreach (GskPath
|
||||
GskPathForeachFunc func,
|
||||
gpointer user_data);
|
||||
|
||||
#define GSK_TYPE_PATH_BUILDER (gsk_path_builder_get_type ())
|
||||
|
||||
typedef struct _GskPathBuilder GskPathBuilder;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gsk_path_builder_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPathBuilder * gsk_path_builder_new (void);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPathBuilder * gsk_path_builder_ref (GskPathBuilder *builder);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_unref (GskPathBuilder *builder);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPath * gsk_path_builder_free_to_path (GskPathBuilder *builder) G_GNUC_WARN_UNUSED_RESULT;
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPath * gsk_path_builder_to_path (GskPathBuilder *builder) G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_add_path (GskPathBuilder *builder,
|
||||
GskPath *path);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_add_rect (GskPathBuilder *builder,
|
||||
const graphene_rect_t *rect);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_add_circle (GskPathBuilder *builder,
|
||||
const graphene_point_t *center,
|
||||
float radius);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_move_to (GskPathBuilder *builder,
|
||||
float x,
|
||||
float y);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_line_to (GskPathBuilder *builder,
|
||||
float x,
|
||||
float y);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_curve_to (GskPathBuilder *builder,
|
||||
float x1,
|
||||
float y1,
|
||||
float x2,
|
||||
float y2,
|
||||
float x3,
|
||||
float y3);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_close (GskPathBuilder *builder);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_PATH_H__ */
|
||||
|
||||
469
gsk/gskpathbuilder.c
Normal file
469
gsk/gskpathbuilder.c
Normal file
@@ -0,0 +1,469 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gskpathbuilder.h"
|
||||
|
||||
#include "gskpathprivate.h"
|
||||
|
||||
/**
|
||||
* SECTION:gskpathbuilder
|
||||
* @Title: Building paths
|
||||
* @Short_description: Building paths of lines and curves
|
||||
* @See_also: #GskPath, #GskPathMeasure
|
||||
*
|
||||
* This section describes how to construct #GskPath structures.
|
||||
*
|
||||
* A path is constructed like this:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* GskPath *
|
||||
* construct_path (void)
|
||||
* {
|
||||
* GskPathBuilder *builder;
|
||||
*
|
||||
* builder = gsk_path_builder_new ();
|
||||
*
|
||||
* // add contours to the path here
|
||||
*
|
||||
* return gsk_path_builder_free_to_path (builder);
|
||||
* ]|
|
||||
*
|
||||
* Adding contours to the path can be done in two ways.
|
||||
* The easiest option is to use the `gsk_path_builder_add_*` group
|
||||
* of functions that add predefined contours to the current path,
|
||||
* either common shapes like gsk_path_builder_add_circle()
|
||||
* or by adding from other paths like gsk_path_builder_add_path().
|
||||
*
|
||||
* The other option is to define each line and curve manually with
|
||||
* the `gsk_path_builder_*_to` group of functions. You start with
|
||||
* a call to gsk_path_builder_move_to() to set the starting point
|
||||
* and then use multiple calls to any of the drawing functions to
|
||||
* move the pen along the plane. Once you are done, you can call
|
||||
* gsk_path_builder_close() to close the path by connecting it
|
||||
* back with a line to the starting point.
|
||||
* This is similar for how paths are drawn in Cairo.
|
||||
*/
|
||||
|
||||
/**
|
||||
* GskPathBuilder:
|
||||
*
|
||||
* A #GskPathBuilder struct is an opaque struct. It is meant to
|
||||
* not be kept around and only be used to create new #GskPath
|
||||
* objects.
|
||||
*/
|
||||
|
||||
struct _GskPathBuilder
|
||||
{
|
||||
int ref_count;
|
||||
|
||||
GSList *contours; /* (reverse) list of already recorded contours */
|
||||
|
||||
GskPathFlags flags; /* flags for the current path */
|
||||
GArray *ops; /* operations for current contour - size == 0 means no current contour */
|
||||
GArray *points; /* points for the operations */
|
||||
};
|
||||
|
||||
G_DEFINE_BOXED_TYPE (GskPathBuilder,
|
||||
gsk_path_builder,
|
||||
gsk_path_builder_ref,
|
||||
gsk_path_builder_unref)
|
||||
|
||||
|
||||
/**
|
||||
* gsk_path_builder_new:
|
||||
*
|
||||
* Create a new #GskPathBuilder object. The resulting builder
|
||||
* would create an empty #GskPath. Use addition functions to add
|
||||
* types to it.
|
||||
*
|
||||
* Returns: a new #GskPathBuilder
|
||||
**/
|
||||
GskPathBuilder *
|
||||
gsk_path_builder_new (void)
|
||||
{
|
||||
GskPathBuilder *builder;
|
||||
|
||||
builder = g_slice_new0 (GskPathBuilder);
|
||||
builder->ref_count = 1;
|
||||
|
||||
builder->ops = g_array_new (FALSE, FALSE, sizeof (GskStandardOperation));
|
||||
builder->points = g_array_new (FALSE, FALSE, sizeof (graphene_point_t));
|
||||
return builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_builder_ref:
|
||||
* @builder: a #GskPathBuilder
|
||||
*
|
||||
* Acquires a reference on the given @builder.
|
||||
*
|
||||
* This function is intended primarily for bindings. #GskPathBuilder objects
|
||||
* should not be kept around.
|
||||
*
|
||||
* Returns: (transfer none): the given #GskPathBuilder with
|
||||
* its reference count increased
|
||||
*/
|
||||
GskPathBuilder *
|
||||
gsk_path_builder_ref (GskPathBuilder *builder)
|
||||
{
|
||||
g_return_val_if_fail (builder != NULL, NULL);
|
||||
g_return_val_if_fail (builder->ref_count > 0, NULL);
|
||||
|
||||
builder->ref_count += 1;
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_path_builder_append_current (GskPathBuilder *builder,
|
||||
GskPathOperation op,
|
||||
gsize n_points,
|
||||
const graphene_point_t *points)
|
||||
{
|
||||
g_assert (builder->ops->len > 0);
|
||||
g_assert (builder->points->len > 0);
|
||||
g_assert (n_points > 0);
|
||||
|
||||
g_array_append_vals (builder->ops, &(GskStandardOperation) { op, builder->points->len - 1 }, 1);
|
||||
g_array_append_vals (builder->points, points, n_points);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_path_builder_end_current (GskPathBuilder *builder)
|
||||
{
|
||||
GskContour *contour;
|
||||
|
||||
if (builder->ops->len == 0)
|
||||
return;
|
||||
|
||||
contour = gsk_standard_contour_new (builder->flags,
|
||||
(GskStandardOperation *) builder->ops->data,
|
||||
builder->ops->len,
|
||||
(graphene_point_t *) builder->points->data,
|
||||
builder->points->len);
|
||||
|
||||
g_array_set_size (builder->ops, 0);
|
||||
g_array_set_size (builder->points, 0);
|
||||
|
||||
/* do this at the end to avoid inflooping when add_contour calls back here */
|
||||
gsk_path_builder_add_contour (builder, contour);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_path_builder_clear (GskPathBuilder *builder)
|
||||
{
|
||||
gsk_path_builder_end_current (builder);
|
||||
|
||||
g_slist_free_full (builder->contours, g_free);
|
||||
builder->contours = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_builder_unref:
|
||||
* @builder: a #GskPathBuilder
|
||||
*
|
||||
* Releases a reference on the given @builder.
|
||||
*/
|
||||
void
|
||||
gsk_path_builder_unref (GskPathBuilder *builder)
|
||||
{
|
||||
g_return_if_fail (builder != NULL);
|
||||
g_return_if_fail (builder->ref_count > 0);
|
||||
|
||||
builder->ref_count -= 1;
|
||||
|
||||
if (builder->ref_count > 0)
|
||||
return;
|
||||
|
||||
gsk_path_builder_clear (builder);
|
||||
g_array_unref (builder->ops);
|
||||
g_array_unref (builder->points);
|
||||
g_slice_free (GskPathBuilder, builder);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_builder_free_to_path: (skip)
|
||||
* @builder: a #GskPathBuilder
|
||||
*
|
||||
* Creates a new #GskPath from the current state of the
|
||||
* given @builder, and frees the @builder instance.
|
||||
*
|
||||
* Returns: (transfer full): the newly created #GskPath
|
||||
* with all the contours added to @builder
|
||||
*/
|
||||
GskPath *
|
||||
gsk_path_builder_free_to_path (GskPathBuilder *builder)
|
||||
{
|
||||
GskPath *res;
|
||||
|
||||
g_return_val_if_fail (builder != NULL, NULL);
|
||||
|
||||
res = gsk_path_builder_to_path (builder);
|
||||
|
||||
gsk_path_builder_unref (builder);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_builder_to_path:
|
||||
* @builder: a #GskPathBuilder
|
||||
*
|
||||
* Creates a new #GskPath from the given @builder.
|
||||
*
|
||||
* The given #GskPathBuilder is reset once this function returns;
|
||||
* you cannot call this function multiple times on the same @builder instance.
|
||||
*
|
||||
* This function is intended primarily for bindings. C code should use
|
||||
* gsk_path_builder_free_to_path().
|
||||
*
|
||||
* Returns: (transfer full): the newly created #GskPath
|
||||
* with all the contours added to @builder
|
||||
*/
|
||||
GskPath *
|
||||
gsk_path_builder_to_path (GskPathBuilder *builder)
|
||||
{
|
||||
GskPath *path;
|
||||
|
||||
g_return_val_if_fail (builder != NULL, NULL);
|
||||
|
||||
gsk_path_builder_end_current (builder);
|
||||
|
||||
builder->contours = g_slist_reverse (builder->contours);
|
||||
|
||||
path = gsk_path_new_from_contours (builder->contours);
|
||||
|
||||
gsk_path_builder_clear (builder);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_path_builder_add_contour (GskPathBuilder *builder,
|
||||
GskContour *contour)
|
||||
{
|
||||
gsk_path_builder_end_current (builder);
|
||||
|
||||
builder->contours = g_slist_prepend (builder->contours, contour);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_builder_add_path:
|
||||
* @builder: a #GskPathBuilder
|
||||
* @path: (transfer none): the path to append
|
||||
*
|
||||
* Appends all of @path to @builder.
|
||||
**/
|
||||
void
|
||||
gsk_path_builder_add_path (GskPathBuilder *builder,
|
||||
GskPath *path)
|
||||
{
|
||||
gsize i;
|
||||
|
||||
g_return_if_fail (builder != NULL);
|
||||
g_return_if_fail (path != NULL);
|
||||
|
||||
for (i = 0; i < gsk_path_get_n_contours (path); i++)
|
||||
{
|
||||
const GskContour *contour = gsk_path_get_contour (path, i);
|
||||
|
||||
gsk_path_builder_add_contour (builder, gsk_contour_dup (contour));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_builder_add_rect:
|
||||
* @builder: A #GskPathBuilder
|
||||
* @rect: The rectangle to create a path for
|
||||
*
|
||||
* Creates a path representing the given rectangle.
|
||||
*
|
||||
* If the width or height of the rectangle is negative, the start
|
||||
* point will be on the right or bottom, respectively.
|
||||
*
|
||||
* If the the width or height are 0, the path will be a closed
|
||||
* horizontal or vertical line. If both are 0, it'll be a closed dot.
|
||||
*
|
||||
* Returns: a new #GskPath representing a rectangle
|
||||
**/
|
||||
void
|
||||
gsk_path_builder_add_rect (GskPathBuilder *builder,
|
||||
const graphene_rect_t *rect)
|
||||
{
|
||||
GskContour *contour;
|
||||
|
||||
g_return_if_fail (builder != NULL);
|
||||
|
||||
contour = gsk_rect_contour_new (rect);
|
||||
gsk_path_builder_add_contour (builder, contour);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_builder_add_circle:
|
||||
* @builder: a #GskPathBuilder
|
||||
* @center: the center of the circle
|
||||
* @radius: the radius of the circle
|
||||
*
|
||||
* Adds a circle with the @center and @radius.
|
||||
**/
|
||||
void
|
||||
gsk_path_builder_add_circle (GskPathBuilder *builder,
|
||||
const graphene_point_t *center,
|
||||
float radius)
|
||||
{
|
||||
GskContour *contour;
|
||||
|
||||
g_return_if_fail (builder != NULL);
|
||||
g_return_if_fail (center != NULL);
|
||||
g_return_if_fail (radius > 0);
|
||||
|
||||
contour = gsk_circle_contour_new (center, radius, 0, 360);
|
||||
gsk_path_builder_add_contour (builder, contour);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_builder_move_to:
|
||||
* @builder: a #GskPathBuilder
|
||||
* @x: x coordinate
|
||||
* @y: y coordinate
|
||||
*
|
||||
* Starts a new contour by placing the pen at @x, @y.
|
||||
*
|
||||
* If gsk_path_builder_move_to() is called twice in succession, the first
|
||||
* call will result in a contour made up of a single point. The second call
|
||||
* will start a new contour.
|
||||
**/
|
||||
void
|
||||
gsk_path_builder_move_to (GskPathBuilder *builder,
|
||||
float x,
|
||||
float y)
|
||||
{
|
||||
g_return_if_fail (builder != NULL);
|
||||
|
||||
gsk_path_builder_end_current (builder);
|
||||
|
||||
builder->flags = GSK_PATH_FLAT;
|
||||
g_array_append_vals (builder->ops, &(GskStandardOperation) { GSK_PATH_MOVE, 0 }, 1);
|
||||
g_array_append_val (builder->points, GRAPHENE_POINT_INIT(x, y));
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_builder_line_to:
|
||||
* @builder: a #GskPathBuilder
|
||||
* @x: x coordinate
|
||||
* @y: y coordinate
|
||||
*
|
||||
* Draws a line from the current point to @x, @y and makes it the new current
|
||||
* point.
|
||||
**/
|
||||
void
|
||||
gsk_path_builder_line_to (GskPathBuilder *builder,
|
||||
float x,
|
||||
float y)
|
||||
{
|
||||
g_return_if_fail (builder != NULL);
|
||||
|
||||
if (builder->ops->len == 0)
|
||||
{
|
||||
gsk_path_builder_move_to (builder, x, y);
|
||||
return;
|
||||
}
|
||||
|
||||
/* skip the line if it goes to the same point */
|
||||
if (graphene_point_equal (&g_array_index (builder->points, graphene_point_t, builder->points->len - 1),
|
||||
&GRAPHENE_POINT_INIT (x, y)))
|
||||
return;
|
||||
|
||||
gsk_path_builder_append_current (builder,
|
||||
GSK_PATH_LINE,
|
||||
1, (graphene_point_t[1]) {
|
||||
GRAPHENE_POINT_INIT (x, y)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_builder_curve_to:
|
||||
* @builder: a #GskPathBuilder
|
||||
* @x1: x coordinate of first control point
|
||||
* @y1: y coordinate of first control point
|
||||
* @x2: x coordinate of second control point
|
||||
* @y2: y coordinate of second control point
|
||||
* @x3: x coordinate of the end of the curve
|
||||
* @y3: y coordinate of the end of the curve
|
||||
*
|
||||
* Adds a cubic [Bézier curve](https://en.wikipedia.org/wiki/B%C3%A9zier_curve)
|
||||
* from the current point to @x3, @y3 with @x1, @y1 and @x2, @y2 as the control
|
||||
* point.
|
||||
**/
|
||||
void
|
||||
gsk_path_builder_curve_to (GskPathBuilder *builder,
|
||||
float x1,
|
||||
float y1,
|
||||
float x2,
|
||||
float y2,
|
||||
float x3,
|
||||
float y3)
|
||||
{
|
||||
g_return_if_fail (builder != NULL);
|
||||
|
||||
if (builder->ops->len == 0)
|
||||
gsk_path_builder_move_to (builder, x1, y1);
|
||||
|
||||
builder->flags ^= ~GSK_PATH_FLAT;
|
||||
gsk_path_builder_append_current (builder,
|
||||
GSK_PATH_CURVE,
|
||||
3, (graphene_point_t[3]) {
|
||||
GRAPHENE_POINT_INIT (x1, y1),
|
||||
GRAPHENE_POINT_INIT (x2, y2),
|
||||
GRAPHENE_POINT_INIT (x3, y3)
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_path_builder_close:
|
||||
* @builder: a #GskPathBuilder
|
||||
*
|
||||
* Ends the current contour with a line back to the start point.
|
||||
*
|
||||
* Note that this is different from calling gsk_path_builder_line_to()
|
||||
* with the start point in that the contour will be closed. A closed
|
||||
* contour behaves different from an open one when stroking its start
|
||||
* and end point are considered connected, so they will be joined
|
||||
* via the line join, and not ended with line caps.
|
||||
**/
|
||||
void
|
||||
gsk_path_builder_close (GskPathBuilder *builder)
|
||||
{
|
||||
g_return_if_fail (builder != NULL);
|
||||
|
||||
if (builder->ops->len == 0)
|
||||
return;
|
||||
|
||||
builder->flags |= GSK_PATH_CLOSED;
|
||||
gsk_path_builder_append_current (builder,
|
||||
GSK_PATH_CLOSE,
|
||||
1, (graphene_point_t[1]) {
|
||||
g_array_index (builder->points, graphene_point_t, 0)
|
||||
});
|
||||
|
||||
gsk_path_builder_end_current (builder);
|
||||
}
|
||||
|
||||
80
gsk/gskpathbuilder.h
Normal file
80
gsk/gskpathbuilder.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Authors: Benjamin Otte <otte@gnome.org>
|
||||
*/
|
||||
|
||||
#ifndef __GSK_PATH_BUILDER_H__
|
||||
#define __GSK_PATH_BUILDER_H__
|
||||
|
||||
#if !defined (__GSK_H_INSIDE__) && !defined (GTK_COMPILATION)
|
||||
#error "Only <gsk/gsk.h> can be included directly."
|
||||
#endif
|
||||
|
||||
|
||||
#include <gsk/gsktypes.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GSK_TYPE_PATH_BUILDER (gsk_path_builder_get_type ())
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gsk_path_builder_get_type (void) G_GNUC_CONST;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPathBuilder * gsk_path_builder_new (void);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPathBuilder * gsk_path_builder_ref (GskPathBuilder *builder);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_unref (GskPathBuilder *builder);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPath * gsk_path_builder_free_to_path (GskPathBuilder *builder) G_GNUC_WARN_UNUSED_RESULT;
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskPath * gsk_path_builder_to_path (GskPathBuilder *builder) G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_add_path (GskPathBuilder *builder,
|
||||
GskPath *path);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_add_rect (GskPathBuilder *builder,
|
||||
const graphene_rect_t *rect);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_add_circle (GskPathBuilder *builder,
|
||||
const graphene_point_t *center,
|
||||
float radius);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_move_to (GskPathBuilder *builder,
|
||||
float x,
|
||||
float y);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_line_to (GskPathBuilder *builder,
|
||||
float x,
|
||||
float y);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_curve_to (GskPathBuilder *builder,
|
||||
float x1,
|
||||
float y1,
|
||||
float x2,
|
||||
float y2,
|
||||
float x3,
|
||||
float y3);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gsk_path_builder_close (GskPathBuilder *builder);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GSK_PATH_BUILDER_H__ */
|
||||
@@ -416,12 +416,11 @@ gsk_path_measure_add_segment (GskPathMeasure *self,
|
||||
else if (start > 0 || end < self->measures[i].length)
|
||||
{
|
||||
float len = MIN (end, self->measures[i].length);
|
||||
gsk_path_builder_add_contour_segment (builder,
|
||||
self->path,
|
||||
i,
|
||||
self->measures[i].contour_data,
|
||||
start,
|
||||
len);
|
||||
gsk_contour_add_segment (gsk_path_get_contour (self->path, i),
|
||||
builder,
|
||||
self->measures[i].contour_data,
|
||||
start,
|
||||
len);
|
||||
end -= len;
|
||||
start = 0;
|
||||
if (end <= 0)
|
||||
@@ -430,7 +429,7 @@ gsk_path_measure_add_segment (GskPathMeasure *self,
|
||||
else
|
||||
{
|
||||
end -= self->measures[i].length;
|
||||
gsk_path_builder_add_contour (builder, self->path, i);
|
||||
gsk_path_builder_add_contour (builder, gsk_contour_dup (gsk_path_get_contour (self->path, i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,12 +28,44 @@ G_BEGIN_DECLS
|
||||
/* Same as Skia, so looks like a good value. ¯\_(ツ)_/¯ */
|
||||
#define GSK_PATH_TOLERANCE_DEFAULT (0.5)
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GSK_PATH_FLAT,
|
||||
GSK_PATH_CLOSED
|
||||
} GskPathFlags;
|
||||
|
||||
typedef struct _GskContour GskContour;
|
||||
typedef struct _GskContourClass GskContourClass;
|
||||
|
||||
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,
|
||||
gsize n_ops,
|
||||
const graphene_point_t *points,
|
||||
gsize n_points);
|
||||
|
||||
GskPath * gsk_path_new_from_contours (const GSList *contours);
|
||||
|
||||
gsize gsk_path_get_n_contours (GskPath *path);
|
||||
const GskContour * gsk_path_get_contour (GskPath *path,
|
||||
gsize i);
|
||||
gboolean gsk_path_foreach_with_tolerance (GskPath *self,
|
||||
double tolerance,
|
||||
GskPathForeachFunc func,
|
||||
gpointer user_data);
|
||||
|
||||
GskContour * gsk_contour_dup (const GskContour *src);
|
||||
gpointer gsk_contour_init_measure (GskPath *path,
|
||||
gsize i,
|
||||
float tolerance,
|
||||
@@ -57,16 +89,14 @@ gboolean gsk_contour_get_closest_point (GskPath
|
||||
graphene_point_t *out_pos,
|
||||
float *out_offset,
|
||||
graphene_vec2_t *out_tangent);
|
||||
void gsk_contour_add_segment (const GskContour *self,
|
||||
GskPathBuilder *builder,
|
||||
gpointer measure_data,
|
||||
float start,
|
||||
float end);
|
||||
|
||||
void gsk_path_builder_add_contour (GskPathBuilder *builder,
|
||||
GskPath *path,
|
||||
gsize i);
|
||||
void gsk_path_builder_add_contour_segment (GskPathBuilder *builder,
|
||||
GskPath *path,
|
||||
gsize i,
|
||||
gpointer measure_data,
|
||||
float start,
|
||||
float end);
|
||||
void gsk_path_builder_add_contour (GskPathBuilder *builder,
|
||||
GskContour *contour);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <gsk/gskenums.h>
|
||||
|
||||
typedef struct _GskPath GskPath;
|
||||
typedef struct _GskPathBuilder GskPathBuilder;
|
||||
typedef struct _GskPathMeasure GskPathMeasure;
|
||||
typedef struct _GskRenderer GskRenderer;
|
||||
typedef struct _GskStroke GskStroke;
|
||||
|
||||
@@ -24,6 +24,7 @@ gsk_public_sources = files([
|
||||
'gskcairorenderer.c',
|
||||
'gskglshader.c',
|
||||
'gskpath.c',
|
||||
'gskpathbuilder.c',
|
||||
'gskpathmeasure.c',
|
||||
'gskrenderer.c',
|
||||
'gskrendernode.c',
|
||||
@@ -58,6 +59,7 @@ gsk_public_headers = files([
|
||||
'gskenums.h',
|
||||
'gskglshader.h',
|
||||
'gskpath.h',
|
||||
'gskpathbuilder.h',
|
||||
'gskpathmeasure.h',
|
||||
'gskrenderer.h',
|
||||
'gskrendernode.h',
|
||||
|
||||
Reference in New Issue
Block a user