rx
/ry
attributes resolving
In SVG, rectangle corners can be rounded by setting rx
and ry
attributes. Like this:
<rect x="5" y="5" width="10" height="10" rx="2" ry="2"/>
duplicated radiuses. So instead of rx="2" ry="2"
you can write just rx="2"
or ry="2"
.
And the "missing" value will be copied from the present one. Pretty nice.
Of course, it wouldn't be in this "book" if it was that easy.
Remember that SVG supports relative units,
like mm
, em
and %
, which you have to convert into absolute before rendering?
The question is, what should be done first: resolving the missing attribute
or relative to absolute unit conversion? The spec doesn't say.
But who cares! It couldn't be that bad, right? Well... Let's take a look at this example:
<svg viewBox="0 0 20 50">
<rect width="10" height="10" rx="50%"/>
</svg>
To what values rx
and ry
should be resolved?
If we copy the missing radius first, then we will get rx="50%" ry="50%"
and therefore rx="10" ry="25"
(via svg.viewBox.width * 50%
and svg.viewBox.height * 50%
).
Otherwise it will be rx="10" ry="10"
.
The answer is the latter. A parser is suppose to convert units first and only then copy the present value.
Neat! But surely no one actually made such mistake, right?
Well, Batik 1.16, a 20 years old library, still has this bug.
My resvg
library had this bug for 5 years until I accidentally stumbled onto it while fixing
an unrelated issue.
A tiny bug that is almost impossible to hit, but that's what you get when you have a file format with countless interconnected features and no test suite.
Since SVG 2, this logic affects ellipse
as well.