From 368208b1f6a713c5296d5b0bcc8a651c3b83a9ce Mon Sep 17 00:00:00 2001
From: DemchaAV
Date: Sun, 14 Jun 2026 14:23:00 +0100
Subject: [PATCH] docs(api): correct stale Javadoc on the 1.8 surface
- LegendPosition: drop the stale "reserved and rejected by validation"
wording; RIGHT/TOP are laid out for every chart kind.
- DocumentPaint: document why the Linear/Radial (angle/corner) and
LinearAxis/RadialCircle (exact endpoint/radius) forms coexist.
- ShapeContainerBuilder: the missing-outline error and class Javadoc now
name the full set of outline setters, including path(...).
- PathBuilder.dashed(double...): document the IllegalArgumentException it
throws eagerly.
- SvgIcon: document that a gradient href inherits stops only, not geometry.
- CHANGELOG: sealed-permit binary-compat note on ShapeOutline.Path plus a
Documentation entry.
No behaviour change.
---
CHANGELOG.md | 15 ++++++++++++++-
.../compose/document/chart/LegendPosition.java | 12 ++++++------
.../demcha/compose/document/dsl/PathBuilder.java | 7 ++++++-
.../document/dsl/ShapeContainerBuilder.java | 16 +++++++++-------
.../compose/document/style/DocumentPaint.java | 16 ++++++++++++----
.../com/demcha/compose/document/svg/SvgIcon.java | 10 +++++++---
6 files changed, 54 insertions(+), 22 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 495e2602e..6efbb6ad9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -90,7 +90,10 @@ Entries land here as they merge.
mask under `ClipPolicy.CLIP_PATH`. The outline rides the existing
vector-path fragment pipeline (one source of truth for native curves) and
the clip handler emits the same `addPathSegments` geometry, so fill, clip,
- and `addPath(...)` all agree.
+ and `addPath(...)` all agree. The new `Path` permit is additive and keeps
+ the artifact binary-compatible (the `japicmp` gate stays green); only
+ consumer code that exhaustively `switch`es over `ShapeOutline` would need a
+ new branch, and the canonical authoring surface exposes no such switch.
- **SVG path import** (`@since 1.8.0`, **beta** — annotated `@Beta` while
the surface hardens against real-world exporter output). `SvgPath.parse(d)` /
`parse(d, viewBox...)` in the new `document.svg` package lowers the full
@@ -271,6 +274,16 @@ Entries land here as they merge.
### Documentation
+- **Contract-drift Javadoc fixes on the new 1.8 surface.** `LegendPosition`
+ no longer claims `RIGHT`/`TOP` are "reserved and rejected by validation" —
+ all four placements are laid out for every chart kind, as the resolver and
+ its tests already prove. `DocumentPaint` documents why the `Linear`/`Radial`
+ (angle/corner-reaching) and `LinearAxis`/`RadialCircle` (exact endpoint/radius)
+ forms coexist. `ShapeContainerBuilder`'s missing-outline error and class
+ Javadoc now name the full set of outline setters (including `path`).
+ `PathBuilder.dashed(double...)` documents the `IllegalArgumentException` it
+ throws eagerly, and `SvgIcon` documents that a gradient `href` inherits stops
+ only, not geometry attributes.
- **Browsable feature-catalog PDF.** New flagship `FeatureCatalogExample`
renders every shipped capability as a self-documenting block: the heading
lands in the PDF outline (the bookmarks panel works as a clickable index),
diff --git a/src/main/java/com/demcha/compose/document/chart/LegendPosition.java b/src/main/java/com/demcha/compose/document/chart/LegendPosition.java
index f1d1e6f8f..dae0e0807 100644
--- a/src/main/java/com/demcha/compose/document/chart/LegendPosition.java
+++ b/src/main/java/com/demcha/compose/document/chart/LegendPosition.java
@@ -3,10 +3,10 @@
/**
* Placement of the series legend relative to the plot area.
*
- *
v1 of the geometry resolver supports {@link #NONE} and {@link #BOTTOM}; the
- * remaining placements are reserved and rejected by validation until the
- * corresponding layout lands. Adding resolver support for a reserved constant is
- * an additive, non-breaking change.
+ *
All four placements are laid out by the geometry resolver for every chart
+ * kind, including pie: {@link #NONE}, {@link #BOTTOM} (a row below the plot),
+ * {@link #TOP} (a row above), and {@link #RIGHT} (a column beside it). The
+ * resolver reserves the corresponding gutter and packs the entries to fit.
*
* @author Artem Demchyshyn
* @since 1.8.0
@@ -21,11 +21,11 @@ public enum LegendPosition {
*/
BOTTOM,
/**
- * Reserved — legend column to the right of the plot area.
+ * Legend column to the right of the plot area.
*/
RIGHT,
/**
- * Reserved — single legend row above the plot area.
+ * Single legend row above the plot area.
*/
TOP
}
diff --git a/src/main/java/com/demcha/compose/document/dsl/PathBuilder.java b/src/main/java/com/demcha/compose/document/dsl/PathBuilder.java
index 1183e85d7..5140620b7 100644
--- a/src/main/java/com/demcha/compose/document/dsl/PathBuilder.java
+++ b/src/main/java/com/demcha/compose/document/dsl/PathBuilder.java
@@ -241,10 +241,15 @@ public PathBuilder strokePaint(DocumentPaint strokePaint) {
/**
* Makes the stroke dashed using alternating on/off lengths in points
* (the same contract as {@code LineBuilder.dashed}). Affects only the
- * stroke; fills are unaffected.
+ * stroke; fills are unaffected. Validates eagerly: an empty or
+ * non-finite/non-positive pattern is rejected at this call, not at
+ * {@link #build()}.
*
* @param pattern alternating on/off lengths in points
* @return this builder
+ * @throws IllegalArgumentException if no segments are supplied or any
+ * segment is not finite and strictly
+ * positive
*/
public PathBuilder dashed(double... pattern) {
this.dashPattern = DocumentDashPattern.of(pattern);
diff --git a/src/main/java/com/demcha/compose/document/dsl/ShapeContainerBuilder.java b/src/main/java/com/demcha/compose/document/dsl/ShapeContainerBuilder.java
index 3d4b25b05..f071b551c 100644
--- a/src/main/java/com/demcha/compose/document/dsl/ShapeContainerBuilder.java
+++ b/src/main/java/com/demcha/compose/document/dsl/ShapeContainerBuilder.java
@@ -15,11 +15,13 @@
* Builder for {@link ShapeContainerNode}.
*
*
Reads as: "container is a [shape], inside it I'm composing layers".
- * The outline is mandatory — call {@link #rectangle(double, double)},
- * {@link #roundedRect(double, double, double)}, {@link #ellipse(double, double)},
- * or {@link #circle(double)} before {@link #build()}. Layers are appended in
- * source order (first behind, last in front) and each layer carries one of the
- * nine {@link LayerAlign} anchors plus optional on-screen offset.
+ * The outline is mandatory — call one of the outline setters
+ * ({@link #rectangle(double, double)}, {@link #roundedRect(double, double, double)},
+ * {@link #ellipse(double, double)}, {@link #circle(double)}, a polygon factory,
+ * or {@link #path(double, double, java.util.List)}) before {@link #build()}.
+ * Layers are appended in source order (first behind, last in front) and each
+ * layer carries one of the nine {@link LayerAlign} anchors plus optional
+ * on-screen offset.
*
* @author Artem Demchyshyn
* @since 1.0.0
@@ -541,8 +543,8 @@ public ShapeContainerBuilder bottomRight(DocumentNode node) {
public ShapeContainerNode build() {
if (outline == null) {
throw new IllegalStateException(
- "ShapeContainerBuilder '" + name + "' requires an outline; "
- + "call rectangle/roundedRect/ellipse/circle before build().");
+ "ShapeContainerBuilder '" + name + "' requires an outline; call an outline "
+ + "setter (rectangle/roundedRect/ellipse/circle/polygon/path/...) before build().");
}
return new ShapeContainerNode(name, outline, layers, clipPolicy, fillColor, stroke, padding, margin, transform);
}
diff --git a/src/main/java/com/demcha/compose/document/style/DocumentPaint.java b/src/main/java/com/demcha/compose/document/style/DocumentPaint.java
index 23a57a86d..1810f2eb0 100644
--- a/src/main/java/com/demcha/compose/document/style/DocumentPaint.java
+++ b/src/main/java/com/demcha/compose/document/style/DocumentPaint.java
@@ -9,10 +9,18 @@
* single paint vocabulary every fillable surface shares — chart palettes
* today, shape and panel fills as they adopt the {@code fillPaint} component.
*
- *
Backend contract: the PDF backend renders {@link Linear} and
- * {@link Radial} as native axial / radial shadings; a backend (or surface)
- * that cannot paint a gradient degrades to {@link #primaryColor()} — the
- * first stop — so authoring code never branches per backend.
+ *
Backend contract: the PDF backend renders all gradient forms as native
+ * axial / radial shadings; a backend (or surface) that cannot paint a gradient
+ * degrades to {@link #primaryColor()} — the first stop — so authoring code
+ * never branches per backend.
+ *
+ *
Two ways to spell each gradient coexist by design, not by redundancy.
+ * {@link Linear} / {@link Radial} take an ergonomic angle / corner-reaching
+ * geometry and are the chart- and shape-authoring forms; {@link LinearAxis} /
+ * {@link RadialCircle} take exact endpoints / a radius in the unit box and are
+ * the forms the SVG reader emits to reproduce a source gradient verbatim. All
+ * four render through the same shading machinery and degrade to the same
+ * {@link #primaryColor()}.