Compare commits

...

85 Commits

Author SHA1 Message Date
Matthias Clasen
60e08e3191 composetable: Warn for things we can't handle
The compose table stores the keyvals to match against
in a guint16 array, so it can't handle directly encoded
Unicode codepoints (which have a high bit set). Warn
if we encounter those.
2023-08-29 12:18:49 -04:00
Mike FABIAN
208d3cf785 Add another test case for a single char compose sequence, using a code point (<UFEF7>) 2023-08-29 13:05:15 +02:00
Mike FABIAN
9e8bce3436 Add test case for single char compose sequence 2023-08-29 09:16:06 +02:00
Matthias Clasen
67a7602080 Merge branch 'tests-svg-dimensions' into 'main'
testsuite/gsk: add explicit dimensions to <svg> elements

See merge request GNOME/gtk!6359
2023-08-29 04:43:22 +00:00
Matthias Clasen
37db270d19 Merge branch 'contour-foreach' into 'main'
Drop tolerance from gsk_contour_foreach

See merge request GNOME/gtk!6361
2023-08-29 01:58:39 +00:00
Matthias Clasen
f3312f677b measure: Cosmetics 2023-08-28 21:14:28 -04:00
Matthias Clasen
05547d98d6 path: Cosmetics
Reorganize this source file into sections.
2023-08-28 21:13:58 -04:00
Matthias Clasen
11b219bc61 Drop tolerance from gsk_contour_foreach
There is no decomposition going on for any contours,
and the tolerance argument is entirely unused.
Decomposition and tolerance is handled entirely
in gskpath.c by its trampoline.
2023-08-28 20:52:22 -04:00
Matthias Clasen
5721c3cb8f demos: Drop an unused variable 2023-08-28 20:50:38 -04:00
Fran Dieguez
f90ca697af Update Galician translation 2023-08-28 22:36:51 +00:00
Michael Orlitzky
7a0e27b6e8 testsuite/gsk: add explicit dimensions to <svg> elements
Without an explicit width, height, and viewBox, there is no single
correct way to render an SVG. In the absense of said information,
librsvg is capable of making a guess by rendering the SVG to a Cairo
surface and then analyzing that surface; however, this process is
merely heuristic.

There are three GTK tests for SVG images that are missing dimensions.
While this is not a violation of the SVG specification, it does
implicitly couple the test to the librsvg rendering heuristic. In this
commit we add that dimension information so that the expected result
is unambiguous.
2023-08-28 17:14:18 -04:00
Matthias Clasen
e81aa18c82 Merge branch 'closest-point-distance' into 'main'
Change gsk_path_get_closest_point to return distance

See merge request GNOME/gtk!6357
2023-08-28 15:53:51 +00:00
Matthias Clasen
827bbc0cc1 Change gsk_path_get_closest_point to return distance
We already compute it, so lets return it.
Bindings seems fine with this change - they
already return (success, point) as a tuple
anyway.
2023-08-28 11:22:30 -04:00
Matthias Clasen
7095a67910 Merge branch 'matthiasc/for-main' into 'main'
path-tool: Add a reverse command

See merge request GNOME/gtk!6356
2023-08-28 04:38:42 +00:00
Matthias Clasen
dcbca3f0d7 path-tool: Add a reverse command
It does what it says.
2023-08-28 00:27:29 -04:00
Matthias Clasen
702d7c238a Merge branch 'matthiasc/for-main' into 'main'
contour: Simplify gsk_circle_contour_foreach

