Supported SVG Features
PeachPDF renders SVG — inline <svg> elements in HTML, standalone SVG (<img src="x.svg"> / data:image/svg+xml), and SVG used as a CSS background-image/list-style-image url() source — as real vector PDF content. Shapes become native PDF path-construction operators, gradients become native PDF shadings, and clips/masks/patterns become native PDF constructs. SVG stays vector except for one deliberate case: a <filter> that uses a primitive PDF has no operator for (a blur, lighting, morphology, and so on — see Filters) is evaluated over pixels and embedded as a bitmap at the document’s raster resolution. Everything else preserves scalability and keeps the PDF’s file size small regardless of the output resolution. This page documents exactly what is and is not supported. Where a feature is only partially supported, the specific gaps are noted.
SVG Root & Document Structure
| Element | MDN Reference | Notes |
|---|---|---|
svg |
svg | Inline (<svg> inside HTML), standalone (<img src="x.svg">, data:image/svg+xml), and as a CSS background-image/list-style-image url() source are all supported — see HTML & CSS Support for the CSS-side details. viewBox, width, height, and preserveAspectRatio are all honored. A nested <svg> establishes its own viewport, coordinate system, and clip |
g |
g | Full support, including presentation-attribute inheritance |
defs |
defs | Content is never painted directly, only through a reference (<use>, fill="url(#id)", clip-path, mask, marker properties) |
symbol |
symbol | Never painted directly; establishes its own viewport (viewBox/preserveAspectRatio) only when referenced via <use>, sized by the <use> element’s width/height (defaulting to the current viewport’s size, per spec) |
use |
use | Resolves href/xlink:href references, including to symbol, nested svg, and ordinary shapes. x/y offset and (for symbol/nested-svg targets) width/height overrides are supported. The <use> element’s own resolved paint becomes the inherited default for an otherwise-unstyled target. A reference cycle is guarded against (max depth 8) |
switch |
switch | Renders only the first buildable child. PeachPDF has no requiredFeatures/requiredExtensions/systemLanguage conditional-support axis to evaluate, so this is equivalent to every other candidate always failing its (nonexistent) test — a deliberate v1 simplification |
a |
a | Groups children like <g>, and additionally becomes a real PDF link annotation (same-page #id fragments become /GoTo links, other href values become /URI links) covering the transformed content’s bounding box. A rotated/skewed anchor’s link region is approximated by its axis-aligned bounding box, since PDF link annotations are themselves always axis-aligned rectangles |
Shapes
| Element | MDN Reference | Notes |
|---|---|---|
path |
path | Full support for the d attribute grammar: move/line/cubic-bezier/quadratic-bezier/elliptical-arc, absolute and relative, including all shorthand/smooth variants |
rect |
rect | Full support, including independently-rounded corners via rx/ry (each defaults to the other when only one is specified, per spec) |
circle |
circle | Full support |
ellipse |
ellipse | Full support |
line |
line | Full support. Per spec, fill never applies to a <line> (it has no interior) — no fill operator is emitted regardless of the element’s fill paint |
polyline |
polyline | Stroke never closes back to the first point, matching spec, while the fill is painted over the shape closed back to the first point (the spec’s implicit closing segment, for fill purposes only) |
polygon |
polygon | Full support |
Painting: Fill, Stroke, Color
| Feature | MDN Reference | Notes |
|---|---|---|
fill |
fill | Solid colors (named, hex, rgb()), gradient references (url(#id)), pattern references (url(#id)), none, currentColor, and the SVG 2 context-fill / context-stroke keywords (see Context paint) |
visibility |
visibility | visible, hidden and collapse (treated as hidden), inherited. A hidden shape, text or image is not painted but still counts for bounding boxes, clip paths and text layout, and a descendant can set visible again |
fill-rule |
fill-rule | nonzero and evenodd, inherited |
fill-opacity |
fill-opacity | Full support, inherited, independent of opacity and stroke-opacity |
stroke |
stroke | Solid colors and gradient references paint a real stroke (including a real gradient-filled stroke, not an approximation). Pattern-filled strokes are not supported — see Unsupported SVG Features |
stroke-width |
stroke-width | Full support, inherited; a bare number (stroke-width: 6, in user units) or a length from a stylesheet as well as an attribute, a negative width is refused |
stroke-opacity |
stroke-opacity | Full support, inherited |
stroke-linecap |
stroke-linecap | butt, round, square, inherited |
stroke-linejoin |
stroke-linejoin | miter, round, bevel, inherited |
stroke-miterlimit |
stroke-miterlimit | Full support, inherited |
stroke-dasharray |
stroke-dasharray | Full support, inherited. A comma-separated list (2px, 4px) is accepted in a stylesheet or keyframe as well as in the attribute; a bare number is taken as user units |
stroke-dashoffset |
stroke-dashoffset | Full support, inherited; a bare number (stroke-dashoffset: 7) or a length from a stylesheet as well as an attribute |
opacity |
opacity | Not inherited as a property — it composites instead, per spec. On a leaf shape (no children), applied as a simple alpha multiply on the shape’s own fill/stroke/text color. On a container (<g>, <a>, nested <svg>, or a <use> referencing one (directly, or through further <use> aliases) — including a container whose only content is <text> or <image>) it’s rendered as a genuine, isolated PDF transparency group — the container’s children are painted into an offscreen Form XObject and flattened, then that single flattened result is composited once at the container’s own opacity, so overlapping children never double-blend where they overlap. |
currentColor |
currentColor | Resolves to the CSS color property of the inline <svg>’s HTML ancestor; for standalone SVG (no CSS context), resolves to black |
color-interpolation-filters |
color-interpolation-filters | Honoured on a <filter> and its primitives when the filter is evaluated over pixels (see Filters); a vector-only filter always computes in sRGB. |
color-interpolation |
color-interpolation | Honoured on a <linearGradient>/<radialGradient> (own value, else the nearest ancestor’s; auto is sRGB): linearRGB blends the stops in linear light, by sampling extra stops between each pair, so a black-to-white gradient is visibly lighter at its midpoint than the sRGB default. Honoured on a <mask> too: linearRGB takes the mask’s luminance from its content’s colors converted to linear light, so mid-gray content is more transparent than under the sRGB default. The conversion applies to solid fills/strokes and gradient stops in the mask content; a pattern or raster <image> inside a mask keeps its sRGB values |
icc-color() / <color-profile> |
color | A <color> icc-color(name, c1, ...) in fill, stroke, stop-color, flood-color or lighting-color is converted to sRGB through the <color-profile name="..." href="..."> of that name (a data: URI or a fetched resource; rendering-intent honoured). Gray, RGB and CMYK profiles work, with components in 0..1. When the profile is missing, cannot be parsed, or the component count does not fit, the sRGB color written before the icc-color() is used, as the specification prescribes. The CSS @color-profile rule and the color-profile property are not supported |
Context paint
context-fill and context-stroke (SVG 2) are values of fill and stroke that stand for the fill and stroke of the context element:
<use>is the context element of what it instantiates, so one shape can be reused with a different fill and stroke per use: the shape saysfill="context-fill" stroke="context-stroke"and each<use>gives them. A nested<use>changes the context for its own content; a keyword written on the<use>itself refers to the context outside it.fill="context-stroke"(a fill taking the stroke) is valid.- A marker draws with the fill and stroke of the shape it is placed on, for every instance separately — including a
<text>inside the marker, and a shape’sFillPaint/StrokePaintfilter input. - Elsewhere there is no context element and the keywords paint nothing, unless the document was built for something that supplies one: the SVG document of an OpenType SVG glyph is drawn for text, so
context-fillis the text’s fill (its colour) andcontext-strokeits stroke, which is none because PeachPDF’s text has no stroke paint.
Gradients and patterns pass through <use> and through a marker, each keeping the context element’s own coordinate space and bounding box: a gradient or pattern on the shape a marker is drawn on is mapped through the marker’s placement (its position, rotation and scale) so it lines up with the shape as if the marker were not there, and a gradient or pattern through <use> is measured against the box of what the <use> instantiates, mapped through any transform between that element and the shape actually painting it. This holds whether the <use> targets a shape, a <g>, a <symbol>, or a nested <svg> — for the latter two, the box is that target’s own established viewport content, mapped the same way viewBox/preserveAspectRatio map it when actually painted.
Gradients
| Element | MDN Reference | Notes |
|---|---|---|
linearGradient |
linearGradient | x1/y1/x2/y2, gradientUnits (objectBoundingBox — the spec default — and userSpaceOnUse, both fully resolved against the referencing shape’s bounding box or the user-space coordinate system respectively), gradientTransform (translate/scale; a rotated/skewed gradientTransform on a radial gradient can’t turn the circle into a rotated ellipse — see below), spreadMethod |
radialGradient |
radialGradient | cx/cy/r, plus focal point fx/fy (independent of the center, per spec), same gradientUnits/gradientTransform/spreadMethod support as linearGradient. A rotated or skewed gradientTransform renders as a true rotated ellipse |
stop |
stop | offset, stop-color, stop-opacity (as presentation attributes, via style=, and from a <style> rule or the document’s stylesheet, which beats the attribute; currentcolor is the colour of the host element) |
spreadMethod |
spreadMethod | pad, reflect, repeat. reflect/repeat are implemented by tiling the gradient’s own stop list across an axis (or radius) extended to cover the filled shape’s bounding box — mirroring alternate cycles for reflect so adjacent cycles share a color with no seam — capped at 500 tiled cycles as a safety guard against pathological short-axis/large-shape combinations |
Gradients render as native PDF shadings (/ShadingType), not rasterized bitmaps.
Clipping, Masking, Patterns
| Element | MDN Reference | Notes |
|---|---|---|
clipPath |
clipPath | Full support; clip-rule (nonzero/evenodd) controls the clip region’s fill rule. clipPathUnits (userSpaceOnUse — the default — and objectBoundingBox, where the clip’s 0..1 geometry auto-scales to the referencing element’s bounding box) are both supported. Renders as a real PDF clipping path (W n), not a mask. A clip shape’s own transform is applied to its clip geometry — whether set directly on the shape, on a wrapping <g>, or on a <use> (including its x/y), so one shape defined in <defs> can be reused as a clip at several positions (and composes correctly with objectBoundingBox units) |
mask |
mask | Renders as a real PDF luminosity soft mask (/SMask via /ExtGState) — mask content is painted (not just used for geometry, unlike clipPath) into an offscreen form, and its luminance becomes the mask’s alpha. maskUnits/maskContentUnits (objectBoundingBox/userSpaceOnUse) are both supported, including the spec’s -10%/-10%/120%/120% default region |
pattern |
pattern | patternUnits/patternContentUnits (objectBoundingBox/userSpaceOnUse), patternTransform, viewBox/preserveAspectRatio. Implemented by rendering the pattern’s content once into a PDF Form XObject “tile,” then drawing that same tile repeatedly (clipped to the filled shape’s geometry) across the fill region — every repeat is a reference to the same underlying vector content, never a rasterized bitmap, but this is not a native PDF /PatternType 1 tiling pattern object. Capped at 10,000 tile placements per fill as a safety guard against pathological pattern/shape size ratios |
Inheritance: content inside <pattern>, <mask>, <marker> and <clipPath> inherits presentation properties (fill, stroke, stroke-width, fill-opacity, font properties, …) from the definition element’s own ancestors — and from the definition element itself — not from the element that references it. <svg fill="#fff"> around a <mask> whose unstyled content should paint white therefore works as it does in a browser. (A pattern never inherits a paint that references itself, and a marker never inherits a marker-* reference to itself, so neither can draw itself without end.)
Filters
| Element | MDN Reference | Notes |
|---|---|---|
filter |
filter | A real primitive graph. When every primitive can be expressed in PDF (feFlood, feOffset, feMerge, feTile, the Porter-Duff feComposite operators, feBlend, a channel-independent feColorMatrix, and a linear feComponentTransfer), it is evaluated over PDF tiles and the result stays vector: ordinary fills, placements, blend modes, soft masks, and PDF ExtGState /TR transfer functions. If any primitive needs pixels, the whole filter is evaluated over pixels instead: the element’s content is painted into a bitmap covering the filter region, every primitive runs on it, and the result is placed on the page at PdfGenerateConfig.RasterizationDpi. Supports named result/in/in2 references to any earlier primitive (not only the immediately-preceding one), plus the reserved input names SourceGraphic, SourceAlpha, FillPaint, StrokePaint, BackgroundImage and BackgroundAlpha. FillPaint and StrokePaint fill the whole filter region with the referencing element’s fill or stroke paint (a colour, gradient or pattern; none is transparent; fill-opacity/stroke-opacity are not applied). BackgroundImage is what was painted behind the element inside its isolation group: for an inline <svg>, the page behind it over white paper (its ancestors’ backgrounds, the SVG’s own background included) followed by the SVG’s own content painted before the element; BackgroundAlpha is that image’s opacity. An SVG used as an <img>, a CSS image or a standalone document is a separate document, so its backdrop is only its own earlier content over transparency, and a group inside the SVG with opacity, mask or filter starts its backdrop empty. feImage places a stand-alone image (raster, or SVG through a data: or fetched URL) into its primitive subregion using its own preserveAspectRatio, or, for an href="#id" fragment, renders that element in the filtered element’s user space, moved by the subregion’s x/y. A fragment that names nothing leaves the primitive transparent. Any filter using one of these inputs or feImage is evaluated over pixels. Browsers generally treat BackgroundImage/BackgroundAlpha as transparent, so a document that relies on them looks different there. Over white paper an inline SVG’s BackgroundAlpha is fully opaque across the filter region. The filter region (x/y/width/height, filterUnits) defaults to the spec’s -10%/-10%/120%/120% of the referencing element’s bounding box, in both objectBoundingBox (the default) and userSpaceOnUse units; an element with no measurable bounding box (text, for instance) uses its viewport instead. primitiveUnits applies to the lengths of the pixel primitives. A <filter> containing a primitive or type this renderer does not support (an unknown fe* element, or an feComposite operator that does not parse) is rejected as a whole at parse time: the referencing element paints completely unfiltered, the same as a filter attribute naming a nonexistent id — never a partially-applied graph. |
feFlood |
feFlood | Full support — fills the filter region with flood-color/flood-opacity |
feOffset |
feOffset | Full support — dx/dy, resolved per primitiveUnits |
feMerge / feMergeNode |
feMerge | Full support — layers each child feMergeNode’s in via ordinary compositing, in document order |
feTile |
feTile | Repeats its input’s own subregion across the whole filter region |
feComposite |
feComposite | over, in, out, atop, xor — all via alpha-masked compositing in vector form (SourceAlpha and every alpha-based in/in2 reference a real /Alpha-subtype PDF soft mask, not a luminosity approximation). arithmetic (k1–k4) needs pixels: it makes the filter a bitmap one |
feBlend |
feBlend | All standard blend modes, via the same real PDF blend mode (ExtGState /BM) CSS mix-blend-mode uses — see HTML & CSS Support |
feColorMatrix |
feColorMatrix | type="matrix" with a channel-independent (diagonal) matrix is applied via a PDF ExtGState /TR transfer function and stays vector; type="luminanceToAlpha" uses the same /Luminosity soft mask mask uses. type="saturate", type="hueRotate" and any type="matrix" with a nonzero off-diagonal term mix colour channels, which PDF cannot express, so they make the filter a bitmap one (the full 4×5 matrix is applied per pixel) |
feComponentTransfer |
feComponentTransfer | type="linear" (slope/intercept) on feFuncR/feFuncG/feFuncB is composed into a PDF /TR transfer function and stays vector; a missing channel function defaults to identity, per spec. type="gamma", "table", "discrete" and any non-identity feFuncA make the filter a bitmap one |
feGaussianBlur |
feGaussianBlur | stdDeviation (one or two numbers, in user units or fractions of the bounding box per primitiveUnits). A zero or negative deviation disables its axis; both disabled passes the input through. Bitmap evaluation |
feDropShadow |
feDropShadow | dx, dy, stdDeviation, flood-color, flood-opacity. Bitmap evaluation |
feMorphology |
feMorphology | operator erode/dilate, radius per axis. The area outside the filter region counts as transparent. Bitmap evaluation |
feConvolveMatrix |
feConvolveMatrix | order, kernelMatrix, divisor, bias, targetX/targetY, edgeMode (duplicate, wrap, none), preserveAlpha; kernelUnitLength is ignored (the kernel runs at the bitmap’s own pixel pitch). A malformed kernel rejects the filter. Bitmap evaluation |
feTurbulence |
feTurbulence | type turbulence/fractalNoise, baseFrequency, numOctaves, seed, stitchTiles; the specification’s reference algorithm, so a given seed draws the same noise as other conforming renderers. Bitmap evaluation |
feDisplacementMap |
feDisplacementMap | scale, xChannelSelector, yChannelSelector; nearest-pixel sampling, transparent where a pixel is displaced from outside the region. Bitmap evaluation |
feDiffuseLighting / feSpecularLighting |
feDiffuseLighting | surfaceScale, diffuseConstant/specularConstant, specularExponent, lighting-color, and a feDistantLight, fePointLight or feSpotLight child (with limitingConeAngle). The surface normal uses the specification’s Sobel kernels, with its edge and corner variants. Bitmap evaluation. A lighting primitive with no light source rejects the filter |
Colour space and subregions (bitmap evaluation). Each primitive computes in the colour space color-interpolation-filters names — linearRGB (the initial value) or sRGB — converting its inputs as needed, and the last result is converted to sRGB for the page. Intermediate results are 8 bits per channel in whichever space, so the darkest few sRGB levels quantize in linear light (an sRGB value below about 8 can round to 0 in a linearRGB pass). A vector-only filter cannot do this (PDF has no working space to interpolate in) and computes in sRGB throughout. Per-primitive x/y/width/height subregions are honoured and make the filter a bitmap one; a primitive without one covers the whole filter region (the specification’s default is the union of its inputs’ subregions, which this simplifies).
Every primitive above builds a fresh PDF tile from its input(s) rather than mutating shared state, so a named result can be referenced by more than one later primitive, and non-adjacent references (a primitive whose in names a result from several steps earlier, not just the previous one) work exactly like an adjacent reference.
Markers
| Element | MDN Reference | Notes |
|---|---|---|
marker |
marker | refX/refY, markerWidth/markerHeight, viewBox/preserveAspectRatio, markerUnits (strokeWidth/userSpaceOnUse), orient (auto, auto-start-reverse, and a fixed angle) |
marker-start / marker-mid / marker-end |
marker-start | Full support, plus the marker shorthand (sets all three; an individually-specified property overrides just that one). Inherited. Per spec, markers only attach to path/line/polyline/polygon — not basic shapes like rect/circle/ellipse, which have no defined vertex sequence |
| Tangent/orientation math | — | Exact for every segment kind: straight lines and cubic béziers use the segment’s own control-point vectors, and elliptical arcs use the true derivative of the ellipse at the vertex (a degenerate arc, which renders as a straight line, uses its chord) |
Links
See a in SVG Root & Document Structure above.
Raster & Nested Content
| Element | MDN Reference | Notes |
|---|---|---|
image |
image | href/xlink:href resolves as a data: URI, a network URL, or a local file path — the same resource-loading pipeline HTML <img> uses (so it obeys <base href>, and a network URL requires a network loader to be configured, exactly like <img>). A raster payload (PNG, JPEG, etc.) embeds as a real PDF image XObject; an image/svg+xml payload (detected by a .svg extension or a Content-Type: image/svg+xml response header) renders as its own real vector scene graph (never rasterized), with its own url(#id) references resolving against its own definitions. A nested SVG payload’s own <image> elements resolve recursively — a network/file <image> inside a referenced SVG is fetched too, with its relative hrefs resolved against that nested SVG’s own location. x/y/width/height/preserveAspectRatio are all honored — including for raster images, which are fit into their box per preserveAspectRatio’s alignment/meet/slice rules, the same math used for viewports elsewhere in this renderer. An unresolvable href (no configured loader, missing resource, malformed payload) leaves the element blank rather than erroring. A relative href inside a standalone (<img src="x.svg"> / fetched) SVG resolves against the SVG’s own location |
Nested svg |
see svg above |
Establishes its own viewport, coordinate system, and clip |
foreignObject |
foreignObject | Embeds HTML in SVG user space, in an inline <svg> in an HTML document: the element’s children are laid out by the ordinary HTML engine as an isolated block width user units wide (one user unit being one CSS pixel), and painted at (x, y) clipped to the width×height viewport. Document and inline styles apply to the HTML, selectors inside match as HTML (case-insensitively), and transform, opacity, clip-path, mask and filter on the foreignObject apply to it like any other element. The width/height must be positive lengths (percentages are not resolved; a missing one paints nothing). Limits: the content is never split across pages, a <a href> inside is not a link annotation, and it adds nothing to the tagged-PDF structure. In a standalone SVG (<img src="x.svg">, a data: URI, a CSS image) the element is not built, so a surrounding switch falls through to its next child |
Network and file-path <image> references are fetched through PeachPDF’s general asynchronous resource-loading pipeline ahead of the (synchronous) SVG scene-graph build; a data: URI still resolves inline with no I/O. As with any external asset, a network URL only loads when a network loader is configured — otherwise the element simply renders blank.
Text
| Element | MDN Reference | Notes |
|---|---|---|
text |
text | x/y/dx/dy/rotate as both single values and per-character lists (x="10 20 30", rotate="0 15 30", SVG 1.1 §10.4) — each glyph is positioned/rotated by its own list value, a new absolute x/y starts a text chunk, and text-anchor (start/middle/end) is applied per chunk. font-family/font-size/font-weight/font-style/font-stretch (as both presentation attributes and style=) inherit from any ancestor (<g>/<svg>/<use>), and relative font-size (em/%, and the measured ex/ch/cap/ic/lh, taken from the parent’s font) resolves against the parent’s used size (rem and the r* forms against the root’s); letter-spacing/word-spacing accept the same units against the element’s own font. Bridges directly into PeachPDF’s existing font/text-measurement pipeline — the same font resolution and OpenType shaping ordinary HTML text uses, including letter-spacing, word-spacing, text-transform (uppercase/lowercase/capitalize/full-width), font-variant-ligatures/-caps/-numeric/-east-asian, font-feature-settings, font-kerning, and text-decoration-line/-style/-color (underline/overline/line-through, own value only — not inherited, per CSS Text Decoration 3 — but a descendant with no decoration of its own still shows an ancestor’s line flowing across it, matching real browser behavior; see the known-simplifications list for this feature’s own v1 scope). fill and stroke: a solid fill is painted as a selectable text run; a gradient/pattern fill (fill="url(#…)") or any stroke instead outlines each glyph to a vector path and fills/strokes it through the same paint machinery shapes use (see the known-simplifications list below for the outlined-text trade-offs) |
tspan |
tspan | A tspan without its own x/y flows immediately after the preceding text in the <text> subtree; a tspan with its own x and/or y starts a new absolute position (text chunk). Loose text and child tspans are laid out in document order (text authored after a child element keeps its place), and its own per-character x/y/dx/dy/rotate lists apply to its characters. Font properties and paint (fill/stroke/etc.) are inherited from the enclosing text/tspan when not overridden |
tref |
tref (deprecated in SVG2, still supported here) | href/xlink:href resolves to another element’s own text content, reused as this run’s text |
textPath |
textPath | href/xlink:href resolves to a <path> or a basic shape (rect/circle/ellipse/line/polyline/polygon), whose geometry the run’s glyphs — including any nested <tspan>s — are laid along: each glyph is placed at its own midpoint distance along the path and rotated to the path tangent, plus any per-character rotate/dx/dy. method (align, the default, turns each glyph rigidly to the tangent; stretch bends each glyph’s outline along the curve point by point) and spacing (auto is laid out as exact, which the specification allows). startOffset (a length or a % of the total path length), text-anchor, and side (left/right) shift/flip where the run runs along the path; a glyph whose midpoint falls before the start or past the end of the path is not rendered. Uses the same glyph-outline paint as gradient/stroked text, so a <textPath> also supports gradient/pattern fill and stroke. The outlines are painted in the text’s user space: a userSpaceOnUse gradient/pattern stays fixed there, and an objectBoundingBox one measures against the whole text (the union of its glyph cells), not each glyph. Always flows horizontally along the path regardless of the <text> root’s own writing-mode — there is no vertical variant of path-following text |
writing-mode / text-orientation |
writing-mode / text-orientation | writing-mode (resolved once from the <text> root — see below) advances the pen down the column instead of along a line for vertical-rl/vertical-lr; sideways-rl/sideways-lr and SVG 1.1’s legacy tb/tb-rl/etc. keywords fall back to horizontal-tb. text-orientation (mixed, the default; upright; sideways) is genuinely per-glyph and can be overridden on a nested <tspan>: mixed classifies each glyph by Unicode’s Vertical_Orientation property (the same table the HTML pipeline shares), painting CJK/kana upright and Latin/digits rotated 90°; upright/sideways force one answer for every glyph on that run. An explicit per-character rotate="" always overrides the orientation-driven default rotation for that glyph. An upright glyph’s down-the-column advance consults the font’s own real OpenType vertical metrics (vhea/vmtx) when it carries them (mainly professional CJK vertical fonts), clipped to its own reserved cell so a glyph never bleeds into its neighbor’s; a font without real vertical metrics — the common case — falls back to approximating the advance as the font’s own line height. An upright glyph’s anchor position additionally consults the font’s real VORG vertical-origin table when it has one — CFF/CFF2 fonts only, per the OpenType spec’s own restriction; a TrueType-outline font’s VORG table (rare in practice) is never consulted, and such a font falls back to the plain top-of-cell anchor exactly as a font with no VORG at all does. A rotated glyph’s down-the-column footprint is always its own natural pre-rotation width, matching real browser behavior for sideways-oriented text |
direction / unicode-bidi |
direction / unicode-bidi | A full Unicode Bidirectional Algorithm (UAX #9) implementation, matching how CSS text integrates bidi (CSS Writing Modes 3 §5.2) and shared with HTML’s own bidi resolver: direction (ltr/rtl, inherited, resolved from any ancestor) sets the <text> root’s paragraph base direction; unicode-bidi (normal/embed/isolate/bidi-override/isolate-override/plaintext, not inherited — resolved fresh per element, per spec) on a <tspan> contributes an explicit embedding/isolate/override push over exactly the characters that <tspan> (including its own descendants) contributes. Per-character bidi class (which characters actually reorder) is always auto-detected from each character’s real Unicode Bidi_Class, independent of direction/unicode-bidi — a strong-right-to-left run (e.g. Arabic or Hebrew text) reorders and a mirrorable character pair (parentheses, brackets) swaps identity even with no direction/unicode-bidi set anywhere, matching real browser behavior |
Known text simplifications:
- Outlined text stays selectable. A solid
fillkeeps the fast text-showing path (selectable, copy/paste- and tagged-PDF-friendly). A gradient/patternfill, astroke, or a<textPath>withmethod="stretch"draws each glyph as a filled/stroked vector outline, and the same text is also placed invisibly over it (PDF text render mode 3, the way a rasterized HTML subtree supplies its text), so it can still be selected and searched. This needs a decodable outline: aglyf-outline (TrueType) font, or any CFF/OpenType-CFF font (ordinary or CID-keyed). A bitmap-only font has no outline, so its glyphs are drawn through the raster backend: a gradient/patternfillis painted through the glyphs’ coverage, and astrokeis a band of the stroke width centred on their edge (an approximation, since a bitmap has no vector edge). A<textPath>on such a font turns its glyphs rigidly rather than bending them. - A
<text>’s bounding box forobjectBoundingBoxclipping, masking and paint is the union of its glyph cells (advance wide, ascent to descent) as laid out; a<g>/<use>containing text takes the union of its children’s. A bitmap font’s glyph has no outline, so formethod="stretch"its pixels are carried point by point along the path (a resampled, so slightly soft, bend), and its stroke is an approximation of the edge. - OpenType shaping (see Text shaping) applies to
<text>/<tspan>/<textPath>the same way it does to HTML text, including the outlined (gradient/pattern-filled or stroked) path — ligatures, caps/numeric/east-asian variants, arbitraryfont-feature-settingstags,font-kerning-gated GPOS kerning, and per-language GSUB feature selection (an element’s ownlang/xml:lang, or its nearest ancestor’s — including an inline<svg>’s surrounding HTML document, when nothing in the SVG’s own tree sets one) are all requestable per-element, same as HTML. - Font selection and variants follow HTML text too:
font-variant-alternateswith@font-feature-values,font-palettewith@font-palette-values(selecting the CPAL palette of a color font),font-variant-emoji,font-variation-settings,font-optical-sizing, numericfont-weightandfont-style: oblique <angle>. An inline<svg>reads the page’s@font-feature-values/@font-palette-valuesrules; a standalone SVG image reads those in its own<style>. Text painted as outlines (gradient/pattern fill, stroke,<textPath>with a non-solid paint) is drawn in the font’s default palette. - Font family lists, shorthands and fallback: the whole
font-familylist is honoured (first available family), and a character the chosen font has no glyph for is drawn from the next family in the list that has one, then from a system fallback font, as in HTML text. Thefont,font-variantandtext-decorationshorthands are expanded wherever they appear — a stylesheet,style="", or a presentation attribute (font="12px serif",text-decoration="underline"). - Decoration geometry:
text-decoration-thickness,text-underline-offset,text-underline-position(from-font,under), thedoubleandwavystyles, andtext-decoration-skip-ink(underlines and overlines skip glyph ink by default;noneturns it off, and underautoCJK text is left unskipped) work as in HTML text. text-shadow(inherited, any number of layers, blur radius included) paints under the text as in HTML. A glyph painted under its own transform (an explicitrotate="", a vertical-mode rotated glyph, a glyph stretched bytextLength, or a<textPath>glyph) offsets its shadow in user space and blurs it through that transform.paint-orderdecides whether a stroked or gradient-filled<text>paints its stroke before its fill (paint-order: strokefor a halo). It applies to text only — shapes always paint fill, stroke, markers.- Whitespace: by default whitespace collapses and the ends are trimmed.
xml:space="preserve"and the CSSwhite-spacevaluespre,pre-wrapandbreak-spaceskeep every space; a line break becomes a space unless the text is auto-wrapped, and a tab becomestab-sizespaces underwhite-space(default 8) or one space underxml:space.tab-sizetakes a number. - Baselines:
dominant-baseline(alphabetic,middle,central,hanging,mathematical,ideographic,text-top,text-bottom),alignment-baselineon a nested element andbaseline-shift(sub,super, a length or a percentage of the font size, accumulating through nested elements) move text off its default baseline. Where the font has an OpenTypeBASEtable, theideographic,hanging,mathematicalandcentralbaselines (the last as the middle of the ideographic character face) are read from it, for the horizontal axis under horizontal writing and the vertical axis under a verticalwriting-mode; the other baselines, and any baseline a font does not state, are approximated from the font’s metrics. Under a verticalwriting-modethe default baseline iscentraland a baseline property moves the column sideways (baseline-shifttowards the line-over side); a column that sets none stays centred. On a<textPath>the shift moves each glyph along the path’s normal, likedy. TheBASEtable is read for the font’s default script (a font’s per-script baselines are not selected by the text’s script), and its per-languageMinMaxextents and variable-font deltas are not read. textLengthwithlengthAdjust="spacing"(the default) on<text>and<tspan>spreads or squeezes the gaps between characters so the element spans exactly that length (a single character is left alone).lengthAdjust="spacingAndGlyphs"instead scales each glyph’s position and advance about the element’s start and stretches the glyphs themselves along the line (decorations, shadows,text-anchorand the bounding box follow the stretched text; a nested element’s stretch composes with its ancestors’). Both modes also apply on<textPath>(along the path’s distance) and under a verticalwriting-mode(down the column, with upright and rotated glyphs alike).font-size-adjust(none, a number,from-font, and theex-height/cap-height/ch-width/ic-width/ic-heightmetric forms) scales the glyph font so the chosen metric of each face — the primary and every fallback face on its own — matches the given value, as in HTML text. It never changesfont-size, soemlengths and nestedfont-size: 2emkeep the unadjusted size.font-synthesisand its-weight/-stylelonghands (the shorthand is expanded from a stylesheet,style=""or a presentation attribute) turn off the faux bold and faux italic a face gets when it lacks the requested weight or style; SVG text has no small-caps or sub/superscript synthesis for-small-caps/-positionto switch off.-webkit-text-stroke(and its-width/-colorlonghands, accepted from a stylesheet orstyle=""; a vendor-prefixed name cannot be an XML attribute) strokes the glyph outlines of<text>/<tspan>/<textPath>: for text it applies to, it takes the place ofstrokeandstroke-width(the colour iscurrentcolorunless given), and it paints with the same outline path, sopaint-order,<textPath>and the decorations behave as for a stroked text. A zero width draws nothing extra.text-rendering: optimizeSpeedturns off kerning and optional ligatures wherefont-kerningisautoandfont-variant-ligaturesisnormal; the other keywords are accepted and change nothing for PDF output.font-language-overrideselects the OpenType language system for the text’s substitution features, as in HTML text (a presentation attribute takes the quoted string,font-language-override="'SRB'").- Auto-wrapped text: a
<text>with aninline-size(SVG 2) or ashape-insideis laid out in line boxes instead of on one line.- The box.
inline-sizeis the width of the line box; it starts at the<text>’sxand runs towards the end of the line (so leftwards fordirection: rtl), and the first baseline is aty.shape-insidetakes a basic shape (inset(),circle(),ellipse()orpolygon(), in user space, with percentages of the viewport): each line uses the stretch of the shape that holds the whole line box, and a line that fits nowhere at its height is moved down; text that does not fit before the bottom of the shape is not painted. A setshape-insidereplacesinline-size.shape-subtractcuts the same kind of shapes out of whichever box is in use; a line broken in two by a cut-out continues in the second stretch. - Breaking. Lines break at the opportunities of the Unicode line breaking algorithm, as in HTML text (a word wider than the box overflows on a line of its own, except in a shape, where the line moves to where the word fits).
hyphens: manual(the default) breaks at a soft hyphen (U+00AD) and draws the hyphen;hyphens: autoalso uses the hyphenation patterns of the text’slang;hyphens: noneignores soft hyphens. white-space.normalandnowrapcollapse spaces and line breaks (andnowrapnever wraps);prekeeps spaces and breaks at each line feed without wrapping;pre-wrapkeeps spaces, breaks at line feeds and wraps (spaces at the end of a line hang outside it);pre-linecollapses spaces but breaks at line feeds;break-spaceswraps likepre-wrap. A line feed is a space in text that is not auto-wrapped.- Line boxes.
line-height(normal, a number, a length or a percentage; inherited) sets each line’s height from the tallest content on it.text-indent(a length or a percentage of the box width) indents the first line.text-align(start,end,left,right,center,justify,match-parent) aligns each line in the box; without ittext-anchorstands in (start,middleascenter,end), andjustifystretches the spaces of every line except the last and one that ends in a line feed. Bidi reordering is done per line. - What does not apply.
textLengthand the per-characterx/y/dx/dylists have no effect on wrapped text (rotatestill turns the glyphs it names), and<textPath>descendants lay out along their path as usual. Wrapping applies to horizontal writing modes only: under a verticalwriting-mode,inline-sizeandshape-insideare ignored.shape-insideandshape-subtractdo not takeurl()references,path()or a reference box, and a circle or ellipse is approximated by a polygon.text-indent’shanging/each-linekeywords,text-align-last,text-wrap/white-space-collapse,hyphenate-limit-charsand theshape-margin/shape-paddingproperties are not applied;break-spacesdoes not wrap after preserved spaces, andline-heightleading is added around the content by splitting it evenly.
- The box.
- Arabic-family joining and Devanagari USE syllable reordering (see Text shaping) also apply to
<text>/<tspan>content — each character’s real joining form or USE category is resolved over the whole<text>element’s flattened character stream, and a maximal run of mutually-joining or same-syllable characters shapes, measures, and (for a right-to-left run) display-reverses as one atomic glyph run, the same per-word treatment HTML text gets. A run never crosses a<tspan>boundary, never forms across non-zeroletter-spacing(which already disables optional joining/ligatures in real shapers), and never includes a character other than its own first with an explicitx/y/dx/dy/rotate— such a character has no well-defined position inside a shaped multi-character glyph (SVG 2 §11.5), so the run simply ends there instead of guessing. Not supported for<textPath>(glyphs there are still isolated nominal forms, each positioned independently along the path) or under a verticalwriting-mode. text-decorationv1 scope: painted for horizontal-tb, non-<textPath>, non-per-character-rotated text only. A vertical-writing-mode<text>and<textPath>glyphs don’t yet paint a decoration line at all (a real per-glyph-rotated decoration path is a larger follow-up); a glyph with an explicit per-characterrotate=""is skipped for the same “no well-defined single line” reason. No small-caps synthesis fallback exists forfont-variant-caps: small-caps/all-small-capsthe way HTML’sCssBoxhas — SVG only requests the real OpenTypesmcp/c2scGSUB features, silently inert on a font that lacks them.writing-mode’s pen-advance axis is resolved once from the<text>root, not per nested<tspan>— unliketext-orientation, a mid-text change of writing-mode has no defined real-world meaning to preserve, so awriting-modeset on a descendant is ignored for layout purposes (only the root’s own resolved value is consulted).
Coordinate Systems & Units
| Feature | Notes |
|---|---|
viewBox |
Full support, including all 9 preserveAspectRatio alignment keywords (xMinYMin, xMidYMid, xMaxYMax, etc.) and both meet and slice, plus none (independent-axis stretch) |
| Length units | Unitless numbers, % (resolved against the viewport width/height/diagonal per the axis, per spec), px, pt, pc, in, cm, mm, and the font-relative units em/ex/ch/cap/ic/lh and rem/rex/rch/rcap/ric/rlh, in the length attributes of shapes, text, <use>, nested <svg> and <image>, in stroke-width/stroke-dasharray/stroke-dashoffset, and inside calc(). They resolve against the element’s own font-family/font-size — and the root <svg>’s for the r* forms — measured from the real font. An SVG that never declares a font-size anywhere keeps CSS’s 16px initial size for em/rem. ic measures the ideograph in the element’s primary font only (1em when that font lacks it); lh is the font’s normal line height (not the line-height that auto-wrapped text uses). Content inside <pattern>, <marker>, <mask> and <clipPath>, and the coordinates of a gradient, resolve them against the definition element’s own font — inherited from its ancestors like any other element’s |
transform |
matrix(), translate(), scale(), rotate() (including the 3-argument rotate(angle, cx, cy) form), skewX(), skewY(). Multiple functions may be chained; they compose per spec. The CSS syntax of the property is read too (from a stylesheet, a keyframe or style=, and, being one parser, from the attribute as well, which a browser’s attribute grammar does not take): angles with a unit (deg, grad, rad, turn), lengths in px, pt, pc, in, cm, mm and Q, a percentage in scale() (the same number), translateX(), translateY(), scaleX(), scaleY(), skew() and rotateZ(). em, rem and percentage lengths resolve in translate(), translateX() and translateY() (a percentage is of the transform-box, which for an SVG element is the view box by default, or the element’s fill or stroke bounding box with fill-box or stroke-box), and so does a calc() of them in a stylesheet, a keyframe or style= (not in the transform attribute, whose grammar is numbers only). The 3D functions (translate3d(), translateZ(), scale3d(), scaleZ(), rotate3d(), rotateX(), rotateY(), matrix3d() and perspective()) are read too; see 3D transforms. A function with an argument that cannot be resolved here (a unit it does not know, a calc() in the attribute) does nothing, and the functions after it still apply. transform-origin (also as an attribute) turns the transform about that point, measured in transform-box (view-box, the default; fill-box/content-box; stroke-box/border-box); without a transform-origin an SVG element turns about the user-space origin whatever the box. In style= a declaration that is not valid CSS (rotate(10) or translate(10, 20) with no unit) is dropped, as in a browser, and the rule or attribute answers; gradientTransform and patternTransform take bare numbers only |
3D transforms
The 3D transform functions apply to every SVG element that has a transform: shapes, text, images, <g>, <a>, <use>, nested <svg> and <foreignObject>. They are the same machinery as CSS 3D transforms on HTML boxes, pointed at an SVG element: the element, with its clip, filter, mask and opacity, is painted as it would be without its transform and the result is carried through the 4×4 matrix.
| Feature | Notes |
|---|---|
3D functions in transform |
Composed as one 4×4 matrix about transform-origin, whose optional third value (a length) is the origin’s z offset, measured in transform-box like the other two. Without perspective the matrix projects onto the element’s plane as a plain 2D matrix, so rotateX(), rotateY(), translateZ() and scale3d() stay vector artwork |
perspective |
none (default) or a length in user units (a distance under one unit is one unit; zero is none). A container’s property: it is how far the viewer is from the plane for the container’s direct children, which the container itself is not moved by. Applies to <g>, <a>, <use>, nested <svg> and the root <svg>. Not inherited. The perspective() function in a transform is the same view for the one element it is in |
perspective-origin |
The vanishing point, a <position> measured in transform-box (the view box by default); 50% 50% initially |
backface-visibility |
visible (default) or hidden: a hidden element is not painted while its back faces the viewer (rotateY(180deg) shows the back, scaleX(-1) does not) |
transform-style |
flat (default) or preserve-3d: on a container, its children share its 3D space, depth-sorted and, where they intersect, resolved per pixel. opacity below 1, filter, clip-path and mask on the container force flat, as does a nested <svg>, which clips |
| Where 3D is ignored | A transform list that holds a 3D function is ignored as a whole in gradientTransform and patternTransform, and on a <clipPath> the 3D list of a child is the projection of its matrix onto the plane (a clip is a flat shape). <clipPath>, <mask> and <pattern> content is always flat |
| How it is written | A projective result (a real perspective, or a perspective() function) is drawn into a bitmap at the rasterization resolution and warped; one that stays within a quarter of a device pixel of an affine matrix is written as vector artwork instead. A preserve-3d context whose planes are only tilted (no perspective) and do not pierce one another is also vector, drawn back to front; otherwise its planes are depth-tested in one bitmap. A plane turned edge-on, wholly behind the viewer, or turned away with backface-visibility: hidden paints nothing, and neither does an element whose matrix cannot be inverted |
| Limits | Text drawn into a warped bitmap is not selectable; a link inside a warped element covers the bounding box of its orthographic projection (without the perspective); a nested <svg> or <use> whose children are in a 3D context is not itself a context root; vector-effect is not supported at all |
CSS Integration
| Feature | Notes | |
|---|---|---|
| Presentation attributes | Every property above is readable as a plain XML attribute (e.g. fill="red") |
|
| Geometry properties | r, cx, cy, rx, ry, x, y, width, height and d are CSS properties as well as attributes (SVG 2): a <style> rule, the document’s stylesheet, style= or a @keyframes block can set them on circle, ellipse, rect, image, foreignObject, nested svg and use (and d: path("...") / d: none on path), inline style= beating a rule beating the attribute. Percentages resolve against the viewport. x/y/width/height are not read from CSS on mask, pattern, filter or text |
|
| SVG-only properties in a stylesheet | flood-color, flood-opacity, lighting-color, paint-order, mask, marker, marker-start/-mid/-end, clip-rule, color-interpolation-filters, transform-box, alignment-baseline, baseline-shift, dominant-baseline, inline-size, shape-inside and shape-subtract can be written in a <style> rule, the document’s stylesheet or a @keyframes block, as well as in style= or as an attribute, and @supports recognises them (transform-box is read but not yet applied to transform). Colour, opacity, marker-* and clip-rule values are checked against their grammar; for the rest the value is checked when the element is built |
|
style="..." |
Inline style= is supported on every element, taking precedence over presentation attributes and <style> rules, per CSS cascade rules |
|
<style> element |
Fully supported for both inline <svg> and standalone SVG, matched through PeachPDF’s full CSS selector engine — type (rect), class (.foo), ID (#foo), compound (rect.foo), comma-separated lists, descendant/child/sibling combinators (g rect, .wrap > circle), attribute selectors ([gradientUnits="userSpaceOnUse"], [data-x^="a"], …), and structural pseudo-classes (:first-child, :nth-of-type(), :only-of-type, :not(), :empty, …). :empty matches an element with no children other than white-space-only text; comments and processing instructions do not count as children, while any child element, or any text or CDATA section that is not pure white space, does. Standard specificity/cascade order applies, including !important: an !important declaration overrides normal declarations regardless of specificity (CSS Cascade §Importance). var() custom properties and calc()/min()/max()/clamp() length expressions are resolved too. Precedence is inline style= > <style> rule (by specificity) > presentation attribute. A guaranteed-invalid var() (missing custom property with no fallback, or a cyclic reference) is invalid at computed-value time (CSS Custom Properties): the declaration still wins the cascade and the property computes to its inherited (or initial) value — it does not fall back to a lower-priority declaration such as the presentation attribute. The CSS-wide keywords are supported on the SVG paint/geometry properties in a <style> rule: initial computes to the property’s SVG initial value (fill→black, stroke→none, stroke-width→1, …), inherit takes the parent’s value, and unset/revert/revert-layer roll the author cascade back to a lower origin — since an SVG presentation attribute is itself author-origin (specificity 0), the property computes to its inherited/initial value rather than the presentation attribute (with no @layer support, revert-layer behaves as revert; every SVG paint property is inherited, so unset behaves as inherit) |
|
@property registrations |
Honored in SVG styling, standalone and inline. A custom property registered with an @property rule contributes its initial-value (the value a var() reference resolves to when the property is otherwise unset), its inherits flag (a descendant that doesn’t set an inherits: false property resolves it to the initial-value rather than the ancestor’s value), and syntax validation (a set value that doesn’t match falls back to the initial-value) — the same behavior as for HTML. A standalone SVG uses @property rules from its own <style>; an inline <svg> uses the host document’s registry |
|
| Document CSS cascades into inline SVG | For an inline <svg>, rules in the HTML document’s own <style>/<link> stylesheets that match SVG elements (e.g. circle { fill: red } in <head>) apply to the SVG shapes — inline SVG participates in the document cascade (SVG 2 §6 Styling). A standalone SVG (<img src="x.svg"> / data:image/svg+xml) is an independent document and is styled only by its own <style> — host-document CSS does not reach it |
|
| Selector case-sensitivity | SVG is XML, so selectors match SVG element types, attribute names/values, classes, and IDs case-sensitively (Selectors 4 §6) — e.g. RECT {} does not match <rect>. This holds even for an attribute name that would otherwise be on the HTML Standard’s fixed case-insensitive legacy-attribute list (type, dir, align, …) — that exception is scoped to elements in the HTML namespace only, so it never applies inside <svg>. (HTML matching stays ASCII case-insensitive by default for that same fixed list, and case-sensitive otherwise.) |
|
class / id |
Read for <style> selector matching, same as HTML (case-sensitively for SVG) |
|
display |
display | From a presentation attribute, style=, a <style> rule or the document cascade. none removes the element and everything under it from rendering, wherever it is reached from: a <use> instance, a pattern or marker’s content, a <tspan> (whose text drops out of the run). A <switch> whose first candidate is display: none still picks it, so it renders nothing, as in a browser. contents strips g, a, switch, use, tspan and textPath from the formatting tree and keeps their content (CSS Display 3, SVG elements): the element’s own opacity, transform, clip-path, mask and filter no longer apply, a use loses its x/y offset, a tspan or textPath loses its position and rotation lists and a textPath its path, while inherited properties such as fill still reach the content. On every other SVG element, contents computes to none. |
CSS animations
With PdfGenerateConfig.AnimationProgress set (see Animations), the elements of an inline <svg> take the value their CSS animation has at the sampled point, as an HTML box does: rect { animation: pulse 2s linear } with a @keyframes pulse { from { fill: red } to { fill: blue } } in the document’s stylesheet.
- Properties. Those the SVG renderer reads from the cascade:
fill,stroke,opacity,fill-opacity,stroke-opacity,stroke-width,stroke-dashoffset(a bare number is user units, so the usual line-drawing animation,stroke-dashoffset: 300to0, works),stroke-dasharray(lists of the same length, ornone; lists of different length flip where a browser repeats them to a common length),transform(rotate(),translateX(),scale(),skew()and lists of them, mixed function by function, or as matrices when the lists differ),stop-colorandstop-opacityon a gradient stop,display, the text propertiesfont-size,letter-spacingandword-spacing, and the geometry properties (r,cx,cy,rx,ry,x,y,width,height;autodoes not mix with a length, so it flips at the midpoint; on a nested<svg>they are read from CSS, andwidth/heighton a<use>too; a browser ignores CSS geometry there), where a bare number from an attribute counts as user units against a keyframe’spx(a bare number written in the keyframe itself, and a comma-separatedstroke-dasharray, are not read from a stylesheet or keyframe at all). A percentage opacity (opacity,fill-opacity,stroke-opacity,stop-opacity:50%) is the number it stands for and mixes with one. Colours mix as they do for HTML (in Oklab when one is not a legacy colour), andcurrentcolorin a keyframe is thecolorof the<svg>element’s HTML ancestor, as it is forfill="currentColor"anywhere else in the SVG (acolorset on an element inside the SVG is not seen, so acurrentcolorend point of an animation turns to that colour at the very end, and not before). - Cascade. The animation sits above the presentation attribute, a
<style>rule and an inlinestyle="", and below an!importantdeclaration. A keyframe that leaves the property out of its first or last step stands for the value the element has without the animation: its own declaration, else the value inherited from the parent (an animated<g>’sfillreaches its children as it changes), else the initial value.inherit,initial,unsetandvar()work in a keyframe. Several animations on one element apply in order, a later one seeing the earlier one’s result. - Not animated.
points,d(a path in a keyframe switches at the halfway point where a browser mixes the two shapes),offseton a gradient stop,visibility(which the SVG renderer does not read),filter, and the individualrotate/scale/translateproperties. Content reached through<use>mixes from the referenced tree’s value where a browser mixes from the<use>’s, when a keyframe leaves out its first or last step. The elements of a standalone SVG (<img src="x.svg">, adata:URI) are not animated either: its@keyframesandanimationare ignored. A.svgfile given directly to the command-line tool is parsed as inline SVG, so its CSS animations are sampled like those of an inline<svg>. SVG’s own animation elements are covered under SMIL below.
Unsupported SVG Features
The following SVG 1.0/1.1 features are not supported, each for the reason given:
- SMIL animation (
animate,animateColor,animateMotion,animateTransform,set) — a static PDF page has no animation/timeline model to target. - Scripting (
script, event-handler attributes likeonclick) — no script execution context exists in a static PDF page. cursor— no pointer/cursor model exists for embedded vector content in a PDF.view— fragment-based view navigation has no equivalent in static PDF page content.- Legacy SVG glyph-outline fonts (
font,glyph,missing-glyph,hkern,vkern,font-faceand its children) — this would duplicate PeachPDF’s existing full TrueType/CFF/WOFF/WOFF2 font pipeline for a mechanism SVG2 itself deprecated in favor of ordinary web fonts; use real fonts viafont-family/@font-faceinstead.