Hatena::Grouprekken

murawaki の雑記

2011-01-22

Rendering Traditional Mongolian with Pango

Linux (UNIX) 上で縦書きモンゴル文字を表示する方法。現実逃避の成果 (?)。font の仕組みも何もかもわかっていないので、いろいろ調べながら。

Linux 上でテキストの rendering を行っているのは pango。現行版はモンゴル文字をサポートしていない。パッチがあったので試してみた。フォントとしては Windows 7 についてくる Mongolian Baiti を使う。よくわかんないけど、ライセンス違反でないことを願う。

2011/01/23 追記: 実はサポート済みとのこと。バグ報告が長らく止まっていると思ったら、大改造が進行中らしい。shaper は harfbuzz 側でサポートされているとのこと。確かに harfbuzz の hb-ot-shape-complex-arabic.cc に記述されていた。2010-12-21 の commit。アラビア文字などと一緒に処理されている。U+180E MONGOLIAN VOWEL SEPARATOR は相変わらずスペースとして表示されないらしい。そのうち harfbuzz を試してみるかもしれない。なにしろ基盤層をいじるので、環境構築が大変そう。

見つかったパッチは 3種類。github にあがっているのと、pango のバグ報告に添付されているのが2種類。ソースのコメントによると、作者は全部 Erdene-Ochir Tuguldur という人。github のが最新版のようだが、とりあえずバグ報告の2番目のパッチを使う。

基本的な手順はブログ記事にある通り。Ubuntu 上で行うなら。package 化されたの pango1.0 の source を取ってきて、patch をあてて debuild。必要なツールは apt-get install しろと上記の記事には書いてある。他にも gtk-doc-tools を install しないと configure.in からの生成に失敗する。aclocal, autoconf, automake -a が必要っぽい気がする。エラーが出て試行錯誤したので本当のところは分からなくなってしまった。

rendering のテストには Mongolian Unicode Test Page が使える。だいたいうまく表示される。大きな問題は二つ。制御文字の MVS (Mongolian Vowel Separator) がそのまま表示される。一か所だけ FVS1 (これも制御文字) が表示される。これらは後でもう一度取り上げる。

パッチの中身。モンゴル文字処理用に mongolian という module を追加している。モンゴル文字は、孤立形、語頭形、語中形、語末形を持つが、これを処理しているだけ。これらは OpenType font の Glyph Substitution の feature で制御される。対応する feature は isol, init, medi, fina。そのいずれかをテキスト中の各文字に付与。

実際には、文脈に応じてもっと多くの異形態がある。孤立形、語頭形、語中形、語末形の4種類ではすまない。ligature もある。どうしてこんな単純な処理だけでうまくいくのか。実は glyph 選択規則はほとんど font 側に書いてあった。モンゴル文字用に特別な処理を書かなくても、pango の OpenType 一般のルーチンで処理できている。

これを確認するために寄り道。fontforge という package を取ってくる。fontforge は font editor。編集する用がなくても、browser として使える。fontforge に monbaiti.ttf を与えて、Mongolian Baiti を眺める。

適当にモンゴル文字を選んで context menu から Glyph Info を選ぶ。Substitutions を見る。LETTER A の場合、Subtable の一つとして 'init' Initial Forms in Mongolian lookup 9 subtable がある。これに対応する Replacement Glyph Name が uni1820.init。語頭形なら語頭形の glyph を使うということ。isol, fina, medi, init は通常の gsub feature。OpenType の Single Substitution というやつ。substitution の選択は mongolian module がやっている。

LETTER A の Subtable には Single Substitution lookup 94 subtable というものもある。対応する Replacement Glyph Info は uni1820.mvsvar1。どうやって使うのか。各 code point から Glyph Info を見ていてもわからない。menu の Fonto Info... から Lookups に移って GSUB の一覧を見るとわかる。

Substitution には Ligature Substitution というものもある。FVS を使った強制的な異形態表示は ligature で処理されていた。Standardized Variants にある規則はフォントに書いてある。ᠨᠠ᠋ᠨ (n-a-FVS1-n) とかやると、LETTER A が uni1820.medivar1 で表示される。Glyph Substitution Table に書いてある通り。

Chaining Substitution はもっと複雑なパターンマッチング。解読するのが大変。

ちゃんと動作確認するために、Unicode 5.2 の 13.2 Mongolian に書いてある例を片っ端から試してみる。

U+200D ZERO WIDTH JOINER は正しく処理されない。全部 isolate。

  • isolate
  • ᠠ‍ initial
  • ‍ᠠ final
  • ‍ᠠ‍ medial

Uniscribe でもそれぞれ isolate, initial, isolate, initial が表示された。手前の ZWJ が処理されてない。

FVS はうまくいく。

  • ᠭᠠᠯ (gal with dots)
  • ᠭ᠋ᠠᠯ (gal without dots)。

母音調和の処理もうまくいく。

  • ᠵᠠᠷᠯᠢᠭ jarlig (masculine g)
  • ᠴᠢᠷᠢᠭ chirig (feminine g)

最後の g の shape を区別するには、上の例では母音 a の出現を、下の例では i 以外の母音が出現しないことを認識する必要がある。かなり長距離の依存。g には Chaining Substitution の rule がいっぱい書いてある。そのどれかが対応しているのだろう。

MVS。

  • ᠬᠠᠨᠠ xana
  • ᠬᠠᠨ᠎ᠠ xan-a

n の shape は正しい。Chaining Substitution が効いている。MVS をそのまま表示するのがまずい。

再び Mongolian Unicode Test Page の表示について。

  • ᠲᠥᠷᠥᠯ töröl。最初の ö は牙 (silbi) 付きで二番目は牙なし。ü/ö のデフォルトの medi は牙なし。どの規則で牙ありにしてるのかと思ったら、contextual 50。initial の直後の ü/ö だけヒゲを生やす。この規則はモンゴル語の語頭に重子音が来ないことに頼っている。外来語で CC + ü という構造を探してみたところ、見つかったのは ᠺᠯᠦᠪ (klüb) だけ。案の定牙なしで表示される。ᠺᠯᠦ᠋ᠪ と FVS1 を挿入したらいけた。
  • ᠪᠤᠢ ᠵ᠎ᠠ bui-ǰ-a。元のページでは j の shape がおかしいが、コピペすると正しく表示されるようになった。謎。
  • ᠰᠣᠨᠣᠰᠲᠠᠭᠰᠠᠨ᠋᠎ᠠ sonostaɣsan-a。これはよくわからない。final の n に FVS1 を加える規則は定義されていない。おかしいのはテキストの方。rendering engine は単に FVS1 を無視すればよい。
  • ᠰᠠᠢᠨ sain。以前も取り上げた語。牙が2本欲しいが1本しか表示されない。Mongolian Baiti の仕様通りの振る舞い。

まとめると、意外とうまくいっている。問題は2点。U+200D ZERO WIDTH JOINER を処理していないことと制御文字をそのまま表示していること。複雑な規則は font に書いてある。text rendering 側でやるべきことは多くない。font を作るのは本当に大変そう。一応は表音文字なのに。

そういえば、禁則処理とかはどうなっているのだろうか。

2012年10月9日追記: ブログ記事によると、Linux の Firefox がようやくモンゴル文字サポートの入った Harfbuzz を使うようになったとのこと。ひとまずめでたい。まあ一番の問題はフォントなわけだが。