Compare commits
84 Commits
foreach-ap
...
path-dash
Author | SHA1 | Date | |
---|---|---|---|
|
027461b209 | ||
|
ff17fd0e82 | ||
|
dea4d52d1a | ||
|
f7e248c7fe | ||
|
37db270d19 | ||
|
f3312f677b | ||
|
05547d98d6 | ||
|
11b219bc61 | ||
|
5721c3cb8f | ||
|
f90ca697af | ||
|
e81aa18c82 | ||
|
827bbc0cc1 | ||
|
7095a67910 | ||
|
dcbca3f0d7 | ||
|
702d7c238a | ||
|
5a3ed65ad8 | ||
|
2e24a9ece4 | ||
|
2a17320314 | ||
|
0dbff14555 | ||
|
c5d89d00f1 | ||
|
6f3be310f4 | ||
|
0ea6b70d55 | ||
|
2ca9982b91 | ||
|
a40282b2fb | ||
|
ad9fb1e101 | ||
|
02a9652af4 | ||
|
6f823d2d0d | ||
|
a5c9cd5657 | ||
|
21ab5b6fa3 | ||
|
2582fd45e4 | ||
|
0a28a5d53a | ||
|
ddd4855bbc | ||
|
204216e3d5 | ||
|
1e6a124665 | ||
|
78c5aff956 | ||
|
8d1844135b | ||
|
b5dd9dae0d | ||
|
ebcb518e4f | ||
|
b7ea22f168 | ||
|
f0b3381660 | ||
|
0796c72049 | ||
|
822e988efe | ||
|
cee043f977 | ||
|
b420540b15 | ||
|
031c0ec3e5 | ||
|
43b6822eb0 | ||
|
ba3a657c48 | ||
|
5f2f116c28 | ||
|
1db75e521d | ||
|
2297a353b8 | ||
|
80903e5f44 | ||
|
7342ce5bca | ||
|
167b38dfa1 | ||
|
ead88c36ec | ||
|
b8a3d7fa00 | ||
|
0fce24674a | ||
|
739084e9bc | ||
|
99ad585252 | ||
|
949b6692ac | ||
|
eb0479d8ed | ||
|
6defdb4e8a | ||
|
9fdad6d4ee | ||
|
b6e285844f | ||
|
c989a06718 | ||
|
1c8bd8658d | ||
|
ab50cba4e9 | ||
|
57918813e2 | ||
|
a4df8d8818 | ||
|
4b00cfc1ce | ||
|
889688c978 | ||
|
0bf1ae033d | ||
|
994afcaeed | ||
|
b69cc832ef | ||
|
ca188b41ae | ||
|
81c8d1dd28 | ||
|
32d00ca9ed | ||
|
01b9997590 | ||
|
677e19042d | ||
|
bd79f61cc5 | ||
|
361cdecfe4 | ||
|
2782daadb4 | ||
|
81821978ae | ||
|
ae7ec40cf2 | ||
|
8aaecc3416 |
@@ -207,9 +207,7 @@ msys2-mingw64:
|
||||
|
||||
macos-x86_64:
|
||||
rules:
|
||||
# run merge request pipelines
|
||||
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
|
||||
# do not run in forks
|
||||
# Do not run in forks as the runner is not available there.
|
||||
- if: $CI_PROJECT_NAMESPACE == "GNOME"
|
||||
stage: build
|
||||
tags:
|
||||
|
77
NEWS
77
NEWS
@@ -1,6 +1,81 @@
|
||||
Overview of Changes in 4.13.0, xx-xx-xxxx
|
||||
Overview of Changes in 4.13.1, xx-xx-xxxx
|
||||
=========================================
|
||||
|
||||
Overview of Changes in 4.13.0, 25-08-2023
|
||||
=========================================
|
||||
|
||||
* GskPath, GskPathBuilder, GskPathMeasure:
|
||||
Data types and APIs for path rendering. These APIs are still
|
||||
considered experimental, and may change until 4.14. Please try
|
||||
them out and give us feedback. Documentation can be found
|
||||
here: https://docs.gtk.org/gsk4/paths.html
|
||||
|
||||
* GtkGridView:
|
||||
- Fix a crash when scrolling
|
||||
|
||||
* GtkColumnView:
|
||||
- Fix a refcounting issue in the new scroll_to api
|
||||
|
||||
* GtkTreeView
|
||||
- Fix style classes for sort arrows
|
||||
|
||||
* GtkEntry:
|
||||
- Improve tracking of user changes (for undo)
|
||||
|
||||
* GtkNotebook:
|
||||
- Fix a critical when switching pages
|
||||
|
||||
* GtkColor/FontDialogButton:
|
||||
- Make these widgets activatable
|
||||
|
||||
* GtkMenuButton:
|
||||
- Fix problems with focus handling
|
||||
- Fix problems with DND
|
||||
- Make flags a settable property
|
||||
|
||||
* GtkShortcutsWindow:
|
||||
- Add API to build shortcuts windows programmatically
|
||||
|
||||
* Printing
|
||||
- Fix the cpdb backend build
|
||||
|
||||
* MacOS:
|
||||
- Make file filters work again
|
||||
|
||||
* GSK:
|
||||
- Fix issues with color matrix nodes
|
||||
|
||||
* Wayland:
|
||||
- Fix a crash with compositors other than gnome-shell
|
||||
|
||||
* Deprecations:
|
||||
- Remaining GtkTreeModel-related types
|
||||
|
||||
* Demos:
|
||||
- Add a few path demos to gtk4-demo
|
||||
|
||||
* Tools:
|
||||
- gtk4-path-tool provides a commandline interface for paths
|
||||
|
||||
* Translation updates:
|
||||
Basque
|
||||
Catalan
|
||||
Finnish
|
||||
Galician
|
||||
Georgian
|
||||
German
|
||||
Greek
|
||||
Indonesian
|
||||
Kazakh
|
||||
Persian
|
||||
Polish
|
||||
Romanian
|
||||
Spanish
|
||||
Swedish
|
||||
Turkish
|
||||
Ukrainian
|
||||
|
||||
|
||||
Overview of Changes in 4.12.0, 05-08-2023
|
||||
=========================================
|
||||
|
||||
|
@@ -127,6 +127,7 @@
|
||||
<file>fishbowl.ui</file>
|
||||
<file>gtkfishbowl.c</file>
|
||||
<file>gtkfishbowl.h</file>
|
||||
<file>tiger.node</file>
|
||||
</gresource>
|
||||
<gresource prefix="/frames">
|
||||
<file>frames.ui</file>
|
||||
@@ -336,6 +337,7 @@
|
||||
<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>
|
||||
|
@@ -11,6 +11,9 @@
|
||||
#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);"
|
||||
@@ -208,6 +211,18 @@ 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);
|
||||
@@ -225,6 +240,8 @@ 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;
|
||||
|
153
demos/gtk-demo/graphwidget.c
Normal file
153
demos/gtk-demo/graphwidget.c
Normal file
@@ -0,0 +1,153 @@
|
||||
#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);
|
||||
}
|
8
demos/gtk-demo/graphwidget.h
Normal file
8
demos/gtk-demo/graphwidget.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#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);
|
@@ -73,6 +73,7 @@ demos = files([
|
||||
'panes.c',
|
||||
'password_entry.c',
|
||||
'path_fill.c',
|
||||
'path_maze.c',
|
||||
'path_spinner.c',
|
||||
'path_walk.c',
|
||||
'path_text.c',
|
||||
@@ -140,6 +141,8 @@ extra_demo_sources = files([
|
||||
'unicode-names.c',
|
||||
'suggestionentry.c',
|
||||
'language-names.c',
|
||||
'nodewidget.c',
|
||||
'graphwidget.c',
|
||||
])
|
||||
|
||||
if os_unix
|
||||
|
76
demos/gtk-demo/nodewidget.c
Normal file
76
demos/gtk-demo/nodewidget.c
Normal file
@@ -0,0 +1,76 @@
|
||||
#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);
|
||||
}
|
8
demos/gtk-demo/nodewidget.h
Normal file
8
demos/gtk-demo/nodewidget.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#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);
|
348
demos/gtk-demo/path_maze.c
Normal file
348
demos/gtk-demo/path_maze.c
Normal file
@@ -0,0 +1,348 @@
|
||||
/* 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;
|
||||
}
|
@@ -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,32 +190,21 @@ update_path (GtkSpinnerPaintable *self)
|
||||
{
|
||||
GskPathBuilder *builder;
|
||||
GskPathPoint start, end;
|
||||
GskTransform *t;
|
||||
graphene_point_t p, p0, p1;
|
||||
graphene_point_t 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);
|
||||
|
||||
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);
|
||||
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));
|
||||
|
||||
g_clear_pointer (&self->path, gsk_path_unref);
|
||||
|
||||
gsk_path_get_closest_point (self->circle, &p0, INFINITY, &start);
|
||||
gsk_path_get_closest_point (self->circle, &p1, INFINITY, &end);
|
||||
gsk_path_get_closest_point (self->circle, &p0, INFINITY, &start, NULL);
|
||||
gsk_path_get_closest_point (self->circle, &p1, INFINITY, &end, NULL);
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
gsk_path_builder_add_segment (builder, self->circle, &start, &end);
|
||||
|
@@ -501,15 +501,13 @@ 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))
|
||||
&point,
|
||||
NULL))
|
||||
{
|
||||
gsk_path_point_get_position (&point, self->line_path, &pos);
|
||||
|
||||
gtk_widget_queue_draw (GTK_WIDGET (self));
|
||||
}
|
||||
}
|
||||
|
2218
demos/gtk-demo/tiger.node
Normal file
2218
demos/gtk-demo/tiger.node
Normal file
File diff suppressed because it is too large
Load Diff
@@ -147,6 +147,19 @@ Creates a node like `gsk_cross_fade_node_new()` with the given properties.
|
||||
|
||||
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 |
|
||||
|
||||
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.
|
||||
|
||||
### glshader
|
||||
|
||||
| property | syntax | default | printed |
|
||||
@@ -289,6 +302,24 @@ Creates a node like `gsk_rounded_clip_node_new()` with the given properties.
|
||||
|
||||
Creates a node like `gsk_shadow_node_new()` with the given properties.
|
||||
|
||||
### stroke
|
||||
|
||||
| property | syntax | default | printed |
|
||||
| ----------- | ------------------ | ----------------- | ----------- |
|
||||
| child | `<node>` | *see below* | always |
|
||||
| path | `<string>` | "" | always |
|
||||
| line-width | `<number>` | 0 | non-default |
|
||||
| line-cap | `<line-cap>` | butt | always |
|
||||
| line-join | `<line-join>` | miter | always |
|
||||
| miter-limit | `<number>` | 4 | non-default |
|
||||
| dash | `<number>{+}|none` | none | non-default |
|
||||
| dash-offset | `<number>` | 0 | non-default |
|
||||
|
||||
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.
|
||||
|
||||
### text
|
||||
|
||||
| property | syntax | default | printed |
|
||||
|
@@ -15,6 +15,7 @@ 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
|
||||
@@ -181,6 +182,12 @@ 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
|
||||
^^^^
|
||||
|
||||
|
@@ -95,10 +95,11 @@ static gboolean
|
||||
gdk_gl_texture_invoke_callback (gpointer data)
|
||||
{
|
||||
InvokeData *invoke = data;
|
||||
GdkGLContext *context;
|
||||
GdkGLContext *context, *previous;
|
||||
|
||||
context = gdk_display_get_gl_context (gdk_gl_context_get_display (invoke->self->context));
|
||||
|
||||
previous = gdk_gl_context_get_current ();
|
||||
gdk_gl_context_make_current (context);
|
||||
|
||||
if (invoke->self->sync && context != invoke->self->context)
|
||||
@@ -110,6 +111,11 @@ gdk_gl_texture_invoke_callback (gpointer data)
|
||||
|
||||
g_atomic_int_set (&invoke->spinlock, 1);
|
||||
|
||||
if (previous)
|
||||
gdk_gl_context_make_current (previous);
|
||||
else
|
||||
gdk_gl_context_clear_current ();
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
1856
gsk/gskcontour.c
1856
gsk/gskcontour.c
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "gskpathprivate.h"
|
||||
#include "gskpathpointprivate.h"
|
||||
#include "gskpathpoint.h"
|
||||
#include "gskpathopprivate.h"
|
||||
#include "gskboundingboxprivate.h"
|
||||
|
||||
@@ -34,6 +34,12 @@ 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);
|
||||
@@ -49,36 +55,32 @@ 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,
|
||||
GskRealPathPoint *result,
|
||||
GskPathPoint *result,
|
||||
float *out_dist);
|
||||
void gsk_contour_get_position (const GskContour *self,
|
||||
GskRealPathPoint *point,
|
||||
const GskPathPoint *point,
|
||||
graphene_point_t *pos);
|
||||
void gsk_contour_get_tangent (const GskContour *self,
|
||||
GskRealPathPoint *point,
|
||||
const GskPathPoint *point,
|
||||
GskPathDirection direction,
|
||||
graphene_vec2_t *tangent);
|
||||
float gsk_contour_get_curvature (const GskContour *self,
|
||||
GskRealPathPoint *point,
|
||||
const GskPathPoint *point,
|
||||
GskPathDirection direction,
|
||||
graphene_point_t *center);
|
||||
void gsk_contour_add_segment (const GskContour *self,
|
||||
GskPathBuilder *builder,
|
||||
gboolean emit_move_to,
|
||||
GskRealPathPoint *start,
|
||||
GskRealPathPoint *end);
|
||||
const GskPathPoint *start,
|
||||
const GskPathPoint *end);
|
||||
|
||||
gpointer gsk_contour_init_measure (const GskContour *self,
|
||||
float tolerance,
|
||||
@@ -88,9 +90,13 @@ void gsk_contour_free_measure (const GskContou
|
||||
void gsk_contour_get_point (const GskContour *self,
|
||||
gpointer measure_data,
|
||||
float distance,
|
||||
GskRealPathPoint *result);
|
||||
GskPathPoint *result);
|
||||
float gsk_contour_get_distance (const GskContour *self,
|
||||
GskRealPathPoint *point,
|
||||
const GskPathPoint *point,
|
||||
gpointer measure_data);
|
||||
gboolean gsk_contour_dash (const GskContour *contour,
|
||||
GskStroke *stroke,
|
||||
GskPathForeachFunc func,
|
||||
gpointer user_data);
|
||||
|
||||
G_END_DECLS
|
||||
|
@@ -2,7 +2,7 @@
|
||||
* see https://pomax.github.io/bezierinfo/legendre-gauss.html
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#if defined(USE_64_SAMPLES)
|
||||
/* n = 64 */
|
||||
static const double T[] = {
|
||||
-0.0243502926634244325089558428537156614268871093149758091634531663960566965166295288529853061657116894882370493013671717560479926679408068852617342586968190919443025679363843727751902756254975073084367002129407854253246662805532069172532219089321005870178809284335033318073251039701073379759,
|
||||
@@ -137,7 +137,8 @@ static const double C[] = {
|
||||
0.0017832807216964329472960791449719331799593472719279556695308063655858546954239803486698215802150348282744786016134857283616955449868451969230490863774274598030023211055562492709717566919237924255297982774711177411074145151155610163293142044147991553384925940046957893721166251082473659733,
|
||||
0.0017832807216964329472960791449719331799593472719279556695308063655858546954239803486698215802150348282744786016134857283616955449868451969230490863774274598030023211055562492709717566919237924255297982774711177411074145151155610163293142044147991553384925940046957893721166251082473659733
|
||||
};
|
||||
#else
|
||||
|
||||
#elif defined(USE_32_SAMPLES)
|
||||
/* n = 32 */
|
||||
|
||||
static double T[] = {
|
||||
@@ -210,4 +211,62 @@ 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
|
||||
|
140
gsk/gskcurve.c
140
gsk/gskcurve.c
@@ -84,6 +84,9 @@ 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 */
|
||||
@@ -208,6 +211,41 @@ 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 */
|
||||
|
||||
@@ -426,6 +464,23 @@ 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,
|
||||
@@ -448,6 +503,7 @@ 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,
|
||||
};
|
||||
|
||||
/* }}} */
|
||||
@@ -721,6 +777,19 @@ 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;
|
||||
@@ -828,6 +897,14 @@ 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,
|
||||
@@ -850,6 +927,7 @@ 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,
|
||||
};
|
||||
|
||||
/* }}} */
|
||||
@@ -1298,6 +1376,14 @@ 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,
|
||||
@@ -1320,6 +1406,7 @@ 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,
|
||||
};
|
||||
|
||||
/* }}} */
|
||||
@@ -1853,7 +1940,20 @@ gsk_conic_curve_decompose_or_add (const GskCurve *curve,
|
||||
GskCurveAddCurveFunc add_curve_func,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (gsk_conic_is_close_to_cubic (curve, cubic, tolerance))
|
||||
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))
|
||||
return add_curve_func (GSK_PATH_CUBIC, cubic->cubic.points, 4, 0.f, user_data);
|
||||
else
|
||||
{
|
||||
@@ -1895,7 +1995,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 (or conic?) approximation */
|
||||
/* FIXME: Quadratic approximation */
|
||||
return gsk_conic_curve_decompose (curve,
|
||||
tolerance,
|
||||
gsk_curve_add_line_cb,
|
||||
@@ -1992,6 +2092,14 @@ 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,
|
||||
@@ -2014,6 +2122,7 @@ 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,
|
||||
};
|
||||
|
||||
/* }}} */
|
||||
@@ -2363,32 +2472,7 @@ gsk_curve_at_length (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;
|
||||
return get_class (curve->op)->get_at_length (curve, length, epsilon);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
350
gsk/gskpath.c
350
gsk/gskpath.c
@@ -23,8 +23,8 @@
|
||||
|
||||
#include "gskcurveprivate.h"
|
||||
#include "gskpathbuilder.h"
|
||||
#include "gskpathpointprivate.h"
|
||||
#include "gsksplineprivate.h"
|
||||
#include "gskpathpoint.h"
|
||||
#include "gskcontourprivate.h"
|
||||
|
||||
/**
|
||||
* GskPath:
|
||||
@@ -66,6 +66,8 @@ 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)
|
||||
{
|
||||
@@ -110,6 +112,31 @@ 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`
|
||||
@@ -153,22 +180,6 @@ 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`
|
||||
@@ -177,7 +188,7 @@ gsk_path_get_flags (const GskPath *self)
|
||||
* Converts @self into a human-readable string representation suitable
|
||||
* for printing.
|
||||
*
|
||||
* The string is compatible with
|
||||
* The string is compatible with (a superset of)
|
||||
* [SVG path syntax](https://www.w3.org/TR/SVG11/paths.html#PathData),
|
||||
* see [func@Gsk.Path.parse] for a summary of the syntax.
|
||||
*
|
||||
@@ -295,20 +306,6 @@ 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`
|
||||
@@ -421,6 +418,7 @@ gsk_path_get_bounds (GskPath *self,
|
||||
*
|
||||
* Returns: `TRUE` if the path has bounds, `FALSE` if the path is known
|
||||
* to be empty and have no bounds.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
gboolean
|
||||
@@ -510,17 +508,19 @@ 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;
|
||||
|
||||
res->contour = 0;
|
||||
res->idx = 1;
|
||||
res->t = 0;
|
||||
/* 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;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -543,17 +543,15 @@ 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;
|
||||
|
||||
res->contour = self->n_contours - 1;
|
||||
res->idx = gsk_contour_get_n_ops (self->contours[self->n_contours - 1]) - 1;
|
||||
res->t = 1;
|
||||
result->contour = self->n_contours - 1;
|
||||
result->idx = gsk_contour_get_n_ops (self->contours[self->n_contours - 1]) - 1;
|
||||
result->t = 1;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -564,6 +562,7 @@ 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.
|
||||
@@ -580,9 +579,9 @@ gboolean
|
||||
gsk_path_get_closest_point (GskPath *self,
|
||||
const graphene_point_t *point,
|
||||
float threshold,
|
||||
GskPathPoint *result)
|
||||
GskPathPoint *result,
|
||||
float *distance)
|
||||
{
|
||||
GskRealPathPoint *res = (GskRealPathPoint *) result;
|
||||
gboolean found;
|
||||
|
||||
g_return_val_if_fail (self != NULL, FALSE);
|
||||
@@ -594,19 +593,26 @@ gsk_path_get_closest_point (GskPath *self,
|
||||
|
||||
for (int i = 0; i < self->n_contours; i++)
|
||||
{
|
||||
float distance;
|
||||
float dist;
|
||||
|
||||
if (gsk_contour_get_closest_point (self->contours[i], point, threshold, res, &distance))
|
||||
if (gsk_contour_get_closest_point (self->contours[i], point, threshold, result, &dist))
|
||||
{
|
||||
found = TRUE;
|
||||
res->contour = i;
|
||||
threshold = distance;
|
||||
g_assert (0 <= result->t && result->t <= 1);
|
||||
result->contour = i;
|
||||
threshold = dist;
|
||||
|
||||
if (distance)
|
||||
*distance = dist;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
/* {{{ Foreach and decomposition */
|
||||
|
||||
/**
|
||||
* gsk_path_foreach:
|
||||
* @self: a `GskPath`
|
||||
@@ -804,14 +810,15 @@ gsk_path_foreach_with_tolerance (GskPath *self,
|
||||
|
||||
for (i = 0; i < self->n_contours; i++)
|
||||
{
|
||||
if (!gsk_contour_foreach (self->contours[i], tolerance, func, user_data))
|
||||
if (!gsk_contour_foreach (self->contours[i], func, user_data))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* path parser and utilities */
|
||||
/* }}} */
|
||||
/* {{{ Parser and utilities */
|
||||
|
||||
static void
|
||||
skip_whitespace (const char **p)
|
||||
@@ -953,6 +960,195 @@ 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
|
||||
@@ -1037,15 +1233,56 @@ gsk_path_parse (const char *string)
|
||||
case 'M':
|
||||
case 'm':
|
||||
{
|
||||
double x1, y1;
|
||||
double x1, y1, w, h, r;
|
||||
GskRoundedRect rr;
|
||||
|
||||
if (parse_coordinate_pair (&p, &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 (cmd == 'm')
|
||||
{
|
||||
x1 += x;
|
||||
y1 += y;
|
||||
}
|
||||
|
||||
if (repeat)
|
||||
gsk_path_builder_line_to (builder, x1, y1);
|
||||
else
|
||||
@@ -1057,6 +1294,7 @@ gsk_path_parse (const char *string)
|
||||
path_y = y1;
|
||||
}
|
||||
}
|
||||
|
||||
x = x1;
|
||||
y = y1;
|
||||
}
|
||||
@@ -1296,7 +1534,7 @@ gsk_path_parse (const char *string)
|
||||
parse_coordinate_pair (&p, &x2, &y2) &&
|
||||
parse_nonnegative_number (&p, &weight))
|
||||
{
|
||||
if (cmd == 'c')
|
||||
if (cmd == 'o')
|
||||
{
|
||||
x1 += x;
|
||||
y1 += y;
|
||||
@@ -1375,3 +1613,7 @@ error:
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
||||
/* vim:set foldmethod=marker expandtab: */
|
||||
|
@@ -135,7 +135,8 @@ GDK_AVAILABLE_IN_4_14
|
||||
gboolean gsk_path_get_closest_point (GskPath *self,
|
||||
const graphene_point_t *point,
|
||||
float threshold,
|
||||
GskPathPoint *result);
|
||||
GskPathPoint *result,
|
||||
float *distance);
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
gboolean gsk_path_foreach (GskPath *self,
|
||||
@@ -143,6 +144,12 @@ 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
|
||||
|
@@ -24,6 +24,7 @@
|
||||
#include "gskpathbuilder.h"
|
||||
|
||||
#include "gskpathprivate.h"
|
||||
#include "gskpathpointprivate.h"
|
||||
#include "gskcontourprivate.h"
|
||||
|
||||
/**
|
||||
@@ -64,7 +65,7 @@
|
||||
* [method@Gsk.PathBuilder.close] to close the path by connecting it
|
||||
* back with a line to the starting point.
|
||||
*
|
||||
* This is similar for how paths are drawn in Cairo.
|
||||
* This is similar to how paths are drawn in Cairo.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
@@ -240,7 +241,7 @@ gsk_path_builder_unref (GskPathBuilder *self)
|
||||
* @self: a `GskPathBuilder`
|
||||
*
|
||||
* Creates a new `GskPath` from the current state of the
|
||||
* given builder, and frees the @builder instance.
|
||||
* given builder, and unrefs the @builder instance.
|
||||
*
|
||||
* Returns: (transfer full): the newly created `GskPath`
|
||||
* with all the contours added to the builder
|
||||
@@ -310,12 +311,14 @@ gsk_path_builder_add_contour (GskPathBuilder *self,
|
||||
* gsk_path_builder_get_current_point:
|
||||
* @self: a `GskPathBuilder`
|
||||
*
|
||||
* Gets the current point. The current point is used for relative
|
||||
* drawing commands and updated after every operation.
|
||||
* Gets the current point.
|
||||
*
|
||||
* When the builder is created, the default current point is set to (0, 0).
|
||||
* Note that this is different from cairo, which starts out without
|
||||
* a current point.
|
||||
* The current point is used for relative drawing commands and
|
||||
* updated after every operation.
|
||||
*
|
||||
* When the builder is created, the default current point is set
|
||||
* to `0, 0`. Note that this is different from cairo, which starts
|
||||
* out without a current point.
|
||||
*
|
||||
* Returns: (transfer none): The current point
|
||||
*
|
||||
@@ -443,9 +446,6 @@ 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,20 +455,13 @@ void
|
||||
gsk_path_builder_add_rect (GskPathBuilder *self,
|
||||
const graphene_rect_t *rect)
|
||||
{
|
||||
graphene_point_t current;
|
||||
graphene_rect_t r;
|
||||
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (rect != NULL);
|
||||
|
||||
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;
|
||||
graphene_rect_normalize_r (rect, &r);
|
||||
gsk_path_builder_add_contour (self, gsk_rect_contour_new (&r));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -486,59 +479,10 @@ 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);
|
||||
|
||||
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;
|
||||
gsk_path_builder_add_contour (self, gsk_rounded_rect_contour_new (rect));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -551,6 +495,8 @@ 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
|
||||
@@ -558,34 +504,11 @@ 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);
|
||||
|
||||
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;
|
||||
gsk_path_builder_add_contour (self, gsk_circle_contour_new (center, radius));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -828,7 +751,9 @@ gsk_path_builder_cubic_to (GskPathBuilder *self,
|
||||
*
|
||||
* Adds a [cubic Bézier curve](https://en.wikipedia.org/wiki/B%C3%A9zier_curve)
|
||||
* from the current point to @x3, @y3 with @x1, @y1 and @x2, @y2 as the control
|
||||
* points. All coordinates are given relative to the current point.
|
||||
* points.
|
||||
*
|
||||
* All coordinates are given relative to the current point.
|
||||
*
|
||||
* This is the relative version of [method@Gsk.PathBuilder.cubic_to].
|
||||
*
|
||||
@@ -865,7 +790,7 @@ gsk_path_builder_rel_cubic_to (GskPathBuilder *self,
|
||||
*
|
||||
* Adds a [conic curve](https://en.wikipedia.org/wiki/Non-uniform_rational_B-spline)
|
||||
* from the current point to @x2, @y2 with the given @weight and @x1, @y1 as the
|
||||
* single control point.
|
||||
* control point.
|
||||
*
|
||||
* The weight determines how strongly the curve is pulled towards the control point.
|
||||
* A conic with weight 1 is identical to a quadratic Bézier curve with the same points.
|
||||
@@ -914,7 +839,9 @@ gsk_path_builder_conic_to (GskPathBuilder *self,
|
||||
*
|
||||
* Adds a [conic curve](https://en.wikipedia.org/wiki/Non-uniform_rational_B-spline)
|
||||
* from the current point to @x2, @y2 with the given @weight and @x1, @y1 as the
|
||||
* single control point.
|
||||
* control point.
|
||||
*
|
||||
* All coordinates are given relative to the current point.
|
||||
*
|
||||
* This is the relative version of [method@Gsk.PathBuilder.conic_to].
|
||||
*
|
||||
@@ -985,8 +912,9 @@ gsk_path_builder_arc_to (GskPathBuilder *self,
|
||||
* @y2: y coordinate of second control point
|
||||
*
|
||||
* Adds an elliptical arc from the current point to @x3, @y3
|
||||
* with @x1, @y1 determining the tangent directions. All coordinates
|
||||
* are given relative to the current point.
|
||||
* with @x1, @y1 determining the tangent directions.
|
||||
*
|
||||
* All coordinates are given relative to the current point.
|
||||
*
|
||||
* This is the relative version of [method@Gsk.PathBuilder.arc_to].
|
||||
*
|
||||
@@ -1332,7 +1260,6 @@ angle_between_points (const graphene_point_t *c,
|
||||
* the circle with the given radius touches the line from
|
||||
* @x1, @y1 to @x2, @y2.
|
||||
*
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
void
|
||||
@@ -1417,8 +1344,7 @@ gsk_path_builder_rel_html_arc_to (GskPathBuilder *self,
|
||||
* @self: a #GskPathBuilder
|
||||
* @layout: the pango layout to add
|
||||
*
|
||||
* Adds the outlines for the glyphs in @layout to
|
||||
* the builder.
|
||||
* Adds the outlines for the glyphs in @layout to the builder.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
@@ -1468,8 +1394,6 @@ 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;
|
||||
@@ -1477,51 +1401,49 @@ gsk_path_builder_add_segment (GskPathBuilder *self,
|
||||
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (path != NULL);
|
||||
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);
|
||||
g_return_if_fail (gsk_path_point_valid (start, path));
|
||||
g_return_if_fail (gsk_path_point_valid (end, path));
|
||||
|
||||
current = self->current_point;
|
||||
|
||||
contour = gsk_path_get_contour (path, s->contour);
|
||||
contour = gsk_path_get_contour (path, start->contour);
|
||||
n_ops = gsk_contour_get_n_ops (contour);
|
||||
|
||||
if (s->contour == e->contour)
|
||||
if (start->contour == end->contour)
|
||||
{
|
||||
if (gsk_path_point_compare (start, end) < 0)
|
||||
{
|
||||
gsk_contour_add_segment (contour, self, TRUE, s, e);
|
||||
gsk_contour_add_segment (contour, self, TRUE, start, end);
|
||||
goto out;
|
||||
}
|
||||
else if (n_contours == 1)
|
||||
{
|
||||
if (n_ops > 1)
|
||||
gsk_contour_add_segment (contour, self, TRUE,
|
||||
s,
|
||||
&(GskRealPathPoint) { s->contour, n_ops - 1, 1 });
|
||||
start,
|
||||
&GSK_PATH_POINT_INIT (start->contour, n_ops - 1, 1.f));
|
||||
gsk_contour_add_segment (contour, self, n_ops <= 1,
|
||||
&(GskRealPathPoint) { s->contour, 1, 0 },
|
||||
e);
|
||||
&GSK_PATH_POINT_INIT (start->contour, 1, 0.f),
|
||||
end);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (n_ops > 1)
|
||||
gsk_contour_add_segment (contour, self, TRUE,
|
||||
s,
|
||||
&(GskRealPathPoint) { s->contour, n_ops - 1, 1. });
|
||||
start,
|
||||
&GSK_PATH_POINT_INIT (start->contour, n_ops - 1, 1.f));
|
||||
|
||||
for (gsize i = (s->contour + 1) % n_contours; i != e->contour; i = (i + 1) % n_contours)
|
||||
for (gsize i = (start->contour + 1) % n_contours; i != end->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, e->contour);
|
||||
contour = gsk_path_get_contour (path, end->contour);
|
||||
n_ops = gsk_contour_get_n_ops (contour);
|
||||
|
||||
if (n_ops > 1)
|
||||
gsk_contour_add_segment (contour, self, TRUE,
|
||||
&(GskRealPathPoint) { e->contour, 1, 0 },
|
||||
e);
|
||||
&GSK_PATH_POINT_INIT (end->contour, 1, 0.f),
|
||||
end);
|
||||
|
||||
out:
|
||||
gsk_path_builder_end_current (self);
|
||||
|
280
gsk/gskpathdash.c
Normal file
280
gsk/gskpathdash.c
Normal file
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "gskpathbuilder.h"
|
||||
#include "gskpathpointprivate.h"
|
||||
#include "gskcontourprivate.h"
|
||||
#include "gskpathprivate.h"
|
||||
|
||||
/**
|
||||
@@ -38,6 +39,8 @@
|
||||
*
|
||||
* A `GskPathMeasure` struct is a reference counted struct
|
||||
* and should be treated as opaque.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
|
||||
typedef struct _GskContourMeasure GskContourMeasure;
|
||||
@@ -69,7 +72,8 @@ G_DEFINE_BOXED_TYPE (GskPathMeasure, gsk_path_measure,
|
||||
* gsk_path_measure_new:
|
||||
* @path: the path to measure
|
||||
*
|
||||
* Creates a measure object for the given @path.
|
||||
* Creates a measure object for the given @path with the
|
||||
* default tolerance.
|
||||
*
|
||||
* Returns: a new `GskPathMeasure` representing @path
|
||||
*
|
||||
@@ -255,7 +259,6 @@ gsk_path_measure_get_point (GskPathMeasure *self,
|
||||
float distance,
|
||||
GskPathPoint *result)
|
||||
{
|
||||
GskRealPathPoint *res = (GskRealPathPoint *) result;
|
||||
gsize i;
|
||||
const GskContour *contour;
|
||||
|
||||
@@ -281,8 +284,11 @@ 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, res);
|
||||
res->contour = i;
|
||||
gsk_contour_get_point (contour, self->measures[i].contour_data, distance, result);
|
||||
|
||||
g_assert (0 <= result->t && result->t <= 1);
|
||||
|
||||
result->contour = i;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
@@ -303,21 +309,16 @@ 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 (p->contour < measure->n_contours, 0);
|
||||
|
||||
contour = gsk_path_get_contour (measure->path, p->contour);
|
||||
g_return_val_if_fail (gsk_path_point_valid (point, measure->path), 0);
|
||||
|
||||
for (gsize i = 0; i < measure->n_contours; i++)
|
||||
{
|
||||
if (contour == gsk_path_get_contour (measure->path, i))
|
||||
return contour_offset + gsk_contour_get_distance (contour,
|
||||
p,
|
||||
if (i == point->contour)
|
||||
return contour_offset + gsk_contour_get_distance (gsk_path_get_contour (measure->path, i),
|
||||
point,
|
||||
measure->measures[i].contour_data);
|
||||
|
||||
contour_offset += measure->measures[i].length;
|
||||
|
@@ -22,9 +22,7 @@
|
||||
#include <math.h>
|
||||
|
||||
#include "gskpathpointprivate.h"
|
||||
|
||||
#include "gskcontourprivate.h"
|
||||
|
||||
#include "gdk/gdkprivate.h"
|
||||
|
||||
#define RAD_TO_DEG(x) ((x) / (G_PI / 180.f))
|
||||
@@ -34,15 +32,17 @@
|
||||
*
|
||||
* `GskPathPoint` is an opaque type representing a point on a path.
|
||||
*
|
||||
* It can be queried for properties of the path at that point, such as its
|
||||
* tangent or its curvature.
|
||||
* It can be queried for properties of the path at that point, such as
|
||||
* its tangent or its curvature.
|
||||
*
|
||||
* To obtain a `GskPathPoint`, use [method@Gsk.Path.get_closest_point].
|
||||
* To obtain a `GskPathPoint`, use [method@Gsk.Path.get_closest_point],
|
||||
* [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 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 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.
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
@@ -51,7 +51,6 @@ G_DEFINE_BOXED_TYPE (GskPathPoint, gsk_path_point,
|
||||
gsk_path_point_copy,
|
||||
gsk_path_point_free)
|
||||
|
||||
|
||||
GskPathPoint *
|
||||
gsk_path_point_copy (GskPathPoint *point)
|
||||
{
|
||||
@@ -59,7 +58,7 @@ gsk_path_point_copy (GskPathPoint *point)
|
||||
|
||||
copy = g_new0 (GskPathPoint, 1);
|
||||
|
||||
memcpy (copy, point, sizeof (GskRealPathPoint));
|
||||
memcpy (copy, point, sizeof (GskPathPoint));
|
||||
|
||||
return copy;
|
||||
}
|
||||
@@ -85,19 +84,18 @@ gsk_path_point_free (GskPathPoint *point)
|
||||
* same location.
|
||||
*
|
||||
* Return: `TRUE` if @point1 and @point2 are equal
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
gboolean
|
||||
gsk_path_point_equal (const GskPathPoint *point1,
|
||||
const GskPathPoint *point2)
|
||||
{
|
||||
const GskRealPathPoint *p1 = (const GskRealPathPoint *) point1;
|
||||
const GskRealPathPoint *p2 = (const GskRealPathPoint *) point2;
|
||||
|
||||
if (p1->contour == p2->contour)
|
||||
if (point1->contour == point2->contour)
|
||||
{
|
||||
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))
|
||||
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))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -114,28 +112,27 @@ gsk_path_point_equal (const GskPathPoint *point1,
|
||||
* Returns: -1 if @point1 is before @point2,
|
||||
* 1 if @point1 is after @point2,
|
||||
* 0 if they are equal
|
||||
*
|
||||
* Since: 4.14
|
||||
*/
|
||||
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 (p1->contour < p2->contour)
|
||||
if (point1->contour < point2->contour)
|
||||
return -1;
|
||||
else if (p1->contour > p2->contour)
|
||||
else if (point1->contour > point2->contour)
|
||||
return 1;
|
||||
else if (p1->idx < p2->idx)
|
||||
else if (point1->idx < point2->idx)
|
||||
return -1;
|
||||
else if (p1->idx > p2->idx)
|
||||
else if (point1->idx > point2->idx)
|
||||
return 1;
|
||||
else if (p1->t < p2->t)
|
||||
else if (point1->t < point2->t)
|
||||
return -1;
|
||||
else if (p1->t > p2->t)
|
||||
else if (point1->t > point2->t)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
@@ -157,16 +154,14 @@ 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, self->contour),
|
||||
gsk_contour_get_position (contour, self, position);
|
||||
contour = gsk_path_get_contour (path, point->contour),
|
||||
gsk_contour_get_position (contour, point, position);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,16 +192,14 @@ 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, self->contour),
|
||||
gsk_contour_get_tangent (contour, self, direction, tangent);
|
||||
contour = gsk_path_get_contour (path, point->contour),
|
||||
gsk_contour_get_tangent (contour, point, direction, tangent);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -231,12 +224,10 @@ 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 (self->contour < gsk_path_get_n_contours (path), 0);
|
||||
g_return_val_if_fail (gsk_path_point_valid (point, path), 0);
|
||||
|
||||
gsk_path_point_get_tangent (point, path, direction, &tangent);
|
||||
|
||||
@@ -260,6 +251,8 @@ 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,
|
||||
@@ -281,13 +274,11 @@ 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 (self->contour < gsk_path_get_n_contours (path), 0);
|
||||
g_return_val_if_fail (gsk_path_point_valid (point, path), 0);
|
||||
|
||||
contour = gsk_path_get_contour (path, self->contour);
|
||||
return gsk_contour_get_curvature (contour, self, direction, center);
|
||||
contour = gsk_path_get_contour (path, point->contour);
|
||||
return gsk_contour_get_curvature (contour, point, direction, center);
|
||||
}
|
||||
|
@@ -34,9 +34,14 @@ typedef struct _GskPathPoint GskPathPoint;
|
||||
struct _GskPathPoint {
|
||||
/*< private >*/
|
||||
union {
|
||||
float f[8];
|
||||
gpointer p[8];
|
||||
} data;
|
||||
struct {
|
||||
gsize contour;
|
||||
gsize idx;
|
||||
float t;
|
||||
};
|
||||
gpointer padding[8];
|
||||
graphene_vec4_t alignment;
|
||||
};
|
||||
};
|
||||
|
||||
GDK_AVAILABLE_IN_4_14
|
||||
|
@@ -5,14 +5,35 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
struct _GskRealPathPoint
|
||||
{
|
||||
gsize contour;
|
||||
gsize idx;
|
||||
float t;
|
||||
};
|
||||
#define GSK_PATH_POINT_INIT(c,i,tt) ((GskPathPoint){ .contour=(c), .idx=(i), .t=(tt) })
|
||||
|
||||
G_STATIC_ASSERT (sizeof (GskRealPathPoint) <= sizeof (GskPathPoint));
|
||||
static inline gboolean
|
||||
gsk_path_point_valid (const GskPathPoint *point,
|
||||
GskPath *path)
|
||||
{
|
||||
const GskContour *contour;
|
||||
gsize n_ops;
|
||||
|
||||
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_END_DECLS
|
||||
|
||||
|
@@ -1172,10 +1172,16 @@ create_default_texture (void)
|
||||
return texture;
|
||||
}
|
||||
|
||||
static GskRenderNode *
|
||||
create_default_render_node_with_bounds (const graphene_rect_t *rect)
|
||||
{
|
||||
return gsk_color_node_new (&GDK_RGBA("FF00CC"), rect);
|
||||
}
|
||||
|
||||
static GskRenderNode *
|
||||
create_default_render_node (void)
|
||||
{
|
||||
return gsk_color_node_new (&GDK_RGBA("FF00CC"), &GRAPHENE_RECT_INIT (0, 0, 50, 50));
|
||||
return create_default_render_node_with_bounds (&GRAPHENE_RECT_INIT (0, 0, 50, 50));
|
||||
}
|
||||
|
||||
static GskPath *
|
||||
@@ -2254,10 +2260,14 @@ parse_fill_node (GtkCssParser *parser,
|
||||
GskRenderNode *result;
|
||||
|
||||
parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations));
|
||||
if (child == NULL)
|
||||
child = create_default_render_node ();
|
||||
if (path == NULL)
|
||||
path = create_default_path ();
|
||||
if (child == NULL)
|
||||
{
|
||||
graphene_rect_t bounds;
|
||||
gsk_path_get_bounds (path, &bounds);
|
||||
child = create_default_render_node_with_bounds (&bounds);
|
||||
}
|
||||
|
||||
result = gsk_fill_node_new (child, path, rule);
|
||||
|
||||
@@ -2311,8 +2321,6 @@ parse_stroke_node (GtkCssParser *parser,
|
||||
GskRenderNode *result;
|
||||
|
||||
parse_declarations (parser, context, declarations, G_N_ELEMENTS (declarations));
|
||||
if (child == NULL)
|
||||
child = create_default_render_node ();
|
||||
if (path == NULL)
|
||||
path = create_default_path ();
|
||||
|
||||
@@ -2327,6 +2335,13 @@ parse_stroke_node (GtkCssParser *parser,
|
||||
}
|
||||
gsk_stroke_set_dash_offset (stroke, dash_offset);
|
||||
|
||||
if (child == NULL)
|
||||
{
|
||||
graphene_rect_t bounds;
|
||||
gsk_path_get_stroke_bounds (path, stroke, &bounds);
|
||||
child = create_default_render_node_with_bounds (&bounds);
|
||||
}
|
||||
|
||||
result = gsk_stroke_node_new (child, path, stroke);
|
||||
|
||||
gsk_path_unref (path);
|
||||
|
208
gsk/gskspline.c
208
gsk/gskspline.c
@@ -1,208 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
@@ -1,41 +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>
|
||||
*/
|
||||
|
||||
|
||||
#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__ */
|
||||
|
@@ -368,7 +368,7 @@ gsk_stroke_get_miter_limit (const GskStroke *self)
|
||||
* gsk_stroke_set_dash:
|
||||
* @self: a `GskStroke`
|
||||
* @dash: (array length=n_dash) (transfer none) (nullable):
|
||||
* the array of dashes
|
||||
* the array of dashes
|
||||
* @n_dash: number of elements in @dash
|
||||
*
|
||||
* Sets the dash pattern to use by this stroke.
|
||||
|
@@ -27,6 +27,7 @@ gsk_public_sources = files([
|
||||
'gskdiff.c',
|
||||
'gskglshader.c',
|
||||
'gskpath.c',
|
||||
'gskpathdash.c',
|
||||
'gskpathbuilder.c',
|
||||
'gskpathmeasure.c',
|
||||
'gskpathpoint.c',
|
||||
@@ -47,7 +48,6 @@ gsk_private_sources = files([
|
||||
'gskdebug.c',
|
||||
'gskprivate.c',
|
||||
'gskprofiler.c',
|
||||
'gskspline.c',
|
||||
'gl/gskglattachmentstate.c',
|
||||
'gl/gskglbuffer.c',
|
||||
'gl/gskglcommandqueue.c',
|
||||
|
@@ -560,6 +560,9 @@ 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);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
project('gtk', 'c',
|
||||
version: '4.13.0',
|
||||
version: '4.13.1',
|
||||
default_options: [
|
||||
'buildtype=debugoptimized',
|
||||
'warning_level=1',
|
||||
|
@@ -429,6 +429,7 @@ 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
|
||||
|
@@ -37,6 +37,8 @@ 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
187
po/ca.po
@@ -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-05 10:34+0000\n"
|
||||
"PO-Revision-Date: 2023-08-05 11:18+0100\n"
|
||||
"POT-Creation-Date: 2023-08-26 02:30+0000\n"
|
||||
"PO-Revision-Date: 2023-08-26 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:1863
|
||||
#: gdk/gdkglcontext.c:1864
|
||||
#, 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:805 gdk/x11/gdkdrop-x11.c:235
|
||||
#: gdk/x11/gdkclipboard-x11.c:807 gdk/x11/gdkdrop-x11.c:235
|
||||
msgid "No compatible transfer format found"
|
||||
msgstr "No s'ha trobat cap format de transferència compatible"
|
||||
|
||||
@@ -770,10 +770,9 @@ msgid "No GL implementation is available"
|
||||
msgstr "No hi ha cap implementació GL disponible"
|
||||
|
||||
#: gdk/win32/gdkglcontext-win32-wgl.c:396
|
||||
#, fuzzy, c-format
|
||||
#| msgid "EGL version %d.%d is too old. GTK requires %d.%d"
|
||||
#, c-format
|
||||
msgid "WGL version %d.%d is too low, need at least %d.%d"
|
||||
msgstr "La versió de l'EGL %d.%d és massa antiga. La GTK requereix %d.%d"
|
||||
msgstr "La versió %d.%d de WGL és massa baixa, cal com a mínim %d.%d"
|
||||
|
||||
#: gdk/win32/gdkglcontext-win32-wgl.c:414
|
||||
#, c-format
|
||||
@@ -838,11 +837,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:475
|
||||
#: gdk/x11/gdkclipboard-x11.c:477
|
||||
msgid "Clipboard manager could not store selection."
|
||||
msgstr "El gestor de porta-retalls no ha pogut desar la selecció."
|
||||
|
||||
#: gdk/x11/gdkclipboard-x11.c:655
|
||||
#: gdk/x11/gdkclipboard-x11.c:657
|
||||
msgid "Cannot store clipboard. No clipboard manager is active."
|
||||
msgstr ""
|
||||
"No es pot emmagatzemar el porta-retalls. No està actiu el gestor del porta-"
|
||||
@@ -1111,13 +1110,13 @@ msgid "Pick a Color"
|
||||
msgstr "Trieu un color"
|
||||
|
||||
#: gtk/deprecated/gtkcolorbutton.c:502 gtk/gtkcolorchooserwidget.c:313
|
||||
#: gtk/gtkcolordialogbutton.c:302
|
||||
#: gtk/gtkcolordialogbutton.c:335
|
||||
#, 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:308
|
||||
#: gtk/gtkcolordialogbutton.c:341
|
||||
#, c-format
|
||||
msgid "Red %d%%, Green %d%%, Blue %d%%"
|
||||
msgstr "Vermell %d%%, verd %d%%, blau %d%%"
|
||||
@@ -1132,11 +1131,11 @@ msgid "Pick a Font"
|
||||
msgstr "Trieu un tipus de lletra"
|
||||
|
||||
#: gtk/deprecated/gtkfontbutton.c:597 gtk/gtkfilechooserwidget.c:3871
|
||||
#: gtk/gtkfontdialogbutton.c:115 gtk/inspector/visual.ui:169
|
||||
#: gtk/gtkfontdialogbutton.c:126 gtk/inspector/visual.ui:169
|
||||
msgid "Font"
|
||||
msgstr "Tipus de lletra"
|
||||
|
||||
#: gtk/deprecated/gtkfontbutton.c:1152 gtk/gtkfontdialogbutton.c:614
|
||||
#: gtk/deprecated/gtkfontbutton.c:1152 gtk/gtkfontdialogbutton.c:652
|
||||
msgctxt "font"
|
||||
msgid "None"
|
||||
msgstr "Cap"
|
||||
@@ -2109,7 +2108,7 @@ msgstr "Personalitzat"
|
||||
|
||||
#: gtk/gtkcolorchooserwidget.c:571
|
||||
msgid "Add Color"
|
||||
msgstr "Afegeix color"
|
||||
msgstr "Afegeix un color"
|
||||
|
||||
#: gtk/gtkcolorchooserwidget.c:593
|
||||
#, c-format
|
||||
@@ -2274,7 +2273,7 @@ msgstr "_Obre"
|
||||
msgid "_Save"
|
||||
msgstr "_Desa"
|
||||
|
||||
#: gtk/gtkfilechoosernativequartz.c:340 gtk/ui/gtkfilechooserwidget.ui:288
|
||||
#: gtk/gtkfilechoosernativequartz.c:344 gtk/ui/gtkfilechooserwidget.ui:288
|
||||
msgid "Select which types of files are shown"
|
||||
msgstr "Seleccioneu quins tipus de fitxers es mostren"
|
||||
|
||||
@@ -2347,7 +2346,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:6125 gtk/gtktextview.c:9018
|
||||
#: gtk/gtklabel.c:5695 gtk/gtktext.c:6145 gtk/gtktextview.c:9018
|
||||
msgid "_Delete"
|
||||
msgstr "_Suprimeix"
|
||||
|
||||
@@ -2488,7 +2487,7 @@ msgstr "Programa"
|
||||
msgid "Audio"
|
||||
msgstr "Àudio"
|
||||
|
||||
#: gtk/gtkfilechooserwidget.c:3872 gtk/gtkfilefilter.c:1035
|
||||
#: gtk/gtkfilechooserwidget.c:3872 gtk/gtkfilefilter.c:1032
|
||||
msgid "Image"
|
||||
msgstr "Imatge"
|
||||
|
||||
@@ -2599,7 +2598,7 @@ msgstr "Selecciona carpetes"
|
||||
msgid "Select a Folder"
|
||||
msgstr "Selecciona una carpeta"
|
||||
|
||||
#: gtk/gtkfilefilter.c:1048
|
||||
#: gtk/gtkfilefilter.c:1045
|
||||
msgid "Unspecified"
|
||||
msgstr "No especificat"
|
||||
|
||||
@@ -2691,19 +2690,19 @@ msgstr "Tanca"
|
||||
msgid "Close the infobar"
|
||||
msgstr "Tanca la barra d'informació"
|
||||
|
||||
#: gtk/gtklabel.c:5692 gtk/gtktext.c:6113 gtk/gtktextview.c:9006
|
||||
#: gtk/gtklabel.c:5692 gtk/gtktext.c:6133 gtk/gtktextview.c:9006
|
||||
msgid "Cu_t"
|
||||
msgstr "Re_talla"
|
||||
|
||||
#: gtk/gtklabel.c:5693 gtk/gtktext.c:6117 gtk/gtktextview.c:9010
|
||||
#: gtk/gtklabel.c:5693 gtk/gtktext.c:6137 gtk/gtktextview.c:9010
|
||||
msgid "_Copy"
|
||||
msgstr "_Copia"
|
||||
|
||||
#: gtk/gtklabel.c:5694 gtk/gtktext.c:6121 gtk/gtktextview.c:9014
|
||||
#: gtk/gtklabel.c:5694 gtk/gtktext.c:6141 gtk/gtktextview.c:9014
|
||||
msgid "_Paste"
|
||||
msgstr "_Enganxa"
|
||||
|
||||
#: gtk/gtklabel.c:5700 gtk/gtktext.c:6134 gtk/gtktextview.c:9039
|
||||
#: gtk/gtklabel.c:5700 gtk/gtktext.c:6154 gtk/gtktextview.c:9039
|
||||
msgid "Select _All"
|
||||
msgstr "Seleccion_a-ho tot"
|
||||
|
||||
@@ -2913,7 +2912,7 @@ msgstr "Pestanya anterior"
|
||||
msgid "Next tab"
|
||||
msgstr "Pestanya següent"
|
||||
|
||||
#: gtk/gtknotebook.c:4331 gtk/gtknotebook.c:6539
|
||||
#: gtk/gtknotebook.c:4331 gtk/gtknotebook.c:6541
|
||||
#, c-format
|
||||
msgid "Page %u"
|
||||
msgstr "Pàgina %u"
|
||||
@@ -3658,7 +3657,7 @@ msgctxt "accessibility"
|
||||
msgid "Sidebar"
|
||||
msgstr "Barra lateral"
|
||||
|
||||
#: gtk/gtktext.c:6139 gtk/gtktextview.c:9044
|
||||
#: gtk/gtktext.c:6159 gtk/gtktextview.c:9044
|
||||
msgid "Insert _Emoji"
|
||||
msgstr "Insereix _emoji"
|
||||
|
||||
@@ -7204,20 +7203,7 @@ msgid "Can’t close stream"
|
||||
msgstr "No es pot tancar el flux"
|
||||
|
||||
#: tools/gtk-builder-tool.c:36
|
||||
#, 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"
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Usage:\n"
|
||||
" gtk4-builder-tool [COMMAND] [OPTION…] FILE\n"
|
||||
@@ -7243,7 +7229,8 @@ msgstr ""
|
||||
" simplify Simplifica el fitxer\n"
|
||||
" enumerate Llista tots els objectes anomenats\n"
|
||||
" preview Previsualitza el fitxer\n"
|
||||
" screenshot Fes una captura de pantalla\n"
|
||||
" render Fes una captura de pantalla del fitxer\n"
|
||||
" screenshot Fes una captura de pantalla del fitxer\n"
|
||||
"\n"
|
||||
|
||||
#: tools/gtk-builder-tool-enumerate.c:56 tools/gtk-builder-tool-preview.c:179
|
||||
@@ -7288,10 +7275,9 @@ 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
|
||||
#, fuzzy, c-format
|
||||
#| msgid "Could not initialize EGL display"
|
||||
#, c-format
|
||||
msgid "Could not initialize windowing system\n"
|
||||
msgstr "No s'ha pogut inicialitzar la pantalla EGL"
|
||||
msgstr "No s'ha pogut inicialitzar el sistema de finestres\n"
|
||||
|
||||
#: tools/gtk-builder-tool-preview.c:195
|
||||
msgid "Preview the file."
|
||||
@@ -7306,13 +7292,14 @@ msgid "No .ui file specified\n"
|
||||
msgstr "No s'ha especificat un fitxer .ui\n"
|
||||
|
||||
#: tools/gtk-builder-tool-preview.c:214
|
||||
#, fuzzy, c-format
|
||||
#, 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 simplificar un únic fitxer .ui sense --replace\n"
|
||||
msgstr "Només es pot previsualitzar un únic fitxer .ui\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"
|
||||
|
||||
@@ -7323,10 +7310,9 @@ msgstr "Els objectes del tipus %s no poden ser captura de pantalla\n"
|
||||
|
||||
# FIXME
|
||||
#: tools/gtk-builder-tool-screenshot.c:298
|
||||
#, fuzzy, c-format
|
||||
#| msgid "Failed to write hash table\n"
|
||||
#, c-format
|
||||
msgid "Failed to take a screenshot\n"
|
||||
msgstr "No s'ha pogut escriure la taula de resum\n"
|
||||
msgstr "No s'ha pogut fer una captura de pantalla\n"
|
||||
|
||||
#: tools/gtk-builder-tool-screenshot.c:309
|
||||
#, c-format
|
||||
@@ -7345,10 +7331,9 @@ msgstr "Sortida escrita a %s.\n"
|
||||
|
||||
#: tools/gtk-builder-tool-screenshot.c:336
|
||||
#: tools/gtk-rendernode-tool-render.c:176
|
||||
#, fuzzy, c-format
|
||||
#| msgid "Failed to open file %s : %s\n"
|
||||
#, c-format
|
||||
msgid "Failed to save %s: %s\n"
|
||||
msgstr "No s'ha pogut obrir el fitxer %s: %s\n"
|
||||
msgstr "No s'ha pogut desar %s: %s\n"
|
||||
|
||||
#: tools/gtk-builder-tool-screenshot.c:359
|
||||
msgid "Screenshot only the named object"
|
||||
@@ -7372,10 +7357,9 @@ 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 simplificar un únic fitxer .ui sense --replace\n"
|
||||
msgstr ""
|
||||
"Només es pot renderitzar un únic fitxer .ui a un únic fitxer de sortida\n"
|
||||
|
||||
#: tools/gtk-builder-tool-simplify.c:444
|
||||
#, c-format
|
||||
@@ -7383,28 +7367,24 @@ msgid "%s:%d: Couldn’t 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, fuzzy
|
||||
#| msgid "%s:%d: %sproperty %s::%s not found\n"
|
||||
#, c-format
|
||||
msgid "Property %s not found"
|
||||
msgstr "No s'ha trobat la propietat %s"
|
||||
|
||||
#: tools/gtk-builder-tool-simplify.c:661
|
||||
#, c-format, fuzzy
|
||||
#| msgid "%s:%d: %sproperty %s::%s not found\n"
|
||||
#, c-format
|
||||
msgid "Packing property %s not found"
|
||||
msgstr "No s'ha trobat la propietat d'empaquetatge %s"
|
||||
|
||||
#: tools/gtk-builder-tool-simplify.c:664
|
||||
#, fuzzy, c-format
|
||||
#| msgid "%s:%d: %sproperty %s::%s not found\n"
|
||||
#, c-format
|
||||
msgid "Cell property %s not found"
|
||||
msgstr "%s:%d: %sproperty %s::%s no s'ha trobat\n"
|
||||
msgstr "No s'ha trobat la propietat de cel·la %s"
|
||||
|
||||
#: tools/gtk-builder-tool-simplify.c:667
|
||||
#, fuzzy, c-format
|
||||
#| msgid "%s:%d: %sproperty %s::%s not found\n"
|
||||
#, c-format
|
||||
msgid "Layout property %s not found"
|
||||
msgstr "%s:%d: %sproperty %s::%s no s'ha trobat\n"
|
||||
msgstr "No s'ha trobat la propietat de disposició %s"
|
||||
|
||||
#: tools/gtk-builder-tool-simplify.c:1397
|
||||
#, c-format
|
||||
@@ -7430,7 +7410,6 @@ 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"
|
||||
|
||||
@@ -7452,9 +7431,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, fuzzy
|
||||
#, c-format
|
||||
msgid "Failed to lookup template parent type %s\n"
|
||||
msgstr "No s'ha pogut cercar el tipus pare de la plantilla %s"
|
||||
msgstr "No s'ha pogut cercar el tipus pare de la plantilla %s\n"
|
||||
|
||||
#: tools/gtk-builder-tool-validate.c:123
|
||||
msgid "Deprecated types:\n"
|
||||
@@ -7529,20 +7508,7 @@ 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
|
||||
#, 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"
|
||||
#, c-format
|
||||
msgid ""
|
||||
"Usage:\n"
|
||||
" gtk4-rendernode-tool [COMMAND] [OPTION…] FILE\n"
|
||||
@@ -7556,16 +7522,14 @@ msgid ""
|
||||
"\n"
|
||||
msgstr ""
|
||||
"Ús:\n"
|
||||
" gtk-builder-tool [ORDRE] [OPCIONS…] FITXER\n"
|
||||
" gtk4-rendernode-tool [ORDRE] [OPCIÓ...] FITXER\n"
|
||||
"\n"
|
||||
"Fes diverses tasques en fitxers GtkBuilder .ui.\n"
|
||||
"Realitza diverses tasques als nodes de renderització GTK.\n"
|
||||
"\n"
|
||||
"Ordres:\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"
|
||||
" info Proporciona informació sobre el node\n"
|
||||
" show Mostra el node\n"
|
||||
" render Fes una captura de pantalla del node\n"
|
||||
"\n"
|
||||
|
||||
#: tools/gtk-rendernode-tool-info.c:177
|
||||
@@ -7594,44 +7558,39 @@ 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
|
||||
#, fuzzy, c-format
|
||||
#| msgid "No .ui file specified\n"
|
||||
#, c-format
|
||||
msgid "No .node file specified\n"
|
||||
msgstr "No s'ha especificat un fitxer .ui\n"
|
||||
msgstr "No s'ha especificat un fitxer .node\n"
|
||||
|
||||
#: tools/gtk-rendernode-tool-info.c:228
|
||||
#, fuzzy, c-format
|
||||
#| msgid "Can only simplify a single .ui file without --replace\n"
|
||||
#, c-format
|
||||
msgid "Can only accept a single .node file\n"
|
||||
msgstr "Només es pot simplificar un únic fitxer .ui sense --replace\n"
|
||||
msgstr "Només es pot acceptar un únic fitxer .node\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
|
||||
#, fuzzy, c-format
|
||||
#| msgid "Can only simplify a single .ui file without --replace\n"
|
||||
#, c-format
|
||||
msgid "Can only preview a single .node file\n"
|
||||
msgstr "Només es pot simplificar un únic fitxer .ui sense --replace\n"
|
||||
msgstr "Només es pot previsualitzar un únic fitxer .node\n"
|
||||
|
||||
#: tools/gtk-rendernode-tool-render.c:123
|
||||
#, c-format, fuzzy
|
||||
#, c-format
|
||||
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."
|
||||
"Si voleu sobreescriure, especifiqueu el nom del fitxer.\n"
|
||||
|
||||
#: tools/gtk-rendernode-tool-render.c:137
|
||||
#, fuzzy, c-format
|
||||
#| msgid "Failed to open file %s : %s\n"
|
||||
#, c-format
|
||||
msgid "Failed to generate SVG: %s\n"
|
||||
msgstr "No s'ha pogut obrir el fitxer %s: %s\n"
|
||||
msgstr "No s'ha pogut generar el SVG: %s\n"
|
||||
|
||||
#: tools/gtk-rendernode-tool-render.c:196
|
||||
#, fuzzy
|
||||
msgid "Renderer to use"
|
||||
msgstr "Renderitzador a utilitzar"
|
||||
|
||||
@@ -7640,15 +7599,14 @@ 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, fuzzy
|
||||
#, c-format
|
||||
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"
|
||||
"Només es pot renderitzar un únic fitxer .node a un únic fitxer de sortida\n"
|
||||
|
||||
#: tools/gtk-rendernode-tool-utils.c:51
|
||||
#, c-format
|
||||
@@ -7762,22 +7720,3 @@ 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 "Can’t parse “%s”\n"
|
||||
#~ msgstr "No es pot analitzar «%s»\n"
|
||||
|
101
po/gl.po
101
po/gl.po
@@ -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-23 19:17+0000\n"
|
||||
"PO-Revision-Date: 2023-08-24 08:19+0200\n"
|
||||
"POT-Creation-Date: 2023-08-28 15:54+0000\n"
|
||||
"PO-Revision-Date: 2023-08-29 00:36+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:6539
|
||||
#: gtk/gtknotebook.c:4331 gtk/gtknotebook.c:6541
|
||||
#, c-format
|
||||
msgid "Page %u"
|
||||
msgstr "Páxina %u"
|
||||
@@ -3565,7 +3565,7 @@ msgctxt "keyboard side marker"
|
||||
msgid "R"
|
||||
msgstr "D"
|
||||
|
||||
#: gtk/gtkshortcutssection.c:407
|
||||
#: gtk/gtkshortcutssection.c:414
|
||||
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:855 gtk/gtkshortcutswindow.c:922
|
||||
#: gtk/gtkshortcutswindow.c:927
|
||||
#: gtk/gtkshortcutswindow.c:879 gtk/gtkshortcutswindow.c:946
|
||||
#: gtk/gtkshortcutswindow.c:951
|
||||
msgid "Search Shortcuts"
|
||||
msgstr "Atallos da busca"
|
||||
|
||||
#. Translators: This is the window title for the shortcuts window in normal mode
|
||||
#: gtk/gtkshortcutswindow.c:887 gtk/inspector/window.ui:498
|
||||
#: gtk/gtkshortcutswindow.c:911 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:892
|
||||
#: gtk/gtkshortcutswindow.c:916
|
||||
msgid "Search Results"
|
||||
msgstr "Resultados da busca"
|
||||
|
||||
#: gtk/gtkshortcutswindow.c:989 gtk/ui/gtkemojichooser.ui:349
|
||||
#: gtk/gtkshortcutswindow.c:1013 gtk/ui/gtkemojichooser.ui:349
|
||||
#: gtk/ui/gtkfilechooserwidget.ui:239
|
||||
msgid "No Results Found"
|
||||
msgstr "Non se atopou ningún resultado"
|
||||
|
||||
#: gtk/gtkshortcutswindow.c:1000 gtk/ui/gtkemojichooser.ui:362
|
||||
#: gtk/gtkshortcutswindow.c:1024 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:133
|
||||
#: tools/gtk-path-tool-info.c:132
|
||||
msgid "Bounds"
|
||||
msgstr "Limiares"
|
||||
|
||||
@@ -7482,95 +7482,105 @@ 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] FICHEIRO\n"
|
||||
" gtk4-path-tool [ORDE] [OPCIÓN…] 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:80
|
||||
#: tools/gtk-path-tool-decompose.c:84
|
||||
msgid "Allow quadratic Bézier curves"
|
||||
msgstr "Permitir curvas Bézier cuadráticas"
|
||||
|
||||
#: tools/gtk-path-tool-decompose.c:81
|
||||
#: tools/gtk-path-tool-decompose.c:85
|
||||
msgid "Allow cubic Bézier curves"
|
||||
msgstr "Permitir curvas Bézier cúbicas"
|
||||
|
||||
#: tools/gtk-path-tool-decompose.c:82
|
||||
msgid "Allow elliptical arcs"
|
||||
msgstr "Permitir arcos elípticos"
|
||||
#: 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:83 tools/gtk-path-tool-info.c:93
|
||||
#: tools/gtk-path-tool-render.c:58 tools/gtk-path-tool-show.c:127
|
||||
#: 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
|
||||
msgid "PATH"
|
||||
msgstr "RUTA"
|
||||
|
||||
#: tools/gtk-path-tool-decompose.c:95
|
||||
#: tools/gtk-path-tool-decompose.c:99
|
||||
msgid "Decompose a path."
|
||||
msgstr "Descompoñer unha ruta."
|
||||
|
||||
#: tools/gtk-path-tool-decompose.c:108 tools/gtk-path-tool-info.c:117
|
||||
#: tools/gtk-path-tool-decompose.c:112 tools/gtk-path-tool-info.c:113
|
||||
#: tools/gtk-path-tool-restrict.c:64
|
||||
msgid "No paths given."
|
||||
msgstr "Non se forneceron rutas."
|
||||
|
||||
#: tools/gtk-path-tool-decompose.c:136
|
||||
#: tools/gtk-path-tool-decompose.c:140 tools/gtk-path-tool-restrict.c:94
|
||||
msgid "That didn't work out."
|
||||
msgstr "Iso non funcionou."
|
||||
|
||||
#: tools/gtk-path-tool-info.c:104
|
||||
#: tools/gtk-path-tool-info.c:100
|
||||
msgid "Print information about a path."
|
||||
msgstr "Mostra a información sobre a ruta."
|
||||
|
||||
#: tools/gtk-path-tool-info.c:124
|
||||
#: tools/gtk-path-tool-info.c:121
|
||||
msgid "Path is empty."
|
||||
msgstr "A ruta está baleira."
|
||||
|
||||
#: tools/gtk-path-tool-info.c:130
|
||||
#: tools/gtk-path-tool-info.c:127
|
||||
msgid "Path is closed"
|
||||
msgstr "A ruta está pechada"
|
||||
|
||||
#: tools/gtk-path-tool-info.c:139
|
||||
#: tools/gtk-path-tool-info.c:129
|
||||
msgid "Path length"
|
||||
msgstr "Lonxitude da ruta"
|
||||
|
||||
#: tools/gtk-path-tool-info.c:138
|
||||
#, c-format
|
||||
msgid "%d contours"
|
||||
msgstr "%d contornos"
|
||||
|
||||
#: tools/gtk-path-tool-info.c:141
|
||||
#: tools/gtk-path-tool-info.c:140
|
||||
#, c-format
|
||||
msgid "%d operations"
|
||||
msgstr "%d operacións"
|
||||
|
||||
#: tools/gtk-path-tool-info.c:145
|
||||
#: tools/gtk-path-tool-info.c:144
|
||||
#, c-format
|
||||
msgid "%d lines"
|
||||
msgstr "%d liñas"
|
||||
|
||||
#: tools/gtk-path-tool-info.c:150
|
||||
#: tools/gtk-path-tool-info.c:149
|
||||
#, c-format
|
||||
msgid "%d quadratics"
|
||||
msgstr "%d cuadráticas"
|
||||
|
||||
#: tools/gtk-path-tool-info.c:155
|
||||
#: tools/gtk-path-tool-info.c:154
|
||||
#, c-format
|
||||
msgid "%d cubics"
|
||||
msgstr "%d cúbicas"
|
||||
|
||||
#: tools/gtk-path-tool-info.c:160
|
||||
#: tools/gtk-path-tool-info.c:159
|
||||
#, c-format
|
||||
msgid "%d arcs"
|
||||
msgstr "%d arcos"
|
||||
msgid "%d conics"
|
||||
msgstr "%d cónicas"
|
||||
|
||||
#: tools/gtk-path-tool-render.c:53 tools/gtk-path-tool-show.c:123
|
||||
msgid "Fill the path (the default)"
|
||||
@@ -7694,6 +7704,22 @@ 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"
|
||||
@@ -7949,5 +7975,12 @@ 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"
|
||||
|
@@ -188,6 +188,12 @@ 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);
|
||||
@@ -198,7 +204,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.5);
|
||||
g_assert_cmpfloat_with_epsilon (l, l1 + l2, 0.62);
|
||||
}
|
||||
|
||||
int
|
||||
|
191
testsuite/gsk/dash.c
Normal file
191
testsuite/gsk/dash.c
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* 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 ();
|
||||
}
|
@@ -295,6 +295,8 @@ node_parser_tests = [
|
||||
'empty-transform.ref.node',
|
||||
'fill.node',
|
||||
'fill.ref.node',
|
||||
'fill2.node',
|
||||
'fill2.ref.node',
|
||||
'glshader.node',
|
||||
'glshader.ref.node',
|
||||
'glshader.errors',
|
||||
@@ -364,6 +366,7 @@ tests = [
|
||||
['shader'],
|
||||
['path'],
|
||||
['path-special-cases'],
|
||||
['dash'],
|
||||
]
|
||||
|
||||
test_cargs = []
|
||||
@@ -396,6 +399,7 @@ endforeach
|
||||
internal_tests = [
|
||||
[ 'curve' ],
|
||||
[ 'curve-special-cases' ],
|
||||
[ 'path-private' ],
|
||||
[ 'diff' ],
|
||||
[ 'half-float' ],
|
||||
['rounded-rect'],
|
||||
|
@@ -1,6 +1,6 @@
|
||||
fill {
|
||||
child: color {
|
||||
bounds: 0 0 50 50;
|
||||
bounds: 1.22359 0 47.5528 45.2254;
|
||||
color: rgb(255,0,204);
|
||||
}
|
||||
path: "\
|
||||
|
@@ -1,6 +1,6 @@
|
||||
stroke {
|
||||
child: color {
|
||||
bounds: 0 0 50 50;
|
||||
bounds: -2.77641 -4 55.5528 53.2254;
|
||||
color: rgb(255,0,204);
|
||||
}
|
||||
path: "\
|
||||
|
4
testsuite/gsk/nodeparser/fill2.node
Normal file
4
testsuite/gsk/nodeparser/fill2.node
Normal file
@@ -0,0 +1,4 @@
|
||||
fill {
|
||||
path: "M 0 0 O 10 10 20 20 5";
|
||||
fill-rule: even-odd;
|
||||
}
|
9
testsuite/gsk/nodeparser/fill2.ref.node
Normal file
9
testsuite/gsk/nodeparser/fill2.ref.node
Normal file
@@ -0,0 +1,9 @@
|
||||
fill {
|
||||
child: color {
|
||||
bounds: 0 0 20 20;
|
||||
color: rgb(255,0,204);
|
||||
}
|
||||
path: "\
|
||||
M 0 0 O 10 10, 20 20, 5";
|
||||
fill-rule: even-odd;
|
||||
}
|
10
testsuite/gsk/nodeparser/stroke2.node
Normal file
10
testsuite/gsk/nodeparser/stroke2.node
Normal file
@@ -0,0 +1,10 @@
|
||||
stroke {
|
||||
child: color { bounds: 0 0 100 100; color: red; }
|
||||
path: "M 10, 10 L 90, 90 M 90, 10 L 10, 90";
|
||||
line-width: 2.5;
|
||||
line-cap: butt;
|
||||
line-join: miter;
|
||||
miter-limit: 3.1;
|
||||
dash: 0 1 4.5 10;
|
||||
dash-offset: 2.1;
|
||||
}
|
17
testsuite/gsk/nodeparser/stroke2.ref.node
Normal file
17
testsuite/gsk/nodeparser/stroke2.ref.node
Normal file
@@ -0,0 +1,17 @@
|
||||
stroke {
|
||||
child: color {
|
||||
bounds: 0 0 100 100;
|
||||
color: rgb(255,0,0);
|
||||
}
|
||||
path: "\
|
||||
M 10 10\
|
||||
L 90 90\
|
||||
M 90 10\
|
||||
L 10 90";
|
||||
line-width: 2.5;
|
||||
line-cap: butt;
|
||||
line-join: miter;
|
||||
miter-limit: 3.1;
|
||||
dash: 0 1 4.5 10;
|
||||
dash-offset: 2.1;
|
||||
}
|
276
testsuite/gsk/path-private.c
Normal file
276
testsuite/gsk/path-private.c
Normal file
@@ -0,0 +1,276 @@
|
||||
/*
|
||||
* 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 ();
|
||||
}
|
@@ -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));
|
||||
g_assert_false (gsk_path_get_closest_point (path, &GRAPHENE_POINT_INIT (0, 0), INFINITY, &point, NULL));
|
||||
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
@@ -314,6 +314,7 @@ 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));
|
||||
@@ -323,7 +324,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 L 200 0 L 200 100 L 0 100 Z");
|
||||
g_assert_cmpstr (s, ==, "M 0 0 h 200 v 100 h -200 z");
|
||||
g_free (s);
|
||||
|
||||
g_assert_true (gsk_path_get_bounds (path, &bounds));
|
||||
@@ -332,7 +333,9 @@ 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));
|
||||
g_assert_true (gsk_path_get_closest_point (path, &GRAPHENE_POINT_INIT (200, 200), INFINITY, &point, &distance));
|
||||
|
||||
g_assert_true (distance == 100);
|
||||
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
@@ -429,21 +432,11 @@ 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;
|
||||
@@ -454,23 +447,23 @@ test_path_point (void)
|
||||
ret = gsk_path_get_start_point (path, &point);
|
||||
g_assert_true (ret);
|
||||
|
||||
g_assert_true (rp->contour == 0);
|
||||
g_assert_true (rp->idx == 1);
|
||||
g_assert_true (rp->t == 0);
|
||||
g_assert_true (point.contour == 0);
|
||||
g_assert_true (point.idx == 1);
|
||||
g_assert_true (point.t == 0);
|
||||
|
||||
ret = gsk_path_get_end_point (path, &point);
|
||||
g_assert_true (ret);
|
||||
|
||||
g_assert_true (rp->contour == 0);
|
||||
g_assert_true (rp->idx == 4);
|
||||
g_assert_true (rp->t == 1);
|
||||
g_assert_true (point.contour == 0);
|
||||
g_assert_true (point.idx == 4);
|
||||
g_assert_true (point.t == 1);
|
||||
|
||||
ret = gsk_path_get_closest_point (path, &GRAPHENE_POINT_INIT (200, 200), INFINITY, &point);
|
||||
ret = gsk_path_get_closest_point (path, &GRAPHENE_POINT_INIT (200, 200), INFINITY, &point, NULL);
|
||||
g_assert_true (ret);
|
||||
|
||||
g_assert_true (rp->contour == 0);
|
||||
g_assert_true (rp->idx == 2);
|
||||
g_assert_true (rp->t == 1);
|
||||
g_assert_true (point.contour == 0);
|
||||
g_assert_true (point.idx == 2);
|
||||
g_assert_true (point.t == 1);
|
||||
|
||||
gsk_path_point_get_position (&point, path, &pos);
|
||||
gsk_path_point_get_tangent (&point, path, GSK_PATH_FROM_START, &t1);
|
||||
@@ -483,12 +476,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);
|
||||
ret = gsk_path_get_closest_point (path, &GRAPHENE_POINT_INIT (100, 50), INFINITY, &point, NULL);
|
||||
g_assert_true (ret);
|
||||
|
||||
g_assert_true (rp->contour == 0);
|
||||
g_assert_true (rp->idx == 2);
|
||||
g_assert_true (rp->t == 0.5);
|
||||
g_assert_true (point.contour == 0);
|
||||
g_assert_true (point.idx == 2);
|
||||
g_assert_true (point.t == 0.5);
|
||||
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
@@ -544,8 +537,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));
|
||||
g_assert_true (gsk_path_get_closest_point (path, &tests[i].p2, INFINITY, &p2));
|
||||
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));
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
gsk_path_builder_add_segment (builder, path, &p1, &p2);
|
||||
@@ -612,7 +605,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);
|
||||
gsk_path_get_closest_point (path, &GRAPHENE_POINT_INIT (50, 50), INFINITY, &point1, NULL);
|
||||
gsk_path_get_end_point (path, &point2);
|
||||
|
||||
surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 100, 100);
|
||||
@@ -785,6 +778,8 @@ 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),
|
||||
@@ -798,14 +793,58 @@ test_rounded_rect (void)
|
||||
|
||||
path = gsk_path_builder_free_to_path (builder);
|
||||
|
||||
for (int i = 0; i < 1000; i++)
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
graphene_point_t p = GRAPHENE_POINT_INIT (g_test_rand_double_range (0, 200),
|
||||
g_test_rand_double_range (0, 200));
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -813,9 +852,11 @@ static void
|
||||
test_circle (void)
|
||||
{
|
||||
GskPathBuilder *builder;
|
||||
GskPath *path;
|
||||
GskPathMeasure *measure;
|
||||
float length;
|
||||
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;
|
||||
|
||||
builder = gsk_path_builder_new ();
|
||||
gsk_path_builder_add_circle (builder, &GRAPHENE_POINT_INIT (0, 0), 1);
|
||||
@@ -826,8 +867,81 @@ 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
|
||||
@@ -875,6 +989,66 @@ 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, ¢er);
|
||||
|
||||
g_assert_true (k == INFINITY);
|
||||
g_assert_true (graphene_point_equal (¢er, &GRAPHENE_POINT_INIT (1, 2)));
|
||||
|
||||
gsk_path_unref (path);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
@@ -882,7 +1056,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", test_rect_path);
|
||||
g_test_add_func ("/path/rect-path", 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);
|
||||
@@ -891,8 +1065,11 @@ 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 ();
|
||||
}
|
||||
|
@@ -22,7 +22,7 @@
|
||||
static GskPath *
|
||||
create_random_degenerate_path (guint max_contours)
|
||||
{
|
||||
#define N_DEGENERATE_PATHS 14
|
||||
#define N_DEGENERATE_PATHS 15
|
||||
GskPathBuilder *builder;
|
||||
guint i;
|
||||
|
||||
@@ -132,6 +132,14 @@ 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),
|
||||
@@ -141,7 +149,7 @@ create_random_degenerate_path (guint max_contours)
|
||||
}
|
||||
break;
|
||||
|
||||
case 13:
|
||||
case 14:
|
||||
/* a cubic with start == end */
|
||||
{
|
||||
graphene_point_t point = GRAPHENE_POINT_INIT (g_test_rand_double_range (-1000, 1000),
|
||||
@@ -801,7 +809,7 @@ test_split (void)
|
||||
|
||||
length = gsk_path_measure_get_length (measure);
|
||||
/* chosen high enough to stop the testsuite from failing */
|
||||
epsilon = MAX (length / 1000, 1.f / 1024);
|
||||
epsilon = MAX (length / 250, 1.f / 1024);
|
||||
|
||||
split = g_test_rand_double_range (0, length);
|
||||
|
||||
|
168
tools/gtk-path-tool-dash.c
Normal file
168
tools/gtk-path-tool-dash.c
Normal file
@@ -0,0 +1,168 @@
|
||||
/* 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);
|
||||
}
|
||||
}
|
@@ -89,6 +89,7 @@ do_info (int *argc, const char ***argv)
|
||||
{ NULL, },
|
||||
};
|
||||
GskPath *path;
|
||||
GskPathMeasure *measure;
|
||||
graphene_rect_t bounds;
|
||||
|
||||
g_set_prgname ("gtk4-path-tool info");
|
||||
@@ -114,6 +115,7 @@ 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."));
|
||||
@@ -124,6 +126,8 @@ 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,
|
||||
|
97
tools/gtk-path-tool-restrict.c
Normal file
97
tools/gtk-path-tool-restrict.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/* 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);
|
||||
}
|
||||
}
|
81
tools/gtk-path-tool-reverse.c
Normal file
81
tools/gtk-path-tool-reverse.c
Normal file
@@ -0,0 +1,81 @@
|
||||
/* 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);
|
||||
}
|
||||
}
|
@@ -39,6 +39,9 @@ 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"
|
||||
@@ -124,12 +127,18 @@ main (int argc, const char *argv[])
|
||||
argv++;
|
||||
argc--;
|
||||
|
||||
if (strcmp (argv[0], "decompose") == 0)
|
||||
if (strcmp (argv[0], "dash") == 0)
|
||||
do_dash (&argc, &argv);
|
||||
else 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
|
||||
|
@@ -1,7 +1,10 @@
|
||||
#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);
|
||||
|
||||
|
@@ -24,9 +24,12 @@ 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]],
|
||||
|
Reference in New Issue
Block a user