Skip to content

feat(svg): SvgIcon whole-file reader + addSvgIcon DSL stacking#173

Merged
DemchaAV merged 5 commits into
developfrom
feat/svg-icon-reader
Jun 12, 2026
Merged

feat(svg): SvgIcon whole-file reader + addSvgIcon DSL stacking#173
DemchaAV merged 5 commits into
developfrom
feat/svg-icon-reader

Conversation

@DemchaAV

Copy link
Copy Markdown
Owner

What

Stacked on #172 (uses SvgPath + a package-private parseTransformed affine hook). Whole SVG files now drop into documents:

SvgIcon logo = SvgIcon.read(Path.of("logo.svg"));
flow.addSvgIcon(logo, 48);   // layers stack back-to-front, native curves
  • Subset reader (icons, not a browser): every <path> + rect/circle/ellipse/line/polyline/polygon lowered to synthesized path data through the one tested parser; <g> nesting with translate/scale/rotate/matrix accumulated as exact affines (affine maps are exact on Bézier control points); fill/stroke/stroke-width with SVG inheritance and defaults (missing fill = black, none skips, style="" wins over inherited).
  • addSvgIcon(icon, width) on every flow builder — ordered layers through LayerStack, height from the icon's aspect ratio.
  • Security: the XML reader refuses DOCTYPEs — XXE cannot reach the file system (tested).
  • Deliberately out of scope: gradients, CSS stylesheets, text, masks, filters, <use>.

Verification

  • 11 SvgIconTest cases: layer order/paints, black-fill default + none, shape lowering (circle → arc cubics), exact translate·scale and rotate(90° about center) coordinates, inheritance + style precedence, width/height fallback, DOCTYPE refusal, four context-carrying error contracts, DSL bridge end-to-end.
  • Example gains a two-tone badge (tinted disc behind the Material heart) — regenerated preview eyeballed: layer order correct, single page.
  • API hygiene green; full gate ./mvnw verify -pl .1287 tests, 0 failures, BUILD SUCCESS.

Merge order

Stacked: merge #172 first (without deleting its branch), retarget this PR to develop, then merge.

SvgIcon.read(file)/parse(xml) reads the practical icon subset of an SVG document: every path plus rect/circle/ellipse/line/polyline/polygon lowered to synthesized path data through the one tested parser, g-nesting with translate/scale/rotate/matrix transforms accumulated as exact affines on Bezier control points (via a package-private SvgPath.parseTransformed hook), and fill/stroke/stroke-width styling with SVG inheritance and defaults (missing fill = black, none skips, style attribute wins). addSvgIcon(icon, width) stacks the ordered layers back-to-front through LayerStack. Security: DOCTYPE refused (XXE cannot reach the file system). Out of scope by design: gradients, CSS, text, filters. 11 SvgIconTest cases incl. exact transform math, inheritance, XXE refusal and the DSL bridge; example ships a two-tone badge via SvgIcon.parse. Full gate: see below.
}
String widthAttr = attrOrStyle(element, "stroke-width");
if (widthAttr != null) {
strokeWidth = Double.parseDouble(widthAttr.replace("px", "").trim());

private static double num(Element element, String attribute) {
String value = element.getAttribute(attribute).trim();
return value.isEmpty() ? 0.0 : Double.parseDouble(value);
@DemchaAV DemchaAV merged commit 6040f37 into develop Jun 12, 2026
11 checks passed
@DemchaAV DemchaAV deleted the feat/svg-icon-reader branch June 12, 2026 14:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants