1. 496_

    Posted

    496_
Changes in title
+OpenTypeの仕様入門 (中編)
Changes in tags
Changes in body
Source | HTML | Preview

コードポイントからグリフIDを取得するまで

今回は、前回触れたOpenTypeフォントに含まれる代表的なテーブル、cmapについてお話しします。
こちらはすべてのOpenTypeフォントに含まれる必須の情報です。

cmap: Character to glyph mapping

cmapは文字コードのコードポイントをグリフID (GID) に変換するものです。
グリフというのはフォントの中に入ってる描画要素≒文字のことでした。

見つかったGIDに対応するグリフを描画することで、我々のディスプレイには正しい文字が表示されるのです。
もしここでコードポイントが見つからなければ、GIDが0のグリフが使用されます(.notdefと呼ばれることもあります)。
これはNotoフォントの名前の由来にもなった豆腐というやつですね。

cmapには複数の変換表が存在する

cmapには複数のマップ: 文字コード↦GIDが存在し得ます。
これは例えば、Shift_JIS↦GIDとUnicode↦GIDがある場合であったり、UnicodeだけだとしてもUCS-2↦GIDとUSC-4↦GIDが存在する場合であったりします。
ここで、

  • GID = [0,グリフ総数) ⊆ {0,1,...,65535},
  • UCS-2 ⊂ UTF-16 ⊂ UCS-4 = UTF32.

複数の変換表があるため、cmapの先頭には自身がいくつの変換表を持っているかという情報を持ちます。
そして、それぞれの変換表はplatformIDplatformSpecificID/encodingIDを持ちます。

  • platformID
    • Macintosh, Microsoft, Unicodeのどれか(すごいね)
  • platformSpecificID/encodingID
    • Unicodeのバージョンや符号化方式、文字コード

これの情報から自分の求める変換表を見つけ出し、その表に従ってコードポイントからGIDを取得します。
ここは仕様に唯々諾々と従うのみです。
今のフォントには多くの場合、Unicodeからの変換表があるので安心して大丈夫です。

cmapの変換表は基本的にはひとつのコードポイントからひとつのGIDへの変換になっています。
ただし、2つほど例外があります。

Format 13

これはひとつのコードポイント範囲からひとつのGIDへの変換になっています。
この変換表の主な用途はフォールバックフォントです。
つまり、他にそのコードポイントのグリフがない場合に、Unicodeの範囲ごとに異なるグリフを返すことができるようになります。
(どの言語のグリフなのかという程度の情報を人間に授けることができます)

Format 14

これはUnicode Variation Sequences (UVS) と呼ばれるもので、日本では異体字セレクタなどと呼ばれています。
これは漢字の後ろに異体字セレクタと呼ばれるUnicodeのコードポイントを置くことで、

  • 東京都葛󠄁飾区の葛󠄁
  • 奈良県葛󠄀城市の葛󠄀

といった字体の違いを表現することができます。
ここでは

  • 葛󠄁: 葛の後ろにU+E0101が続く
  • 葛󠄀: 葛の後ろにU+E0100が続く

というように1文字が漢字+異体字セレクタで構成されています。
あれ? ということはつまり、コードポイント2つがcmapで1つのグリフに変換されていますね。
(リガチャなどの合字とは違ってcmapのレベルで変換されているのが面白ポイントです。そしてリガチャの話はGSUBテーブルのところで説明します)

cmapのつらい制約

グリフIDの最大値は65535 ( = 2^16 - 1) です。
一方Unicodeのコードポイントの数は(定義されているかどうかは別にして)100万以上あります。
素晴らしいですね。
(はやく最大グリフ数が増える仕様が策定されないかなあ)

おわりに

フォントのグリフ数が65535個(.notdefを除く)という制約は思いの外厳しく、Source Hans Sansなどはそれをフルに埋めたことで話題になりました。

さて明日、明日こそOpenTypeの仕様入門を完結させます。
内容は、

  1. GSUBテーブル
    • 文字列からcmapで変換されたGID列をさらに別のGID列に変換する
  2. GPOSテーブル
    • グリフとグリフの位置関係をGIDベースで調整する

です。