Compare commits

..

2 Commits

Author SHA1 Message Date
Matthias Clasen
c1e6e8e2a7 Add more fill and stroke node tests 2023-08-26 00:48:31 -04:00
Matthias Clasen
61756ab39d Document node format for stroke and fill nodes 2023-08-26 00:48:31 -04:00
47 changed files with 985 additions and 6569 deletions

View File

@@ -207,7 +207,9 @@ msys2-mingw64:
macos-x86_64:
rules:
# Do not run in forks as the runner is not available there.
# run merge request pipelines
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
# do not run in forks
- if: $CI_PROJECT_NAMESPACE == "GNOME"
stage: build
tags:

View File

@@ -127,7 +127,6 @@
<file>fishbowl.ui</file>
<file>gtkfishbowl.c</file>
<file>gtkfishbowl.h</file>
<file>tiger.node</file>
</gresource>
<gresource prefix="/frames">
<file>frames.ui</file>
@@ -337,7 +336,6 @@
<file>panes.c</file>
<file>password_entry.c</file>
<file>path_fill.c</file>
<file>path_maze.c</file>
<file>path_spinner.c</file>
<file>path_walk.c</file>
<file>path_text.c</file>

View File

@@ -11,9 +11,6 @@
#include "gtkgears.h"
#include "gskshaderpaintable.h"
#include "nodewidget.h"
#include "graphwidget.h"
const char *const css =
".blurred-button {"
" box-shadow: 0px 0px 5px 10px rgba(0, 0, 0, 0.5);"
@@ -211,18 +208,6 @@ create_menu_button (void)
return w;
}
static GtkWidget *
create_tiger (void)
{
return node_widget_new ("/fishbowl/tiger.node");
}
static GtkWidget *
create_graph (void)
{
return graph_widget_new ();
}
static const struct {
const char *name;
GtkWidget * (*create_func) (void);
@@ -240,8 +225,6 @@ static const struct {
{ "Switch", create_switch },
{ "Menubutton", create_menu_button },
{ "Shader", create_cogs },
{ "Tiger", create_tiger },
{ "Graph", create_graph },
};
static int selected_widget_type = -1;

View File

@@ -1,153 +0,0 @@
#include "graphwidget.h"
struct _GraphWidget
{
GtkWidget parent_instance;
GskPath *path;
GskStroke *stroke;
GdkRGBA color;
guint tick_cb;
guint64 start_time;
double period;
double amplitude;
};
struct _GraphWidgetClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE (GraphWidget, graph_widget, GTK_TYPE_WIDGET)
static void
update_path (GraphWidget *self,
float amplitude)
{
graphene_point_t p[20];
GskPathBuilder *builder;
g_clear_pointer (&self->path, gsk_path_unref);
for (int i = 0; i < 20; i++)
{
p[i].x = 10 * i;
p[i].y = 50;
if (i % 4 == 1 || i % 4 == 2)
{
if (i % 8 < 4)
p[i].y += amplitude;
else
p[i].y -= amplitude;
}
}
builder = gsk_path_builder_new ();
gsk_path_builder_move_to (builder, p[0].x, p[0].y);
for (int i = 0; i < 20; i += 4)
gsk_path_builder_cubic_to (builder,
p[i+1].x, p[i+1].y,
p[i+2].x, p[i+2].y,
p[i+3].x, p[i+3].y);
self->path = gsk_path_builder_free_to_path (builder);
}
static gboolean
tick_cb (GtkWidget *widget,
GdkFrameClock *frame_clock,
gpointer user_data)
{
GraphWidget *self = GRAPH_WIDGET (widget);
guint64 now;
double angle;
now = gdk_frame_clock_get_frame_time (frame_clock);
if (self->start_time == 0)
self->start_time = now;
angle = 360 * (now - self->start_time) / (double)(self->period * G_TIME_SPAN_MINUTE);
update_path (self, sin (angle) * self->amplitude);
gtk_widget_queue_draw (widget);
return G_SOURCE_CONTINUE;
}
static void
graph_widget_init (GraphWidget *self)
{
self->color.red = g_random_double_range (0, 1);
self->color.green = g_random_double_range (0, 1);
self->color.blue = g_random_double_range (0, 1);
self->color.alpha = 1;
self->period = g_random_double_range (0.5, 1);
self->amplitude = g_random_double_range (10, 25);
self->stroke = gsk_stroke_new (2);
update_path (self, 0);
self->start_time = 0;
self->tick_cb = gtk_widget_add_tick_callback (GTK_WIDGET (self), tick_cb, NULL, NULL);
}
static void
graph_widget_dispose (GObject *object)
{
GraphWidget *self = GRAPH_WIDGET (object);
g_clear_pointer (&self->path, gsk_path_unref);
gsk_stroke_free (self->stroke);
G_OBJECT_CLASS (graph_widget_parent_class)->dispose (object);
}
static void
graph_widget_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
GraphWidget *self = GRAPH_WIDGET (widget);
gtk_snapshot_append_stroke (snapshot, self->path, self->stroke, &self->color);
}
static void
graph_widget_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline)
{
if (orientation == GTK_ORIENTATION_HORIZONTAL)
*minimum = *natural = 200;
else
*minimum = *natural = 100;
}
static void
graph_widget_class_init (GraphWidgetClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->dispose = graph_widget_dispose;
widget_class->snapshot = graph_widget_snapshot;
widget_class->measure = graph_widget_measure;
}
GtkWidget *
graph_widget_new (void)
{
return g_object_new (GRAPH_TYPE_WIDGET, NULL);
}

View File

@@ -1,8 +0,0 @@
#pragma once
#include <gtk/gtk.h>
#define GRAPH_TYPE_WIDGET (graph_widget_get_type ())
G_DECLARE_FINAL_TYPE (GraphWidget, graph_widget, GRAPH, WIDGET, GtkWidget)
GtkWidget * graph_widget_new (void);

View File

