El diseño del texto XeTeX es extrañamente sensible a los espacios

El diseño del texto XeTeX es extrañamente sensible a los espacios

Tengo un documento en un script que requierediseño de texto complejoque creo que se supone que funciona en XeTeX. Pero obtengo resultados sorprendentes:

\documentclass{article}
\usepackage{fontspec}

\tracinglostchars=2 % https://tex.stackexchange.com/a/41235/48
\def\testtext{R ಶ್ರೀವತ್ಸ \quad Rಶ್ರೀವತ್ಸ}

\begin{document}

\fontspec{Arial Unicode MS} \testtext

\fontspec{Noto Sans Kannada} \testtext

\fontspec{Noto Serif Kannada} \testtext

\fontspec{Kedage} \testtext

\end{document}

Cuando se compila con xelatexesto, se obtiene:

producción

Para aquellos que no pueden leer el script, lo de la izquierda (cuando la entrada tiene R ಶ್ರೀವತ್ಸun espacio después de la R) es correcto, mientras que lo de la derecha (la entrada tiene el mismo texto pero sin el espacio después de la R) es correcto. no.

Entiendo los "cuadros" en el resultado: se deben a que las fuentes Kannada seleccionadas no tienen el carácter R. (Se imprime un mensaje a este efecto en el terminal gracias a \tracinglostchars=2.)

Pregunta: ¿Por qué el resultado es incorrecto cuando se omite el espacio? ¿Y cómo puedo hacer que las cosas funcionen correctamente incluso sin espacio?

Según tengo entendido, en XeTeX el diseño del texto (también conocido como representación de texto, también conocido como modelado de texto) lo proporciona la biblioteca HarfBuzz, que es utilizada por muchas otras aplicaciones y debería poder manejar este texto correctamente. En LuaTeX intentan evitar dependencias del sistema y esperan implementar todo ellos mismos (en código Lua), lo que probablemente subestima la complejidad del diseño del texto y, en cualquier caso, LuaTeX actualmente no tiene soporte para ningún script índico que no sea Devanagari y Malayalam. Entonces esto es lo que lualatexproduce el archivo anterior:

lualatex

(¡Al menos está siempre mal, lo cual tengo entendido!)


Editar: Gracias a la respuesta de @cfr a continuación, sé lo que debo hacer para resolver el problema real: especificar el script al cargar la fuente (por ejemplo, \fontspec{Noto Sans Kannada}[Script=Kannada]o la mejor manera en su respuesta). Entonces es posible resolver el problema; la única pregunta que queda es:¿Qué está sucediendo?

Y por si sirve de algo, aquí hay un archivo XeTeX simple y mínimo que reproduce el problema (compilar con xetexen lugar de xelatex):

\font\notosansnone="Noto Sans Kannada"
% \font\notosanskndt="Noto Sans Kannada:script=knd2"
\font\notosansknda="Noto Sans Kannada:script=knda"

\def\testtext{R ಶ್ರೀ Rಶ್ರೀ}

{\notosansnone \testtext} (No script)

% {\notosanskndt \testtext} (knd2)

{\notosansknda \testtext} (knda)

\bye

Respuesta1

No tengo la primera ni la última fuente. Sin embargo, Polyglossia me funciona correctamente. (Supongo que probablemente también funcionaría solo con la configuración de fuente correcta, pero lo hice de esta manera porque presumiblemente es lo que quieres al final).

\documentclass{article}
\usepackage{polyglossia}
\setmainlanguage{kannada}
\setotherlanguage[variant=british]{english}
\newfontfamily\kannadafont{Noto Serif Kannada}[Script=Kannada]
\newfontfamily\kannadafontsf{Noto Sans Kannada}[Script=Kannada]
\tracinglostchars=2 % https://tex.stackexchange.com/a/41235/48
\def\testtext{R ಶ್ರೀವತ್ಸ \quad Rಶ್ರೀವತ್ಸ}

\begin{document}

% \fontspec{Arial Unicode MS} \testtext

\testtext

\sffamily \testtext

% \fontspec{Kedage} \testtext

\end{document}

configuración de fuente

Respuesta2

(Compartiendo lo que entendí como resultado de todo esto).

Soluciones

En primer lugar, las soluciones al problema:

  • ComoLa respuesta de @cfrseñaló, debería haber usado [Script=Kannada]para esta fuente, como se documenta en los manuales fontspecy polyglossia. Y cuando se usa, todo funciona como se esperaba: con espacio o sin él, todo el texto se representa según sea apropiado para la escritura kannada.
  • Además, en realidad no queremos que los caracteres que no sean kannada, como la R, se representen en la escritura kannada: los caracteres de escritura diferente como Rdeben marcarse como si estuvieran en un idioma diferente o al menos con una fuente diferente (consulte a continuación cómo hacerlo). este).

Entonces, ¿es esto un error, ya sea en XeTeX o en alguna biblioteca que utiliza? No, yo diría que es un error del usuario. Aún así, el hecho de que todo funcione bien cuando hay espacios entre palabras (sin tener que especificar el script) quizás hace que este error de usuario sea más probable.

Explicación

