XeTeX テキストレイアウトはスペースに対して異常に敏感です

XeTeX テキストレイアウトはスペースに対して異常に敏感です

スクリプトで必要な文書があります複雑なテキストレイアウトこれは XeTeX で動作するはずだと信じています。しかし、驚くべき結果が得られました。

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

これをコンパイルするとxelatex次のようになります:

出力

スクリプトを読めない人のために説明すると、左側のもの(入力にR ಶ್ರೀವತ್ಸR の後にスペースがある場合)は正しいのですが、右側のもの(入力に同じテキストがありますが、 R の後にスペースがありません)は正しくありません。

出力内の「ボックス」は、選択された Kannada フォントに R 文字が含まれていないために発生するものであると理解しています。(この趣旨のメッセージは、 のおかげでターミナルに表示されます\tracinglostchars=2。)

質問: スペースを省略すると出力が間違っているのはなぜですか? また、スペースがなくても正常に動作させるにはどうすればよいですか?

私の理解では、XeTeX ではテキスト レイアウト (別名テキスト レンダリング、別名テキスト シェーピング) は、他の多くのアプリケーションで使用されているライブラリ HarfBuzz によって提供されており、このテキストを問題なく処理できるはずです。LuaTeX では、システム依存性を回避し、すべてを独自に (Lua コードで) 実装しようとしていますが、これはおそらくテキスト レイアウトの複雑さを過小評価しており、いずれにしても、LuaTeX は現在、デーヴァナーガリー文字とマラヤーラム文字以外のインド系スクリプトをまったくサポートしていません。したがって、lualatex上記のファイルでは次のものが生成されます。

ルアラテックス

(少なくとも、それは一貫して間違っていると私は理解しています!)


編集: 以下の @cfr の回答のおかげで、実際の問題を解決するために何をすべきかがわかりました。フォントをロードするときにスクリプトを指定します (たとえば、\fontspec{Noto Sans Kannada}[Script=Kannada]または彼女の回答のより良い方法)。したがって、問題を解決することは可能です。残る唯一の質問は次のとおりです。どうしたの?

参考までに、問題を再現する最小限のプレーン XeTeX ファイルを次に示します (xetexではなくでコンパイルします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

答え1

最初のフォントも最後のフォントもありません。ただし、Polyglossia は正常に動作します。(正しいフォント設定でもおそらく動作すると思いますが、最終的にはこれが必要なため、この方法で実行しました。)

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

フォント設定

答え2

(このすべての結果として私が理解したことを共有します。)

ソリューション

まず、問題の解決策は次のとおりです。

  • として@cfr の回答指摘されたように、マニュアル[Script=Kannada]に記載されているように、このフォントには を使用すべきでした。実際に使用すると、すべてが期待どおりに機能します。スペースの有無にかかわらず、テキスト全体がカンナダ語のスクリプトに適切にレンダリングされます。fontspecpolyglossia
  • さらに、実際には、R のような非カンナダ語文字をカンナダ語のスクリプトでレンダリングしたくありません。異なるスクリプトの文字は、R別の言語または少なくとも別のフォントとしてマークする必要があります (これを行う方法については、以下を参照してください)。

これは XeTeX のバグか、それともそれが使用するライブラリのバグでしょうか? いいえ、ユーザー エラーだと思います。それでも、単語間にスペースがある場合 (スクリプトを指定する必要がない場合) はすべて正常に機能するという事実は、おそらくこのユーザー エラーの可能性を高めます。

説明

スペースに応じて動作が異なる理由は何でしょうか (何が起こっているのでしょうか)? また、この動作は XeTeX で変更できますか? 私が見つけたのは次のとおりです。

XeTeXがテキストレイアウトに使用するライブラリ、すなわちハーフバズ(Firefox、Chrome、LibreOfficeなどで使用されています。Harfbuzzとは何ですか?hb-view) には、フォントとテキスト文字列を指定して呼び出すことができる というコマンドライン プログラムが付属しています。これを使用すると、次の出力が得られます。

  • hb-view NotoSansKannada-Regular.ttf "ಶ್ರೀ"そして以下と--script=knda

    スクリプトなし、スペースなし スクリプト、スペース付き

  • hb-view NotoSansKannada-Regular.ttf " ಶ್ರೀ"そして以下と--script=knda

    スクリプトなし、スペースで始まる スクリプト付き、スペースで始まる

  • hb-view NotoSansKannada-Regular.ttf "Rಶ್ರೀ"そして--script=knda

    スクリプトなし、スペースなしのRで始まる スクリプト付き、スペースなしの R で始まる

  • hb-view NotoSansKannada-Regular.ttf "R ಶ್ರೀ"そして--script=knda

    スクリプトなし、Rとスペースで始まる スクリプト付き、Rとスペースで始まる

これは、出力が正しいことを示しています。どちらか最初のスペース以外の文字は右の文字から来ている、またはスクリプトは明示的に指定されます。

XeTeXで見られる動作(「Rಶ್ರೀ」と「R ಶ್ರೀ」の違い)は、次のように説明されます。@ウルリケ・フィッシャー指摘されたXeTeX コンパニオン:

XeTeX のアプローチは次のとおりです。

  • 組版プロセスでは、システムライブラリへのAPIを介して幅が取得された文字(単語)の連続を収集し、幅を決定します。

  • XeTeXの段落は、言葉ノードはのり

したがって、XeTeX の組版エンジンはグリフではなく単語を配置し、グリフはフォント レンダリング エンジンによって描画されます。

(上記の「システムライブラリ」と「フォントレンダリングエンジン」は現在HarfBuzzです(ハレド・ホスニー(以前はICUでした。)だから

  • 「Rಶ್ರೀವತ್ಸ」では、XeTeXはHarfBuzzにその文字列全体を1つの単位としてレンダリングするように要求しますが、これは(上記のhb-viewの実験で見られるように)目的のスクリプトの文字で始まっておらず、スクリプトも正しく指定されていないため失敗します。

  • “R ಶ್ರೀವತ್ಸ” の場合、XeTeX は 2 つの単語それぞれについて HarfBuzz に個別に問い合わせます。この場合、2 番目の単語は正しいスクリプトの文字で始まるため、(スクリプトを指定しなかった場合でも) 正しくレンダリングされます。

それでも、そのような推測に頼らず、スクリプトを明示的に指定するのが最善のようです。

両方のスクリプトの操作

両方のスクリプトをスムーズに動作させるには、Rのような文字が異なる言語であることを指定する必要があります。これを行うには、\textenglish{R}ಶ್ರೀವತ್ಸの代わりに と記述しRಶ್ರೀವತ್ಸます。ただし、入力を変更したくない場合は、ucharclassesパッケージ

何らかの理由でうまく動作しなかったため、手動で実行しました(の例ではtexdoc xetexそして役職の著者から引用ucharclassesし、例えば で述べられているように 255 を 4095 に変更した。この答え):

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

Rこれにより、英語の文字 (上記のみ) と単語境界 (4095) または通常の (英語であると指定されていない) 文字 (0)の間を移動するたびに言語が変更されます。

私の元の文書では、すべての英語の文字を処理するために、次のようなループを作成しました。

\XeTeXcharclass `R = \CharEnglish

アルファベットの大文字と小文字ごとに:

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

関連情報