@@ -73,7 +73,6 @@ demos = files([
'panes.c',
'password_entry.c',
'path_fill.c',
'path_maze.c',
'path_spinner.c',
'path_walk.c',
'path_text.c',
@@ -141,8 +140,6 @@ extra_demo_sources = files([
'unicode-names.c',
'suggestionentry.c',
'language-names.c',
'nodewidget.c',
'graphwidget.c',
])
if os_unix

View File

@@ -1,76 +0,0 @@
#include "nodewidget.h"
struct _NodeWidget
{
GtkWidget parent_instance;
GskRenderNode *node;
};
struct _NodeWidgetClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE (NodeWidget, node_widget, GTK_TYPE_WIDGET)
static void
node_widget_init (NodeWidget *self)
{
}
static void
node_widget_dispose (GObject *object)
{
NodeWidget *self = NODE_WIDGET (object);
gsk_render_node_unref (self->node);
G_OBJECT_CLASS (node_widget_parent_class)->dispose (object);
}
static void
node_widget_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot)
{
NodeWidget *self = NODE_WIDGET (widget);
gtk_snapshot_append_node (snapshot, self->node);
}
static void
node_widget_class_init (NodeWidgetClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->dispose = node_widget_dispose;
widget_class->snapshot = node_widget_snapshot;
}
GtkWidget *
node_widget_new (const char *resource)
{
NodeWidget *self;
GBytes *bytes;
GskRenderNode *node;
graphene_rect_t bounds;
float scale;
GskTransform *transform;
self = g_object_new (NODE_TYPE_WIDGET, NULL);
bytes = g_resources_lookup_data (resource, 0, NULL);
node = gsk_render_node_deserialize (bytes, NULL, NULL);
g_bytes_unref (bytes);
gsk_render_node_get_bounds (node, &bounds);
scale = MIN (100.0/bounds.size.width, 100.0/bounds.size.height);
transform = gsk_transform_scale (NULL, scale, scale);
self->node = gsk_transform_node_new (node, transform);
gsk_transform_unref (transform);
gsk_render_node_unref (node);
return GTK_WIDGET (self);
}

View File

@@ -1,8 +0,0 @@
#pragma once
#include <gtk/gtk.h>
#define NODE_TYPE_WIDGET (node_widget_get_type ())
G_DECLARE_FINAL_TYPE (NodeWidget, node_widget, NODE, WIDGET, GtkWidget)
GtkWidget * node_widget_new (const char *file);

View File

@@ -1,348 +0,0 @@
/* Path/Maze
*
* This demo shows how to use a GskPath to create a maze and use
* gsk_path_get_closest_point() to check the mouse stays
* on the path.
*
* It also shows off the performance of GskPath (or not) as this
* is a rather complex path.
*/
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include "paintable.h"
#define MAZE_GRID_SIZE 20
#define MAZE_STROKE_SIZE_ACTIVE (MAZE_GRID_SIZE - 4)
#define MAZE_STROKE_SIZE_INACTIVE (MAZE_GRID_SIZE - 12)
#define MAZE_WIDTH 31
#define MAZE_HEIGHT 21
#define GTK_TYPE_MAZE (gtk_maze_get_type ())
G_DECLARE_FINAL_TYPE (GtkMaze, gtk_maze, GTK, MAZE, GtkWidget)
struct _GtkMaze
{
GtkWidget parent_instance;
int width;
int height;
GskPath *path;
GskPathMeasure *measure;
GdkPaintable *background;
gboolean active;
};
struct _GtkMazeClass
{
GtkWidgetClass parent_class;
};
G_DEFINE_TYPE (GtkMaze, gtk_maze, GTK_TYPE_WIDGET)
static void
gtk_maze_measure (GtkWidget *widget,
GtkOrientation orientation,
int for_size,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline)
{
GtkMaze *self = GTK_MAZE (widget);
if (orientation == GTK_ORIENTATION_HORIZONTAL)
*minimum = *natural = self->width;
else
*minimum = *natural = self->height;
}
static void
gtk_maze_snapshot (GtkWidget *widget,
GdkSnapshot *snapshot)
{
GtkMaze *self = GTK_MAZE (widget);
double width = gtk_widget_get_width (widget);
double height = gtk_widget_get_height (widget);
GskStroke *stroke;
stroke = gsk_stroke_new (MAZE_STROKE_SIZE_INACTIVE);
if (self->active)
gsk_stroke_set_line_width (stroke, MAZE_STROKE_SIZE_ACTIVE);
gsk_stroke_set_line_join (stroke, GSK_LINE_JOIN_ROUND);
gsk_stroke_set_line_cap (stroke, GSK_LINE_CAP_ROUND);
gtk_snapshot_push_stroke (snapshot, self->path, stroke);
gsk_stroke_free (stroke);
if (self->background)
{
gdk_paintable_snapshot (self->background, snapshot, width, height);
}
else
{
gtk_snapshot_append_linear_gradient (snapshot,
&GRAPHENE_RECT_INIT (0, 0, width, height),
&GRAPHENE_POINT_INIT (0, 0),
&GRAPHENE_POINT_INIT (width, height),
(GskColorStop[8]) {
{ 0.0, { 1.0, 0.0, 0.0, 1.0 } },
{ 0.2, { 1.0, 0.0, 0.0, 1.0 } },
{ 0.3, { 1.0, 1.0, 0.0, 1.0 } },
{ 0.4, { 0.0, 1.0, 0.0, 1.0 } },
{ 0.6, { 0.0, 1.0, 1.0, 1.0 } },
{ 0.7, { 0.0, 0.0, 1.0, 1.0 } },
{ 0.8, { 1.0, 0.0, 1.0, 1.0 } },
{ 1.0, { 1.0, 0.0, 1.0, 1.0 } }
},
8);
}
gtk_snapshot_pop (snapshot);
}
static void
gtk_maze_dispose (GObject *object)
{
GtkMaze *self = GTK_MAZE (object);
g_clear_pointer (&self->path, gsk_path_unref);
g_clear_pointer (&self->measure, gsk_path_measure_unref);
if (self->background)
{
g_signal_handlers_disconnect_matched (self->background, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
g_clear_object (&self->background);
}
G_OBJECT_CLASS (gtk_maze_parent_class)->dispose (object);
}
static void
gtk_maze_class_init (GtkMazeClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = gtk_maze_dispose;
widget_class->measure = gtk_maze_measure;
widget_class->snapshot = gtk_maze_snapshot;
}
static void
pointer_motion (GtkEventControllerMotion *controller,
double x,
double y,
GtkMaze *self)
{
GskPathPoint point;
float distance;
if (!self->active)
return;
if (gsk_path_get_closest_point (self->path,
&GRAPHENE_POINT_INIT (x, y),
INFINITY,
&point,
&distance))
{
if (distance < MAZE_STROKE_SIZE_ACTIVE / 2.f)
return;
}
self->active = FALSE;
gtk_widget_queue_draw (GTK_WIDGET (self));
}
static void
pointer_leave (GtkEventControllerMotion *controller,
GtkMaze *self)
{
if (!self->active)
{
self->active = TRUE;
gtk_widget_queue_draw (GTK_WIDGET (self));
}
}
static void
gtk_maze_init (GtkMaze *self)
{
GtkEventController *controller;
controller = GTK_EVENT_CONTROLLER (gtk_event_controller_motion_new ());
g_signal_connect (controller, "motion", G_CALLBACK (pointer_motion), self);
g_signal_connect (controller, "leave", G_CALLBACK (pointer_leave), self);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
self->active = TRUE;
}
static void
gtk_maze_set_path (GtkMaze *self,
GskPath *path)
{
g_clear_pointer (&self->path, gsk_path_unref);
g_clear_pointer (&self->measure, gsk_path_measure_unref);
self->path = gsk_path_ref (path);
self->measure = gsk_path_measure_new (path);
gtk_widget_queue_draw (GTK_WIDGET (self));
}
GtkWidget *
gtk_maze_new (GskPath *path,
GdkPaintable *background,
int width,
int height)
{
GtkMaze *self;
self = g_object_new (GTK_TYPE_MAZE, NULL);
gtk_maze_set_path (self, path);
gsk_path_unref (path);
self->background = background;
if (self->background)
{
g_signal_connect_swapped (self->background, "invalidate-contents", G_CALLBACK (gtk_widget_queue_draw), self);
g_signal_connect_swapped (self->background, "invalidate-size", G_CALLBACK (gtk_widget_queue_resize), self);
}
self->width = width;
self->height = height;
return GTK_WIDGET (self);
}
static void
add_point_to_maze (GtkBitset *maze,
GskPathBuilder *builder,
guint x,
guint y)
{
gboolean set[4] = { FALSE, FALSE, FALSE, FALSE };
guint dir;
gtk_bitset_add (maze, y * MAZE_WIDTH + x);
while (TRUE)
{
set[0] = set[0] || x == 0 || gtk_bitset_contains (maze, y * MAZE_WIDTH + x - 1);
set[1] = set[1] || y == 0 || gtk_bitset_contains (maze, (y - 1) * MAZE_WIDTH + x);
set[2] = set[2] || x + 1 == MAZE_WIDTH || gtk_bitset_contains (maze, y * MAZE_WIDTH + x + 1);
set[3] = set[3] || y + 1 == MAZE_HEIGHT || gtk_bitset_contains (maze, (y + 1) * MAZE_WIDTH + x);
if (set[0] && set[1] && set[2] && set[3])
return;
do
{
dir = g_random_int_range (0, 4);
}
while (set[dir]);
switch (dir)
{
case 0:
gsk_path_builder_move_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
gsk_path_builder_line_to (builder, (x - 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
add_point_to_maze (maze, builder, x - 1, y);
break;
case 1:
gsk_path_builder_move_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
gsk_path_builder_line_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y - 0.5) * MAZE_GRID_SIZE);
add_point_to_maze (maze, builder, x, y - 1);
break;
case 2:
gsk_path_builder_move_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
gsk_path_builder_line_to (builder, (x + 1.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
add_point_to_maze (maze, builder, x + 1, y);
break;
case 3:
gsk_path_builder_move_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 0.5) * MAZE_GRID_SIZE);
gsk_path_builder_line_to (builder, (x + 0.5) * MAZE_GRID_SIZE, (y + 1.5) * MAZE_GRID_SIZE);
add_point_to_maze (maze, builder, x, y + 1);
break;
default:
g_assert_not_reached ();
break;
}
}
}
static GskPath *
create_path_for_maze (GtkWidget *widget)
{
GskPathBuilder *builder;
GtkBitset *maze;
builder = gsk_path_builder_new ();
maze = gtk_bitset_new_empty ();
/* make sure the outer lines are unreachable:
* Set the full range, then remove the center again. */
gtk_bitset_add_range (maze, 0, MAZE_WIDTH * MAZE_HEIGHT);
gtk_bitset_remove_rectangle (maze, MAZE_WIDTH + 1, MAZE_WIDTH - 2, MAZE_HEIGHT - 2, MAZE_WIDTH);
/* Fill the maze */
add_point_to_maze (maze, builder, MAZE_WIDTH / 2, MAZE_HEIGHT / 2);
/* Add start and stop lines */
gsk_path_builder_move_to (builder, 1.5 * MAZE_GRID_SIZE, -0.5 * MAZE_GRID_SIZE);
gsk_path_builder_line_to (builder, 1.5 * MAZE_GRID_SIZE, 1.5 * MAZE_GRID_SIZE);
gsk_path_builder_move_to (builder, (MAZE_WIDTH - 1.5) * MAZE_GRID_SIZE, (MAZE_HEIGHT - 1.5) * MAZE_GRID_SIZE);
gsk_path_builder_line_to (builder, (MAZE_WIDTH - 1.5) * MAZE_GRID_SIZE, (MAZE_HEIGHT + 0.5) * MAZE_GRID_SIZE);
gtk_bitset_unref (maze);
return gsk_path_builder_free_to_path (builder);
}
GtkWidget *
do_path_maze (GtkWidget *do_widget)
{
static GtkWidget *window = NULL;
if (!window)
{
GtkWidget *maze;
GtkMediaStream *stream;
GskPath *path;
window = gtk_window_new ();
gtk_window_set_resizable (GTK_WINDOW (window), TRUE);
gtk_window_set_title (GTK_WINDOW (window), "Follow the maze with the mouse");
g_object_add_weak_pointer (G_OBJECT (window), (gpointer *)&window);
#if 0
stream = gtk_media_file_new_for_resource ("/images/gtk-logo.webm");
#else
stream = gtk_nuclear_media_stream_new ();
#endif
gtk_media_stream_play (stream);
gtk_media_stream_set_loop (stream, TRUE);
path = create_path_for_maze (window);
maze = gtk_maze_new (path,
GDK_PAINTABLE (stream),
MAZE_WIDTH * MAZE_GRID_SIZE,
MAZE_HEIGHT * MAZE_GRID_SIZE);
gtk_window_set_child (GTK_WINDOW (window), maze);
}
if (!gtk_widget_get_visible (window))
gtk_window_present (GTK_WINDOW (window));
else
gtk_window_destroy (GTK_WINDOW (window));
return window;
}

View File

@@ -56,9 +56,9 @@ gtk_spinner_paintable_get_intrinsic_height (GdkPaintable *paintable)
static void
gtk_spinner_paintable_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot,
double width,
double height)
GdkSnapshot *snapshot,
double width,
double height)
{
GtkSpinnerPaintable *self = GTK_SPINNER_PAINTABLE (paintable);
@@ -190,21 +190,32 @@ update_path (GtkSpinnerPaintable *self)
{
GskPathBuilder *builder;
GskPathPoint start, end;
graphene_point_t p0, p1;
GskTransform *t;
graphene_point_t p, p0, p1;
float start_angle, end_angle;
p = GRAPHENE_POINT_INIT (40, 0);
start_angle = self->angle;
end_angle = fmod (self->angle + 360 * self->completion / 100, 360);
p0 = GRAPHENE_POINT_INIT (50 + 40 * cos (M_PI * start_angle / 180),
50 + 40 * sin (M_PI * start_angle / 180));
p1 = GRAPHENE_POINT_INIT (50 + 40 * cos (M_PI * end_angle / 180),
50 + 40 * sin (M_PI * end_angle / 180));
t = gsk_transform_translate (
gsk_transform_rotate (
gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (50, 50)),
start_angle),
&GRAPHENE_POINT_INIT (-50, -50));
gsk_transform_transform_point (t, &p, &p0);
t = gsk_transform_translate (
gsk_transform_rotate (
gsk_transform_translate (NULL, &GRAPHENE_POINT_INIT (50, 50)),
end_angle),
&GRAPHENE_POINT_INIT (-50, -50));
gsk_transform_transform_point (t, &p, &p1);
g_clear_pointer (&self->path, gsk_path_unref);
gsk_path_get_closest_point (self->circle, &p0, INFINITY, &start, NULL);
gsk_path_get_closest_point (self->circle, &p1, INFINITY, &end, NULL);
gsk_path_get_closest_point (self->circle, &p0, INFINITY, &start);
gsk_path_get_closest_point (self->circle, &p1, INFINITY, &end);
builder = gsk_path_builder_new ();
gsk_path_builder_add_segment (builder, self->circle, &start, &end);

View File

@@ -501,13 +501,15 @@ pointer_motion (GtkEventControllerMotion *controller,
GtkPathWidget *self)
{
GskPathPoint point;
graphene_point_t pos;
if (gsk_path_get_closest_point (self->line_path,
&GRAPHENE_POINT_INIT (x, y),
INFINITY,
&point,
NULL))
&point))
{
gsk_path_point_get_position (&point, self->line_path, &pos);
gtk_widget_queue_draw (GTK_WIDGET (self));
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -149,16 +149,15 @@ Creates a node like `gsk_debug_node_new()` with the given properties.
### fill
| property | syntax | default | printed |
| --------- | --------------- | ---------------------- | ----------- |
| child | `<node>` | *see below* | always |
| path | `<string>` | "" | always |
| fill-rule | `<fill-rule>` | winding | always |
| property | syntax | default | printed |
| -------- | ---------------- | ---------------------- | ----------- |
| child | `<node>` | *see below* | always |
| path | `<string>` | "" | always |
| fill-rule| `<fill-rule>` | winding | always |
Creates a node like `gsk_fill_node_new()` with the given properties.
The default child node is the default color node, but created with the
bounds of the path.
The default child node is created with the bounds of the path.
### glshader
@@ -317,8 +316,7 @@ Creates a node like `gsk_shadow_node_new()` with the given properties.
Creates a node like `gsk_stroke_node_new()` with the given properties.
The default child node is the default color node, but created with the
stroke bounds of the path.
The default child node is created with the stroke bounds of the path.
### text

View File

@@ -15,7 +15,6 @@ SYNOPSIS
| **gtk4-path-tool** decompose [OPTIONS...] <PATH>
| **gtk4-path-tool** show [OPTIONS...] <PATH>
| **gtk4-path-tool** render [OPTIONS...] <PATH>
| **gtk4-path-tool** reverse [OPTIONS...] <PATH>
| **gtk4-path-tool** info [OPTIONS...] <PATH>
DESCRIPTION
@@ -182,12 +181,6 @@ The interior of the path is filled.
The offset into the dash pattern where dashing should begin.
The default value is 0.
Reversing
^^^^^^^^^
The ``reverse`` command changes the direction of the path. The resulting
paths starts where the original path ends.
Info
^^^^

File diff suppressed because it is too large Load Diff

View File

@@ -21,7 +21,7 @@
#pragma once
#include "gskpathprivate.h"
#include "gskpathpoint.h"
#include "gskpathpointprivate.h"
#include "gskpathopprivate.h"
#include "gskboundingboxprivate.h"
@@ -34,12 +34,6 @@ GskContour * gsk_standard_contour_new (GskPathFlags
gsize n_ops,
gssize offset);
GskContour * gsk_circle_contour_new (const graphene_point_t *center,
float radius);
GskContour * gsk_rect_contour_new (const graphene_rect_t *rect);
GskContour * gsk_rounded_rect_contour_new (const GskRoundedRect *rounded_rect);
const char * gsk_contour_get_type_name (const GskContour *self);
void gsk_contour_copy (GskContour * dest,
const GskContour *src);
GskContour * gsk_contour_dup (const GskContour *src);
@@ -55,32 +49,36 @@ gboolean gsk_contour_get_stroke_bounds (const GskContou
const GskStroke *stroke,
GskBoundingBox *bounds);
gboolean gsk_contour_foreach (const GskContour *self,
float tolerance,
GskPathForeachFunc func,
gpointer user_data);
void gsk_contour_get_start_end (const GskContour *self,
graphene_point_t *start,
graphene_point_t *end);
int gsk_contour_get_winding (const GskContour *self,
const graphene_point_t *point);
gsize gsk_contour_get_n_ops (const GskContour *self);
gboolean gsk_contour_get_closest_point (const GskContour *self,
const graphene_point_t *point,
float threshold,
GskPathPoint *result,
GskRealPathPoint *result,
float *out_dist);
void gsk_contour_get_position (const GskContour *self,
const GskPathPoint *point,
GskRealPathPoint *point,
graphene_point_t *pos);
void gsk_contour_get_tangent (const GskContour *self,
const GskPathPoint *point,
GskRealPathPoint *point,
GskPathDirection direction,
graphene_vec2_t *tangent);
float gsk_contour_get_curvature (const GskContour *self,
const GskPathPoint *point,
GskRealPathPoint *point,
GskPathDirection direction,
graphene_point_t *center);
void gsk_contour_add_segment (const GskContour *self,
GskPathBuilder *builder,
gboolean emit_move_to,
const GskPathPoint *start,
const GskPathPoint *end);
GskRealPathPoint *start,
GskRealPathPoint *end);
gpointer gsk_contour_init_measure (const GskContour *self,
float tolerance,
@@ -90,13 +88,9 @@ void gsk_contour_free_measure (const GskContou
void gsk_contour_get_point (const GskContour *self,
gpointer measure_data,
float distance,
GskPathPoint *result);
GskRealPathPoint *result);
float gsk_contour_get_distance (const GskContour *self,
const GskPathPoint *point,
GskRealPathPoint *point,
gpointer measure_data);
gboolean gsk_contour_dash (const GskContour *contour,
GskStroke *stroke,
GskPathForeachFunc func,
gpointer user_data);
G_END_DECLS

View File

@@ -2,7 +2,7 @@
* see https://pomax.github.io/bezierinfo/legendre-gauss.html
*/
#if defined(USE_64_SAMPLES)
#if 0
/* n = 64 */
static const double T[] = {
-0.0243502926634244325089558428537156614268871093149758091634531663960566965166295288529853061657116894882370493013671717560479926679408068852617342586968190919443025679363843727751902756254975073084367002129407854253246662805532069172532219089321005870178809284335033318073251039701073379759,
@@ -137,8 +137,7 @@ static const double C[] = {
0.0017832807216964329472960791449719331799593472719279556695308063655858546954239803486698215802150348282744786016134857283616955449868451969230490863774274598030023211055562492709717566919237924255297982774711177411074145151155610163293142044147991553384925940046957893721166251082473659733,
0.0017832807216964329472960791449719331799593472719279556695308063655858546954239803486698215802150348282744786016134857283616955449868451969230490863774274598030023211055562492709717566919237924255297982774711177411074145151155610163293142044147991553384925940046957893721166251082473659733
};
#elif defined(USE_32_SAMPLES)
#else
/* n = 32 */
static double T[] = {
@@ -211,62 +210,4 @@ static double C[] = {
0.0070186100094700966004070637388531825133772207289396032320082356192151241454178686953297376907573215077936155545790593837513204206518026084505878987243348925784479817181234617862457418214505322067610482902501455504204433524520665822704844582452877416001060465891907497519632353148380799619
};
#else
/* n = 24 */
static double T[] = {
-0.0640568928626056260850430826247450385909991954207473934243510817897392835939101078028928761342525090823242273835115756994869112500371756765277735374378372436515481804668409746233647956019276711845937319580510697455314397618513360822351096139837050674073737720614748330506959387258141490546,
0.0640568928626056260850430826247450385909991954207473934243510817897392835939101078028928761342525090823242273835115756994869112500371756765277735374378372436515481804668409746233647956019276711845937319580510697455314397618513360822351096139837050674073737720614748330506959387258141490546,
-0.1911188674736163091586398207570696318404051033147533561489185765880859526918717419824911112452097307135934146013595461392721542943443689459384015952736491888634107638852139839821480663334386199430823059446316182589874503457282270169922471283825305735240671464262733609193984099421023790425,
0.1911188674736163091586398207570696318404051033147533561489185765880859526918717419824911112452097307135934146013595461392721542943443689459384015952736491888634107638852139839821480663334386199430823059446316182589874503457282270169922471283825305735240671464262733609193984099421023790425,
-0.3150426796961633743867932913198102407864782608248172687542301295298821563412434083438735095552082106072251617364030643536658931791308690387340350108862316429911426633492164449851684039691011610681827256891467485494251442677599304969349712405008328365242087382043028815467866505618650936915,
0.3150426796961633743867932913198102407864782608248172687542301295298821563412434083438735095552082106072251617364030643536658931791308690387340350108862316429911426633492164449851684039691011610681827256891467485494251442677599304969349712405008328365242087382043028815467866505618650936915,
-0.4337935076260451384870842319133497124524215109279688080808012846567644070336309140577354304660756168836170633415002629755076381975174699198632370585889341378575229685577710965327823199539830928400741454067377627746745635503614810834602257701251585352190552527778684113280867150779959852524,
0.4337935076260451384870842319133497124524215109279688080808012846567644070336309140577354304660756168836170633415002629755076381975174699198632370585889341378575229685577710965327823199539830928400741454067377627746745635503614810834602257701251585352190552527778684113280867150779959852524,
-0.5454214713888395356583756172183723700107839925876181754336143898305648391795708970958348674408062501977746653313676778948810297400650828985504068941547021866808914316854182653519436295728612315264181208390018064915325250677148594855874434492614547180849377989457776201862945948751249939033,
0.5454214713888395356583756172183723700107839925876181754336143898305648391795708970958348674408062501977746653313676778948810297400650828985504068941547021866808914316854182653519436295728612315264181208390018064915325250677148594855874434492614547180849377989457776201862945948751249939033,
-0.6480936519369755692524957869107476266696582986189567802989336650244483175685397719281177703657272433990519954414744003453347794058626075519074876962003580684127104697893556584036149935275154534232685850207671594298434446955488396349075497667624732345971957611938685137884801129695447597312,
0.6480936519369755692524957869107476266696582986189567802989336650244483175685397719281177703657272433990519954414744003453347794058626075519074876962003580684127104697893556584036149935275154534232685850207671594298434446955488396349075497667624732345971957611938685137884801129695447597312,
-0.7401241915785543642438281030999784255232924870141854568663823682719003386409229324413313561311287943298526270745398288213617461973439599491355223046073660810109486527571776420522757185953076208759863287235084614803697918067466580746275122563457575959399650481778575563118955957829855078072,
0.7401241915785543642438281030999784255232924870141854568663823682719003386409229324413313561311287943298526270745398288213617461973439599491355223046073660810109486527571776420522757185953076208759863287235084614803697918067466580746275122563457575959399650481778575563118955957829855078072,
-0.8200019859739029219539498726697452080761264776678555872439810260013829789535545400822605211725837960666424765858309152369975956748693910897310401393217997751433463343851603146734984964062776585418194561809063555489816762580329418137298754264378316716417347949040725111554705589243953692169,
0.8200019859739029219539498726697452080761264776678555872439810260013829789535545400822605211725837960666424765858309152369975956748693910897310401393217997751433463343851603146734984964062776585418194561809063555489816762580329418137298754264378316716417347949040725111554705589243953692169,
-0.8864155270044010342131543419821967550873330433089200403710379167756748343989591721041235019961817012535295108910075024175885664874383567124270976139069615059721185542370372118538064873468961679956606315961988138722471292807573552657465373246065266349095264290446955886450980216411579068464,
0.8864155270044010342131543419821967550873330433089200403710379167756748343989591721041235019961817012535295108910075024175885664874383567124270976139069615059721185542370372118538064873468961679956606315961988138722471292807573552657465373246065266349095264290446955886450980216411579068464,
-0.9382745520027327585236490017087214496548196580774513466350271759095894960525356709599646415358699555094267057623515929895997449470704383076095012442349544937551633313675972481722466159802428487600880633341786121580661077521685134893546419567859808853944866142065617471979973235700469563606,
0.9382745520027327585236490017087214496548196580774513466350271759095894960525356709599646415358699555094267057623515929895997449470704383076095012442349544937551633313675972481722466159802428487600880633341786121580661077521685134893546419567859808853944866142065617471979973235700469563606,
-0.9747285559713094981983919930081690617411830530401787198115935651071811212809802245386374742817154549827412585755713491144798180281062083910290010368962899139003272102551955405455775700818480561392470581718221938768668731616756379649281934548623489251537698395239432800432811839537332490367,
0.9747285559713094981983919930081690617411830530401787198115935651071811212809802245386374742817154549827412585755713491144798180281062083910290010368962899139003272102551955405455775700818480561392470581718221938768668731616756379649281934548623489251537698395239432800432811839537332490367,
-0.9951872199970213601799974097007368118745976925960028774416005451142838320694577378833972893371157088623453462978965853994497237745715598401409351804188189455255566266162142239452364851560816782389596967291836243391359167365098731808888455424405665558369621091780571617968925046375452278564,
0.9951872199970213601799974097007368118745976925960028774416005451142838320694577378833972893371157088623453462978965853994497237745715598401409351804188189455255566266162142239452364851560816782389596967291836243391359167365098731808888455424405665558369621091780571617968925046375452278564,
};
static double C[] = {
0.1279381953467521569740561652246953718517112395416678824212995763723475915405364024120919775667347423307078678605027534354336365506630173201256407760369958705384835762891562911475479559477218918074170718365754182501974550951925484331523758090745471505157505768499921691572488912345533434646,
0.1279381953467521569740561652246953718517112395416678824212995763723475915405364024120919775667347423307078678605027534354336365506630173201256407760369958705384835762891562911475479559477218918074170718365754182501974550951925484331523758090745471505157505768499921691572488912345533434646,
0.1258374563468282961213753825111836887264033255813454041780915168813938726666625968820381792564211407244125340112283619371640023694354842556219623307075721695505167028832011944572440814161265754364153991752782846305315778293182951298508346824950922490384565834525141570991957343073460241123,
0.1258374563468282961213753825111836887264033255813454041780915168813938726666625968820381792564211407244125340112283619371640023694354842556219623307075721695505167028832011944572440814161265754364153991752782846305315778293182951298508346824950922490384565834525141570991957343073460241123,
0.1216704729278033912044631534762624256070295592038057787774717545126253937177169619177578034307728419129571458407698685455109927385962626203664197972099671299080663146992247474377374928428629909818345130957392521139337403891946990001210368274459006298591636884893163373907763429334385715701,
0.1216704729278033912044631534762624256070295592038057787774717545126253937177169619177578034307728419129571458407698685455109927385962626203664197972099671299080663146992247474377374928428629909818345130957392521139337403891946990001210368274459006298591636884893163373907763429334385715701,
0.1155056680537256013533444839067835598622703113764964705844493600886702535513185499403442576468127956599599096047023274406552399890629831050388267870570157536484442644788074009392626299528272339158271789101012709245867329169327356527615681351864802567093740938014246237226139721687821239517,
0.1155056680537256013533444839067835598622703113764964705844493600886702535513185499403442576468127956599599096047023274406552399890629831050388267870570157536484442644788074009392626299528272339158271789101012709245867329169327356527615681351864802567093740938014246237226139721687821239517,
0.107444270115965634782577342446606222794628690134220021766541640886821866394437105980586727120915236672945076498454815476823439901643102885282830543962266851556251956709331696682107380679861280071851870323872823740641856241992841364843152888380035317713347953732555881218806283399463124951,
0.107444270115965634782577342446606222794628690134220021766541640886821866394437105980586727120915236672945076498454815476823439901643102885282830543962266851556251956709331696682107380679861280071851870323872823740641856241992841364843152888380035317713347953732555881218806283399463124951,
0.097618652104113888269880664464247154427918968853685944083310610022954338577591978348020039690718187482414745713364268645676642419728572107043424944384211806071042042791689191672508012725933985685876262715739521302925263010913644942223616059647289160432915821120275634713911721781926285332,
0.097618652104113888269880664464247154427918968853685944083310610022954338577591978348020039690718187482414745713364268645676642419728572107043424944384211806071042042791689191672508012725933985685876262715739521302925263010913644942223616059647289160432915821120275634713911721781926285332,
0.0861901615319532759171852029837426671850805882379330055884071438612868844607805312688886562972816971732787465671984327992158782827038381983594380916492525003385563462630861694048857276454548529177279961693054540872738963763950131372564031674654030737773100525128451496727198421916322556908,
0.0861901615319532759171852029837426671850805882379330055884071438612868844607805312688886562972816971732787465671984327992158782827038381983594380916492525003385563462630861694048857276454548529177279961693054540872738963763950131372564031674654030737773100525128451496727198421916322556908,
0.0733464814110803057340336152531165181193365098484994714027024906600413884758709348323251422694445551958844309079341158927693012247996928526423877450601776912550600854944985229487704917122675007345403564777169078420148392438502785281584325129303566997853186794893103931008654660416023204965,
0.0733464814110803057340336152531165181193365098484994714027024906600413884758709348323251422694445551958844309079341158927693012247996928526423877450601776912550600854944985229487704917122675007345403564777169078420148392438502785281584325129303566997853186794893103931008654660416023204965,
0.0592985849154367807463677585001085845412001265652134910373765512940983031775082415660683556106090092998654733952492642466909653073834070291103432919838456250955380753837859345492817299145644958959367291816621761687898337760987530926613795554356869343124524696513178977787335055019515914172,
0.0592985849154367807463677585001085845412001265652134910373765512940983031775082415660683556106090092998654733952492642466909653073834070291103432919838456250955380753837859345492817299145644958959367291816621761687898337760987530926613795554356869343124524696513178977787335055019515914172,
0.0442774388174198061686027482113382288593128418338578967413972297210243762822664396343947170155594934934611803046066530352490769669525012630503089839091175520932522330681764807671830570648211944799908348398720715944900305481342571090714940628894962186599515560606956040614089479788668773348,
0.0442774388174198061686027482113382288593128418338578967413972297210243762822664396343947170155594934934611803046066530352490769669525012630503089839091175520932522330681764807671830570648211944799908348398720715944900305481342571090714940628894962186599515560606956040614089479788668773348,
0.0285313886289336631813078159518782864491977979319081166016648047576440056374291434256854254228098755422737224452711633426188506404779428430343631052424983978091405445557790206527391293478807818130301641760878492678184457761229065303399826533483010921962299302202888714000294545957159715602,
0.0285313886289336631813078159518782864491977979319081166016648047576440056374291434256854254228098755422737224452711633426188506404779428430343631052424983978091405445557790206527391293478807818130301641760878492678184457761229065303399826533483010921962299302202888714000294545957159715602,
0.0123412297999871995468056670700372915759100408913665168172873209410917255178811137917987186719204245118391668507179752021919736085531955203240536027970786521356478573832633493407323107496772162595516230980489700767963287958540270795597236457014112169997285946194632806836898378754527134097,
0.0123412297999871995468056670700372915759100408913665168172873209410917255178811137917987186719204245118391668507179752021919736085531955203240536027970786521356478573832633493407323107496772162595516230980489700767963287958540270795597236457014112169997285946194632806836898378754527134097,
};
#endif

View File

@@ -84,9 +84,6 @@ struct _GskCurveClass
const graphene_point_t *point);
float (* get_length_to) (const GskCurve *curve,
float t);
float (* get_at_length) (const GskCurve *curve,
float distance,
float epsilon);
};
/* {{{ Utilities */
@@ -211,41 +208,6 @@ get_length_by_approximation (const GskCurve *curve,
return z * sum;
}
/* Compute the inverse of the arclength using bisection,
* to a given precision
*/
static float
get_t_by_bisection (const GskCurve *curve,
float length,
float epsilon)
{
float t1, t2, t, l;
GskCurve c1;
g_assert (epsilon >= FLT_EPSILON);
t1 = 0;
t2 = 1;
while (t1 < t2)
{
t = (t1 + t2) / 2;
if (t == t1 || t == t2)
break;
gsk_curve_split (curve, t, &c1, NULL);
l = gsk_curve_get_length (&c1);
if (fabsf (length - l) < epsilon)
break;
else if (l < length)
t1 = t;
else
t2 = t;
}
return t;
}
/* }}} */
/* {{{ Line */
@@ -464,23 +426,6 @@ gsk_line_curve_get_length_to (const GskCurve *curve,
return t * graphene_point_distance (&pts[0], &pts[1], NULL, NULL);
}
static float
gsk_line_curve_get_at_length (const GskCurve *curve,
float distance,
float epsilon)
{
const GskLineCurve *self = &curve->line;
const graphene_point_t *pts = self->points;
float length;
length = graphene_point_distance (&pts[0], &pts[1], NULL, NULL);
if (length == 0)
return 0;
return CLAMP (distance / length, 0, 1);
}
static const GskCurveClass GSK_LINE_CURVE_CLASS = {
gsk_line_curve_init,
gsk_line_curve_init_foreach,
@@ -503,7 +448,6 @@ static const GskCurveClass GSK_LINE_CURVE_CLASS = {
gsk_line_curve_get_derivative_at,
gsk_line_curve_get_crossing,
gsk_line_curve_get_length_to,
gsk_line_curve_get_at_length,
};
/* }}} */
@@ -777,19 +721,6 @@ gsk_quad_curve_decompose_curve (const GskCurve *curve,
if (flags & GSK_PATH_FOREACH_ALLOW_QUAD)
return add_curve_func (GSK_PATH_QUAD, self->points, 3, 0.f, user_data);
else if (graphene_point_equal (&curve->conic.points[0], &curve->conic.points[1]) ||
graphene_point_equal (&curve->conic.points[1], &curve->conic.points[2]))
{
if (!graphene_point_equal (&curve->conic.points[0], &curve->conic.points[2]))
return add_curve_func (GSK_PATH_LINE,
(graphene_point_t[2]) {
curve->conic.points[0],
curve->conic.points[2],
},
2, 0.f, user_data);
else
return TRUE;
}
else if (flags & GSK_PATH_FOREACH_ALLOW_CUBIC)
{
GskCurve c;
@@ -897,14 +828,6 @@ gsk_quad_curve_get_length_to (const GskCurve *curve,
return get_length_by_approximation (curve, t);
}
static float
gsk_quad_curve_get_at_length (const GskCurve *curve,
float t,
float epsilon)
{
return get_t_by_bisection (curve, t, epsilon);
}
static const GskCurveClass GSK_QUAD_CURVE_CLASS = {
gsk_quad_curve_init,
gsk_quad_curve_init_foreach,
@@ -927,10 +850,9 @@ static const GskCurveClass GSK_QUAD_CURVE_CLASS = {
gsk_quad_curve_get_derivative_at,
gsk_quad_curve_get_crossing,
gsk_quad_curve_get_length_to,
gsk_quad_curve_get_at_length,
};
/* }}} */
/* }}} */
/* {{{ Cubic */
static void
@@ -1376,14 +1298,6 @@ gsk_cubic_curve_get_length_to (const GskCurve *curve,
return get_length_by_approximation (curve, t);
}
static float
gsk_cubic_curve_get_at_length (const GskCurve *curve,
float t,
float epsilon)
{
return get_t_by_bisection (curve, t, epsilon);
}
static const GskCurveClass GSK_CUBIC_CURVE_CLASS = {
gsk_cubic_curve_init,
gsk_cubic_curve_init_foreach,
@@ -1406,7 +1320,6 @@ static const GskCurveClass GSK_CUBIC_CURVE_CLASS = {
gsk_cubic_curve_get_derivative_at,
gsk_cubic_curve_get_crossing,
gsk_cubic_curve_get_length_to,
gsk_cubic_curve_get_at_length,
};
/* }}} */
@@ -1940,20 +1853,7 @@ gsk_conic_curve_decompose_or_add (const GskCurve *curve,
GskCurveAddCurveFunc add_curve_func,
gpointer user_data)
{
if (graphene_point_equal (&curve->conic.points[0], &curve->conic.points[1]) ||
graphene_point_equal (&curve->conic.points[1], &curve->conic.points[3]))
{
if (!graphene_point_equal (&curve->conic.points[0], &curve->conic.points[3]))
return add_curve_func (GSK_PATH_LINE,
(graphene_point_t[2]) {
curve->conic.points[0],
curve->conic.points[3],
},
2, 0.f, user_data);
else
return TRUE;
}
else if (gsk_conic_is_close_to_cubic (curve, cubic, tolerance))
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);
else
{
@@ -1995,7 +1895,7 @@ gsk_conic_curve_decompose_curve (const GskCurve *curve,
return gsk_conic_curve_decompose_or_add (curve, &c, tolerance, add_curve_func, user_data);
}
/* FIXME: Quadratic approximation */
/* FIXME: Quadratic (or conic?) approximation */
return gsk_conic_curve_decompose (curve,
tolerance,
gsk_curve_add_line_cb,
@@ -2092,14 +1992,6 @@ gsk_conic_curve_get_length_to (const GskCurve *curve,
return get_length_by_approximation (curve, t);
}
static float
gsk_conic_curve_get_at_length (const GskCurve *curve,
float t,
float epsilon)
{
return get_t_by_bisection (curve, t, epsilon);
}
static const GskCurveClass GSK_CONIC_CURVE_CLASS = {
gsk_conic_curve_init,
gsk_conic_curve_init_foreach,
@@ -2122,7 +2014,6 @@ static const GskCurveClass GSK_CONIC_CURVE_CLASS = {
gsk_conic_curve_get_derivative_at,
gsk_conic_curve_get_crossing,
gsk_conic_curve_get_length_to,
gsk_conic_curve_get_at_length,
};
/* }}} */
@@ -2472,7 +2363,32 @@ gsk_curve_at_length (const GskCurve *curve,
float length,
float epsilon)
{
return get_class (curve->op)->get_at_length (curve, length, epsilon);
float t1, t2, t, l;
GskCurve c1;
g_assert (epsilon >= FLT_EPSILON);
t1 = 0;
t2 = 1;
while (t1 < t2)
{
t = (t1 + t2) / 2;
if (t == t1 || t == t2)
break;
gsk_curve_split (curve, t, &c1, NULL);
l = gsk_curve_get_length (&c1);
if (fabsf (length - l) < epsilon)
break;
else if (l < length)
t1 = t;
else
t2 = t;
}
return t;
}
static inline void

View File

@@ -23,8 +23,8 @@
#include "gskcurveprivate.h"
#include "gskpathbuilder.h"
#include "gskpathpoint.h"
#include "gskcontourprivate.h"
#include "gskpathpointprivate.h"
#include "gsksplineprivate.h"
/**
* GskPath:
@@ -66,8 +66,6 @@ struct _GskPath
G_DEFINE_BOXED_TYPE (GskPath, gsk_path, gsk_path_ref, gsk_path_unref)
/* {{{ Private API */
GskPath *
gsk_path_new_from_contours (const GSList *contours)
{
@@ -112,31 +110,6 @@ gsk_path_new_from_contours (const GSList *contours)
return path;
}
const GskContour *
gsk_path_get_contour (const GskPath *self,
gsize i)
{
if (i < self->n_contours)
return self->contours[i];
else
return NULL;
}
GskPathFlags
gsk_path_get_flags (const GskPath *self)
{
return self->flags;
}
gsize
gsk_path_get_n_contours (const GskPath *self)
{
return self->n_contours;
}
/* }}} */
/* {{{ Public API */
/**
* gsk_path_ref:
* @self: a `GskPath`
@@ -180,6 +153,22 @@ gsk_path_unref (GskPath *self)
g_free (self);
}
const GskContour *
gsk_path_get_contour (const GskPath *self,
gsize i)
{
if (i < self->n_contours)
return self->contours[i];
else
return NULL;
}
GskPathFlags
gsk_path_get_flags (const GskPath *self)
{
return self->flags;
}
/**
* gsk_path_print:
* @self: a `GskPath`
@@ -306,6 +295,20 @@ gsk_path_to_cairo (GskPath *self,
cr);
}
/*< private >
* gsk_path_get_n_contours:
* @path: a `GskPath`
*
* Gets the number of contours @path is composed out of.
*
* Returns: the number of contours in @path
*/
gsize
gsk_path_get_n_contours (const GskPath *self)
{
return self->n_contours;
}
/**
* gsk_path_is_empty:
* @self: a `GskPath`
@@ -508,19 +511,17 @@ gboolean
gsk_path_get_start_point (GskPath *self,
GskPathPoint *result)
{
GskRealPathPoint *res = (GskRealPathPoint *) result;
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (result != NULL, FALSE);
if (self->n_contours == 0)
return FALSE;
/* Conceptually, there is always a move at the
* beginning, which jumps from where to the start
* point of the contour, so we use idx == 1 here.
*/
result->contour = 0;
result->idx = 1;
result->t = 0;
res->contour = 0;
res->idx = 1;
res->t = 0;
return TRUE;
}
@@ -543,15 +544,17 @@ gboolean
gsk_path_get_end_point (GskPath *self,
GskPathPoint *result)
{
GskRealPathPoint *res = (GskRealPathPoint *) result;
g_return_val_if_fail (self != NULL, FALSE);
g_return_val_if_fail (result != NULL, FALSE);
if (self->n_contours == 0)
return FALSE;
result->contour = self->n_contours - 1;
result->idx = gsk_contour_get_n_ops (self->contours[self->n_contours - 1]) - 1;
result->t = 1;
res->contour = self->n_contours - 1;
res->idx = gsk_contour_get_n_ops (self->contours[self->n_contours - 1]) - 1;
res->t = 1;
return TRUE;
}
@@ -562,7 +565,6 @@ gsk_path_get_end_point (GskPath *self,
* @point: the point
* @threshold: maximum allowed distance
* @result: (out caller-allocates): return location for the closest point
* @distance: (out) (optional): return location for the distance
*
* Computes the closest point on the path to the given point
* and sets the @result to it.
@@ -579,9 +581,9 @@ gboolean
gsk_path_get_closest_point (GskPath *self,
const graphene_point_t *point,
float threshold,
GskPathPoint *result,
float *distance)
GskPathPoint *result)
{
GskRealPathPoint *res = (GskRealPathPoint *) result;
gboolean found;
g_return_val_if_fail (self != NULL, FALSE);
@@ -593,26 +595,19 @@ gsk_path_get_closest_point (GskPath *self,
for (int i = 0; i < self->n_contours; i++)
{
float dist;
float distance;
if (gsk_contour_get_closest_point (self->contours[i], point, threshold, result, &dist))
if (gsk_contour_get_closest_point (self->contours[i], point, threshold, res, &distance))
{
found = TRUE;
g_assert (0 <= result->t && result->t <= 1);
result->contour = i;
threshold = dist;
if (distance)
*distance = dist;
res->contour = i;
threshold = distance;
}
}
return found;
}
/* }}} */
/* {{{ Foreach and decomposition */
/**
* gsk_path_foreach:
* @self: a `GskPath`
@@ -810,15 +805,14 @@ gsk_path_foreach_with_tolerance (GskPath *self,
for (i = 0; i < self->n_contours; i++)
{
if (!gsk_contour_foreach (self->contours[i], func, user_data))
if (!gsk_contour_foreach (self->contours[i], tolerance, func, user_data))
return FALSE;
}
return TRUE;
}
/* }}} */
/* {{{ Parser and utilities */
/* path parser and utilities */
static void
skip_whitespace (const char **p)
@@ -960,195 +954,6 @@ parse_command (const char **p,
return FALSE;
}
static gboolean
parse_string (const char **p,
const char *s)
{
int len = strlen (s);
if (strncmp (*p, s, len) != 0)
return FALSE;
(*p) += len;
return TRUE;
}
#define NEAR(x, y) (fabs ((x) - (y)) < 0.001)
static gboolean
is_rect (double x0, double y0,
double x1, double y1,
double x2, double y2,
double x3, double y3)
{
return NEAR (x0, x3) && NEAR (x1, x2) &&
NEAR (y0, y1) && NEAR (y2, y3) &&
x0 < x1 && y1 < y2;
}
static gboolean
is_line (double x0, double y0,
double x1, double y1,
double x2, double y2,
double x3, double y3)
{
if (NEAR (y0, y3))
return x0 <= x1 && x1 <= x2 && x2 <= x3 &&
NEAR (y0, y1) && NEAR (y0, y2) && NEAR (y0, y3);
else
return y0 <= y1 && y1 <= y2 && y2 <= y3 &&
NEAR (x0, x1) && NEAR (x0, x2) && NEAR (x0, x3);
}
static gboolean
parse_rectangle (const char **p,
double *x,
double *y,
double *w,
double *h)
{
const char *o = *p;
double w2;
if (parse_coordinate_pair (p, x, y) &&
parse_string (p, "h") &&
parse_coordinate (p, w) &&
parse_string (p, "v") &&
parse_coordinate (p, h) &&
parse_string (p, "h") &&
parse_coordinate (p, &w2) &&
parse_string (p, "z") &&
w2 == -*w && *w >= 0 && *h >= 0)
{
skip_whitespace (p);
return TRUE;
}
*p = o;
return FALSE;
}
static gboolean
parse_circle (const char **p,
double *cx,
double *cy,
double *r)
{
const char *o = *p;
double x0, y0, x1, y1, x2, y2, x3, y3;
double x4, y4, x5, y5, x6, y6, x7, y7;
double x8, y8, w0, w1, w2, w3;
double rr;
if (parse_coordinate_pair (p, &x0, &y0) &&
parse_string (p, "o") &&
parse_coordinate_pair (p, &x1, &y1) &&
parse_coordinate_pair (p, &x2, &y2) &&
parse_nonnegative_number (p, &w0) &&
parse_string (p, "o") &&
parse_coordinate_pair (p, &x3, &y3) &&
parse_coordinate_pair (p, &x4, &y4) &&
parse_nonnegative_number (p, &w1) &&
parse_string (p, "o") &&
parse_coordinate_pair (p, &x5, &y5) &&
parse_coordinate_pair (p, &x6, &y6) &&
parse_nonnegative_number (p, &w2) &&
parse_string (p, "o") &&
parse_coordinate_pair (p, &x7, &y7) &&
parse_coordinate_pair (p, &x8, &y8) &&
parse_nonnegative_number (p, &w3) &&
parse_string (p, "z"))
{
rr = y1;
if (x1 == 0 && y1 == rr &&
x2 == -rr && y2 == rr &&
x3 == -rr && y3 == 0 &&
x4 == -rr && y4 == -rr &&
x5 == 0 && y5 == -rr &&
x6 == rr && y6 == -rr &&
x7 == rr && y7 == 0 &&
x8 == rr && y8 == rr &&
NEAR (w0, M_SQRT1_2) && NEAR (w1, M_SQRT1_2) &&
NEAR (w2, M_SQRT1_2) && NEAR (w3, M_SQRT1_2))
{
*cx = x0 - rr;
*cy = y0;
*r = rr;
skip_whitespace (p);
return TRUE;
}
}
*p = o;
return FALSE;
}
static gboolean
parse_rounded_rect (const char **p,
GskRoundedRect *rr)
{
const char *o = *p;
double x0, y0, x1, y1, x2, y2, x3, y3;
double x4, y4, x5, y5, x6, y6, x7, y7;
double x8, y8, x9, y9, x10, y10, x11, y11;
double x12, y12, w0, w1, w2, w3;
if (parse_coordinate_pair (p, &x0, &y0) &&
parse_string (p, "L") &&
parse_coordinate_pair (p, &x1, &y1) &&
parse_string (p, "O") &&
parse_coordinate_pair (p, &x2, &y2) &&
parse_coordinate_pair (p, &x3, &y3) &&
parse_nonnegative_number (p, &w0) &&
parse_string (p, "L") &&
parse_coordinate_pair (p, &x4, &y4) &&
parse_string (p, "O") &&
parse_coordinate_pair (p, &x5, &y5) &&
parse_coordinate_pair (p, &x6, &y6) &&
parse_nonnegative_number (p, &w1) &&
parse_string (p, "L") &&
parse_coordinate_pair (p, &x7, &y7) &&
parse_string (p, "O") &&
parse_coordinate_pair (p, &x8, &y8) &&
parse_coordinate_pair (p, &x9, &y9) &&
parse_nonnegative_number (p, &w2) &&
parse_string (p, "L") &&
parse_coordinate_pair (p, &x10, &y10) &&
parse_string (p, "O") &&
parse_coordinate_pair (p, &x11, &y11) &&
parse_coordinate_pair (p, &x12, &y12) &&
parse_nonnegative_number (p, &w3) &&
parse_string (p, "Z"))
{
if (NEAR (x0, x12) && NEAR (y0, y12) &&
is_rect (x11, y11, x2, y2, x5, y5, x8, y8) &&
is_line (x11, y11, x0, y0, x1, y1, x2, y2) &&
is_line (x2, y2, x3, y3, x4, y4, x5, y5) &&
is_line (x8, y8, x7, y7, x6, y6, x5, y5) &&
is_line (x11, y11, x10, y10, x9, y9, x8, y8) &&
NEAR (w0, M_SQRT1_2) && NEAR (w1, M_SQRT1_2) &&
NEAR (w2, M_SQRT1_2) && NEAR (w3, M_SQRT1_2))
{
rr->bounds = GRAPHENE_RECT_INIT (x11, y11, x5 - x11, y5 - y11);
rr->corner[GSK_CORNER_TOP_LEFT] = GRAPHENE_SIZE_INIT (x12 - x11, y10 - y11);
rr->corner[GSK_CORNER_TOP_RIGHT] = GRAPHENE_SIZE_INIT (x2 - x1, y3 - y2);
rr->corner[GSK_CORNER_BOTTOM_RIGHT] = GRAPHENE_SIZE_INIT (x5 - x6, y5 - y4);
rr->corner[GSK_CORNER_BOTTOM_LEFT] = GRAPHENE_SIZE_INIT (x7 - x8, y8 - y7);
skip_whitespace (p);
return TRUE;
}
}
*p = o;
return FALSE;
}
#undef NEAR
/**
* gsk_path_parse:
* @string: a string
@@ -1233,56 +1038,15 @@ gsk_path_parse (const char *string)
case 'M':
case 'm':
{
double x1, y1, w, h, r;
GskRoundedRect rr;
double x1, y1;
/* Look for special contours */
if (parse_rectangle (&p, &x1, &y1, &w, &h))
{
gsk_path_builder_add_rect (builder, &GRAPHENE_RECT_INIT (x1, y1, w, h));
if (_strchr ("zZX", prev_cmd))
{
path_x = x1;
path_y = y1;
}
x = x1;
y = y1;
}
else if (parse_circle (&p, &x1, &y1, &r))
{
gsk_path_builder_add_circle (builder, &GRAPHENE_POINT_INIT (x1, y1), r);
if (_strchr ("zZX", prev_cmd))
{
path_x = x1 + r;
path_y = y1;
}
x = x1 + r;
y = y1;
}
else if (parse_rounded_rect (&p, &rr))
{
gsk_path_builder_add_rounded_rect (builder, &rr);
if (_strchr ("zZX", prev_cmd))
{
path_x = rr.bounds.origin.x + rr.corner[GSK_CORNER_TOP_LEFT].width;
path_y = rr.bounds.origin.y;
}
x = rr.bounds.origin.x + rr.corner[GSK_CORNER_TOP_LEFT].width;
y = rr.bounds.origin.y;
}
else if (parse_coordinate_pair (&p, &x1, &y1))
if (parse_coordinate_pair (&p, &x1, &y1))
{
if (cmd == 'm')
{
x1 += x;
y1 += y;
}
if (repeat)
gsk_path_builder_line_to (builder, x1, y1);
else
@@ -1294,7 +1058,6 @@ gsk_path_parse (const char *string)
path_y = y1;
}
}
x = x1;
y = y1;
}
@@ -1534,7 +1297,7 @@ gsk_path_parse (const char *string)
parse_coordinate_pair (&p, &x2, &y2) &&
parse_nonnegative_number (&p, &weight))
{
if (cmd == 'o')
if (cmd == 'c')
{
x1 += x;
y1 += y;
@@ -1613,7 +1376,3 @@ error:
return NULL;
}
/* }}} */
/* vim:set foldmethod=marker expandtab: */

View File

@@ -135,8 +135,7 @@ GDK_AVAILABLE_IN_4_14
gboolean gsk_path_get_closest_point (GskPath *self,
const graphene_point_t *point,
float threshold,
GskPathPoint *result,
float *distance);
GskPathPoint *result);
GDK_AVAILABLE_IN_4_14
gboolean gsk_path_foreach (GskPath *self,
@@ -144,12 +143,6 @@ gboolean gsk_path_foreach (GskPath
GskPathForeachFunc func,
gpointer user_data);
GDK_AVAILABLE_IN_4_14
gboolean gsk_path_dash (GskPath *self,
GskStroke *stroke,
GskPathForeachFunc func,
gpointer user_data);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GskPath, gsk_path_unref)
G_END_DECLS

View File

@@ -24,7 +24,6 @@
#include "gskpathbuilder.h"
#include "gskpathprivate.h"
#include "gskpathpointprivate.h"
#include "gskcontourprivate.h"
/**
@@ -446,6 +445,9 @@ gsk_path_builder_add_cairo_path (GskPathBuilder *self,
*
* The path is going around the rectangle in clockwise direction.
*
* 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.
*
@@ -455,13 +457,20 @@ void
gsk_path_builder_add_rect (GskPathBuilder *self,
const graphene_rect_t *rect)
{
graphene_rect_t r;
graphene_point_t current;
g_return_if_fail (self != NULL);
g_return_if_fail (rect != NULL);
graphene_rect_normalize_r (rect, &r);
gsk_path_builder_add_contour (self, gsk_rect_contour_new (&r));
current = self->current_point;
gsk_path_builder_move_to (self, rect->origin.x, rect->origin.y);
gsk_path_builder_rel_line_to (self, rect->size.width, 0);
gsk_path_builder_rel_line_to (self, 0, rect->size.height);
gsk_path_builder_rel_line_to (self, - rect->size.width, 0);
gsk_path_builder_close (self);
self->current_point = current;
}
/**
@@ -479,10 +488,59 @@ void
gsk_path_builder_add_rounded_rect (GskPathBuilder *self,
const GskRoundedRect *rect)
{
graphene_point_t current;
g_return_if_fail (self != NULL);
g_return_if_fail (rect != NULL);
gsk_path_builder_add_contour (self, gsk_rounded_rect_contour_new (rect));
current = self->current_point;
gsk_path_builder_move_to (self,
rect->bounds.origin.x + rect->corner[GSK_CORNER_TOP_LEFT].width,
rect->bounds.origin.y);
/* top */
gsk_path_builder_line_to (self,
rect->bounds.origin.x + rect->bounds.size.width - rect->corner[GSK_CORNER_TOP_RIGHT].width,
rect->bounds.origin.y);
/* topright corner */
gsk_path_builder_arc_to (self,
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);
/* right */
gsk_path_builder_line_to (self,
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_arc_to (self,
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);
/* bottom */
gsk_path_builder_line_to (self,
rect->bounds.origin.x + rect->corner[GSK_CORNER_BOTTOM_LEFT].width,
rect->bounds.origin.y + rect->bounds.size.height);
/* bottomleft corner */
gsk_path_builder_arc_to (self,
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);
/* left */
gsk_path_builder_line_to (self,
rect->bounds.origin.x,
rect->bounds.origin.y + rect->corner[GSK_CORNER_TOP_LEFT].height);
/* topleft corner */
gsk_path_builder_arc_to (self,
rect->bounds.origin.x,
rect->bounds.origin.y,
rect->bounds.origin.x + rect->corner[GSK_CORNER_TOP_LEFT].width,
rect->bounds.origin.y);
/* done */
gsk_path_builder_close (self);
self->current_point = current;
}
/**
@@ -495,8 +553,6 @@ gsk_path_builder_add_rounded_rect (GskPathBuilder *self,
*
* The path is going around the circle in clockwise direction.
*
* If @radius is zero, the contour will be a closed point.
*
* Since: 4.14
*/
void
@@ -504,11 +560,34 @@ gsk_path_builder_add_circle (GskPathBuilder *self,
const graphene_point_t *center,
float radius)
{
graphene_point_t current;
g_return_if_fail (self != NULL);
g_return_if_fail (center != NULL);
g_return_if_fail (radius >= 0);
g_return_if_fail (radius > 0);
gsk_path_builder_add_contour (self, gsk_circle_contour_new (center, radius));
current = self->current_point;
gsk_path_builder_move_to (self, center->x + radius, center->y);
// bottom right quarter
gsk_path_builder_arc_to (self,
center->x + radius, center->y + radius,
center->x, center->y + radius);
// bottom left quarter
gsk_path_builder_arc_to (self,
center->x - radius, center->y + radius,
center->x - radius, center->y);
// top left quarter
gsk_path_builder_arc_to (self,
center->x - radius, center->y - radius,
center->x, center->y - radius);
// top right quarter
gsk_path_builder_arc_to (self,
center->x + radius, center->y - radius,
center->x + radius, center->y);
// done
gsk_path_builder_close (self);
self->current_point = current;
}
/**
@@ -1394,6 +1473,8 @@ gsk_path_builder_add_segment (GskPathBuilder *self,
const GskPathPoint *start,
const GskPathPoint *end)
{
GskRealPathPoint *s = (GskRealPathPoint *) start;
GskRealPathPoint *e = (GskRealPathPoint *) end;
const GskContour *contour;
gsize n_contours = gsk_path_get_n_contours (path);
graphene_point_t current;
@@ -1401,49 +1482,51 @@ gsk_path_builder_add_segment (GskPathBuilder *self,
g_return_if_fail (self != NULL);
g_return_if_fail (path != NULL);
g_return_if_fail (gsk_path_point_valid (start, path));
g_return_if_fail (gsk_path_point_valid (end, path));
g_return_if_fail (start != NULL);
g_return_if_fail (end != NULL);
g_return_if_fail (s->contour < n_contours);
g_return_if_fail (e->contour < n_contours);
current = self->current_point;
contour = gsk_path_get_contour (path, start->contour);
contour = gsk_path_get_contour (path, s->contour);
n_ops = gsk_contour_get_n_ops (contour);
if (start->contour == end->contour)
if (s->contour == e->contour)
{
if (gsk_path_point_compare (start, end) < 0)
{
gsk_contour_add_segment (contour, self, TRUE, start, end);
gsk_contour_add_segment (contour, self, TRUE, s, e);
goto out;
}
else if (n_contours == 1)
{
if (n_ops > 1)
gsk_contour_add_segment (contour, self, TRUE,
start,
&GSK_PATH_POINT_INIT (start->contour, n_ops - 1, 1.f));
s,
&(GskRealPathPoint) { s->contour, n_ops - 1, 1 });
gsk_contour_add_segment (contour, self, n_ops <= 1,
&GSK_PATH_POINT_INIT (start->contour, 1, 0.f),
end);
&(GskRealPathPoint) { s->contour, 1, 0 },
e);
goto out;
}
}
if (n_ops > 1)
gsk_contour_add_segment (contour, self, TRUE,
start,
&GSK_PATH_POINT_INIT (start->contour, n_ops - 1, 1.f));
s,
&(GskRealPathPoint) { s->contour, n_ops - 1, 1. });
for (gsize i = (start->contour + 1) % n_contours; i != end->contour; i = (i + 1) % n_contours)
for (gsize i = (s->contour + 1) % n_contours; i != e->contour; i = (i + 1) % n_contours)
gsk_path_builder_add_contour (self, gsk_contour_dup (gsk_path_get_contour (path, i)));
contour = gsk_path_get_contour (path, end->contour);
contour = gsk_path_get_contour (path, e->contour);
n_ops = gsk_contour_get_n_ops (contour);
if (n_ops > 1)
gsk_contour_add_segment (contour, self, TRUE,
&GSK_PATH_POINT_INIT (end->contour, 1, 0.f),
end);
&(GskRealPathPoint) { e->contour, 1, 0 },
e);
out:
gsk_path_builder_end_current (self);

View File

@@ -1,280 +0,0 @@
/*
* 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 "gskcontourprivate.h"
#include "gskcurveprivate.h"
#include "gskpathprivate.h"
#include "gskstrokeprivate.h"
typedef struct
{
float offset; /* how much of the current dash we've spent */
gsize dash_index; /* goes from 0 to n_dash * 2, so we don't have to care about on/off
* for uneven dashes
*/
gboolean on; /* If we're currently dashing or not */
gboolean may_close; /* TRUE if we haven't turned the dash off in this contour */
gboolean needs_move_to; /* If we have emitted the initial move_to() yet */
enum {
NORMAL, /* no special behavior required */
SKIP, /* skip the next dash */
ONLY, /* only do the first dash */
DONE /* done with the first dash */
} first_dash_behavior; /* How to handle the first dash in the loop. We loop closed contours
* twice to make sure the first dash and the last dash can get joined
*/
float collect_start; /* We're collecting multiple line segments when decomposing. */
/* from the stroke */
float *dash;
gsize n_dash;
float dash_length;
float dash_offset;
GskPathForeachFunc func;
gpointer user_data;
} GskPathDash;
static void
gsk_path_dash_setup (GskPathDash *self)
{
self->offset = fmodf (self->dash_offset, 2 * self->dash_length);
self->dash_index = 0;
self->on = TRUE;
self->may_close = TRUE;
while (self->offset > self->dash[self->dash_index % self->n_dash])
{
self->offset -= self->dash[self->dash_index % self->n_dash];
self->dash_index++;
self->on = !self->on;
}
if (self->first_dash_behavior != ONLY)
self->needs_move_to = TRUE;
}
static gboolean
gsk_path_dash_ensure_move_to (GskPathDash *self,
const graphene_point_t *pt)
{
if (!self->needs_move_to)
return TRUE;
if (!self->func (GSK_PATH_MOVE, pt, 1, 0.f, self->user_data))
return FALSE;
self->needs_move_to = FALSE;
return TRUE;
}
static gboolean
gsk_path_dash_add_curve (const GskCurve *curve,
GskPathDash *self)
{
float remaining, t_start, t_end;
float used;
remaining = gsk_curve_get_length (curve);
used = 0;
t_start = 0;
while (remaining > 0)
{
float piece;
if (self->offset + remaining <= self->dash[self->dash_index % self->n_dash])
piece = remaining;
else
piece = self->dash[self->dash_index % self->n_dash] - self->offset;
t_end = gsk_curve_at_length (curve, used + piece, 0.001);
if (self->on)
{
if (self->first_dash_behavior != SKIP)
{
GskCurve segment;
if (piece > 0)
{
gsk_curve_segment (curve, t_start, t_end, &segment);
if (!gsk_path_dash_ensure_move_to (self, gsk_curve_get_start_point (&segment)))
return FALSE;
if (!gsk_pathop_foreach (gsk_curve_pathop (&segment), self->func, self->user_data))
return FALSE;
}
else
{
graphene_point_t p;
gsk_curve_get_point (curve, t_start, &p);
if (!gsk_path_dash_ensure_move_to (self, &p))
return FALSE;
}
}
}
else
{
self->may_close = FALSE;
if (self->first_dash_behavior == ONLY)
{
self->first_dash_behavior = DONE;
return FALSE;
}
self->first_dash_behavior = NORMAL;
}
if (self->offset + remaining <= self->dash[self->dash_index % self->n_dash])
{
self->offset += remaining;
remaining = 0;
}
else
{
t_start = t_end;
remaining -= piece;
used += piece;
self->offset = 0;
self->dash_index++;
self->dash_index %= 2 * self->n_dash;
self->on = !self->on;
self->needs_move_to = TRUE;
}
}
return TRUE;
}
static gboolean
gsk_path_dash_foreach (GskPathOperation op,
const graphene_point_t *pts,
gsize n_pts,
float weight,
gpointer user_data)
{
GskPathDash *self = user_data;
GskCurve curve;
switch (op)
{
case GSK_PATH_MOVE:
gsk_path_dash_setup (self);
break;
case GSK_PATH_CLOSE:
if (self->may_close)
{
if (graphene_point_equal (&pts[0], &pts[1]))
return self->func (GSK_PATH_CLOSE, pts, 2, weight, self->user_data);
}
else
op = GSK_PATH_LINE;
G_GNUC_FALLTHROUGH;
case GSK_PATH_LINE:
case GSK_PATH_QUAD:
case GSK_PATH_CUBIC:
case GSK_PATH_CONIC:
gsk_curve_init_foreach (&curve, op, pts, n_pts, weight);
if (!gsk_path_dash_add_curve (&curve, self))
return FALSE;
break;
default:
g_assert_not_reached ();
break;
}
return TRUE;
}
gboolean
gsk_contour_dash (const GskContour *contour,
GskStroke *stroke,
GskPathForeachFunc func,
gpointer user_data)
{
GskPathDash self = {
.offset = 0,
.dash = stroke->dash,
.n_dash = stroke->n_dash,
.dash_length = stroke->dash_length,
.dash_offset = stroke->dash_offset,
.func = func,
.user_data = user_data
};
gboolean is_closed = gsk_contour_get_flags (contour) & GSK_PATH_CLOSED ? TRUE : FALSE;
self.first_dash_behavior = is_closed ? SKIP : NORMAL;
if (!gsk_contour_foreach (contour, gsk_path_dash_foreach, &self))
return FALSE;
if (is_closed)
{
if (self.first_dash_behavior == NORMAL)
self.first_dash_behavior = ONLY;
else
self.first_dash_behavior = NORMAL;
self.needs_move_to = !self.on;
if (!gsk_contour_foreach (contour, gsk_path_dash_foreach, &self) &&
self.first_dash_behavior != DONE)
return FALSE;
}
return TRUE;
}
/**
* gsk_path_dash:
* @self: the `GskPath` to dash
* @stroke: the stroke containing the dash parameters
* @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 that is the result
* of dashing @self with the dash pattern from @stroke.
*
* Returns: `FALSE` if @func returned FALSE`, `TRUE` otherwise.
*
* Since: 4.14
*/
gboolean
gsk_path_dash (GskPath *self,
GskStroke *stroke,
GskPathForeachFunc func,
gpointer user_data)
{
gsize i;
/* Dashing disabled, no need to do any work */
if (stroke->dash_length <= 0)
return gsk_path_foreach (self, -1, func, user_data);
for (i = 0; i < gsk_path_get_n_contours (self); i++)
{
if (!gsk_contour_dash (gsk_path_get_contour (self, i), stroke, func, user_data))
return FALSE;
}
return TRUE;
}

View File

@@ -23,7 +23,6 @@
#include "gskpathbuilder.h"
#include "gskpathpointprivate.h"
#include "gskcontourprivate.h"
#include "gskpathprivate.h"
/**
@@ -39,8 +38,6 @@
*
* A `GskPathMeasure` struct is a reference counted struct
* and should be treated as opaque.
*
* Since: 4.14
*/
typedef struct _GskContourMeasure GskContourMeasure;
@@ -259,6 +256,7 @@ gsk_path_measure_get_point (GskPathMeasure *self,
float distance,
GskPathPoint *result)
{
GskRealPathPoint *res = (GskRealPathPoint *) result;
gsize i;
const GskContour *contour;
@@ -284,11 +282,8 @@ gsk_path_measure_get_point (GskPathMeasure *self,
contour = gsk_path_get_contour (self->path, i);
gsk_contour_get_point (contour, self->measures[i].contour_data, distance, result);
g_assert (0 <= result->t && result->t <= 1);
result->contour = i;
gsk_contour_get_point (contour, self->measures[i].contour_data, distance, res);
res->contour = i;
return TRUE;
}
@@ -309,16 +304,21 @@ float
gsk_path_point_get_distance (const GskPathPoint *point,
GskPathMeasure *measure)
{
GskRealPathPoint *p = (GskRealPathPoint *)point;
const GskContour *contour;
float contour_offset = 0;
g_return_val_if_fail (point != NULL, 0);
g_return_val_if_fail (measure != NULL, 0);
g_return_val_if_fail (gsk_path_point_valid (point, measure->path), 0);
g_return_val_if_fail (p->contour < measure->n_contours, 0);
contour = gsk_path_get_contour (measure->path, p->contour);
for (gsize i = 0; i < measure->n_contours; i++)
{
if (i == point->contour)
return contour_offset + gsk_contour_get_distance (gsk_path_get_contour (measure->path, i),
point,
if (contour == gsk_path_get_contour (measure->path, i))
return contour_offset + gsk_contour_get_distance (contour,
p,
measure->measures[i].contour_data);
contour_offset += measure->measures[i].length;

View File

@@ -22,7 +22,9 @@
#include <math.h>
#include "gskpathpointprivate.h"
#include "gskcontourprivate.h"
#include "gdk/gdkprivate.h"
#define RAD_TO_DEG(x) ((x) / (G_PI / 180.f))
@@ -39,10 +41,10 @@
* [method@Gsk.Path.get_start_point], [method@Gsk.Path.get_end_point]
* or [method@Gsk.PathMeasure.get_point].
*
* Note that `GskPathPoint` structs are meant to be stack-allocated,
* and don't hold a reference to the path object they are obtained from.
* It is the callers responsibility to keep a reference to the path
* as long as the `GskPathPoint` is used.
* Note that `GskPathPoint` structs are meant to be stack-allocated, and
* don't a reference to the path object they are obtained from. It is the
* callers responsibility to keep a reference to the path as long as the
* `GskPathPoint` is used.
*
* Since: 4.14
*/
@@ -51,6 +53,7 @@ G_DEFINE_BOXED_TYPE (GskPathPoint, gsk_path_point,
gsk_path_point_copy,
gsk_path_point_free)
GskPathPoint *
gsk_path_point_copy (GskPathPoint *point)
{
@@ -58,7 +61,7 @@ gsk_path_point_copy (GskPathPoint *point)
copy = g_new0 (GskPathPoint, 1);
memcpy (copy, point, sizeof (GskPathPoint));
memcpy (copy, point, sizeof (GskRealPathPoint));
return copy;
}
@@ -91,11 +94,14 @@ gboolean
gsk_path_point_equal (const GskPathPoint *point1,
const GskPathPoint *point2)
{
if (point1->contour == point2->contour)
const GskRealPathPoint *p1 = (const GskRealPathPoint *) point1;
const GskRealPathPoint *p2 = (const GskRealPathPoint *) point2;
if (p1->contour == p2->contour)
{
if ((point1->idx == point2->idx && point1->t == point2->t) ||
(point1->idx + 1 == point2->idx && point1->t == 1 && point2->t == 0) ||
(point1->idx == point2->idx + 1 && point1->t == 0 && point2->t == 1))
if ((p1->idx == p2->idx && p1->t == p2->t) ||
(p1->idx + 1 == p2->idx && p1->t == 1 && p2->t == 0) ||
(p1->idx == p2->idx + 1 && p1->t == 0 && p2->t == 1))
return TRUE;
}
@@ -119,20 +125,23 @@ int
gsk_path_point_compare (const GskPathPoint *point1,
const GskPathPoint *point2)
{
const GskRealPathPoint *p1 = (const GskRealPathPoint *) point1;
const GskRealPathPoint *p2 = (const GskRealPathPoint *) point2;
if (gsk_path_point_equal (point1, point2))
return 0;
if (point1->contour < point2->contour)
if (p1->contour < p2->contour)
return -1;
else if (point1->contour > point2->contour)
else if (p1->contour > p2->contour)
return 1;
else if (point1->idx < point2->idx)
else if (p1->idx < p2->idx)
return -1;
else if (point1->idx > point2->idx)
else if (p1->idx > p2->idx)
return 1;
else if (point1->t < point2->t)
else if (p1->t < p2->t)
return -1;
else if (point1->t > point2->t)
else if (p1->t > p2->t)
return 1;
return 0;
@@ -154,14 +163,16 @@ gsk_path_point_get_position (const GskPathPoint *point,
GskPath *path,
graphene_point_t *position)
{
GskRealPathPoint *self = (GskRealPathPoint *) point;
const GskContour *contour;
g_return_if_fail (self != NULL);
g_return_if_fail (path != NULL);
g_return_if_fail (gsk_path_point_valid (point, path));
g_return_if_fail (position != NULL);
g_return_if_fail (self->contour < gsk_path_get_n_contours (path));
contour = gsk_path_get_contour (path, point->contour),
gsk_contour_get_position (contour, point, position);
contour = gsk_path_get_contour (path, self->contour),
gsk_contour_get_position (contour, self, position);
}
/**
@@ -192,14 +203,16 @@ gsk_path_point_get_tangent (const GskPathPoint *point,
GskPathDirection direction,
graphene_vec2_t *tangent)
{
GskRealPathPoint *self = (GskRealPathPoint *) point;
const GskContour *contour;
g_return_if_fail (self != NULL);
g_return_if_fail (path != NULL);
g_return_if_fail (gsk_path_point_valid (point, path));
g_return_if_fail (tangent != NULL);
g_return_if_fail (self->contour < gsk_path_get_n_contours (path));
contour = gsk_path_get_contour (path, point->contour),
gsk_contour_get_tangent (contour, point, direction, tangent);
contour = gsk_path_get_contour (path, self->contour),
gsk_contour_get_tangent (contour, self, direction, tangent);
}
/**
@@ -224,10 +237,12 @@ gsk_path_point_get_rotation (const GskPathPoint *point,
GskPath *path,
GskPathDirection direction)
{
GskRealPathPoint *self = (GskRealPathPoint *) point;
graphene_vec2_t tangent;
g_return_val_if_fail (self != NULL, 0);
g_return_val_if_fail (path != NULL, 0);
g_return_val_if_fail (gsk_path_point_valid (point, path), 0);
g_return_val_if_fail (self->contour < gsk_path_get_n_contours (path), 0);
gsk_path_point_get_tangent (point, path, direction, &tangent);
@@ -251,8 +266,6 @@ gsk_path_point_get_rotation (const GskPathPoint *point,
* Lines have a curvature of zero (indicating an osculating circle of
* infinite radius. In this case, the @center is not modified.
*
* Circles with a radius of zero have `INFINITY` as curvature
*
* Note that certain points on a path may not have a single curvature,
* such as sharp turns. At such points, there are two curvatures --
* the (limit of) the curvature of the path going into the point,
@@ -274,11 +287,13 @@ gsk_path_point_get_curvature (const GskPathPoint *point,
GskPathDirection direction,
graphene_point_t *center)
{
GskRealPathPoint *self = (GskRealPathPoint *) point;
const GskContour *contour;
g_return_val_if_fail (self != NULL, 0);
g_return_val_if_fail (path != NULL, 0);
g_return_val_if_fail (gsk_path_point_valid (point, path), 0);
g_return_val_if_fail (self->contour < gsk_path_get_n_contours (path), 0);
contour = gsk_path_get_contour (path, point->contour);
return gsk_contour_get_curvature (contour, point, direction, center);
contour = gsk_path_get_contour (path, self->contour);
return gsk_contour_get_curvature (contour, self, direction, center);
}

View File

@@ -34,14 +34,9 @@ typedef struct _GskPathPoint GskPathPoint;
struct _GskPathPoint {
/*< private >*/
union {
struct {
gsize contour;
gsize idx;
float t;
};
gpointer padding[8];
graphene_vec4_t alignment;
};
float f[8];
gpointer p[8];
} data;
};
GDK_AVAILABLE_IN_4_14

View File

@@ -5,35 +5,14 @@
G_BEGIN_DECLS
#define GSK_PATH_POINT_INIT(c,i,tt) ((GskPathPoint){ .contour=(c), .idx=(i), .t=(tt) })
static inline gboolean
gsk_path_point_valid (const GskPathPoint *point,
GskPath *path)
struct _GskRealPathPoint
{
const GskContour *contour;
gsize n_ops;
gsize contour;
gsize idx;
float t;
};
if (point == NULL)
return FALSE;
if (path == NULL)
return TRUE;
if (point->contour >= gsk_path_get_n_contours (path))
return FALSE;
contour = gsk_path_get_contour (path, point->contour);
n_ops = gsk_contour_get_n_ops (contour);
if ((n_ops > 1 && point->idx >= n_ops) ||
(n_ops == 1 && point->idx > n_ops))
return FALSE;
if (point->t < 0 || point->t > 1)
return FALSE;
return TRUE;
}
G_STATIC_ASSERT (sizeof (GskRealPathPoint) <= sizeof (GskPathPoint));
G_END_DECLS

208
gsk/gskspline.c Normal file
View File

@@ -0,0 +1,208 @@
/*
* Copyright © 2002 University of Southern California
* 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>
* Carl D. Worth <cworth@cworth.org>
*/
#include "config.h"
#include "gsksplineprivate.h"
#include <math.h>
/* Spline deviation from the circle in radius would be given by:
error = sqrt (x**2 + y**2) - 1
A simpler error function to work with is:
e = x**2 + y**2 - 1
From "Good approximation of circles by curvature-continuous Bezier
curves", Tor Dokken and Morten Daehlen, Computer Aided Geometric
Design 8 (1990) 22-41, we learn:
abs (max(e)) = 4/27 * sin**6(angle/4) / cos**2(angle/4)
and
abs (error) =~ 1/2 * e
Of course, this error value applies only for the particular spline
approximation that is used in _cairo_gstate_arc_segment.
*/
static float
arc_error_normalized (float angle)
{
return 2.0/27.0 * pow (sin (angle / 4), 6) / pow (cos (angle / 4), 2);
}
static float
arc_max_angle_for_tolerance_normalized (float tolerance)
{
float angle, error;
guint i;
/* Use table lookup to reduce search time in most cases. */
struct {
float angle;
float error;
} table[] = {
{ G_PI / 1.0, 0.0185185185185185036127 },
{ G_PI / 2.0, 0.000272567143730179811158 },
{ G_PI / 3.0, 2.38647043651461047433e-05 },
{ G_PI / 4.0, 4.2455377443222443279e-06 },
{ G_PI / 5.0, 1.11281001494389081528e-06 },
{ G_PI / 6.0, 3.72662000942734705475e-07 },
{ G_PI / 7.0, 1.47783685574284411325e-07 },
{ G_PI / 8.0, 6.63240432022601149057e-08 },
{ G_PI / 9.0, 3.2715520137536980553e-08 },
{ G_PI / 10.0, 1.73863223499021216974e-08 },
{ G_PI / 11.0, 9.81410988043554039085e-09 },
};
for (i = 0; i < G_N_ELEMENTS (table); i++)
{
if (table[i].error < tolerance)
return table[i].angle;
}
i++;
do {
angle = G_PI / i++;
error = arc_error_normalized (angle);
} while (error > tolerance);
return angle;
}
static guint
arc_segments_needed (float angle,
float radius,
float tolerance)
{
float max_angle;
/* the error is amplified by at most the length of the
* major axis of the circle; see cairo-pen.c for a more detailed analysis
* of this. */
max_angle = arc_max_angle_for_tolerance_normalized (tolerance / radius);
return ceil (fabs (angle) / max_angle);
}
/* We want to draw a single spline approximating a circular arc radius
R from angle A to angle B. Since we want a symmetric spline that
matches the endpoints of the arc in position and slope, we know
that the spline control points must be:
(R * cos(A), R * sin(A))
(R * cos(A) - h * sin(A), R * sin(A) + h * cos (A))
(R * cos(B) + h * sin(B), R * sin(B) - h * cos (B))
(R * cos(B), R * sin(B))
for some value of h.
"Approximation of circular arcs by cubic polynomials", Michael
Goldapp, Computer Aided Geometric Design 8 (1991) 227-238, provides
various values of h along with error analysis for each.
From that paper, a very practical value of h is:
h = 4/3 * R * tan(angle/4)
This value does not give the spline with minimal error, but it does
provide a very good approximation, (6th-order convergence), and the
error expression is quite simple, (see the comment for
_arc_error_normalized).
*/
static gboolean
gsk_spline_decompose_arc_segment (const graphene_point_t *center,
float radius,
float angle_A,
float angle_B,
GskSplineAddCurveFunc curve_func,
gpointer user_data)
{
float r_sin_A, r_cos_A;
float r_sin_B, r_cos_B;
float h;
r_sin_A = radius * sin (angle_A);
r_cos_A = radius * cos (angle_A);
r_sin_B = radius * sin (angle_B);
r_cos_B = radius * cos (angle_B);
h = 4.0/3.0 * tan ((angle_B - angle_A) / 4.0);
return curve_func ((graphene_point_t[4]) {
GRAPHENE_POINT_INIT (
center->x + r_cos_A,
center->y + r_sin_A
),
GRAPHENE_POINT_INIT (
center->x + r_cos_A - h * r_sin_A,
center->y + r_sin_A + h * r_cos_A
),
GRAPHENE_POINT_INIT (
center->x + r_cos_B + h * r_sin_B,
center->y + r_sin_B - h * r_cos_B
),
GRAPHENE_POINT_INIT (
center->x + r_cos_B,
center->y + r_sin_B
)
},
user_data);
}
gboolean
gsk_spline_decompose_arc (const graphene_point_t *center,
float radius,
float tolerance,
float start_angle,
float end_angle,
GskSplineAddCurveFunc curve_func,
gpointer user_data)
{
float step = start_angle - end_angle;
guint i, n_segments;
/* Recurse if drawing arc larger than pi */
if (ABS (step) > G_PI)
{
float mid_angle = (start_angle + end_angle) / 2.0;
return gsk_spline_decompose_arc (center, radius, tolerance, start_angle, mid_angle, curve_func, user_data)
&& gsk_spline_decompose_arc (center, radius, tolerance, mid_angle, end_angle, curve_func, user_data);
}
else if (ABS (step) < tolerance)
{
return gsk_spline_decompose_arc_segment (center, radius, start_angle, end_angle, curve_func, user_data);
}
n_segments = arc_segments_needed (ABS (step), radius, tolerance);
step = (end_angle - start_angle) / n_segments;
for (i = 0; i < n_segments - 1; i++, start_angle += step)
{
if (!gsk_spline_decompose_arc_segment (center, radius, start_angle, start_angle + step, curve_func, user_data))
return FALSE;
}
return gsk_spline_decompose_arc_segment (center, radius, start_angle, end_angle, curve_func, user_data);
}

41
gsk/gsksplineprivate.h Normal file
View File

@@ -0,0 +1,41 @@
/*
* 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_SPLINE_PRIVATE_H__
#define __GSK_SPLINE_PRIVATE_H__
#include "gskpath.h"
G_BEGIN_DECLS
typedef gboolean (* GskSplineAddCurveFunc) (const graphene_point_t curve[4],
gpointer user_data);
gboolean gsk_spline_decompose_arc (const graphene_point_t *center,
float radius,
float tolerance,
float start_angle,
float end_angle,
GskSplineAddCurveFunc curve_func,
gpointer user_data);
G_END_DECLS
#endif /* __GSK_SPLINE_PRIVATE_H__ */

View File

@@ -27,7 +27,6 @@ gsk_public_sources = files([
'gskdiff.c',
'gskglshader.c',
'gskpath.c',
'gskpathdash.c',
'gskpathbuilder.c',
'gskpathmeasure.c',
'gskpathpoint.c',
@@ -48,6 +47,7 @@ gsk_private_sources = files([
'gskdebug.c',
'gskprivate.c',
'gskprofiler.c',
'gskspline.c',
'gl/gskglattachmentstate.c',
'gl/gskglbuffer.c',
'gl/gskglcommandqueue.c',

View File

@@ -302,8 +302,8 @@ gtk_tooltip_set_icon_from_gicon (GtkTooltip *tooltip,
* Replaces the widget packed into the tooltip with
* @custom_widget. @custom_widget does not get destroyed when the tooltip goes
* away.
* By default a box with a `GtkImage` and `GtkLabel` is embedded in
* the tooltip, which can be configured using gtk_tooltip_set_markup()
* By default a box with a `GtkImage` and `GtkLabel` is embedded in
* the tooltip, which can be configured using gtk_tooltip_set_markup()
* and gtk_tooltip_set_icon().
*/
void
@@ -560,9 +560,6 @@ gtk_tooltip_run_requery (GtkWidget **widget,
{
GtkWidget *parent = gtk_widget_get_parent (*widget);
if (GTK_IS_NATIVE (*widget))
break;
if (parent)
{
graphene_point_t r = GRAPHENE_POINT_INIT (*x, *y);

View File

@@ -429,7 +429,6 @@ tools/gtk-path-tool.c
tools/gtk-path-tool-decompose.c
tools/gtk-path-tool-info.c
tools/gtk-path-tool-render.c
tools/gtk-path-tool-restrict.c
tools/gtk-path-tool-show.c
tools/gtk-path-tool-utils.c
tools/gtk-rendernode-tool.c

View File

@@ -37,8 +37,6 @@ demos/gtk-demo/main.ui
demos/gtk-demo/menus.ui
demos/gtk-demo/offscreen_window2.c
demos/gtk-demo/paint.c
demos/gtk-demo/path_text.ui
demos/gtk-demo/path_walk.ui
demos/gtk-demo/popover.ui
demos/gtk-demo/revealer.ui
demos/gtk-demo/scale.ui

187
po/ca.po
View File

@@ -34,8 +34,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gtk+ 2.8.2\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gtk/-/issues/\n"
"POT-Creation-Date: 2023-08-26 02:30+0000\n"
"PO-Revision-Date: 2023-08-26 11:18+0100\n"
"POT-Creation-Date: 2023-08-05 10:34+0000\n"
"PO-Revision-Date: 2023-08-05 11:18+0100\n"
"Last-Translator: Jordi Mas i Hernàndez <jmas@softcatala.org>\n"
"Language-Team: Catalan <tradgnome@softcatala.org>\n"
"Language: ca\n"
@@ -161,7 +161,7 @@ msgstr "L'aplicació no admet API de %s"
#. translators: This is about OpenGL backend names, like
#. * "Trying to use X11 GLX, but EGL is already in use"
#: gdk/gdkglcontext.c:1864
#: gdk/gdkglcontext.c:1863
#, c-format
msgid "Trying to use %s, but %s is already in use"
msgstr "S'està intentant utilitzar %s, però ja s'està utilitzant %s"
@@ -596,7 +596,7 @@ msgstr "No s'ha pogut llegir les dades a la fila %d"
#: gdk/macos/gdkmacospasteboard.c:211 gdk/wayland/gdkclipboard-wayland.c:240
#: gdk/wayland/gdkdrop-wayland.c:207 gdk/wayland/gdkprimary-wayland.c:343
#: gdk/win32/gdkdrop-win32.c:1018 gdk/win32/gdkdrop-win32.c:1063
#: gdk/x11/gdkclipboard-x11.c:807 gdk/x11/gdkdrop-x11.c:235
#: gdk/x11/gdkclipboard-x11.c:805 gdk/x11/gdkdrop-x11.c:235
msgid "No compatible transfer format found"
msgstr "No s'ha trobat cap format de transferència compatible"
@@ -770,9 +770,10 @@ msgid "No GL implementation is available"
msgstr "No hi ha cap implementació GL disponible"
#: gdk/win32/gdkglcontext-win32-wgl.c:396
#, c-format
#, fuzzy, c-format
#| msgid "EGL version %d.%d is too old. GTK requires %d.%d"
msgid "WGL version %d.%d is too low, need at least %d.%d"
msgstr "La versió %d.%d de WGL és massa baixa, cal com a mínim %d.%d"
msgstr "La versió de l'EGL %d.%d és massa antiga. La GTK requereix %d.%d"
#: gdk/win32/gdkglcontext-win32-wgl.c:414
#, c-format
@@ -837,11 +838,11 @@ msgid_plural "Opening %d Items"
msgstr[0] "S'està obrint %d element"
msgstr[1] "S'estan obrint %d elements"
#: gdk/x11/gdkclipboard-x11.c:477
#: gdk/x11/gdkclipboard-x11.c:475
msgid "Clipboard manager could not store selection."
msgstr "El gestor de porta-retalls no ha pogut desar la selecció."
#: gdk/x11/gdkclipboard-x11.c:657
#: gdk/x11/gdkclipboard-x11.c:655
msgid "Cannot store clipboard. No clipboard manager is active."
msgstr ""
"No es pot emmagatzemar el porta-retalls. No està actiu el gestor del porta-"
@@ -1110,13 +1111,13 @@ msgid "Pick a Color"
msgstr "Trieu un color"
#: gtk/deprecated/gtkcolorbutton.c:502 gtk/gtkcolorchooserwidget.c:313
#: gtk/gtkcolordialogbutton.c:335
#: gtk/gtkcolordialogbutton.c:302
#, c-format
msgid "Red %d%%, Green %d%%, Blue %d%%, Alpha %d%%"
msgstr "Vermell %d%%, verd %d%%, blau %d%%, alfa %d%%"
#: gtk/deprecated/gtkcolorbutton.c:508 gtk/gtkcolorchooserwidget.c:319
#: gtk/gtkcolordialogbutton.c:341
#: gtk/gtkcolordialogbutton.c:308
#, c-format
msgid "Red %d%%, Green %d%%, Blue %d%%"
msgstr "Vermell %d%%, verd %d%%, blau %d%%"
@@ -1131,11 +1132,11 @@ msgid "Pick a Font"
msgstr "Trieu un tipus de lletra"
#: gtk/deprecated/gtkfontbutton.c:597 gtk/gtkfilechooserwidget.c:3871
#: gtk/gtkfontdialogbutton.c:126 gtk/inspector/visual.ui:169
#: gtk/gtkfontdialogbutton.c:115 gtk/inspector/visual.ui:169
msgid "Font"
msgstr "Tipus de lletra"
#: gtk/deprecated/gtkfontbutton.c:1152 gtk/gtkfontdialogbutton.c:652
#: gtk/deprecated/gtkfontbutton.c:1152 gtk/gtkfontdialogbutton.c:614
msgctxt "font"
msgid "None"
msgstr "Cap"
@@ -2108,7 +2109,7 @@ msgstr "Personalitzat"
#: gtk/gtkcolorchooserwidget.c:571
msgid "Add Color"
msgstr "Afegeix un color"
msgstr "Afegeix color"
#: gtk/gtkcolorchooserwidget.c:593
#, c-format
@@ -2273,7 +2274,7 @@ msgstr "_Obre"
msgid "_Save"
msgstr "_Desa"
#: gtk/gtkfilechoosernativequartz.c:344 gtk/ui/gtkfilechooserwidget.ui:288
#: gtk/gtkfilechoosernativequartz.c:340 gtk/ui/gtkfilechooserwidget.ui:288
msgid "Select which types of files are shown"
msgstr "Seleccioneu quins tipus de fitxers es mostren"
@@ -2346,7 +2347,7 @@ msgid "If you delete an item, it will be permanently lost."
msgstr "Si suprimiu un element, es perdrà definitivament."
#: gtk/gtkfilechooserwidget.c:1185 gtk/gtkfilechooserwidget.c:1815
#: gtk/gtklabel.c:5695 gtk/gtktext.c:6145 gtk/gtktextview.c:9018
#: gtk/gtklabel.c:5695 gtk/gtktext.c:6125 gtk/gtktextview.c:9018
msgid "_Delete"
msgstr "_Suprimeix"
@@ -2487,7 +2488,7 @@ msgstr "Programa"
msgid "Audio"
msgstr "Àudio"
#: gtk/gtkfilechooserwidget.c:3872 gtk/gtkfilefilter.c:1032
#: gtk/gtkfilechooserwidget.c:3872 gtk/gtkfilefilter.c:1035
msgid "Image"
msgstr "Imatge"
@@ -2598,7 +2599,7 @@ msgstr "Selecciona carpetes"
msgid "Select a Folder"
msgstr "Selecciona una carpeta"
#: gtk/gtkfilefilter.c:1045
#: gtk/gtkfilefilter.c:1048
msgid "Unspecified"
msgstr "No especificat"
@@ -2690,19 +2691,19 @@ msgstr "Tanca"
msgid "Close the infobar"
msgstr "Tanca la barra d'informació"
#: gtk/gtklabel.c:5692 gtk/gtktext.c:6133 gtk/gtktextview.c:9006
#: gtk/gtklabel.c:5692 gtk/gtktext.c:6113 gtk/gtktextview.c:9006
msgid "Cu_t"
msgstr "Re_talla"
#: gtk/gtklabel.c:5693 gtk/gtktext.c:6137 gtk/gtktextview.c:9010
#: gtk/gtklabel.c:5693 gtk/gtktext.c:6117 gtk/gtktextview.c:9010
msgid "_Copy"
msgstr "_Copia"
#: gtk/gtklabel.c:5694 gtk/gtktext.c:6141 gtk/gtktextview.c:9014
#: gtk/gtklabel.c:5694 gtk/gtktext.c:6121 gtk/gtktextview.c:9014
msgid "_Paste"
msgstr "_Enganxa"
#: gtk/gtklabel.c:5700 gtk/gtktext.c:6154 gtk/gtktextview.c:9039
#: gtk/gtklabel.c:5700 gtk/gtktext.c:6134 gtk/gtktextview.c:9039
msgid "Select _All"
msgstr "Seleccion_a-ho tot"
@@ -2912,7 +2913,7 @@ msgstr "Pestanya anterior"
msgid "Next tab"
msgstr "Pestanya següent"
#: gtk/gtknotebook.c:4331 gtk/gtknotebook.c:6541
#: gtk/gtknotebook.c:4331 gtk/gtknotebook.c:6539
#, c-format
msgid "Page %u"
msgstr "Pàgina %u"
@@ -3657,7 +3658,7 @@ msgctxt "accessibility"
msgid "Sidebar"
msgstr "Barra lateral"
#: gtk/gtktext.c:6159 gtk/gtktextview.c:9044
#: gtk/gtktext.c:6139 gtk/gtktextview.c:9044
msgid "Insert _Emoji"
msgstr "Insereix _emoji"
@@ -7203,7 +7204,20 @@ msgid "Cant close stream"
msgstr "No es pot tancar el flux"
#: tools/gtk-builder-tool.c:36
#, c-format
#, fuzzy, c-format
#| msgid ""
#| "Usage:\n"
#| " gtk-builder-tool [COMMAND] [OPTION…] FILE\n"
#| "\n"
#| "Perform various tasks on GtkBuilder .ui files.\n"
#| "\n"
#| "Commands:\n"
#| " validate Validate the file\n"
#| " simplify Simplify the file\n"
#| " enumerate List all named objects\n"
#| " preview Preview the file\n"
#| " screenshot Take a screenshot of the file\n"
#| "\n"
msgid ""
"Usage:\n"
" gtk4-builder-tool [COMMAND] [OPTION…] FILE\n"
@@ -7229,8 +7243,7 @@ msgstr ""
" simplify Simplifica el fitxer\n"
" enumerate Llista tots els objectes anomenats\n"
" preview Previsualitza el fitxer\n"
" render Fes una captura de pantalla del fitxer\n"
" screenshot Fes una captura de pantalla del fitxer\n"
" screenshot Fes una captura de pantalla\n"
"\n"
#: tools/gtk-builder-tool-enumerate.c:56 tools/gtk-builder-tool-preview.c:179
@@ -7275,9 +7288,10 @@ msgstr "Utilitza l'estil del fitxer CSS"
#: tools/gtk-builder-tool-screenshot.c:370
#: tools/gtk-builder-tool-validate.c:268 tools/gtk-rendernode-tool-show.c:109
#: tools/gtk-rendernode-tool-render.c:204
#, c-format
#, fuzzy, c-format
#| msgid "Could not initialize EGL display"
msgid "Could not initialize windowing system\n"
msgstr "No s'ha pogut inicialitzar el sistema de finestres\n"
msgstr "No s'ha pogut inicialitzar la pantalla EGL"
#: tools/gtk-builder-tool-preview.c:195
msgid "Preview the file."
@@ -7292,14 +7306,13 @@ msgid "No .ui file specified\n"
msgstr "No s'ha especificat un fitxer .ui\n"
#: tools/gtk-builder-tool-preview.c:214
#, c-format
#, fuzzy, c-format
#| msgid "Can only simplify a single .ui file without --replace\n"
msgid "Can only preview a single .ui file\n"
msgstr "Només es pot previsualitzar un únic fitxer .ui\n"
msgstr "Només es pot simplificar un únic fitxer .ui sense --replace\n"
#: tools/gtk-builder-tool-screenshot.c:238
#, c-format
#| msgid "No results found"
msgid "No object found\n"
msgstr "No s'ha trobat cap objecte\n"
@@ -7310,9 +7323,10 @@ msgstr "Els objectes del tipus %s no poden ser captura de pantalla\n"
# FIXME
#: tools/gtk-builder-tool-screenshot.c:298
#, c-format
#, fuzzy, c-format
#| msgid "Failed to write hash table\n"
msgid "Failed to take a screenshot\n"
msgstr "No s'ha pogut fer una captura de pantalla\n"
msgstr "No s'ha pogut escriure la taula de resum\n"
#: tools/gtk-builder-tool-screenshot.c:309
#, c-format
@@ -7331,9 +7345,10 @@ msgstr "Sortida escrita a %s.\n"
#: tools/gtk-builder-tool-screenshot.c:336
#: tools/gtk-rendernode-tool-render.c:176
#, c-format
#, fuzzy, c-format
#| msgid "Failed to open file %s : %s\n"
msgid "Failed to save %s: %s\n"
msgstr "No s'ha pogut desar %s: %s\n"
msgstr "No s'ha pogut obrir el fitxer %s: %s\n"
#: tools/gtk-builder-tool-screenshot.c:359
msgid "Screenshot only the named object"
@@ -7357,9 +7372,10 @@ msgid "Render a .ui file to an image."
msgstr "Renderitza un fitxer .ui a una imatge."
#: tools/gtk-builder-tool-screenshot.c:397
#, fuzzy, c-format
#| msgid "Can only simplify a single .ui file without --replace\n"
msgid "Can only render a single .ui file to a single output file\n"
msgstr ""
"Només es pot renderitzar un únic fitxer .ui a un únic fitxer de sortida\n"
msgstr "Només es pot simplificar un únic fitxer .ui sense --replace\n"
#: tools/gtk-builder-tool-simplify.c:444
#, c-format
@@ -7367,24 +7383,28 @@ msgid "%s:%d: Couldnt parse value for property '%s': %s\n"
msgstr "%s:%d: no s'ha pogut analitzar el valor per a la propietat «%s»: %s\n"
#: tools/gtk-builder-tool-simplify.c:658
#, c-format
#, c-format, fuzzy
#| msgid "%s:%d: %sproperty %s::%s not found\n"
msgid "Property %s not found"
msgstr "No s'ha trobat la propietat %s"
#: tools/gtk-builder-tool-simplify.c:661
#, c-format
#, c-format, fuzzy
#| msgid "%s:%d: %sproperty %s::%s not found\n"
msgid "Packing property %s not found"
msgstr "No s'ha trobat la propietat d'empaquetatge %s"
#: tools/gtk-builder-tool-simplify.c:664
#, c-format
#, fuzzy, c-format
#| msgid "%s:%d: %sproperty %s::%s not found\n"
msgid "Cell property %s not found"
msgstr "No s'ha trobat la propietat de cel·la %s"
msgstr "%s:%d: %sproperty %s::%s no s'ha trobat\n"
#: tools/gtk-builder-tool-simplify.c:667
#, c-format
#, fuzzy, c-format
#| msgid "%s:%d: %sproperty %s::%s not found\n"
msgid "Layout property %s not found"
msgstr "No s'ha trobat la propietat de disposició %s"
msgstr "%s:%d: %sproperty %s::%s no s'ha trobat\n"
#: tools/gtk-builder-tool-simplify.c:1397
#, c-format
@@ -7410,6 +7430,7 @@ msgstr "No s'ha pogut llegir «%s»: %s\n"
#: tools/gtk-builder-tool-simplify.c:2510
#, c-format
#| msgid "Failed to write %s: “%s”\n"
msgid "Failed to write “%s”: “%s”\n"
msgstr "No s'ha pogut escriure «%s»: «%s»\n"
@@ -7431,9 +7452,9 @@ msgid "Can only simplify a single .ui file without --replace\n"
msgstr "Només es pot simplificar un únic fitxer .ui sense --replace\n"
#: tools/gtk-builder-tool-validate.c:45
#, c-format
#, c-format, fuzzy
msgid "Failed to lookup template parent type %s\n"
msgstr "No s'ha pogut cercar el tipus pare de la plantilla %s\n"
msgstr "No s'ha pogut cercar el tipus pare de la plantilla %s"
#: tools/gtk-builder-tool-validate.c:123
msgid "Deprecated types:\n"
@@ -7508,7 +7529,20 @@ msgid "%s: error launching application: %s\n"
msgstr "%s: s'ha produït un error en executar l'aplicació: %s\n"
#: tools/gtk-rendernode-tool.c:35
#, c-format
#, fuzzy, c-format
#| msgid ""
#| "Usage:\n"
#| " gtk-builder-tool [COMMAND] [OPTION…] FILE\n"
#| "\n"
#| "Perform various tasks on GtkBuilder .ui files.\n"
#| "\n"
#| "Commands:\n"
#| " validate Validate the file\n"
#| " simplify Simplify the file\n"
#| " enumerate List all named objects\n"
#| " preview Preview the file\n"
#| " screenshot Take a screenshot of the file\n"
#| "\n"
msgid ""
"Usage:\n"
" gtk4-rendernode-tool [COMMAND] [OPTION…] FILE\n"
@@ -7522,14 +7556,16 @@ msgid ""
"\n"
msgstr ""
"Ús:\n"
" gtk4-rendernode-tool [ORDRE] [OPCIÓ...] FITXER\n"
" gtk-builder-tool [ORDRE] [OPCIONS…] FITXER\n"
"\n"
"Realitza diverses tasques als nodes de renderització GTK.\n"
"Fes diverses tasques en fitxers GtkBuilder .ui.\n"
"\n"
"Ordres:\n"
" info Proporciona informació sobre el node\n"
" show Mostra el node\n"
" render Fes una captura de pantalla del node\n"
" validate Valida el fitxer\n"
" simplify Simplifica el fitxer\n"
" enumerate Llista tots els objectes anomenats\n"
" preview Previsualitza el fitxer\n"
" screenshot Fes una captura de pantalla\n"
"\n"
#: tools/gtk-rendernode-tool-info.c:177
@@ -7558,39 +7594,44 @@ msgstr "Proporciona informació sobre el node de renderització."
#: tools/gtk-rendernode-tool-info.c:222 tools/gtk-rendernode-tool-show.c:130
#: tools/gtk-rendernode-tool-render.c:225
#, c-format
#, fuzzy, c-format
#| msgid "No .ui file specified\n"
msgid "No .node file specified\n"
msgstr "No s'ha especificat un fitxer .node\n"
msgstr "No s'ha especificat un fitxer .ui\n"
#: tools/gtk-rendernode-tool-info.c:228
#, c-format
#, fuzzy, c-format
#| msgid "Can only simplify a single .ui file without --replace\n"
msgid "Can only accept a single .node file\n"
msgstr "Només es pot acceptar un únic fitxer .node\n"
msgstr "Només es pot simplificar un únic fitxer .ui sense --replace\n"
#: tools/gtk-rendernode-tool-show.c:117
msgid "Show the render node."
msgstr "Mostra el node de renderització."
#: tools/gtk-rendernode-tool-show.c:136
#, c-format
#, fuzzy, c-format
#| msgid "Can only simplify a single .ui file without --replace\n"
msgid "Can only preview a single .node file\n"
msgstr "Només es pot previsualitzar un únic fitxer .node\n"
msgstr "Només es pot simplificar un únic fitxer .ui sense --replace\n"
#: tools/gtk-rendernode-tool-render.c:123
#, c-format
#, c-format, fuzzy
msgid ""
"File %s exists.\n"
"If you want to overwrite, specify the filename.\n"
msgstr ""
"El fitxer %s existeix.\n"
"Si voleu sobreescriure, especifiqueu el nom del fitxer.\n"
"Si voleu sobreescriure, especifiqueu el nom del fitxer."
#: tools/gtk-rendernode-tool-render.c:137
#, c-format
#, fuzzy, c-format
#| msgid "Failed to open file %s : %s\n"
msgid "Failed to generate SVG: %s\n"
msgstr "No s'ha pogut generar el SVG: %s\n"
msgstr "No s'ha pogut obrir el fitxer %s: %s\n"
#: tools/gtk-rendernode-tool-render.c:196
#, fuzzy
msgid "Renderer to use"
msgstr "Renderitzador a utilitzar"
@@ -7599,14 +7640,15 @@ msgid "RENDERER"
msgstr "RENDERITZADOR"
#: tools/gtk-rendernode-tool-render.c:212
#, fuzzy
msgid "Render a .node file to an image."
msgstr "Renderitza un fitxer .node a una imatge."
#: tools/gtk-rendernode-tool-render.c:231
#, c-format
#, c-format, fuzzy
msgid "Can only render a single .node file to a single output file\n"
msgstr ""
"Només es pot renderitzar un únic fitxer .node a un únic fitxer de sortida\n"
"Només es pot renderitzar un únic fitxer .node a un únic fitxer de sortida"
#: tools/gtk-rendernode-tool-utils.c:51
#, c-format
@@ -7720,3 +7762,22 @@ msgid ""
msgstr ""
"No hi ha el fitxer índex de tema a «%s».\n"
"Si realment voleu crear una memòria cau d'icones aquí, utilitzeu --ignore-theme-index.\n"
#~ msgid "Tab list"
#~ msgstr "Llista de pestanyes"
#~ msgid "Allocation"
#~ msgstr "Assignació"
#~ msgid "Show fps overlay"
#~ msgstr "Mostra la superposició fps"
#~ msgid "Simulate Touchscreen"
#~ msgstr "Simula una pantalla tàctil"
#~ msgid "Take a screenshot of the file."
#~ msgstr "Feu una captura de pantalla del fitxer."
#, c-format
#~ msgid "Cant parse “%s”\n"
#~ msgstr "No es pot analitzar «%s»\n"

101
po/gl.po
View File

@@ -20,8 +20,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gtk+-master-po-gl-77922___.merged\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gtk/-/issues/\n"
"POT-Creation-Date: 2023-08-28 15:54+0000\n"
"PO-Revision-Date: 2023-08-29 00:36+0200\n"
"POT-Creation-Date: 2023-08-23 19:17+0000\n"
"PO-Revision-Date: 2023-08-24 08:19+0200\n"
"Last-Translator: Fran Dieguez <frandieguez@gnome.org>\n"
"Language-Team: Galician <proxecto@trasno.gal>\n"
"Language: gl\n"
@@ -2896,7 +2896,7 @@ msgstr "Anterior lapela"
msgid "Next tab"
msgstr "Seguinte lapela"
#: gtk/gtknotebook.c:4331 gtk/gtknotebook.c:6541
#: gtk/gtknotebook.c:4331 gtk/gtknotebook.c:6539
#, c-format
msgid "Page %u"
msgstr "Páxina %u"
@@ -3565,7 +3565,7 @@ msgctxt "keyboard side marker"
msgid "R"
msgstr "D"
#: gtk/gtkshortcutssection.c:414
#: gtk/gtkshortcutssection.c:407
msgid "_Show All"
msgstr "_Mostrar todos"
@@ -3602,27 +3602,27 @@ msgid "Swipe right"
msgstr "Deslizar á dereita"
#. Translators: This is placeholder text for the search entry in the shortcuts window
#: gtk/gtkshortcutswindow.c:879 gtk/gtkshortcutswindow.c:946
#: gtk/gtkshortcutswindow.c:951
#: gtk/gtkshortcutswindow.c:855 gtk/gtkshortcutswindow.c:922
#: gtk/gtkshortcutswindow.c:927
msgid "Search Shortcuts"
msgstr "Atallos da busca"
#. Translators: This is the window title for the shortcuts window in normal mode
#: gtk/gtkshortcutswindow.c:911 gtk/inspector/window.ui:498
#: gtk/gtkshortcutswindow.c:887 gtk/inspector/window.ui:498
msgid "Shortcuts"
msgstr "Atallos"
#. Translators: This is the window title for the shortcuts window in search mode
#: gtk/gtkshortcutswindow.c:916
#: gtk/gtkshortcutswindow.c:892
msgid "Search Results"
msgstr "Resultados da busca"
#: gtk/gtkshortcutswindow.c:1013 gtk/ui/gtkemojichooser.ui:349
#: gtk/gtkshortcutswindow.c:989 gtk/ui/gtkemojichooser.ui:349
#: gtk/ui/gtkfilechooserwidget.ui:239
msgid "No Results Found"
msgstr "Non se atopou ningún resultado"
#: gtk/gtkshortcutswindow.c:1024 gtk/ui/gtkemojichooser.ui:362
#: gtk/gtkshortcutswindow.c:1000 gtk/ui/gtkemojichooser.ui:362
#: gtk/ui/gtkfilechooserwidget.ui:252 gtk/ui/gtkplacesview.ui:218
msgid "Try a different search"
msgstr "Tente unha busca diferente"
@@ -3697,7 +3697,7 @@ msgid "Description"
msgstr "Descrición"
#: gtk/inspector/a11y.ui:99 gtk/inspector/misc-info.ui:296
#: tools/gtk-path-tool-info.c:132
#: tools/gtk-path-tool-info.c:133
msgid "Bounds"
msgstr "Limiares"
@@ -7482,105 +7482,95 @@ msgid ""
"\n"
"Commands:\n"
" decompose Decompose the path\n"
" reverse Reverse the path\n"
" restrict Restrict the path to a segment\n"
" show Display the path in a window\n"
" render Render the path as an image\n"
" info Print information about the path\n"
"\n"
msgstr ""
"Uso:\n"
" gtk4-path-tool [ORDE] [OPCIÓN…] FICHEIRO\n"
" gtk4-path-tool [ORDE] FICHEIRO\n"
"\n"
"Leva a cabo varias tarefas en rutas.\n"
"\n"
"Ordes:\n"
"\n"
" decompose Descompoñer a ruta\n"
" reverse Reverter a ruta\n"
"\n"
" restrict Restrinxir a ruta dun segmento\n"
" show Mostra a ruta nunha xanela\n"
" render Renderiza a ruta como unha imaxe\n"
"\n"
" info Fornece información da ruta\n"
"\n"
#: tools/gtk-path-tool-decompose.c:84
#: tools/gtk-path-tool-decompose.c:80
msgid "Allow quadratic Bézier curves"
msgstr "Permitir curvas Bézier cuadráticas"
#: tools/gtk-path-tool-decompose.c:85
#: tools/gtk-path-tool-decompose.c:81
msgid "Allow cubic Bézier curves"
msgstr "Permitir curvas Bézier cúbicas"
#: tools/gtk-path-tool-decompose.c:86
msgid "Allow conic Bézier curves"
msgstr "Permitir curvas Bézier cónicas"
#: tools/gtk-path-tool-decompose.c:82
msgid "Allow elliptical arcs"
msgstr "Permitir arcos elípticos"
#: tools/gtk-path-tool-decompose.c:87 tools/gtk-path-tool-info.c:88
#: tools/gtk-path-tool-render.c:58 tools/gtk-path-tool-restrict.c:38
#: tools/gtk-path-tool-show.c:127
#: tools/gtk-path-tool-decompose.c:83 tools/gtk-path-tool-info.c:93
#: tools/gtk-path-tool-render.c:58 tools/gtk-path-tool-show.c:127
msgid "PATH"
msgstr "RUTA"
#: tools/gtk-path-tool-decompose.c:99
#: tools/gtk-path-tool-decompose.c:95
msgid "Decompose a path."
msgstr "Descompoñer unha ruta."
#: tools/gtk-path-tool-decompose.c:112 tools/gtk-path-tool-info.c:113
#: tools/gtk-path-tool-restrict.c:64
#: tools/gtk-path-tool-decompose.c:108 tools/gtk-path-tool-info.c:117
msgid "No paths given."
msgstr "Non se forneceron rutas."
#: tools/gtk-path-tool-decompose.c:140 tools/gtk-path-tool-restrict.c:94
#: tools/gtk-path-tool-decompose.c:136
msgid "That didn't work out."
msgstr "Iso non funcionou."
#: tools/gtk-path-tool-info.c:100
#: tools/gtk-path-tool-info.c:104
msgid "Print information about a path."
msgstr "Mostra a información sobre a ruta."
#: tools/gtk-path-tool-info.c:121
#: tools/gtk-path-tool-info.c:124
msgid "Path is empty."
msgstr "A ruta está baleira."
#: tools/gtk-path-tool-info.c:127
#: tools/gtk-path-tool-info.c:130
msgid "Path is closed"
msgstr "A ruta está pechada"
#: tools/gtk-path-tool-info.c:129
msgid "Path length"
msgstr "Lonxitude da ruta"
#: tools/gtk-path-tool-info.c:138
#: tools/gtk-path-tool-info.c:139
#, c-format
msgid "%d contours"
msgstr "%d contornos"
#: tools/gtk-path-tool-info.c:140
#: tools/gtk-path-tool-info.c:141
#, c-format
msgid "%d operations"
msgstr "%d operacións"
#: tools/gtk-path-tool-info.c:144
#: tools/gtk-path-tool-info.c:145
#, c-format
msgid "%d lines"
msgstr "%d liñas"
#: tools/gtk-path-tool-info.c:149
#: tools/gtk-path-tool-info.c:150
#, c-format
msgid "%d quadratics"
msgstr "%d cuadráticas"
#: tools/gtk-path-tool-info.c:154
#: tools/gtk-path-tool-info.c:155
#, c-format
msgid "%d cubics"
msgstr "%d cúbicas"
#: tools/gtk-path-tool-info.c:159
#: tools/gtk-path-tool-info.c:160
#, c-format
msgid "%d conics"
msgstr "%d cónicas"
msgid "%d arcs"
msgstr "%d arcos"
#: tools/gtk-path-tool-render.c:53 tools/gtk-path-tool-show.c:123
msgid "Fill the path (the default)"
@@ -7704,22 +7694,6 @@ msgstr "Fallou o gardado do png en «%s»"
msgid "Output written to '%s'."
msgstr "Saída escrita en «%s»."
#: tools/gtk-path-tool-restrict.c:36
msgid "Beginning of segment"
msgstr "Comezo do segmento"
#: tools/gtk-path-tool-restrict.c:36 tools/gtk-path-tool-restrict.c:37
msgid "LENGTH"
msgstr "LONXITUDE"
#: tools/gtk-path-tool-restrict.c:37
msgid "End of segment"
msgstr "Final do segmento"
#: tools/gtk-path-tool-restrict.c:51
msgid "Restrict a path to a segment."
msgstr "Restrinxir unha ruta a unha segmento."
#: tools/gtk-path-tool-show.c:43 tools/gtk-path-tool-show.c:78
msgid "Path Preview"
msgstr "Vista previa"
@@ -7975,12 +7949,5 @@ msgstr ""
"Se está seguro de que quere crear unha caché de iconas aquí, use --ignore-"
"theme-index.\n"
#~ msgid "Allow elliptical arcs"
#~ msgstr "Permitir arcos elípticos"
#, c-format
#~ msgid "%d arcs"
#~ msgstr "%d arcos"
#~ msgid "Stroke the path instead of filling it"
#~ msgstr "Traza a ruta en lugar de enchela"

View File

@@ -188,12 +188,6 @@ test_curve_length (void)
GskCurve c, c1, c2;
float l, l1, l2, l1a;
/* This curve is a bad case for our sampling, since it has
* a very sharp turn. gskcontour.c handles these better, by
* splitting at the curvature extrema.
*
* Here, we just bump our epsilon up high enough.
*/
parse_curve (&c, "M 1462.632080 -1593.118896 C 751.533630 -74.179169 -914.280090 956.537720 -83.091866 207.213776");
gsk_curve_split (&c, 0.5, &c1, &c2);
@@ -204,7 +198,7 @@ test_curve_length (void)
l2 = gsk_curve_get_length (&c2);
g_assert_cmpfloat_with_epsilon (l1, l1a, 0.1);
g_assert_cmpfloat_with_epsilon (l, l1 + l2, 0.62);
g_assert_cmpfloat_with_epsilon (l, l1 + l2, 0.5);
}
int

View File

@@ -1,191 +0,0 @@
/*
* 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 <gtk/gtk.h>
static gboolean
build_path (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_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_QUAD:
gsk_path_builder_quad_to (builder, pts[1].x, pts[1].y, pts[2].x, pts[2].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);
break;
case GSK_PATH_CONIC:
gsk_path_builder_conic_to (builder, pts[1].x, pts[1].y, pts[2].x, pts[2].y, weight);
break;
default:
g_assert_not_reached ();
break;
}
return TRUE;
}
static void
test_simple (void)
{
const struct {
const char *test;
float dash[4];
gsize n_dash;
float dash_offset;
const char *result;
} tests[] = {
/* a line with a dash of a quarter its size, very simple test */
{
"M 0 0 L 20 0",
{ 5, }, 1, 0.f,
"M 0 0 L 5 0 M 10 0 L 15 0",
},
/* a square with a dash of half its size, another simple test */
{
"M 0 0 h 10 v 10 h -10 z",
{ 5, }, 1, 0.f,
"M 10 0 L 10 5 M 10 10 L 5 10 M 0 10 L 0 5 M 0 0 L 5 0"
},
/* a square smaller than the dash, make sure it closes */
{
"M 0 0 h 10 v 10 h -10 z",
{ 50, }, 1, 0.f,
"M 0 0 L 10 0 L 10 10 L 0 10 Z"
},
/* a square exactly the dash's size, make sure it still closes */
{
"M 0 0 h 10 v 10 h -10 z",
{ 40, }, 1, 0.f,
"M 0 0 L 10 0 L 10 10 L 0 10 Z"
},
/* a dash with offset */
{
"M 0 0 h 10 v 10 h -10 z",
{ 5, }, 1, 2.5f,
"M 7.5 0 L 10 0 L 10 2.5 M 10 7.5 L 10 10 L 7.5 10 M 2.5 10 L 0 10 L 0 7.5 M 0 2.5 L 0 0 L 2.5 0"
},
/* a dash with offset, but this time the rect isn't closed */
{
"M 0 0 L 10 0 L 10 10 L 0 10 L 0 0",
{ 5, }, 1, 2.5f,
"M 0 0 L 2.5 0 M 7.5 0 L 10 0 L 10 2.5 M 10 7.5 L 10 10 L 7.5 10 M 2.5 10 L 0 10 L 0 7.5 M 0 2.5 L 0 0"
},
/* a dash with offset into an empty dash */
{
"M 0 0 h 10 v 10 h -10 z",
{ 5, }, 1, 7.5f,
"M 2.5 0 L 7.5 0 M 10 2.5 L 10 7.5 M 7.5 10 L 2.5 10 M 0 7.5 L 0 2.5"
},
/* a dash with offset where the whole rectangle fits into one element - make sure it closes */
{
"M 0 0 h 10 v 10 h -10 z",
{ 1, 1, 100 }, 3, 3.f,
"M 0 0 L 10 0 L 10 10 L 0 10 Z"
},
/* a dash with 0-length elements, aka dotting */
{
"M 0 0 h 10 v 10 h -10 z",
{ 0, 5 }, 2, 0.f,
"M 5 0 M 10 0 M 10 5 M 10 10 M 5 10 M 0 10 M 0 5 M 0 0"
},
#if 0
/* a dash of a circle */
{
"M 10 5 O 10 10, 5 10, 0.70710676908493042 O 0 10, 0 5, 0.70710676908493042 O 0 0, 5 0, 0.70710676908493042 O 10 0, 10 5, 0.70710676908493042 Z",
{ 32, }, 1, 0.f,
"M 10 5 O 10 10, 5 10, 0.70710676908493042 O 0 10, 0 5, 0.70710676908493042 O 0 0, 5 0, 0.70710676908493042 O 10 0, 10 5, 0.70710676908493042 Z",
},
#endif
/* a dash with offset and 2 contours */
{
"M 10 10 h 10 v 10 h -10 z M 20 20 h 10 v 10 h -10 z",
{ 5, }, 1, 2.5f,
"M 17.5 10 L 20 10 L 20 12.5 M 20 17.5 L 20 20 L 17.5 20 M 12.5 20 L 10 20 L 10 17.5 M 10 12.5 L 10 10 L 12.5 10 "
"M 27.5 20 L 30 20 L 30 22.5 M 30 27.5 L 30 30 L 27.5 30 M 22.5 30 L 20 30 L 20 27.5 M 20 22.5 L 20 20 L 22.5 20"
},
};
GskPath *path, *result;
GskPathBuilder *builder;
GskStroke *stroke;
char *s;
for (gsize i = 0; i < G_N_ELEMENTS(tests); i++)
{
if (g_test_verbose ())
g_test_message ("%lu: %s", i, tests[i].test);
stroke = gsk_stroke_new (1);
gsk_stroke_set_dash (stroke, tests[i].dash, tests[i].n_dash);
gsk_stroke_set_dash_offset (stroke, tests[i].dash_offset);
path = gsk_path_parse (tests[i].test);
g_assert_nonnull (path);
#if 0
/* This assumes that we have rectangle contours */
s = gsk_path_to_string (path);
g_assert_cmpstr (s, ==, tests[i].test);
g_free (s);
#endif
builder = gsk_path_builder_new ();
gsk_path_dash (path, stroke, build_path, builder);
result = gsk_path_builder_free_to_path (builder);
s = gsk_path_to_string (result);
g_assert_cmpstr (s, ==, tests[i].result);
g_free (s);
gsk_path_unref (result);
gsk_stroke_free (stroke);
gsk_path_unref (path);
}
}
int
main (int argc,
char *argv[])
{
gtk_test_init (&argc, &argv, NULL);
g_test_add_func ("/dash/simple", test_simple);
return g_test_run ();
}

View File

@@ -366,7 +366,6 @@ tests = [
['shader'],
['path'],
['path-special-cases'],
['dash'],
]
test_cargs = []
@@ -399,7 +398,6 @@ endforeach
internal_tests = [
[ 'curve' ],
[ 'curve-special-cases' ],
[ 'path-private' ],
[ 'diff' ],
[ 'half-float' ],
['rounded-rect'],

View File

@@ -1,276 +0,0 @@
/*
* Copyright © 2023 Red Hat, Inc.
*
* 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: Matthias Clasen <mclasen@redhat.com>
*/
#include <gtk/gtk.h>
#include "gsk/gskpathprivate.h"
#include "gsk/gskcontourprivate.h"
static gboolean
add_segment (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_QUAD:
gsk_path_builder_quad_to (builder,
pts[1].x, pts[1].y,
pts[2].x, pts[2].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);
break;
case GSK_PATH_CONIC:
gsk_path_builder_conic_to (builder,
pts[1].x, pts[1].y,
pts[2].x, pts[2].y,
weight);
break;
case GSK_PATH_CLOSE:
gsk_path_builder_close (builder);
break;
default:
g_assert_not_reached ();
}
return TRUE;
}
static GskPath *
convert_to_standard_contour (GskPath *path)
{
GskPathBuilder *builder;
builder = gsk_path_builder_new ();
gsk_path_foreach (path, -1, add_segment, builder);
return gsk_path_builder_free_to_path (builder);
}
static void
test_circle_roundtrip (void)
{
GskPathBuilder *builder;
GskPath *path, *path1;
const GskContour *contour, *contour1;
char *s;
builder = gsk_path_builder_new ();
gsk_path_builder_add_circle (builder, &GRAPHENE_POINT_INIT (100, 100), 33);
path = gsk_path_builder_free_to_path (builder);
contour = gsk_path_get_contour (path, 0);
g_assert_cmpstr (gsk_contour_get_type_name (contour), ==, "GskCircleContour");
s = gsk_path_to_string (path);
path1 = gsk_path_parse (s);
contour1 = gsk_path_get_contour (path1, 0);
g_free (s);
g_assert_cmpstr (gsk_contour_get_type_name (contour1), ==, "GskCircleContour");
gsk_path_unref (path1);
gsk_path_unref (path);
}
static void
test_circle_winding (void)
{
GskPathBuilder *builder;
GskPath *path, *path1, *path2;
const GskContour *contour, *contour1, *contour2;
builder = gsk_path_builder_new ();
gsk_path_builder_add_circle (builder, &GRAPHENE_POINT_INIT (100, 100), 33);
path = gsk_path_builder_free_to_path (builder);
contour = gsk_path_get_contour (path, 0);
path1 = convert_to_standard_contour (path);
contour1 = gsk_path_get_contour (path1, 0);
builder = gsk_path_builder_new ();
gsk_path_builder_add_reverse_path (builder, path);
path2 = gsk_path_builder_free_to_path (builder);
contour2 = gsk_path_get_contour (path2, 0);
g_assert_true (gsk_contour_get_winding (contour, &GRAPHENE_POINT_INIT (100, 100)) == 1);
g_assert_true (gsk_contour_get_winding (contour1, &GRAPHENE_POINT_INIT (100, 100)) == 1);
g_assert_true (gsk_contour_get_winding (contour2, &GRAPHENE_POINT_INIT (100, 100)) == -1);
gsk_path_unref (path2);
gsk_path_unref (path1);
gsk_path_unref (path);
}
static void
test_rounded_rect_roundtrip (void)
{
GskRoundedRect rr;
GskPathBuilder *builder;
GskPath *path, *path2;
const GskContour *contour;
char *s;
rr.bounds = GRAPHENE_RECT_INIT (100, 100, 200, 150);
rr.corner[GSK_CORNER_TOP_LEFT] = GRAPHENE_SIZE_INIT (10, 10);
rr.corner[GSK_CORNER_TOP_RIGHT] = GRAPHENE_SIZE_INIT (20, 10);
rr.corner[GSK_CORNER_BOTTOM_RIGHT] = GRAPHENE_SIZE_INIT (20, 0);
rr.corner[GSK_CORNER_BOTTOM_LEFT] = GRAPHENE_SIZE_INIT (0, 0);
builder = gsk_path_builder_new ();
gsk_path_builder_add_rounded_rect (builder, &rr);
path = gsk_path_builder_free_to_path (builder);
contour = gsk_path_get_contour (path, 0);
g_assert_cmpstr (gsk_contour_get_type_name (contour), ==, "GskRoundedRectContour");
s = gsk_path_to_string (path);
path2 = gsk_path_parse (s);
contour = gsk_path_get_contour (path2, 0);
g_assert_cmpstr (gsk_contour_get_type_name (contour), ==, "GskRoundedRectContour");
g_free (s);
gsk_path_unref (path2);
gsk_path_unref (path);
}
static void
test_rounded_rect_winding (void)
{
GskRoundedRect rr;
GskPathBuilder *builder;
GskPath *path, *path1, *path2;
const GskContour *contour, *contour1, *contour2;
rr.bounds = GRAPHENE_RECT_INIT (100, 100, 200, 150);
rr.corner[GSK_CORNER_TOP_LEFT] = GRAPHENE_SIZE_INIT (10, 10);
rr.corner[GSK_CORNER_TOP_RIGHT] = GRAPHENE_SIZE_INIT (20, 10);
rr.corner[GSK_CORNER_BOTTOM_RIGHT] = GRAPHENE_SIZE_INIT (20, 0);
rr.corner[GSK_CORNER_BOTTOM_LEFT] = GRAPHENE_SIZE_INIT (0, 0);
builder = gsk_path_builder_new ();
gsk_path_builder_add_rounded_rect (builder, &rr);
path = gsk_path_builder_free_to_path (builder);
contour = gsk_path_get_contour (path, 0);
path1 = convert_to_standard_contour (path);
contour1 = gsk_path_get_contour (path1, 0);
builder = gsk_path_builder_new ();
gsk_path_builder_add_reverse_path (builder, path);
path2 = gsk_path_builder_free_to_path (builder);
contour2 = gsk_path_get_contour (path2, 0);
g_assert_true (gsk_contour_get_winding (contour, &GRAPHENE_POINT_INIT (150, 150)) == 1);
g_assert_true (gsk_contour_get_winding (contour1, &GRAPHENE_POINT_INIT (150, 150)) == 1);
g_assert_true (gsk_contour_get_winding (contour2, &GRAPHENE_POINT_INIT (150, 150)) == -1);
gsk_path_unref (path2);
gsk_path_unref (path1);
}
static void
test_rect_roundtrip (void)
{
graphene_rect_t rect;
GskPathBuilder *builder;
GskPath *path, *path2;
const GskContour *contour;
char *s;
rect = GRAPHENE_RECT_INIT (100, 100, 200, 150);
builder = gsk_path_builder_new ();
gsk_path_builder_add_rect (builder, &rect);
path = gsk_path_builder_free_to_path (builder);
contour = gsk_path_get_contour (path, 0);
g_assert_cmpstr (gsk_contour_get_type_name (contour), ==, "GskRectContour");
s = gsk_path_to_string (path);
path2 = gsk_path_parse (s);
contour = gsk_path_get_contour (path2, 0);
g_assert_cmpstr (gsk_contour_get_type_name (contour), ==, "GskRectContour");
g_free (s);
gsk_path_unref (path2);
gsk_path_unref (path);
}
static void
test_rect_winding (void)
{
GskPathBuilder *builder;
GskPath *path, *path1, *path2, *path3;
const GskContour *contour, *contour1, *contour2, *contour3;
builder = gsk_path_builder_new ();
gsk_path_builder_add_rect (builder, &GRAPHENE_RECT_INIT (100, 100, 200, 150));
path = gsk_path_builder_free_to_path (builder);
contour = gsk_path_get_contour (path, 0);
path1 = convert_to_standard_contour (path);
contour1 = gsk_path_get_contour (path1, 0);
builder = gsk_path_builder_new ();
gsk_path_builder_add_reverse_path (builder, path);
path2 = gsk_path_builder_free_to_path (builder);
contour2 = gsk_path_get_contour (path2, 0);
path3 = convert_to_standard_contour (path2);
contour3 = gsk_path_get_contour (path3, 0);
g_assert_true (gsk_contour_get_winding (contour, &GRAPHENE_POINT_INIT (150, 150)) == 1);
g_assert_true (gsk_contour_get_winding (contour1, &GRAPHENE_POINT_INIT (150, 150)) == 1);
g_assert_true (gsk_contour_get_winding (contour2, &GRAPHENE_POINT_INIT (150, 150)) == -1);
g_assert_true (gsk_contour_get_winding (contour3, &GRAPHENE_POINT_INIT (150, 150)) == -1);
gsk_path_unref (path3);
gsk_path_unref (path2);
gsk_path_unref (path1);
}
int
main (int argc, char *argv[])
{
gtk_test_init (&argc, &argv, NULL);
g_test_add_func ("/path/circle/roundtrip", test_circle_roundtrip);
g_test_add_func ("/path/circle/winding", test_circle_winding);
g_test_add_func ("/path/rounded-rect/roundtrip", test_rounded_rect_roundtrip);
g_test_add_func ("/path/rounded-rect/winding", test_rounded_rect_winding);
g_test_add_func ("/path/rect/roundtrip", test_rect_roundtrip);
g_test_add_func ("/path/rect/winding", test_rect_winding);
return g_test_run ();
}

View File

@@ -301,7 +301,7 @@ test_empty_path (void)
g_assert_false (gsk_path_in_fill (path, &GRAPHENE_POINT_INIT (0, 0), GSK_FILL_RULE_WINDING));
g_assert_false (gsk_path_get_closest_point (path, &GRAPHENE_POINT_INIT (0, 0), INFINITY, &point, NULL));
g_assert_false (gsk_path_get_closest_point (path, &GRAPHENE_POINT_INIT (0, 0), INFINITY, &point));
gsk_path_unref (path);
}
@@ -314,7 +314,6 @@ test_rect_path (void)
char *s;
graphene_rect_t bounds;
GskPathPoint point;
float distance;
builder = gsk_path_builder_new ();
gsk_path_builder_add_rect (builder, &GRAPHENE_RECT_INIT (0, 0, 200, 100));
@@ -324,7 +323,7 @@ test_rect_path (void)
g_assert_true (gsk_path_is_closed (path));
s = gsk_path_to_string (path);
g_assert_cmpstr (s, ==, "M 0 0 h 200 v 100 h -200 z");
g_assert_cmpstr (s, ==, "M 0 0 L 200 0 L 200 100 L 0 100 Z");
g_free (s);
g_assert_true (gsk_path_get_bounds (path, &bounds));
@@ -333,9 +332,7 @@ test_rect_path (void)
g_assert_true (gsk_path_in_fill (path, &GRAPHENE_POINT_INIT (50, 50), GSK_FILL_RULE_WINDING));
g_assert_false (gsk_path_in_fill (path, &GRAPHENE_POINT_INIT (200, 200), GSK_FILL_RULE_WINDING));
g_assert_true (gsk_path_get_closest_point (path, &GRAPHENE_POINT_INIT (200, 200), INFINITY, &point, &distance));
g_assert_true (distance == 100);
g_assert_true (gsk_path_get_closest_point (path, &GRAPHENE_POINT_INIT (200, 200), INFINITY, &point));
gsk_path_unref (path);
}
@@ -432,11 +429,21 @@ test_foreach (void)
g_free (s2);
}
/* Test the basics of the path point api */
typedef struct _GskRealPathPoint GskRealPathPoint;
struct _GskRealPathPoint
{
gsize contour;
gsize idx;
float t;
};
static void
test_path_point (void)
{
GskPath *path;
GskPathPoint point;
GskRealPathPoint *rp = (GskRealPathPoint *)&point;
gboolean ret;
graphene_point_t pos, center;
graphene_vec2_t t1, t2, mx;
@@ -447,23 +454,23 @@ test_path_point (void)
ret = gsk_path_get_start_point (path, &point);
g_assert_true (ret);
g_assert_true (point.contour == 0);
g_assert_true (point.idx == 1);
g_assert_true (point.t == 0);
g_assert_true (rp->contour == 0);
g_assert_true (rp->idx == 1);
g_assert_true (rp->t == 0);
ret = gsk_path_get_end_point (path, &point);
g_assert_true (ret);
g_assert_true (point.contour == 0);
g_assert_true (point.idx == 4);
g_assert_true (point.t == 1);
g_assert_true (rp->contour == 0);
g_assert_true (rp->idx == 4);
g_assert_true (rp->t == 1);
ret = gsk_path_get_closest_point (path, &GRAPHENE_POINT_INIT (200, 200), INFINITY, &point, NULL);
ret = gsk_path_get_closest_point (path, &GRAPHENE_POINT_INIT (200, 200), INFINITY, &point);
g_assert_true (ret);
g_assert_true (point.contour == 0);
g_assert_true (point.idx == 2);
g_assert_true (point.t == 1);
g_assert_true (rp->contour == 0);
g_assert_true (rp->idx == 2);
g_assert_true (rp->t == 1);
gsk_path_point_get_position (&point, path, &pos);
gsk_path_point_get_tangent (&point, path, GSK_PATH_FROM_START, &t1);
@@ -476,12 +483,12 @@ test_path_point (void)
g_assert_true (graphene_vec2_equal (&t2, &mx));
g_assert_true (curvature == 0);
ret = gsk_path_get_closest_point (path, &GRAPHENE_POINT_INIT (100, 50), INFINITY, &point, NULL);
ret = gsk_path_get_closest_point (path, &GRAPHENE_POINT_INIT (100, 50), INFINITY, &point);
g_assert_true (ret);
g_assert_true (point.contour == 0);
g_assert_true (point.idx == 2);
g_assert_true (point.t == 0.5);
g_assert_true (rp->contour == 0);
g_assert_true (rp->idx == 2);
g_assert_true (rp->t == 0.5);
gsk_path_unref (path);
}
@@ -537,8 +544,8 @@ test_path_segments (void)
char *str;
path = gsk_path_parse (tests[i].path);
g_assert_true (gsk_path_get_closest_point (path, &tests[i].p1, INFINITY, &p1, NULL));
g_assert_true (gsk_path_get_closest_point (path, &tests[i].p2, INFINITY, &p2, NULL));
g_assert_true (gsk_path_get_closest_point (path, &tests[i].p1, INFINITY, &p1));
g_assert_true (gsk_path_get_closest_point (path, &tests[i].p2, INFINITY, &p2));
builder = gsk_path_builder_new ();
gsk_path_builder_add_segment (builder, path, &p1, &p2);
@@ -605,7 +612,7 @@ test_path_builder_add (void)
path = gsk_path_parse ("M 10 10 L 100 100");
gsk_path_get_closest_point (path, &GRAPHENE_POINT_INIT (50, 50), INFINITY, &point1, NULL);
gsk_path_get_closest_point (path, &GRAPHENE_POINT_INIT (50, 50), INFINITY, &point1);
gsk_path_get_end_point (path, &point2);
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 100, 100);
@@ -778,8 +785,6 @@ test_rounded_rect (void)
GskRoundedRect rect;
GskPathBuilder *builder;
GskPath *path;
GskPathPoint point;
graphene_point_t p;
gsk_rounded_rect_init (&rect, &GRAPHENE_RECT_INIT (10, 10, 100, 50),
&GRAPHENE_SIZE_INIT (0, 0),
@@ -793,58 +798,14 @@ test_rounded_rect (void)
path = gsk_path_builder_free_to_path (builder);
for (int i = 0; i < 100; i++)
for (int i = 0; i < 1000; i++)
{
p = GRAPHENE_POINT_INIT (g_test_rand_double_range (0, 200),
g_test_rand_double_range (0, 200));
graphene_point_t p = GRAPHENE_POINT_INIT (g_test_rand_double_range (0, 200),
g_test_rand_double_range (0, 200));
g_assert_true (gsk_rounded_rect_contains_point (&rect, &p) == gsk_path_in_fill (path, &p, GSK_FILL_RULE_WINDING));
}
gsk_path_get_start_point (path, &point);
gsk_path_point_get_position (&point, path, &p);
g_assert_true (graphene_point_equal (&p, &GRAPHENE_POINT_INIT (10, 10)));
gsk_path_get_end_point (path, &point);
gsk_path_point_get_position (&point, path, &p);
g_assert_true (graphene_point_equal (&p, &GRAPHENE_POINT_INIT (10, 10)));
gsk_path_unref (path);
}
static void
test_rect (void)
{
graphene_rect_t rect;
GskPathBuilder *builder;
GskPath *path;
GskPathPoint point;
graphene_point_t p;
rect = GRAPHENE_RECT_INIT (10, 10, 100, 50);
builder = gsk_path_builder_new ();
gsk_path_builder_add_rect (builder, &rect);
path = gsk_path_builder_free_to_path (builder);
for (int i = 0; i < 100; i++)
{
p = GRAPHENE_POINT_INIT (g_test_rand_double_range (0, 200),
g_test_rand_double_range (0, 200));
g_assert_true (graphene_rect_contains_point (&rect, &p) == gsk_path_in_fill (path, &p, GSK_FILL_RULE_WINDING));
}
gsk_path_get_start_point (path, &point);
gsk_path_point_get_position (&point, path, &p);
g_assert_true (graphene_point_equal (&p, &GRAPHENE_POINT_INIT (10, 10)));
gsk_path_get_end_point (path, &point);
gsk_path_point_get_position (&point, path, &p);
g_assert_true (graphene_point_equal (&p, &GRAPHENE_POINT_INIT (10, 10)));
gsk_path_unref (path);
}
@@ -852,11 +813,9 @@ static void
test_circle (void)
{
GskPathBuilder *builder;
GskPath *path, *path1, *path2, *path3, *path4, *path5, *path6;
GskPathMeasure *measure, *measure1, *measure2, *measure3;
float length, length1, length2, length3;
GskPathPoint point0, point1;
graphene_point_t p;
GskPath *path;
GskPathMeasure *measure;
float length;
builder = gsk_path_builder_new ();
gsk_path_builder_add_circle (builder, &GRAPHENE_POINT_INIT (0, 0), 1);
@@ -867,81 +826,8 @@ test_circle (void)
g_assert_cmpfloat_with_epsilon (length, 2 * M_PI, 0.001);
gsk_path_get_start_point (path, &point0);
gsk_path_point_get_position (&point0, path, &p);
g_assert_true (graphene_point_equal (&p, &GRAPHENE_POINT_INIT (1, 0)));
gsk_path_get_end_point (path, &point0);
gsk_path_point_get_position (&point0, path, &p);
g_assert_true (graphene_point_equal (&p, &GRAPHENE_POINT_INIT (1, 0)));
gsk_path_get_closest_point (path, &GRAPHENE_POINT_INIT (1, 1), INFINITY, &point0, NULL);
gsk_path_get_closest_point (path, &GRAPHENE_POINT_INIT (-1, 1), INFINITY, &point1, NULL);
builder = gsk_path_builder_new ();
gsk_path_builder_add_segment (builder, path, &point0, &point1);
path1 = gsk_path_builder_free_to_path (builder);
measure1 = gsk_path_measure_new (path1);
length1 = gsk_path_measure_get_length (measure1);
g_assert_cmpfloat_with_epsilon (length1, 2 * M_PI * 0.25, 0.001);
builder = gsk_path_builder_new ();
gsk_path_builder_add_segment (builder, path, &point1, &point0);
path2 = gsk_path_builder_free_to_path (builder);
measure2 = gsk_path_measure_new (path2);
length2 = gsk_path_measure_get_length (measure2);
g_assert_cmpfloat_with_epsilon (length2, 2 * M_PI * 0.75, 0.001);
builder = gsk_path_builder_new ();
gsk_path_builder_add_reverse_path (builder, path);
path3 = gsk_path_builder_free_to_path (builder);
measure3 = gsk_path_measure_new (path3);
length3 = gsk_path_measure_get_length (measure3);
g_assert_cmpfloat_with_epsilon (length3, 2 * M_PI, 0.001);
g_assert_true (gsk_path_in_fill (path, &GRAPHENE_POINT_INIT (0, 0), GSK_FILL_RULE_WINDING));
g_assert_true (gsk_path_in_fill (path, &GRAPHENE_POINT_INIT (0, 0), GSK_FILL_RULE_EVEN_ODD));
g_assert_true (gsk_path_in_fill (path3, &GRAPHENE_POINT_INIT (0, 0), GSK_FILL_RULE_WINDING));
g_assert_true (gsk_path_in_fill (path3, &GRAPHENE_POINT_INIT (0, 0), GSK_FILL_RULE_EVEN_ODD));
builder = gsk_path_builder_new ();
gsk_path_builder_add_path (builder, path);
gsk_path_builder_move_to (builder, -2, -2);
gsk_path_builder_line_to (builder, 2, 0);
gsk_path_builder_line_to (builder, 2, 2);
gsk_path_builder_line_to (builder, -2, 2);
gsk_path_builder_close (builder);
path4 = gsk_path_builder_free_to_path (builder);
g_assert_true (gsk_path_in_fill (path4, &GRAPHENE_POINT_INIT (0, 0), GSK_FILL_RULE_WINDING));
g_assert_false (gsk_path_in_fill (path4, &GRAPHENE_POINT_INIT (0, 0), GSK_FILL_RULE_EVEN_ODD));
path5 = gsk_path_parse ("M 2 0 O 2 2 0 2 0.707 O -2 2 -2 0 0.707 O -2 -2 0 -2 0.707 O 2 -2 2 0 0.707 Z");
builder = gsk_path_builder_new ();
gsk_path_builder_add_path (builder, path);
gsk_path_builder_add_path (builder, path5);
path6 = gsk_path_builder_free_to_path (builder);
g_assert_true (gsk_path_in_fill (path6, &GRAPHENE_POINT_INIT (0, 0), GSK_FILL_RULE_WINDING));
g_assert_false (gsk_path_in_fill (path6, &GRAPHENE_POINT_INIT (0, 0), GSK_FILL_RULE_EVEN_ODD));
gsk_path_measure_unref (measure);
gsk_path_measure_unref (measure1);
gsk_path_measure_unref (measure2);
gsk_path_measure_unref (measure3);
gsk_path_unref (path);
gsk_path_unref (path1);
gsk_path_unref (path2);
gsk_path_unref (path3);
gsk_path_unref (path4);
gsk_path_unref (path5);
gsk_path_unref (path6);
}
static void
@@ -989,66 +875,6 @@ test_length (void)
gsk_path_measure_unref (measure2);
}
static void
test_rect_segment (void)
{
GskPathBuilder *builder;
GskPath *path, *path1, *path2;
GskPathMeasure *measure, *measure1, *measure2;
GskPathPoint point0, point1;
builder = gsk_path_builder_new ();
gsk_path_builder_add_rect (builder, &GRAPHENE_RECT_INIT (0, 0, 100, 100));
path = gsk_path_builder_free_to_path (builder);
measure = gsk_path_measure_new (path);
gsk_path_measure_get_point (measure, 20, &point0);
gsk_path_measure_get_point (measure, 80, &point1);
builder = gsk_path_builder_new ();
gsk_path_builder_add_segment (builder, path, &point0, &point1);
path1 = gsk_path_builder_free_to_path (builder);
measure1 = gsk_path_measure_new (path1);
g_assert_cmpfloat_with_epsilon (gsk_path_measure_get_length (measure1), 60, 0.001);
builder = gsk_path_builder_new ();
gsk_path_builder_add_segment (builder, path, &point1, &point0);
path2 = gsk_path_builder_free_to_path (builder);
measure2 = gsk_path_measure_new (path2);
g_assert_cmpfloat_with_epsilon (gsk_path_measure_get_length (measure2), 340, 0.001);
gsk_path_unref (path);
gsk_path_unref (path1);
gsk_path_unref (path2);
gsk_path_measure_unref (measure);
gsk_path_measure_unref (measure1);
gsk_path_measure_unref (measure2);
}
static void
test_circle_point (void)
{
GskPathBuilder *builder;
GskPath *path;
GskPathPoint point;
graphene_point_t center;
float k;
builder = gsk_path_builder_new ();
gsk_path_builder_add_circle (builder, &GRAPHENE_POINT_INIT (1, 2), 0);
path = gsk_path_builder_free_to_path (builder);
gsk_path_get_start_point (path, &point);
k = gsk_path_point_get_curvature (&point, path, GSK_PATH_TO_END, &center);
g_assert_true (k == INFINITY);
g_assert_true (graphene_point_equal (&center, &GRAPHENE_POINT_INIT (1, 2)));
gsk_path_unref (path);
}
int
main (int argc, char *argv[])
{
@@ -1056,7 +882,7 @@ main (int argc, char *argv[])
g_test_add_func ("/path/rsvg-parse", test_rsvg_parse);
g_test_add_func ("/path/empty", test_empty_path);
g_test_add_func ("/path/rect-path", test_rect_path);
g_test_add_func ("/path/rect", test_rect_path);
g_test_add_func ("/path/foreach", test_foreach);
g_test_add_func ("/path/point", test_path_point);
g_test_add_func ("/path/segments", test_path_segments);
@@ -1065,11 +891,8 @@ main (int argc, char *argv[])
g_test_add_func ("/path/builder/add", test_path_builder_add);
g_test_add_func ("/path/rotated-arc", test_rotated_arc);
g_test_add_func ("/path/rounded-rect", test_rounded_rect);
g_test_add_func ("/path/rect", test_rect);
g_test_add_func ("/path/circle", test_circle);
g_test_add_func ("/path/length", test_length);
g_test_add_func ("/path/rect/segment", test_rect_segment);
g_test_add_func ("/path/circle-point", test_circle_point);
return g_test_run ();
}

View File

@@ -22,7 +22,7 @@
static GskPath *
create_random_degenerate_path (guint max_contours)
{
#define N_DEGENERATE_PATHS 15
#define N_DEGENERATE_PATHS 14
GskPathBuilder *builder;
guint i;
@@ -132,14 +132,6 @@ create_random_degenerate_path (guint max_contours)
break;
case 12:
/* circle with radius 0 */
gsk_path_builder_add_circle (builder,
&GRAPHENE_POINT_INIT (g_test_rand_double_range (-1000, 1000),
g_test_rand_double_range (-1000, 1000)),
0);
break;
case 13:
/* a zero-length line */
{
graphene_point_t point = GRAPHENE_POINT_INIT (g_test_rand_double_range (-1000, 1000),
@@ -149,7 +141,7 @@ create_random_degenerate_path (guint max_contours)
}
break;
case 14:
case 13:
/* a cubic with start == end */
{
graphene_point_t point = GRAPHENE_POINT_INIT (g_test_rand_double_range (-1000, 1000),
@@ -809,7 +801,7 @@ test_split (void)
length = gsk_path_measure_get_length (measure);
/* chosen high enough to stop the testsuite from failing */
epsilon = MAX (length / 250, 1.f / 1024);
epsilon = MAX (length / 1000, 1.f / 1024);
split = g_test_rand_double_range (0, length);

View File

@@ -1,168 +0,0 @@
/* Copyright 2023 Red Hat, Inc.
*
* GTK+ 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 of the
* License, or (at your option) any later version.
*
* GLib 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 GTK+; see the file COPYING. If not,
* see <http://www.gnu.org/licenses/>.
*
* Author: Matthias Clasen
*/
#include "config.h"
#include <gtk/gtk.h>
#include "gtk-path-tool.h"
#include <glib/gi18n-lib.h>
static gboolean
collect_path (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_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_QUAD:
gsk_path_builder_quad_to (builder, pts[1].x, pts[1].y,
pts[2].x, pts[2].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);
break;
case GSK_PATH_CONIC:
gsk_path_builder_conic_to (builder, pts[1].x, pts[1].y,
pts[2].x, pts[2].y,
weight);
break;
default:
g_assert_not_reached ();
}
return TRUE;
}
void
do_dash (int *argc, const char ***argv)
{
GError *error = NULL;
char **args = NULL;
const char *dashes = NULL;
double dash_offset = 0;
GOptionContext *context;
GOptionEntry entries[] = {
{ "dashes", 0, 0, G_OPTION_ARG_STRING, &dashes, N_("Dash pattern (comma-separated numbers)"), N_("VALUE") },
{ "dash-offset", 0, 0, G_OPTION_ARG_DOUBLE, &dash_offset, N_("Dash offset (number)"), N_("VALUE") },
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &args, NULL, N_("PATH") },
{ NULL, },
};
GskPath *path, *result;
GskPathBuilder *builder;
GskStroke *stroke;
g_set_prgname ("gtk4-path-tool dash");
context = g_option_context_new (NULL);
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
g_option_context_add_main_entries (context, entries, NULL);
g_option_context_set_summary (context, _("Dash a path."));
if (!g_option_context_parse (context, argc, (char ***)argv, &error))
{
g_printerr ("%s\n", error->message);
g_error_free (error);
exit (1);
}
g_option_context_free (context);
if (args == NULL)
{
g_printerr ("%s\n", _("No paths given."));
exit (1);
}
path = get_path (args[0]);
stroke = gsk_stroke_new (1);
if (dashes != NULL)
{
GArray *d = g_array_new (FALSE, FALSE, sizeof (float));
char **strings;
strings = g_strsplit (dashes, ",", 0);
for (unsigned int i = 0; strings[i]; i++)
{
char *end = NULL;
float f;
f = (float) g_ascii_strtod (strings[i], &end);
if (*end != '\0')
{
char *msg = g_strdup_printf (_("Failed to parse '%s' as number"), strings[i]);
g_printerr ("%s\n", msg);
exit (1);
}
g_array_append_val (d, f);
}
g_strfreev (strings);
gsk_stroke_set_dash (stroke, (const float *)d->data, d->len);
g_array_unref (d);
}
gsk_stroke_set_dash_offset (stroke, dash_offset);
builder = gsk_path_builder_new ();
gsk_path_dash (path, stroke, collect_path, builder);
result = gsk_path_builder_free_to_path (builder);
if (result)
{
char *str = gsk_path_to_string (result);
g_print ("%s\n", str);
g_free (str);
}
else
{
g_printerr ("%s\n", _("That didn't work out."));
exit (1);
}
}

View File

@@ -89,7 +89,6 @@ do_info (int *argc, const char ***argv)
{ NULL, },
};
GskPath *path;
GskPathMeasure *measure;
graphene_rect_t bounds;
g_set_prgname ("gtk4-path-tool info");
@@ -115,7 +114,6 @@ do_info (int *argc, const char ***argv)
}
path = get_path (args[0]);
measure = gsk_path_measure_new (path);
if (gsk_path_is_empty (path))
g_print ("%s\n", _("Path is empty."));
@@ -126,8 +124,6 @@ do_info (int *argc, const char ***argv)
if (gsk_path_is_closed (path))
g_print ("%s\n", _("Path is closed"));
g_print ("%s %g\n", _("Path length"), gsk_path_measure_get_length (measure));
if (gsk_path_get_bounds (path, &bounds))
g_print ("%s: %g %g %g %g\n", _("Bounds"),
bounds.origin.x, bounds.origin.y,

View File

@@ -1,97 +0,0 @@
/* Copyright 2023 Red Hat, Inc.
*
* GTK+ 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 of the
* License, or (at your option) any later version.
*
* GLib 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 GTK+; see the file COPYING. If not,
* see <http://www.gnu.org/licenses/>.
*
* Author: Matthias Clasen
*/
#include "config.h"
#include <gtk/gtk.h>
#include "gtk-path-tool.h"
#include <glib/gi18n-lib.h>
void
do_restrict (int *argc, const char ***argv)
{
GError *error = NULL;
double start = G_MAXDOUBLE;
double end = G_MAXDOUBLE;
char **args = NULL;
GOptionContext *context;
GOptionEntry entries[] = {
{ "start", 0, 0, G_OPTION_ARG_DOUBLE, &start, N_("Beginning of segment"), N_("LENGTH") },
{ "end", 0, 0, G_OPTION_ARG_DOUBLE, &start, N_("End of segment"), N_("LENGTH") },
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &args, NULL, N_("PATH") },
{ NULL, },
};
GskPath *path, *result;
GskPathMeasure *measure;
GskPathBuilder *builder;
GskPathPoint start_point, end_point;
g_set_prgname ("gtk4-path-tool restrict");
context = g_option_context_new (NULL);
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
g_option_context_add_main_entries (context, entries, NULL);
g_option_context_set_summary (context, _("Restrict a path to a segment."));
if (!g_option_context_parse (context, argc, (char ***)argv, &error))
{
g_printerr ("%s\n", error->message);
g_error_free (error);
exit (1);
}
g_option_context_free (context);
if (args == NULL)
{
g_printerr ("%s\n", _("No paths given."));
exit (1);
}
path = get_path (args[0]);
measure = gsk_path_measure_new (path);
if (start == G_MAXDOUBLE)
start = 0;
if (end == G_MAXDOUBLE)
end = gsk_path_measure_get_length (measure);
builder = gsk_path_builder_new ();
gsk_path_measure_get_point (measure, start, &start_point);
gsk_path_measure_get_point (measure, end, &end_point);
gsk_path_builder_add_segment (builder, path, &start_point, &end_point);
result = gsk_path_builder_free_to_path (builder);
if (result)
{
char *str = gsk_path_to_string (result);
g_print ("%s\n", str);
g_free (str);
}
else
{
g_printerr ("%s\n", _("That didn't work out."));
exit (1);
}
}

View File

@@ -1,81 +0,0 @@
/* Copyright 2023 Red Hat, Inc.
*
* GTK+ 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 of the
* License, or (at your option) any later version.
*
* GLib 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 GTK+; see the file COPYING. If not,
* see <http://www.gnu.org/licenses/>.
*
* Author: Matthias Clasen
*/
#include "config.h"
#include <gtk/gtk.h>
#include "gtk-path-tool.h"
#include <glib/gi18n-lib.h>
void
do_reverse (int *argc, const char ***argv)
{
GError *error = NULL;
char **args = NULL;
GOptionContext *context;
GOptionEntry entries[] = {
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &args, NULL, N_("PATH") },
{ NULL, },
};
GskPath *path, *result;
GskPathBuilder *builder;
g_set_prgname ("gtk4-path-tool reverse");
context = g_option_context_new (NULL);
g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
g_option_context_add_main_entries (context, entries, NULL);
g_option_context_set_summary (context, _("Reverse a path."));
if (!g_option_context_parse (context, argc, (char ***)argv, &error))
{
g_printerr ("%s\n", error->message);
g_error_free (error);
exit (1);
}
g_option_context_free (context);
if (args == NULL)
{
g_printerr ("%s\n", _("No paths given."));
exit (1);
}
path = get_path (args[0]);
builder = gsk_path_builder_new ();
gsk_path_builder_add_reverse_path (builder, path);
result = gsk_path_builder_free_to_path (builder);
if (result)
{
char *str = gsk_path_to_string (result);
g_print ("%s\n", str);
g_free (str);
}
else
{
g_printerr ("%s\n", _("That didn't work out."));
exit (1);
}
}

View File

@@ -39,9 +39,6 @@ usage (void)
"\n"
"Commands:\n"
" decompose Decompose the path\n"
" reverse Reverse the path\n"
" dash Dash the path\n"
" restrict Restrict the path to a segment\n"
" show Display the path in a window\n"
" render Render the path as an image\n"
" info Print information about the path\n"
@@ -127,18 +124,12 @@ main (int argc, const char *argv[])
argv++;
argc--;
if (strcmp (argv[0], "dash") == 0)
do_dash (&argc, &argv);
else if (strcmp (argv[0], "decompose") == 0)
if (strcmp (argv[0], "decompose") == 0)
do_decompose (&argc, &argv);
else if (strcmp (argv[0], "info") == 0)
do_info (&argc, &argv);
else if (strcmp (argv[0], "render") == 0)
do_render (&argc, &argv);
else if (strcmp (argv[0], "restrict") == 0)
do_restrict (&argc, &argv);
else if (strcmp (argv[0], "reverse") == 0)
do_reverse (&argc, &argv);
else if (strcmp (argv[0], "show") == 0)
do_show (&argc, &argv);
else

View File

@@ -1,10 +1,7 @@
#pragma once
void do_info (int *argc, const char ***argv);
void do_dash (int *argc, const char ***argv);
void do_decompose (int *argc, const char ***argv);
void do_restrict (int *argc, const char ***argv);
void do_reverse (int *argc, const char ***argv);
void do_render (int *argc, const char ***argv);
void do_show (int *argc, const char ***argv);

View File

@@ -24,12 +24,9 @@ endif
gtk_tools = [
['gtk4-path-tool', ['gtk-path-tool.c',
'gtk-path-tool-dash.c',
'gtk-path-tool-decompose.c',
'gtk-path-tool-info.c',
'gtk-path-tool-render.c',
'gtk-path-tool-restrict.c',
'gtk-path-tool-reverse.c',
'gtk-path-tool-show.c',
'gtk-path-tool-utils.c',
'path-view.c'], [libgtk_dep]],