Up to now, text support in librsvg has been fairly limited. The text chapter in the SVG spec is pretty big and it contains features that are very much outside of my experience (right-to-left languages, vertical text). But now I think I have a plan for how to improve the text features.
Bidirectional text, or "bidi" for short, happens when one has a right-to-left language like Arabic or Hebrew intermixed with things like Arabic numerals, or Latin text.
This is an interesting little example from the SVG spec:
<?xml version="1.0" encoding="utf-8"?> <svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" viewBox="0 0 600 72" direction="rtl" xml:lang="he"> <title direction="ltr" xml:lang="en">Right-to-left Text</title> <desc direction="ltr" xml:lang="en"> An example for using the 'direction' and 'unicode-bidi' properties in documents that predominantly use right-to-left languages. </desc> <text x="300" y="50" text-anchor="middle" font-size="36"> כתובת MAC:‏ <tspan direction="ltr" unicode-bidi="embed">00-24-AF-2A-55-FC</tspan> </text> </svg>
It is supposed to render like this; it says "MAC address: xxx-yyy-zzz":
However, until librsvg 2.52.2 this did not work correctly. You see, librsvg takes each
piece of text inside a
<text> and creates a Span for it. If there is a
element, it also gets a Span created. However, librsvg did not handle the case where an
<tspan> changes the
direction property from its parent
<?xml version="1.0" encoding="utf-8"?> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xml:lang="fa" direction="rtl" width="200" height="100"> <g font-family="Dana-FaNum" font-size="16"> <text x="50%" y="50%"><tspan font-weight="bold">نام: </tspan><tspan>مهدی</tspan></text> </g> </svg>
It is supposed to render more or less like this (the line says, "Name: Mehdi"):
This was broken, too!. I did not realize that within
spans need to be laid out exactly in the text
direction, in this case
rtl. I thought
that it was sufficient to let Pango deal with each group of characters within a span.
Together with that, I fixed
text-anchor for right-to-left text. This is what one uses
to align a text block with respect to its start, middle, or end. It was also broken for
RTL languages before.
One remaining bug is that there should be a space to the left of the
but librsvg is eating it. I think it needs to implement the SVG2
which replaces the ambiguous definition of
xml:space from SVG1.1.
A test that makes me exceedingly happy
This family of images from Wikimedia Commons has been broken for many years. Someone has been painstakingly making SVG2 maps of German rail by writing SVG code by hand; they use features that became available only after Madds Holland's Outreachy internship from last Summer. Also, the maps use text offsetting features that were just broken.
The little arrowheads were broken because librsvg didn't support
orient="auto-start-reverse" in markers (arrowheads get done with SVG's "marker"
feature). Madds added support for that during their Outreachy internship.
Then, most of the the multi-line text objects in there were laid out
incorrectly. Librsvg was laying out spans inside text chunks incorrectly
when they had
dx/dy offsets and the text also had
text-anchor different from the
One last detail which I haven't figured out is that the positioning of glyphs is a bit off. If you look at the slanted label for the LU-Rheingönheim station, the "heim" at the end looks a bit misaligned with the rest of the label. Firefox renders it correctly. Advice is appreciated!
All those fixes will appear in librsvg 2.52.3, due in a few days.
I want to add more tests for right-to-left and bidi text; they can be affected by many properties for which there are no tests right now.
After bidi text works reasonably well, I want to add support for positioning individual
glyphs with the
x/y/dx/dy properties. People from Wikimedia Commons really want this,
to be able to lay out equations and such.
Once individual glyphs can be positioned independently, maybe
textPath support, which
cartographers really like for curved labels.
A handy tool
The font’s em-square is exactly square. Its ascent and descent combined is exactly the size of the em square; this means that the font’s extent is exactly the same as its line-height, meaning that it can be exactly aligned with padding, borders, margins, and so forth.
That is, you can typeset something with the Ahem font and it will appear as contiguous squares. If you render the string ABCD, it will appear as a rectangle four-ems wide by one-em tall. This is wonderful for reproducible tests!
<?xml version="1.0" encoding="utf-8"?> <svg xmlns="http://www.w3.org/2000/svg" width="600" height="300"> <rect x="0" y="0" width="100%" height="100%" fill="white"/> <line x1="50%" y1="0" x2="50%" y2="100%" stroke-width="2" stroke="blue"/> <line x1="0" y1="100" x2="100%" y2="100" stroke-width="2" stroke="blue"/> <text x="50%" y="100" font-family="Ahem" font-size="20" text-anchor="end"><tspan dy="-1em">A</tspan><tspan dx="-40" dy="1em">BC</tspan></text> </svg>
That renders like this:
Text rendering clearly means spending days trying to get three black squares to draw in the correct position.