
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 xelatex
isso dá:
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 lualatex
produz para o arquivo acima:
(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 xetex
em 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}
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 manuaisfontspec
epolyglossia
. 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
R
devem 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-view
que 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
:hb-view NotoSansKannada-Regular.ttf " ಶ್ರೀ"
e com--script=knda
:hb-view NotoSansKannada-Regular.ttf "Rಶ್ರೀ"
e com--script=knda
hb-view NotoSansKannada-Regular.ttf "R ಶ್ರೀ"
e com--script=knda
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 oucharclasses
pacote.
Não consegui fazê-lo funcionar por algum motivo, então fiz isso manualmente (referindo-se ao exemplo emtexdoc xetex
e 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 R
acima) 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