Gradients resolving

A typical gradient in SVG looks like this:

<linearGradient id="lg1">
    <stop offset="0" stop-color="white"/>
    <stop offset="1" stop-color="black"/>
</linearGradient>

But SVG allows one gradient to reference another via the href attribute. When used, gradient's missing stop elements and attributes will be copied from a referenced gradient.

Most libraries are either bad at this or do not support this at all.

Stops resolving

A gradient can reference stop elements from another gradient. The type of a gradient doesn't matter, meaning linear can reference radial and vise versa. Stops will be referenced only when the current gradient doesn't have any stops. Meaning that

<linearGradient id="lg1">
    <stop offset="0" stop-color="white"/>
    <stop offset="1" stop-color="black"/>
</linearGradient>
<linearGradient id="lg2" xlink:href="#lg1"/>

is identical to

<linearGradient id="lg1">
    <stop offset="0" stop-color="white"/>
    <stop offset="1" stop-color="black"/>
</linearGradient>
<linearGradient id="lg2">
    <stop offset="0" stop-color="white"/>
    <stop offset="1" stop-color="black"/>
</linearGradient>

The href chain length is unlimited. A gradient can reference another gradient which references another one and so on until one of the gradients in a chain has non-zero stops. Like so:

<linearGradient id="lg1">
    <stop offset="0" stop-color="red"/>
    <stop offset="1" stop-color="green"/>
</linearGradient>
<!-- lg1 stops are ignored, because lg2 already has stops -->
<linearGradient id="lg2" xlink:href="#lg1">
    <stop offset="0" stop-color="white"/>
    <stop offset="1" stop-color="black"/>
</linearGradient>
<linearGradient id="lg3" xlink:href="#lg2"/> <!-- stops from lg2 and not lg1 will be used -->
<linearGradient id="lg4" xlink:href="#lg3"/> <!-- stops from lg2 via lg3 will be used  -->

Attributes resolving

Similar rules apply to gradient attributes as well. If a gradient has a href link to another gradient and the referenced gradient has attributes not present in the current gradient - those attributes will be copied.

But things are getting weird pretty fast. Some attributes can be copied only from a gradient of the same type. Specifically x1, y1, x2 and y2 linear gradient attributes can be copied only from other linear gradients. Even when one of gradients in the href chain is radial. And cx, cy, fx, fy and r radial gradient attributes can be copied only from other radial gradients.
But gradientUnits, spreadMethod and gradientTransform attributes can be copied from a gradient of any type.

In this example, lg1 will copy spreadMethod from rg1, but will ignore y2.

<radialGradient id="rg1" y2="1" spreadMethod="reflect"/>
<linearGradient id="lg1" xlink:href="#rg1" x2="0.7">
    <stop offset="0" stop-color="white"/>
    <stop offset="1" stop-color="black"/>
</linearGradient>

By extrapolating a bit, we can easily end up with something like this:

<radialGradient id="rg1" xlink:href="#rg2" cx="0.5"/>
<radialGradient id="rg2" xlink:href="#rg3" spreadMethod="reflect" fy="0.65"/>
<radialGradient id="rg3" cy="0.55"/>
<radialGradient id="rg4" xlink:href="#rg1" r="0.5" fx="0.6"/>
<rect fill="url(#rg4)"/>

which is identical to:

<radialGradient id="rg4" cx="0.5" cy="0.55" fx="0.6" fy="0.65" r="0.5" spreadMethod="reflect"/>
<rect fill="url(#rg4)"/>

Radial gradient attributes resolving

Radial gradients increase the complexity even more by requiring a specific order in which attributes must be resolved. Specifically, fx and fy attributes, when not set, are equal to cx and cy. But only when a referenced gradient doesn't set fx and fy either. So in the case of:

<radialGradient id="rg1" cy="0.7" fx="0.8"/>
<radialGradient id="rg2" xlink:href="#rg1" cx="0.4" r="0.1"/>

fx will be resolved to 0.8 and not 0.4, because it's present in a referenced element.
And fy will be resolved to 0.7 and not 0.5, which is the default cx/cy value.

Basically, rg2 first becomes:

<radialGradient id="rg2" cx="0.4" cy="0.7" fx="0.8" r="0.1"/>

And only then we resolve missing fx/fy attributes and end up with:

<radialGradient id="rg2" cx="0.4" cy="0.7" fx="0.8" fy="0.7" r="0.1"/>

Note that stops and attributes resolving are independent.

Patterns and filters

Patterns have a similar logic for resolving its attributes and children. And filter has a similar logic for resolving its attributes, but not children.