Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
/**
* Placement of the series legend relative to the plot area.
*
* <p>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.</p>
* <p>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.</p>
*
* @author Artem Demchyshyn
* @since 1.8.0
Expand All @@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
* Builder for {@link ShapeContainerNode}.
*
* <p>Reads as: <em>"container is a [shape], inside it I'm composing layers"</em>.
* 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.</p>
* 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.</p>
*
* @author Artem Demchyshyn
* @since 1.0.0
Expand Down Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
* <p>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.</p>
* <p>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.</p>
*
* <p>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()}.</p>
*
* @author Artem Demchyshyn
* @since 1.8.0
Expand Down
10 changes: 7 additions & 3 deletions src/main/java/com/demcha/compose/document/svg/SvgIcon.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,13 @@
* {@code <use>} references, nested {@code <svg>} viewBoxes (inner frames
* recurse but their coordinates stay in the outer space), animations, and
* the gradient corners that have no PDF analogue (focal points,
* {@code spreadMethod} other than pad, stop opacity). The XML reader
* refuses DOCTYPEs, so external-entity tricks cannot reach the file
* system.</p>
* {@code spreadMethod} other than pad, stop opacity). A gradient's
* {@code href} / {@code xlink:href} indirection inherits only the referenced
* {@code <stop>} list — not its geometry attributes ({@code x1}/{@code y1}/
* {@code x2}/{@code y2}, {@code cx}/{@code cy}/{@code r}, {@code gradientUnits},
* {@code gradientTransform}); keep the coordinates on the referencing gradient.
* The XML reader refuses DOCTYPEs, so external-entity tricks cannot reach the
* file system.</p>
*
* <pre>{@code
* SvgIcon logo = SvgIcon.read(Path.of("assets/logo.svg"));
Expand Down