See merge request GNOME/gtk!6355
2023-08-28 04:18:48 +00:00
Matthias Clasen
5a3ed65ad8 Improve precondition checks for path points
Add a helper function for checking that a
path point is valid for a path, and use it.
2023-08-28 00:07:50 -04:00
Matthias Clasen
2e24a9ece4 Make GskPathPoint public
The contents are still /*< private >*/, but we
let our tests and the debugger see them, which
helps.
2023-08-28 00:07:50 -04:00
Matthias Clasen
2a17320314 Limit rect variation in path builder
Make gsk_path_builder_add_rect always
produce a clockwise rectangle. This matches
what we do for circles and rounded rects,
which also go clockwise. Note that we
still need to allow negative widths in
the contour code, to implement reverse().
2023-08-28 00:07:50 -04:00
Matthias Clasen
0dbff14555 Allow circles with radius of zero
Not very useful, but we allow rects with
width and height of zero, so lets be consistent.
Curvature is infinite for such contours.

Tests included.
2023-08-28 00:07:50 -04:00
Matthias Clasen
c5d89d00f1 Merge branch 'zbrown/tooltips' into 'main'
tooltip: don't cross native boundaries

Closes #1234, #5998, gnome-calendar#1038, and nautilus#3063

See merge request GNOME/gtk!6346
2023-08-28 03:25:44 +00:00
Matthias Clasen
6f3be310f4 contour: Simplify gsk_circle_contour_foreach
Use the same approach as the rounded rect contour.
2023-08-27 21:31:40 -04:00
Matthias Clasen
0ea6b70d55 Merge branch 'matthiasc/for-main' into 'main'
gtk-demo: Add a few path benchmarks

See merge request GNOME/gtk!6353
2023-08-27 23:45:59 +00:00
Matthias Clasen
2ca9982b91 rect contour: Avoid nans in corner cases
The length of rect contours can be zero,
so we much check before we divide.
2023-08-27 19:17:02 -04:00
Matthias Clasen
a40282b2fb Add gsk_path_point_print
Another private debug API.
2023-08-27 19:06:39 -04:00
Matthias Clasen
ad9fb1e101 Improve quad and conic decomposition
If the control point is equal to either
start or end, just emit a line. This improves
the rendering of rounded rectangles with such
corners.
2023-08-27 16:57:03 -04:00
Matthias Clasen
02a9652af4 Use a more compact representation for circles
Print circles as M-o-o-o-o-z.
2023-08-27 14:32:21 -04:00
Matthias Clasen
6f823d2d0d gtk-demo: Add a few path benchmarks
The Tiger and Graph examples in the fishbowl test
path handling.
2023-08-27 12:59:10 -04:00
Matthias Clasen
a5c9cd5657 Merge branch 'rectangle-contour' into 'main'
Add a rectangle contour

See merge request GNOME/gtk!6351
2023-08-27 16:46:12 +00:00
Matthias Clasen
21ab5b6fa3 Merge branch 'matthiasc/for-main' into 'main'
Add a test for rectangle segments

See merge request GNOME/gtk!6352
2023-08-27 16:45:58 +00:00
Benjamin Otte
2582fd45e4 demos: Add cute maze demo 2023-08-27 12:45:25 -04:00
Matthias Clasen
0a28a5d53a Add a rectangle contour
Add a contour that optimizes some things for
rectangles. Also add rectangle detection to the
path parser, and add tests similar to what we
have for the other special contours.
2023-08-27 12:36:56 -04:00
Matthias Clasen
ddd4855bbc Add a test for rectangle segments 2023-08-27 12:36:30 -04:00
Matthias Clasen
204216e3d5 Merge branch 'matthiasc/for-main' into 'main'
Drop unused code