¿Qué explica esta discrepancia de comportamiento según el espacio (qué está pasando)? ¿Y se puede cambiar este comportamiento en XeTeX? Lo que encontré es lo siguiente.

La biblioteca utilizada por XeTeX para el diseño de texto, a saberHarfBuzz(que se utiliza en Firefox, Chrome, LibreOffice, etc., consulte¿Qué es Harfbuzz?), viene con un programa de línea de comandos llamado hb-viewque se puede invocar con una fuente y una cadena de texto. Con él obtengo el siguiente resultado:

  • hb-view NotoSansKannada-Regular.ttf "ಶ್ರೀ"y con --script=knda:

    sin guión, sin espacio con guión, espacio

  • hb-view NotoSansKannada-Regular.ttf " ಶ್ರೀ"y con --script=knda:

    sin guión, comienza con espacio con guión, comienza con espacio

  • hb-view NotoSansKannada-Regular.ttf "Rಶ್ರೀ"y con--script=knda

    sin script, comienza con R sin espacio con script, comienza con R sin espacio

  • hb-view NotoSansKannada-Regular.ttf "R ಶ್ರೀ"y con--script=knda

    sin script, comienza con R y espacio con script, comienza con R y espacio

Lo que esto muestra es que la salida es correcta sicualquierael primer carácter que no sea un espacio es del guión correcto,oel script se especifica explícitamente.

Entonces, el comportamiento visto en XeTeX (la diferencia entre "Rಶ್ರೀ" y "R ಶ್ರೀ") se explica por lo que@Ulrike Fischerseñalado enEl compañero XeTeX:

El enfoque de XeTeX es el siguiente:

  • el proceso de composición tipográfica recopila tiradas de caracteres (palabras) cuyos anchos se obtienen a través de la API en las bibliotecas del sistema […] para determinar los anchos,

  • un párrafo XeTeX es una secuencia depalabranodos separados porpegamento.

Por lo tanto, el motor de composición tipográfica de XeTeX coloca palabras en lugar de glifos, estos últimos dibujados por el motor de representación de fuentes.

(Las “bibliotecas del sistema” y el “motor de representación de fuentes” anteriores ahora son HarfBuzz (gracias aKhaled Hosny); Solían ser UCI antes.) Entonces

  • con “Rಶ್ರೀವತ್ಸ”, XeTeX le pide a HarfBuzz que represente esa cadena completa como una unidad, lo cual falla (como se ve en los experimentos de hb-view anteriores) porque no comienza con un carácter del script deseado ni especificamos el script correctamente, mientras que

  • con “R ಶ್ರೀವತ್ಸ”, XeTeX le pregunta a HarfBuzz por separado cada una de las dos palabras, y en este caso la segunda palabra se representa correctamente (incluso si no especificamos el guión) porque comienza con un carácter del guión correcto.

Aún así, parece mejor no confiar en tales conjeturas y especificar el guión explícitamente.

Trabajar con ambos scripts

Para que ambos scripts funcionen sin problemas, debemos especificar que los caracteres como R estén en un idioma diferente. Podríamos hacer esto escribiendo \textenglish{R}ಶ್ರೀವತ್ಸen lugar de Rಶ್ರೀವತ್ಸ. Sin embargo, si no queremos cambiar la entrada, hay una manera de hacerlo usando elucharclassespaquete.

No pude hacerlo funcionar por alguna razón, así que lo hice manualmente (refiriéndose ael ejemplo entexdoc xetexy uncorreodel autor de ucharclasses, y con 255 cambiado a 4095 como se menciona en, por ejemploesta respuesta):

\documentclass{article}
\usepackage{fontspec}
\usepackage{polyglossia}

\newfontfamily\kannadafont{Noto Serif Kannada}[Script=Kannada]
\newfontfamily\englishfont{Georgia}
\setdefaultlanguage{kannada}
\setotherlanguage{english}

\XeTeXinterchartokenstate = 1   % Enable the character classes functionality

\newXeTeXintercharclass \CharEnglish
\XeTeXcharclass `R = \CharEnglish

\XeTeXinterchartoks 0 \CharEnglish = {\selectlanguage{english}}
\XeTeXinterchartoks 4095 \CharEnglish = {\selectlanguage{english}}
\XeTeXinterchartoks \CharEnglish 0 = {\selectlanguage{kannada}}
\XeTeXinterchartoks \CharEnglish 4095 = {\selectlanguage{kannada}}

\begin{document}

R ಶ್ರೀವತ್ಸ \quad Rಶ್ರೀವತ್ಸ

\end{document}

Esto cambia el idioma cada vez que nos movemos entre un carácter inglés (solo Rarriba) y un límite de palabra (4095) o un carácter normal (no especificado como inglés) (0).

Para mi documento original, para tratar con todos los caracteres en inglés, escribí un bucle para hacer el equivalente a

\XeTeXcharclass `R = \CharEnglish

para cada letra mayúscula y minúscula del alfabeto:

\newcount\tmpchar
\tmpchar = `A
\loop
  \ifnum \tmpchar < `[          % [ comes just after Z
    \XeTeXcharclass \tmpchar = \CharEnglish
    \XeTeXcharclass \lccode \tmpchar = \CharEnglish
    \advance \tmpchar by 1
\repeat

información relacionada