diff --git a/docs/reference/gsk/gsk4.toml.in b/docs/reference/gsk/gsk4.toml.in
index 4410439a04..e56a5b2ffc 100644
--- a/docs/reference/gsk/gsk4.toml.in
+++ b/docs/reference/gsk/gsk4.toml.in
@@ -32,6 +32,9 @@ show_class_hierarchy = true
base_url = "https://gitlab.gnome.org/GNOME/gtk/-/blob/main/"
[extra]
+content_files = [
+ "paths.md",
+]
content_images = [
"gtk-logo.svg",
"images/caps-dark.png",
@@ -40,13 +43,17 @@ content_images = [
"images/cubic-light.png",
"images/directions-dark.png",
"images/directions-light.png",
+ "images/fill-even-odd.png",
+ "images/fill-winding.png",
"images/join-dark.png",
"images/join-light.png",
"images/line-dark.png",
"images/line-light.png",
- "images/quad-dark.png",
- "images/quad-light.png",
"images/path-dark.png",
"images/path-light.png",
+ "images/quad-dark.png",
+ "images/quad-light.png",
+ "images/stroke-miter.png",
+ "images/stroke-round.png",
]
urlmap_file = "urlmap.js"
diff --git a/docs/reference/gsk/images/fill-even-odd.png b/docs/reference/gsk/images/fill-even-odd.png
new file mode 100644
index 0000000000..a6518e6a2f
Binary files /dev/null and b/docs/reference/gsk/images/fill-even-odd.png differ
diff --git a/docs/reference/gsk/images/fill-winding.png b/docs/reference/gsk/images/fill-winding.png
new file mode 100644
index 0000000000..02c2f1dbbe
Binary files /dev/null and b/docs/reference/gsk/images/fill-winding.png differ
diff --git a/docs/reference/gsk/images/stroke-miter.png b/docs/reference/gsk/images/stroke-miter.png
new file mode 100644
index 0000000000..eaf9f0df7f
Binary files /dev/null and b/docs/reference/gsk/images/stroke-miter.png differ
diff --git a/docs/reference/gsk/images/stroke-round.png b/docs/reference/gsk/images/stroke-round.png
new file mode 100644
index 0000000000..df2d3d7dba
Binary files /dev/null and b/docs/reference/gsk/images/stroke-round.png differ
diff --git a/docs/reference/gsk/meson.build b/docs/reference/gsk/meson.build
index bf3c437077..6b8fa76b1f 100644
--- a/docs/reference/gsk/meson.build
+++ b/docs/reference/gsk/meson.build
@@ -1,3 +1,7 @@
+gsk_expand_content_md_files = [
+ 'paths.md',
+]
+
if get_option('documentation')
gsk4_toml = configure_file(
input: 'gsk4.toml.in',
@@ -21,7 +25,7 @@ if get_option('documentation')
'@INPUT1@',
],
depends: [ gdk_gir[0] ],
- depend_files: [ expand_content_md_files ],
+ depend_files: [ gsk_expand_content_md_files ],
build_by_default: true,
install: true,
install_dir: docs_dir,
diff --git a/docs/reference/gsk/paths.md b/docs/reference/gsk/paths.md
new file mode 100644
index 0000000000..8de93f6fa4
--- /dev/null
+++ b/docs/reference/gsk/paths.md
@@ -0,0 +1,111 @@
+Title: Paths
+Slug: paths
+
+GSK provides a path object that can be used to render more complex
+shapes than lines or rounded rectangles. It is comparable to cairos
+[path API](https://www.cairographics.org/manual/cairo-Paths.html),
+with some notable differences.
+
+In general, a path consists of one or more connected **_contours_**,
+each of which may have multiple **_segments_**, and may or may not be closed.
+
+
+
+
+
+
+ A path with one closed, and one open contour
+
+
+The central object of the GSK path api is the immutable [struct@Gsk.Path]
+struct, which contains path data in compact form suitable for rendering.
+
+## Creating Paths
+
+Since `GskPath` is immutable, the auxiliary [struct@Gsk.PathBuilder] struct
+can be used to construct a path piece by piece. The `GskPathBuilder` API
+has three distinct groups of functions:
+
+- Functions for adding complete contours, such as [method@Gsk.PathBuilder.add_rect],
+ [method@Gsk.PathBuilder.add_rounded_rect], [method@Gsk.PathBuilder.add_circle].
+
+- Functions for building contours from individual segments, like [method@Gsk.PathBuilder.move_to],
+ [method@Gsk.PathBuilder.line_to], [method@Gsk.PathBuilder.cubic_to], [method@Gsk.PathBuilder.close].
+
+- Adding parts of a preexisting path. Functions in this group include
+ [method@Gsk.PathBuilder.add_path] and [method@Gsk.PathBuilder.add_segment].
+
+When you are done with building a path, you can convert the accumulated path
+data into a `GskPath` struct with [method@Gsk.PathBuilder.free_to_path].
+
+A sometimes convenient alternative is to create a path from a serialized
+form, with [func@Gsk.Path.parse]. This function interprets strings
+in SVG path syntax, such as:
+
+ M 100 100 C 100 200 200 200 200 100 Z
+
+## Rendering with Paths
+
+There are two main ways to render with paths. The first is to **_fill_** the
+interior of a path with a color or more complex content, such as a gradient.
+GSK currently supports two different ways of determining what part of the plane
+are interior to the path, which can be selected with a [enum@Gsk.FillRule]
+value.
+
+
+
+
+
+ A path filled with GSK_FILL_RULE_WINDING
+
+
+
+
+
+
+ The same path, filled with GSK_FILL_RULE_EVEN_ODD
+
+
+Alternatively, a path can be **_stroked_**, which means to emulate drawing
+with an idealized pen along the path. The result of stroking a path is another
+path (the **_stroke path_**), which is then filled.
+
+The stroke operation can be influenced with the [struct@Gsk.Stroke] struct
+that collects various stroke parameters, such as the line width, the style
+of line joins and line caps to use, and a dash pattern.
+
+
+
+
+
+ The same path, stroked with GSK_LINE_JOIN_MITER
+
+
+
+
+
+
+ The same path, stroked with GSK_LINE_JOIN_ROUND
+
+
+GSK provides render nodes for these path rendering operations: [class@Gsk.FillNode]
+and [class@Gsk.StrokeNode], and GTK has convenience API to use them with
+[class@Gtk.Snapshot].
+
+## Other Path APIs
+
+Beyond rendering, paths can be used e.g. as trajectories in animations.
+In such uses, it is often important to access properties of paths, such as
+their tangents at certain points. GSK provides an abstract representation
+for points on a path in the form of the [struct@Gsk.PathPoint] struct.
+You can query properties of a path at certain point once you have a
+`GskPathPoint` representing that point.
+
+`GskPathPoint` structs can be compared for equality with [method@Gsk.PathPoint.equal]
+and ordered wrt. to which one comes first, using [method@Gsk.PathPoint.compare].
+
+To obtain a `GskPathPoint`, use [method@Gsk.Path.get_closest_point], [method@Gsk.Path.get_start_point] or [method@Gsk.Path.get_end_point].
+
+To query properties of the path at a point, use [method@Gsk.PathPoint.get_position],
+[method@Gsk.PathPoint.get_tangent], [method@Gsk.PathPoint.get_rotation] and
+[method@Gsk.PathPoint.get_curvature].
diff --git a/gsk/gskcontour.c b/gsk/gskcontour.c
index 47e5786eea..90693f9429 100644
--- a/gsk/gskcontour.c
+++ b/gsk/gskcontour.c
@@ -319,7 +319,7 @@ gsk_standard_contour_get_stroke_bounds (const GskContour *contour,
if (self->n_points == 0)
return FALSE;
- extra = MAX (stroke->line_width / 2, gsk_stroke_get_join_width (stroke) / 2);
+ extra = MAX (stroke->line_width, gsk_stroke_get_join_width (stroke));
gsk_bounding_box_init (bounds, &GRAPHENE_POINT_INIT (self->bounds.min.x - extra,
self->bounds.min.y - extra),