See merge request GNOME/gtk!6350
2023-08-27 16:19:16 +00:00
Matthias Clasen
1e6a124665 Correct the docs of gsk_path_builder_add_rect
The path does *not* always go clockwise!
2023-08-27 12:18:36 -04:00
Matthias Clasen
78c5aff956 Test special contours harder
Check that the start- and endpoint work
as expected and verify that their winding
numbers match the ones of the standard contour,
and are negated when the contour is reversed.
2023-08-27 11:47:40 -04:00
Matthias Clasen
8d1844135b path: Add a comment 2023-08-27 10:10:08 -04:00
Matthias Clasen
b5dd9dae0d rounded rect contour: Fix an oversight
The close operation takes 2 points, so our array
was one too short. Oops.
2023-08-27 10:09:32 -04:00
Matthias Clasen
ebcb518e4f Cosmetics 2023-08-27 09:50:16 -04:00
Matthias Clasen
b7ea22f168 Drop unused code
Nobody is calling gsk_contour_get_start_end, so drop
this internal API.
2023-08-27 09:39:59 -04:00
Matthias Clasen
f0b3381660 Merge branch 'rounded-rect-contour' into 'main'
path: Add a rounded rect contour

See merge request GNOME/gtk!6347
2023-08-27 13:36:53 +00:00
Matthias Clasen
0796c72049 Add roundtrip tests for rounded rect contours
These should survive roundtrips through the
path parser as well now.
2023-08-27 09:31:17 -04:00
Matthias Clasen
822e988efe path: Recognize rounded rects when parsing
We can look out for M-L-O-L-O-L-O-L-O-Z patterns
with matching numbers.
2023-08-27 09:31:17 -04:00
Matthias Clasen
cee043f977 Add a rounded rect contour
This special contour takes advantage of its
rounded-rect-ness for speeding up bounding
boxes and winding numbers. It falls back
to the standard contour code for everything
else.
2023-08-27 09:29:19 -04:00
Matthias Clasen
b420540b15 Merge branch 'matthiasc/for-main' into 'main'
Simplify the path spinner demo

See merge request GNOME/gtk!6349
2023-08-27 13:27:50 +00:00
Matthias Clasen
031c0ec3e5 pathpoint: Add some debug API
Add a private gsk_path_point_to_string that
can be called in the debugger if you want
to see the contents of a GskPathPoint and
are too lazy to cast it to GskRealPathPoint
yourself.
2023-08-27 09:14:47 -04:00
Matthias Clasen
43b6822eb0 Add roundtrip tests for special contours
So far, we only have a circle contour.
Check that it survives a roundtrip through
gsk_path_to_string and gsk_path_parse.
2023-08-27 09:14:03 -04:00
Matthias Clasen
ba3a657c48 contour: Add some debug API
Add a private  way to get the class of a contour,
so we can test that roundtrips through gsk_path_parse
work as expected.
2023-08-27 09:13:32 -04:00
Matthias Clasen
5f2f116c28 circle contour: Fix a typo 2023-08-27 07:43:55 -04:00
Matthias Clasen
1db75e521d Simplify the path spinner demo
The transforms were obscuring a simple
calculation here.
2023-08-27 07:43:55 -04:00
Matthias Clasen
2297a353b8 Merge branch 'circle-contour' into 'main'
path: Add a circle contour

See merge request GNOME/gtk!6345
2023-08-27 11:12:51 +00:00
Matthias Clasen
80903e5f44 Merge branch 'bilelmoussaoui/gi' into 'main'
gi: Add missing since annotation

See merge request GNOME/gtk!6348
2023-08-27 11:05:31 +00:00
Bilal Elmoussaoui
7342ce5bca gi: Add missing since annotation 2023-08-27 08:17:00 +00:00
Matthias Clasen
167b38dfa1 contour: Some reactoring
Make a default print implementation, and use it.
2023-08-26 23:42:52 -04:00
Matthias Clasen
ead88c36ec path: Add circle tests 2023-08-26 23:42:52 -04:00
Matthias Clasen
b8a3d7fa00 path: Recognize circles when parsing
We can look out for the tell-tale
M-O-O-O-O-Z and turn it into a circle
contour.
2023-08-26 23:42:52 -04:00
Matthias Clasen
0fce24674a path: Add a circle contour
This special contour takes advantage of the
circle definition to speed up things like
hit testing and closest point determination.
2023-08-26 23:42:52 -04:00
Zander Brown
739084e9bc tooltip: don't cross native boundaries
When walking the tree looking for tooltips we shouldn't cross from, say,
a popover to it's parent window

