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 multiple contours + +
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 filled path + +
A path filled with GSK_FILL_RULE_WINDING
+
+ +
+ + A filled path + +
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. + +
+ + A stroked path + +
The same path, stroked with GSK_LINE_JOIN_MITER
+
+ +
+ + A stroked path + +
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),