feat(svg): gradient paints end-to-end — fills and strokes as native PDF shadings#179
Merged
Conversation
…es as native PDF shadings - DocumentPaint gains endpoint-exact LinearAxis and RadialCircle forms - PathNode/PathBuilder grow fill(paint) + strokePaint(paint); solid paints normalise to the flat-colour path (byte-identical non-gradient output) - gradient fills clip to the path and emit axial/radial shadings; gradient strokes ride a shading-pattern stroking colour (inlined subtree - nested dicts would dangle as null indirect refs after save) - SvgIconReader resolves url(#id) gradients: userSpaceOnUse and objectBoundingBox units, gradientTransform, percent offsets, multi-stop, one href hop; loud failures for focal/spreadMethod/stop-opacity - SvgIcon#node(width) node form; addSvgIcon delegates; rows accept ShapeContainerNode (same atomic overlay composite as LayerStackNode) - examples simplified onto icon.node(); vector-path gains a gradient block
| return userSpace ? defaultFraction * viewportSize : defaultFraction; | ||
| } | ||
| if (v.endsWith("%")) { | ||
| double fraction = Double.parseDouble(v.substring(0, v.length() - 1)) / 100.0; |
| double fraction = Double.parseDouble(v.substring(0, v.length() - 1)) / 100.0; | ||
| return userSpace ? fraction * viewportSize : fraction; | ||
| } | ||
| return Double.parseDouble(v); |
| return userSpace ? defaultFraction * diagonal : defaultFraction; | ||
| } | ||
| if (v.endsWith("%")) { | ||
| double fraction = Double.parseDouble(v.substring(0, v.length() - 1)) / 100.0; |
| double fraction = Double.parseDouble(v.substring(0, v.length() - 1)) / 100.0; | ||
| return userSpace ? fraction * diagonal : fraction; | ||
| } | ||
| return Double.parseDouble(v); |
| } | ||
| String v = value.trim(); | ||
| if (v.endsWith("%")) { | ||
| return Double.parseDouble(v.substring(0, v.length() - 1)) / 100.0; |
| if (v.endsWith("%")) { | ||
| return Double.parseDouble(v.substring(0, v.length() - 1)) / 100.0; | ||
| } | ||
| return Double.parseDouble(v); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
the SVG surface (beta) now renders
linearGradient/radialGradientnatively, on fills and strokes — all four GraphCompose brand logos parse and render 1:1.Engine
DocumentPaint.LinearAxis/RadialCircle— endpoint-exact gradient forms (the angle/farthest-corner forms can't carry SVG's explicit extents).PathNode+PathBuilder:fill(paint)/strokePaint(paint); solid paints normalise to the flat-colour path inPathDefinition(mirrorsShapeDefinition), so non-gradient documents stay byte-identical (guarded by test)./PatternCS, type 2). Found and fixed a PDFBox serialization trap: nested shading/function dicts get promoted to indirect objects the writer never emits —inlineDeeppins the freshly built subtree direct (test asserts the colour function survives reload).Reader
url(#id)on fill/stroke with SVG inheritance;userSpaceOnUse(through the element's accumulated affine — matches browsers) andobjectBoundingBox(through the shape's bbox) units;gradientTransform; % offsets; multi-stop; onehrefhop (Inkscape/Figma split definitions). NewSvgGradients(file-size rule).spreadMethod,stop-opacity, focal radials.Ergonomics (from the «костыль» review)
SvgIcon#node(width)— node form with a tight box for layer anchors;addSvgIcondelegates; the triplicated stack-building loop in examples is gone.ShapeContainerNodedirectly (same atomic overlay composite as the already-allowedLayerStackNode) — the wrap-in-section ceremony is gone from gallery + catalog.Verification: 1301 tests, BUILD SUCCESS (+14 new: axis mapping incl. y-flip, bbox units, href, gradientTransform, radial, error matrix, pattern+function survival, mini-mark e2e). All four
assets/*.svgbrand logos render correctly (gradient G-outline, gradient dots, wordmarks) — proof render attached to the thread.Stacked on #177; merge after it in the queue.