El texto en librsvg comienza a mejorar

Translations: en - Tags: gnome, librsvg

Hasta ahora, librsvg ha tenido soporte para texto bastante limitado. El capítulo de texto en la especificación de SVG es gigantesco y contiene funcionalidad que está muy lejos de mi experiencia (lenguas que se escriben de derecha a izquierda, texto vertical). Pero creo que ahora tengo un buen plan para mejorar las funciones de texto.

Texto bidireccional

El texto bidireccional, o "bidi", ocurre cuando se tiene una lengua que se escribe de derecha a izquierda como el árabe o hebreo, mezclada con números arábigos o texto latino.

Éste es un ejemplo interesante de la especificación de SVG:

<?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:&#x200F;
    <tspan direction="ltr" unicode-bidi="embed">00-24-AF-2A-55-FC</tspan> 
  </text>

</svg>

Debe renderizarse así; el texto dice "MAC address: xxx-yyy-zzz":

Texto que dice "MAC address: números" en hebreo con un acrónimo en inglés

Hasta librsvg 2.52.2 esto no funcionaba correctamente. Librsvg toma cada pedacito de texto dentro de un elemento <text> y crea un Span (intervalo) para él. Si hay un elemento <tspan>, también se le crea un Span. Sin embargo, librsvg no manejaba bien el caso en el que hay un <tspan> interior que cambia la propiedad direction con respecto a su ancestro <text>.

Otro error:

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

Debe renderizarse más o menos así (la línea dice "Nombre: Mehdi"):

Fragmentos de derecha a izquierda en el texto

Esto también estaba roto.. Yo no sabía que adentro de un <text>, los spans deben ordenarse exactamente según la direction, en este caso rtl (right-to-left, derecha a izquierda). Yo pensaba que era suficiento con dejar que Pango lidiara con cada grupo de caracteres dentro de un span.

Junto con eso, arreglé la propiedad text-anchor para el texto que se escribe de derecha a izquierda. Ésta se usa cuando se quiere alinear un bloque de texto según su principio, mitad, o final. Esto también estaba roto para lenguas de derecha a izquierda.

Un bug que queda es que debería haber un espacio a la izquierda del :, pero librsvg se lo come. Creo que necesita implementar la conducta de white-space de SVG2, la cual sustituye la definición ambigua de xml:space de SVG1.1.

Una prueba que me hace enormemente feliz

Esta familia de imágenes de Wikimedia Commons ha estado rota por muchos años. Alguien ha estado haciendo cuidadosamente unos mapas hermosos de las líneas de tren en Alemania, escribiendo código SVG a mano. Usan funciones que sólo se hicieron disponibles con el internado de Outreachy de Madds Holland el verano pasado. Además, los mapas usan funciones para ajustar la posición del texto que siempre habían estado rotas.

Mapa del S-Bahn para la región Rhein Neckar

Las flechitas estaban rotas porque librsvg no soportaba orient="auto-start-reverse" en los "marcadores" (las flechas se hacen en SVG con el elemento "marker"). Madds añadió soporte para eso durante su internado de Outreachy.

Luego, casi todos los objetos de texto con varias líneas tenían posiciones incorrectas. Librsvg ponía posiciones incorrectas cuando los bloques de texto tienen desplazamientos en dx/dy y además cuando el texto también tiene un text-anchor diferente del default.

Antes:

Pedazo incorrecto del mapa del S-Bahn; las flechas y el texto multi-línea están mal

Ahora:

Buen renderizado del mapa del S-Bahn

Un último detalle que no sé cómo arreglar es que la posición de los caracteres individuales está un poco rara. Si miras la etiqueta en diagonal de la estación LU-Rheingönheim, el "heim" del final se ve un poco desalineado con respecto al resto de la etiqueta. Firefox lo pinta correctamente. ¡Se aceptan sugerencias!

Planes a futuro

Todos estos arreglos aparecerán en librsvg 2.52.3, que saldrá en unos días.

Quiero añadir más pruebas para texto de derecha a izquierda y bidireccional; pueden afectarse por muchas propiedades para las que ahorita no hay pruebas.

Ya que el texto bidi funcione razonablemente bien, quier añadir soporte para posicionar caracteres individuales con las propiedades x/y/dx/dy. La gente de Wikimedia Commons quiere esto para poder pintar ecuaciones y cosas así.

Ya que los caracteres individuales se puedan posicionar de forma individual, tal vez añadir soporte para textPath, que lo quieren quienes hacen cartografía con etiquetas curveadas.

Una herramienta útil

Hace unos días descubrí la fuente Ahem. Es parte de las pruebas de fuentes de CSS, y por ende también parte de los Web Platform Tests. Cito de su descripción:

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.

Es decir, puedes componer un texto con la fuente Ahem y va a aparecer como una serie de cuadritos contiguos. Si pintas la cadena ABCD, aparecerá como un rectángulo de 4 unidades em de ancho por 1 unidad de alto. ¡Esto es maravilloso para poder reproducir los resultados de las pruebas!

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

Se pinta así:

Tres cuadritos negros sobre un fondo blanco

Implementar un renderizador de texto por supuesto significa pasar días intentando poner tres cuadritos negros en la posición correcta.