You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: close clipPath/marker/use/visibility/miterlimit gaps
- <clipPath> now supports <g> and <use> children, including nested
combinations, with any transform/offset along the way baked directly
into the resulting path coordinates (new transformPathData in
geometry/path.ts). A <clipPath> that resolves to zero usable paths now
correctly clips away everything instead of drawing unclipped -- these
were previously silently skipped with no warning at all.
- marker-end on a closed subpath (path/polygon ending in Z) now lands at
the subpath's start point with a bisected angle, per spec, instead of
the last explicit point before Z. A single closed subpath now gets a
separate coincident marker-start and marker-end, not just one.
- <use> referencing a plain nested <svg> now gets the same width/height
override treatment as referencing a <symbol> (own x/y ignored, fallback
chain to 100% of the viewport).
- display="none" now drops an element's subtree entirely, including when
reached indirectly through <use>; visibility="hidden"/"collapse" now
skips drawing while still walking children (so a nested
visibility="visible" can turn itself back on), both previously
unhandled anywhere.
- stroke-miterlimit is now resolved and applied, defaulting to SVG's own
4 rather than leaving it to the PDF writer's default of 10 --
@libpdf/core already exposed the operator, it just wasn't wired up.
New fixtures: clip-path-use-and-group.svg, marker-closed-shape.svg,
use-nested-svg.svg, display-and-visibility.svg, stroke-miterlimit.svg.
Documented two resvg (visual-test reference renderer) rendering gaps
hit along the way -- <g> inside <clipPath> -- in svgEmbed.visual.test.ts
so they're recognized quickly if hit again, rather than mistaken for
svg-pdf regressions.
docs/supported-features.md updated to match: clipPath's remaining
caveat is now only unsupported content types (<text>/<image>), not
transform support.
Copy file name to clipboardExpand all lines: docs/supported-features.md
+3-1Lines changed: 3 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -59,11 +59,13 @@ Each item below notes _why_ it's limited, using four categories: a **PDF format
59
59
-**Patterns and markers with rotation**_(@libpdf/core limitation)_: if a `<pattern>` is reached through a rotated or skewed transform (its own `patternTransform`, or an ancestor `<g>` that's rotated/skewed), it's skipped with a warning instead of being drawn incorrectly. `@libpdf/core`'s tiling-pattern API can only position a repeating pattern using plain, non-rotated numbers — it has no way to hand it a rotation matrix.
60
60
-**Pattern and marker content is limited to solid colors**_(@libpdf/core limitation)_: the inside of a `<pattern>` or `<marker>` can only contain shapes with a plain solid fill/stroke — not another gradient, another pattern, text, or an image nested inside it. Anything like that is skipped individually with a warning. Both are built internally from a bare list of drawing operators with no resource dictionary of their own, so there's nowhere to register a nested font/image/gradient/pattern. (This only affects what's _inside_ the pattern/marker; a marker's overall placement — its rotation, scale, position — is unrestricted.)
61
61
-**Opacity inside a pattern/marker isn't honored**_(@libpdf/core limitation)_: `fill-opacity`/`stroke-opacity`/`opacity` used _inside_ a `<pattern>` or `<marker>`'s own content don't currently have any effect (drawn fully opaque instead, with a warning) — same root cause as above: no resource dictionary means no place to attach the transparency setting. Opacity on the _shape the pattern/marker is applied to_ works fine; this limitation is only about opacity used inside the pattern/marker's own artwork.
62
+
-**`<clipPath>` content is limited to shapes, `<g>`, and `<use>`**_(not yet implemented)_: plain shapes work directly; a `<g>` wrapping several shapes (to union them together) and a `<use>` reusing another shape's geometry both work too, including nested combinations of the two, with any `transform`/offset along the way applied correctly. Something else inside a `<clipPath>` (like `<text>` or `<image>`) is skipped with a warning instead of being drawn wrong. If every child of a `<clipPath>` ends up skipped this way, the clip region is empty and nothing draws at all (an empty clip region hides everything, per spec) rather than drawing unclipped.
62
63
-**`@font-face` only works when the font data is embedded directly**_(design choice)_ in the SVG (`src: url(data:...)`) — a `@font-face` pointing at an external URL instead is skipped with a warning, for the same safety reason external images aren't fetched automatically (see [Images](#images) above). Matching an SVG's requested `font-family`/`font-weight`/`font-style` against an available `@font-face` is a simple, case-insensitive text match, not the more flexible matching real browsers do.
63
64
-**Per-character positioning** (`dx`/`dy`/`rotate` with a list of values on `<text>`/`<tspan>`, letting you nudge or rotate individual characters instead of a whole line) is supported.
64
65
-**`word-spacing` may not visibly do anything with a custom embedded font**_(PDF format limitation)_ — this is a quirk of the PDF format itself, not something svg-pdf can work around: PDF's word-spacing feature only works with a certain kind of font encoding that standard fonts always use, but embedded custom fonts typically don't. `letter-spacing` isn't affected and works either way.
65
-
-**A link's clickable area is a rectangle**_(PDF format limitation)_ (a box around everything it wraps — shapes, text, images, even invisible ones), not an exact outline of the shape — so a link wrapped around a star icon gets a rectangular click target around the star. PDF link annotations are always rectangles; there's no way to give one an arbitrary outline, the same way most SVG-to-PDF tools handle it.
66
+
-**A link's clickable area is a rectangle**_(PDF format limitation)_ (a box around everything it wraps — shapes, text, images, even invisible ones), not an exact outline of the shape — so a link wrapped around a star icon gets a rectangular click target around the star. PDF link annotations are always rectangles; there's no way to give one an arbitrary outline, the same way most SVG to PDF tools handle it.
66
67
-**A link pointing at the same page (`href="#fragment"`) is skipped with a warning**_(design choice)_, since each SVG becomes one standalone PDF page with nothing else to jump to. PDF itself supports internal links between pages/destinations — this would need svg-pdf to support multiple pages or multiple linked SVGs first. Any other kind of link (an external URL, `mailto:`, `tel:`, etc.) is used as-is.
68
+
-**An `<image>` whose data is itself an SVG (a `data:image/svg+xml...` URI, or an `.svg` file fetched via `fetchImage`) isn't drawn as crisp vector content**_(not yet implemented)_: svg-pdf always treats `<image>` bytes as a raster picture to embed, never as a nested SVG document to render. In Node this SVG-as-image case fails to decode and is skipped with a warning (there's no `OffscreenCanvas` to rasterize it with either); this is a real but comparatively uncommon pattern next to plain PNG/JPEG image data.
67
69
-**Text-along-a-path (`<textPath>`)**_(not yet implemented, for what's left)_: each character is individually positioned and rotated to follow the path's curve, starting at a given offset (`startOffset`, as a plain number or a percentage) along the path, respecting the path's own `pathLength` if it has one, and shifted by `text-anchor` the same way regular text is. It always uses a standard font rather than a custom one from `fetchFont`/`@font-face`. Two things aren't supported yet:
68
70
-`textLength` (stretching/compressing the text to fit an exact length) works in its default mode, which only adjusts the spacing _between_ characters. `lengthAdjust="spacingAndGlyphs"`, which would also resize the characters themselves, isn't supported — it falls back to spacing-only with a warning.
69
71
- Nesting a `<tspan>` inside a `<textPath>` isn't supported — its children are skipped with a warning, and only the `<textPath>`'s own direct text is used.
0 commit comments