Skip to content

Inherit gradient attributes and stops through xlink:href - #143

Open
fishloa wants to merge 1 commit into
swhitty:mainfrom
fishloa:gradient-href-inheritance
Open

fishloa wants to merge 1 commit into
swhitty:mainfrom
fishloa:gradient-href-inheritance

Conversation

@fishloa

@fishloa fishloa commented Nov 8, 2026

Copy link
Copy Markdown

Gradients that reference another gradient through xlink:href lose most of what they should inherit. Per SVG 1.1 §13.2.2 and §13.2.3, a gradient inherits from the gradient it references, which may be of either kind:

  • stops, when it has none of its own;
  • gradientUnits and gradientTransform;
  • geometry, from gradients of the same kind only (x1…y2, cx…fr).

makeGradient(for:) currently has three problems:

  1. A radialGradient looks up its href only among radialGradients. A radial gradient that takes its stops from a linearGradient (common in Inkscape output) gets no stops, so the fill is dropped.
  2. Only stops are taken from the referenced gradient. A gradient that defines only x1…y2 and xlink:href falls back to objectBoundingBox and loses the referenced units, geometry and transform.
  3. When the href resolves, the referenced stops replace the element's own stops.

This change follows the whole href chain, across both kinds and with a cycle guard. Each attribute comes from the first gradient in the chain that specifies it. The DOM and the public API are unchanged.

Tests

LayerTree.Builder.GradientTests.swift adds six tests:

  • radial taking stops from linear;
  • units, geometry and transform inherited;
  • own attributes override inherited ones;
  • no geometry inherited across kinds;
  • a three-element chain;
  • a reference cycle.

All 246 tests pass. Before the change, five of the new tests fail.

Real-world check

I rendered 41 TV-channel SVG logos and compared each with a resvg rendering of the same file. Three logos changed and none got worse:

logo mean abs. diff before after
Austria 9 (radial → linear href; ring missing before) 28.9 6.2
W9 HD (radial → linear href) 6.6 1.1
Krone TV (href without own gradientUnits) 5.5 1.9

#142 covers gradient href chains as part of a much larger change. This PR is the focused subset, in case that is easier to review.

A gradient now inherits stops, gradientUnits and gradientTransform from
the gradients it references, of either kind, following the whole href
chain with a cycle guard; geometry is inherited only from gradients of
the same kind (SVG 1.1 §13.2.2, §13.2.3). Previously only stops were
taken, only from the same kind, and they replaced the element's own.
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.

1 participant