Text in librsvg starts to get better

Translations: es - Tags: gnome, librsvg

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

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.

  <text x="300" y="50" text-anchor="middle" font-size="36"> כתובת MAC:&#x200F;
    <tspan direction="ltr" unicode-bidi="embed">00-24-AF-2A-55-FC</tspan> 


It is supposed to render like this; it says "MAC address: xxx-yyy-zzz":

Text that says "MAC address: numbers" in Hebrew with an English acronym

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 <tspan> element, it also gets a Span created. However, librsvg did not handle the case where an inner <tspan> changes the direction property from its parent <text> element.

Another bug:

<?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>

It is supposed to render more or less like this (the line says, "Name: Mehdi"):

Right-to-left spans in text

This was broken, too!. I did not realize that within <text>, the 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 white-space behavior, 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.

S-Bahn map for the Rhein Neckar region

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 default.


Broken rendering of the S-Bahn map; arrows and multi-line text are wrong


Good rendering of the S-Bahn map

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!

Future plans

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

I recently discovered the Ahem font. It is part of the CSS fonts tests, and consequently part of the Web Platform Tests. Quoting from its description:

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>

That renders like this:

Three black squares on a white background

Text rendering clearly means spending days trying to get three black squares to draw in the correct position.