Fix: https://gitlab.gnome.org/GNOME/gtk/-/issues/1234
Fix: https://gitlab.gnome.org/GNOME/gnome-calendar/-/issues/1038
Fix: https://gitlab.gnome.org/GNOME/gtk/-/issues/5998
Fix: https://gitlab.gnome.org/GNOME/nautilus/-/issues/3063
See: https://gitlab.gnome.org/GNOME/console/-/issues/318
2023-08-27 02:36:51 +01:00
Matthias Clasen
99ad585252 Merge branch 'measure-speedups' into 'main'
contour: Stop doing the roundtrip test

See merge request GNOME/gtk!6342
2023-08-27 01:13:41 +00:00
Matthias Clasen
949b6692ac Merge branch 'matthiasc/for-main' into 'main'
Drop unused code

See merge request GNOME/gtk!6344
2023-08-26 16:46:49 +00:00
Piotr Drąg
eb0479d8ed Update POTFILES.in and POTFILES.skip 2023-08-26 17:52:22 +02:00
Matthias Clasen
6defdb4e8a Drop unused code
we are not using any gsk_spline functions currently.
2023-08-26 11:29:09 -04:00
Matthias Clasen
9fdad6d4ee Make randomized path tests less precise
Bump the epsilon in test_split to make these
tests survive longer. They still fail eventually,
unfortunately.
2023-08-26 11:23:02 -04:00
Matthias Clasen
b6e285844f Make curve tests pass 2023-08-26 11:22:58 -04:00
Matthias Clasen
c989a06718 pathmeasure: compute samples on demand
Only do the work for a curve the first time
we need it. This should greatly speed up
use cases where you only create a measure
to get the length of the path.
2023-08-26 10:23:02 -04:00
Matthias Clasen
1c8bd8658d curve: Cosmetics 2023-08-26 10:23:02 -04:00
Matthias Clasen
ab50cba4e9 curve: Reduce the order of our approximation
Use 24 samples instead of 32.
2023-08-26 10:23:02 -04:00
Matthias Clasen
57918813e2 contour: Stop doing the roundtrip test
Doing inverse arclength computations is
a very high overhead operation. And the
tests still pass without it.
2023-08-26 09:39:49 -04:00
Matthias Clasen
a4df8d8818 Merge branch 'path-node-tests' into 'main'
css: Replace border rendering code with GskPath

See merge request GNOME/gtk!6341
2023-08-26 12:13:04 +00:00
Matthias Clasen
4b00cfc1ce Merge branch 'macos_ci' into 'main'
Disable macOS CI for forks

See merge request GNOME/gtk!6337
2023-08-26 11:43:57 +00:00
Matthias Clasen
889688c978 Add more fill and stroke node tests 2023-08-26 07:39:23 -04:00
Matthias Clasen
0bf1ae033d Document node format for stroke and fill nodes 2023-08-26 07:39:23 -04:00
Jordi Mas
994afcaeed Update Catalan translation 2023-08-26 09:50:31 +02:00
Matthias Clasen
b69cc832ef Merge branch 'path-tool-restrict' into 'main'
path-tool: Add a restrict command

See merge request GNOME/gtk!6340
2023-08-26 04:24:06 +00:00
Matthias Clasen
ca188b41ae post-release version bump 2023-08-25 22:29:09 -04:00
Matthias Clasen
81c8d1dd28 path-tool: Add length to info output
This requires GskPathMeasure.
2023-08-25 22:26:54 -04:00
Matthias Clasen
32d00ca9ed path-tool: Add a restrict command
This lets you subset a path between two given lengths.
2023-08-25 22:26:54 -04:00
Matthias Clasen
01b9997590 4.13.0 2023-08-25 22:21:27 -04:00
Matthias Clasen
677e19042d Docs: Cosmetics 2023-08-25 22:21:27 -04:00
Matthias Clasen
bd79f61cc5 pathpoint: Update the docs
We have gained some more ways of getting points.
2023-08-25 22:03:42 -04:00
Matthias Clasen
361cdecfe4 Merge branch 'path-measure-reredone' into 'main'
Add GskPathMeasure

