CairoSVG
CairoSVG copied to clipboard
Incorrect output when tspan combined with middle/end anchor
Hi. There seems to be a bug in how CairoSVG renders a tspan contained inside text that is not left-anchored. Here's an example svg:
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg height="200" width="800" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<rect width="100%" height="100%" fill="white"/>
<line x1="400" y1="0" x2="400" y2="200" style="stroke:red; stroke-width:1" />
<text style="font-family:Times; font-size:20;" x="400" y="40" text-anchor="middle">This is center-anchored regular text</text>
<text style="font-family:Times; font-size:20;" x="400" y="80" text-anchor="start">This is left-anchored <tspan font-style="italic">italic</tspan> text</text>
<text style="font-family:Times; font-size:20;" x="400" y="120" text-anchor="middle">This is center-anchored <tspan font-style="italic">italic</tspan> text</text>
<text style="font-family:Times; font-size:20;" x="400" y="160" text-anchor="end">This is right-anchored <tspan font-style="italic">italic</tspan> text</text>
</svg>
Here's the expected output:

Here's CairoSVG's actual output:

Is this a known bug? I couldn't find a previous report of this.
I've had a look through the code, and it seems like a difficult thing to fix. In this case, it seems that the sentence is rendered as three separate chunks (it's treated as three nodes): "This is center-anchored", "italic", and "text". When the first chunk is positioned, it needs to account for the width of the subsequent two chunks, and then some kind of offset needs to be passed to the subsequent chunks to position them correctly. My hunch is that, in order to do this properly, you need a kind of "pre-rendering" stage, where you figure out the width of the full text element before handling each node separately. Or do you think there could be some simpler ways to fix this?
I can confirm this issue still persists in 2.7.0