Layout de texto XeTeX estranhamente sensível a espaços

Layout de texto XeTeX estranhamente sensível a espaços

Eu tenho um documento em um script que requerlayout de texto complexoque acredito que deveria funcionar no XeTeX. Mas obtenho resultados surpreendentes:

\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}

Quando compilado com xelatexisso dá:

saída

Para quem não consegue ler o script, o que está à esquerda (quando o input tem R ಶ್ರೀವತ್ಸum espaço depois do R) está correto, enquanto o que está à direita (o input tem o mesmo texto mas sem o espaço depois do R) está correto não.

Eu entendo as “caixas” na saída: elas ocorrem porque as fontes Kannada selecionadas não possuem o caractere R nelas. (Uma mensagem nesse sentido é impressa no terminal graças a \tracinglostchars=2.)

Pergunta: Por que a saída está errada quando o espaço é omitido? E como posso fazer as coisas funcionarem bem mesmo sem espaço?

Pelo que entendi, no XeTeX o layout do texto (também conhecido como renderização de texto, também conhecido como modelagem de texto) é fornecido pela biblioteca HarfBuzz, que é usada por muitos outros aplicativos e deve ser capaz de lidar bem com esse texto. No LuaTeX eles tentam evitar dependências do sistema e esperam implementar tudo sozinhos (em código Lua), o que provavelmente subestima a complexidade do layout do texto e em qualquer caso o LuaTeX atualmente não tem absolutamente nenhum suporte para quaisquer scripts índicos além de Devanagari e Malayalam. Então é isso que lualatexproduz para o arquivo acima:

lualatex

(Pelo menos está sempre errado, o que eu entendo!)


Editar: Graças à resposta de @cfr abaixo, sei o que devo fazer para resolver o problema real: especificar o script ao carregar a fonte (por exemplo, \fontspec{Noto Sans Kannada}[Script=Kannada]ou da melhor maneira na resposta dela). Então é possível resolver o problema; a única questão restante é:O que está acontecendo?

E se vale a pena, aqui está um arquivo XeTeX simples mínimo que reproduz o problema (compilar com xetexem vez 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

Responder1

Não tenho a primeira nem a última fonte. No entanto, o Polyglossia funciona corretamente para mim. (Presumo que provavelmente também funcionaria apenas com a configuração correta da fonte, mas fiz dessa maneira, pois provavelmente é isso que você deseja no 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}

configuração de fonte

Responder2

(Compartilhando o que entendi como resultado de tudo isso.)

Soluções

Em primeiro lugar, as soluções para o problema:

  • ComoResposta de @cfrapontou, eu deveria ter usado [Script=Kannada]para esta fonte, conforme documentado nos manuais fontspece polyglossia. E quando usado, tudo funciona conforme o esperado: com ou sem espaço, todo o texto é renderizado conforme apropriado para a escrita Kannada.
  • Além disso, na verdade, não queremos que os caracteres não-Kannada, como o R, sejam renderizados no script Kannada: os caracteres de script diferentes, como Rdevem ser marcados como estando em um idioma diferente ou pelo menos em uma fonte diferente (veja abaixo como fazer esse).

Então isso é um bug no XeTeX ou em alguma biblioteca que ele usa? Não, eu diria que é um erro do usuário. Ainda assim, o fato de tudo funcionar bem quando há espaços entre as palavras (sem a necessidade de especificar o script) talvez torne esse erro do usuário mais provável.

Explicação

O que explica essa discrepância de comportamento dependendo do espaço (exatamente o que está acontecendo)? E esse comportamento pode ser alterado no XeTeX? O que descobri é o seguinte.

A biblioteca usada pelo XeTeX para layout de texto, nomeadamenteHarfBuzz(que é usado no Firefox, Chrome, LibreOffice, etc., consulteO que é Harbuzz?), vem com um programa de linha de comando chamado hb-viewque pode ser invocado com uma fonte e uma string de texto. Com ele obtenho a seguinte saída:

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

    sem roteiro, sem espaço com roteiro, espaço

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

    sem script, começa com espaço com script, começa com espaço

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

    sem script, começa com R sem espaço com script, começa com R sem espaço

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

    sem script, começa com R e espaço com script, começa com R e espaço

O que isso mostra é que a saída está correta sequalquero primeiro caractere sem espaço é do script correto,ouo script é especificado explicitamente.

Portanto, o comportamento visto no XeTeX (a diferença entre "Rಶ್ರೀ" e "R ಶ್ರೀ") é explicado pelo que@Ulrike Fischerapontou emO companheiro XeTeX:

A abordagem do XeTeX é a seguinte:

  • o processo de composição coleta séries de caracteres (palavras) cujas larguras são obtidas através da API para as bibliotecas do sistema [...] para determinar as larguras,

  • um parágrafo XeTeX é uma sequência depalavranós separados porcola.

Assim, o mecanismo de composição tipográfica do XeTeX coloca palavras em vez de glifos, sendo estes últimos desenhados pelo mecanismo de renderização de fontes.

(As “bibliotecas do sistema” e o “mecanismo de renderização de fontes” acima são HarfBuzz agora (graças aKhaled Hosny); eles costumavam ser UTI antes.) Então

  • com “Rಶ್ರೀವತ್ಸ”, o XeTeX pede ao HarfBuzz para renderizar toda a string como uma unidade, o que falha (como visto nos experimentos hb-view acima) porque não começa com um caractere do script desejado nem especificamos o script corretamente, enquanto

  • com “R ಶ್ರೀವತ್ಸ”, o XeTeX pergunta ao HarfBuzz separadamente para cada uma das duas palavras e, neste caso, a segunda palavra é renderizada corretamente (mesmo que não tenhamos especificado o script) porque começa com um caractere do script correto.

Ainda assim, parece melhor não confiar em tais suposições e especificar o script explicitamente.

Trabalhando com ambos os scripts

Para que ambos os scripts funcionem sem problemas, devemos especificar que caracteres como R estão em um idioma diferente. Poderíamos fazer isso escrevendo \textenglish{R}ಶ್ರೀವತ್ಸem vez de Rಶ್ರೀವತ್ಸ. Se não quisermos alterar a entrada, existe uma maneira de fazer isso usando oucharclassespacote.

Não consegui fazê-lo funcionar por algum motivo, então fiz isso manualmente (referindo-se ao exemplo emtexdoc xetexe umpublicardo autor de ucharclasses, e com 255 alterado para 4095 conforme mencionado, por exemploesta resposta):

\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}

Isso altera o idioma toda vez que nos movemos entre um caractere inglês (somente Racima) e um limite de palavra (4095) ou um caractere regular (não especificado como inglês) (0).

Para o meu documento original, para lidar com todos os caracteres ingleses, escrevi um loop para fazer o equivalente a

\XeTeXcharclass `R = \CharEnglish

para cada letra maiúscula e minúscula do alfabeto:

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

informação relacionada