See merge request GNOME/gtk!6326
2023-08-26 01:05:19 +00:00
René de Hesselle
2782daadb4 ci: Do not create macOS jobs for forks
The runner is not available in forks (on purpose / for security
reasons), so jobs created there will be stuck indefinitely until they
timeout and fail the pipeline, which is undesireable.

That also means that the initial goal to enable macOS jobs for all MRs
is out of reach: if you are an external contributor (read: non-project
member), your MR pipelines run in your fork, therefore have no access
to the runner.
2023-08-26 01:56:59 +02:00
Benjamin Otte
81821978ae Merge branch 'wip/otte/for-main' into 'main'
gltexture: Restore previous GL context

See merge request GNOME/gtk!6335
2023-08-25 21:44:17 +00:00
Benjamin Otte
ae7ec40cf2 rendernodeparser: Generate better default child
... for fill and stroke nodes.

It's most likely we want the path bounds (or path stroke bounds),
so make the parser use those by default.
2023-08-25 21:12:12 +02:00
Benjamin Otte
8aaecc3416 gltexture: Restore previous GL context
Texture downloads can be initiated due to the weirdest reasons - and if
they cause a GL context to be changed, it'd be basically unpredictable
when the GL context changes.

An example is the Cairo renderer - if it needs to draw a GL texture, it
will download it.

Now that no longer changes the GL context.
2023-08-24 05:00:29 +02:00
61 changed files with 6073 additions and 995 deletions

View File

@@ -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
View File

@@ -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
=========================================

View File

@@ -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>

View 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;

View 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);
}

View 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);

View File

@@ -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

View 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);
}

View 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
View 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;
}

View File

@@ -56,9 +56,9 @@ gtk_spinner_paintable_get_intrinsic_height (GdkPaintable *paintable)
static void
gtk_spinner_paintable_snapshot (GdkPaintable *paintable,
GdkSnapshot *snapshot,
double width,
double height)
GdkSnapshot *snapshot,
double width,
double height)
{
GtkSpinnerPaintable *self = GTK_SPINNER_PAINTABLE (paintable);
@@ -190,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);

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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 |

View File

@@ -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
^^^^

View File

@@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@@ -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,9 @@ 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);
G_END_DECLS

View File

@@ -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

View File

@@ -721,6 +721,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;
@@ -852,7 +865,7 @@ static const GskCurveClass GSK_QUAD_CURVE_CLASS = {
gsk_quad_curve_get_length_to,
};
/* }}} */
/* }}} */
/* {{{ Cubic */
static void
@@ -1853,7 +1866,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 +1921,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,

View File

@@ -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: */

View File

@@ -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,

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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__ */

View File

@@ -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.

View File

@@ -47,7 +47,6 @@ gsk_private_sources = files([
'gskdebug.c',
'gskprivate.c',
'gskprofiler.c',
'gskspline.c',
'gl/gskglattachmentstate.c',
'gl/gskglbuffer.c',
'gl/gskglcommandqueue.c',

View File

@@ -231,7 +231,7 @@ parse_compose_sequence (const char *seq,
char *start = words[i];
char *end = strchr (words[i], '>');
char *match;
gunichar codepoint;
guint keyval;
if (words[i][0] == '\0')
continue;
@@ -248,18 +248,24 @@ parse_compose_sequence (const char *seq,
if (is_codepoint (match))
{
codepoint = (gunichar) g_ascii_strtoll (match + 1, NULL, 16);
sequence[n] = codepoint;
keyval = gdk_unicode_to_keyval ((gunichar) g_ascii_strtoll (match + 1, NULL, 16));
if (keyval > 0xffff)
g_warning ("Can't handle >16bit keyvals");
sequence[n] = (guint16) keyval;
sequence[n + 1] = 0;
}
else
{
codepoint = (gunichar) gdk_keyval_from_name (match);
sequence[n] = codepoint;
keyval = gdk_keyval_from_name (match);
if (keyval > 0xffff)
g_warning ("Can't handle >16bit keyvals");
sequence[n] = (guint16) keyval;
sequence[n + 1] = 0;
}
if (codepoint == GDK_KEY_VoidSymbol)
if (keyval == GDK_KEY_VoidSymbol)
g_warning ("Could not get code point of keysym %s", match);
g_free (match);
n++;

View File

@@ -302,8 +302,8 @@ gtk_tooltip_set_icon_from_gicon (GtkTooltip *tooltip,
* Replaces the widget packed into the tooltip with
* @custom_widget. @custom_widget does not get destroyed when the tooltip goes
* away.
* By default a box with a `GtkImage` and `GtkLabel` is embedded in
* the tooltip, which can be configured using gtk_tooltip_set_markup()
* By default a box with a `GtkImage` and `GtkLabel` is embedded in
* the tooltip, which can be configured using gtk_tooltip_set_markup()
* and gtk_tooltip_set_icon().
*/
void
@@ -560,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);

View File

@@ -1,5 +1,5 @@
project('gtk', 'c',
version: '4.13.0',
version: '4.13.1',
default_options: [
'buildtype=debugoptimized',
'warning_level=1',

View File

@@ -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

View File

@@ -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
View File

@@ -34,8 +34,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gtk+ 2.8.2\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gtk/-/issues/\n"
"POT-Creation-Date: 2023-08-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 "Cant 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: Couldnt parse value for property '%s': %s\n"
msgstr "%s:%d: no s'ha pogut analitzar el valor per a la propietat «%s»: %s\n"
#: tools/gtk-builder-tool-simplify.c:658
#, c-format, 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 "Cant parse “%s”\n"
#~ msgstr "No es pot analitzar «%s»\n"

101
po/gl.po
View File

@@ -20,8 +20,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gtk+-master-po-gl-77922___.merged\n"
"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gtk/-/issues/\n"
"POT-Creation-Date: 2023-08-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"

View File

@@ -3,6 +3,6 @@ clip {
child: texture-scale {
bounds: 0 0 19991 19991;
filter: nearest;
texture: url('data:,<svg><rect width="10" height="10" style="fill:red" /></svg>');
texture: url('data:,<svg width="10" height="10" viewBox="0 0 10 10"><rect width="10" height="10" style="fill:red" /></svg>');
}
}

View File

@@ -7,5 +7,5 @@ color {
texture {
bounds: 10 10 30 30;
texture: url('data:,<svg><rect width="10" height="10" style="fill:red"/></svg>');
texture: url('data:,<svg width="10" height="10" viewBox="0 0 10 10"><rect width="10" height="10" style="fill:red"/></svg>');
}

View File

@@ -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

View File

@@ -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',
@@ -396,6 +398,7 @@ endforeach
internal_tests = [
[ 'curve' ],
[ 'curve-special-cases' ],
[ 'path-private' ],
[ 'diff' ],
[ 'half-float' ],
['rounded-rect'],

View File

@@ -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: "\

View File

@@ -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: "\

View File

@@ -0,0 +1,4 @@
fill {
path: "M 0 0 O 10 10 20 20 5";
fill-rule: even-odd;
}

View 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;
}

View 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;
}

View 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;
}

View File

@@ -1,22 +1,22 @@
texture-scale {
texture: url('data:,<svg><rect width="10" height="10" style="fill:red"/></svg>');
texture: url('data:,<svg width="10" height="10" viewBox="0 0 10 10"><rect width="10" height="10" style="fill:red"/></svg>');
bounds: 0 0 50 50;
}
texture-scale {
texture: url('data:,<svg><rect width="10" height="10" style="fill:red"/></svg>');
texture: url('data:,<svg width="10" height="10" viewBox="0 0 10 10"><rect width="10" height="10" style="fill:red"/></svg>');
bounds: 0 0 50 50;
filter: linear;
}
texture-scale {
texture: url('data:,<svg><rect width="10" height="10" style="fill:red"/></svg>');
texture: url('data:,<svg width="10" height="10" viewBox="0 0 10 10"><rect width="10" height="10" style="fill:red"/></svg>');
bounds: 0 0 50 50;
filter: nearest;
}
texture-scale {
texture: url('data:,<svg><rect width="10" height="10" style="fill:red"/></svg>');
texture: url('data:,<svg width="10" height="10" viewBox="0 0 10 10"><rect width="10" height="10" style="fill:red"/></svg>');
bounds: 0 0 50 50;
filter: trilinear;
}

View 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 ();
}

View File

@@ -301,7 +301,7 @@ test_empty_path (void)
g_assert_false (gsk_path_in_fill (path, &GRAPHENE_POINT_INIT (0, 0), GSK_FILL_RULE_WINDING));
g_assert_false (gsk_path_get_closest_point (path, &GRAPHENE_POINT_INIT (0, 0), INFINITY, &point));
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, &center);
g_assert_true (k == INFINITY);
g_assert_true (graphene_point_equal (&center, &GRAPHENE_POINT_INIT (1, 2)));
gsk_path_unref (path);
}
int
main (int argc, char *argv[])
{
@@ -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 ();
}

View File

@@ -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);

View File

@@ -2,3 +2,5 @@
<Multi_key> <s> <e> <q> <u> : "?"
<Multi_key> <z> <w> <i> <n> <e> <s> : "🥂"
<Multi_key> <l> <o> <n> <g> : "this is a long replacement string"
<q> : "qq"
<UFEF7> : "foobar"

View File

@@ -242,6 +242,26 @@ compose_table_match (void)
g_assert_true (match);
g_assert_cmpstr (output->str, ==, "this is a long replacement string");
g_string_set_size (output, 0);
buffer[0] = GDK_KEY_q;
buffer[1] = 0;
ret = gtk_compose_table_check (table, buffer, 1, &finish, &match, output);
g_assert_true (ret);
g_assert_false (finish);
g_assert_true (match);
g_assert_cmpstr (output->str, ==, "qq");
g_string_set_size (output, 0);
buffer[0] = 0x0100FEF7;
buffer[1] = 0;
ret = gtk_compose_table_check (table, buffer, 1, &finish, &match, output);
g_assert_true (ret);
g_assert_false (finish);
g_assert_true (match);
g_assert_cmpstr (output->str, ==, "foobar");
g_string_free (output, TRUE);
g_free (file);
}

View File

@@ -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,

View 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);
}
}

View 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);
}
}

View File

@@ -39,6 +39,8 @@ usage (void)
"\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"
@@ -130,6 +132,10 @@ main (int argc, const char *argv[])
do_info (&argc, &argv);
else if (strcmp (argv[0], "render") == 0)
do_render (&argc, &argv);
else if (strcmp (argv[0], "restrict") == 0)
do_restrict (&argc, &argv);
else if (strcmp (argv[0], "reverse") == 0)
do_reverse (&argc, &argv);
else if (strcmp (argv[0], "show") == 0)
do_show (&argc, &argv);
else

View File

@@ -2,6 +2,8 @@
void do_info (int *argc, const char ***argv);
void do_decompose (int *argc, const char ***argv);
void do_restrict (int *argc, const char ***argv);
void do_reverse (int *argc, const char ***argv);
void do_render (int *argc, const char ***argv);
void do_show (int *argc, const char ***argv);

View File

@@ -27,6 +27,8 @@ gtk_tools = [
'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]],