JIS X0213:2004フォントを読む
id:korakurider/20071018/p1 では、Squeak でIPAフォントの JISX0213:2004準拠のものを開こうとして、現在のSqueakでは実装されていないデータ構造であることがわかりました。Windows XPでは 従来のJIS X0208のフォントを使えばよかったわけですが、Windows Vistaの場合はMS明朝なども含めて標準のフォントが JISX0213:2004となっており、JIS X0208のフォントは改めて追加インストールしなければなりません。つまりVista上では現状のSqueakでTrueTypeフォントを使うことが敷居が高いということです。
(http://www.apple.com/jp/macosx/features/japanese.html によれば、新しいMacXではヒラギノを JIS X0208と JISX0213:2004両方使い分けられるようなので、こんな問題は起きなさそうですね)
だいそれたことはできないと思いますが、とりあえずIPAフォントをSqueakで読み込めないか調べていきます。
まずは、ひっかかっているCMAPテーブルを読んでみます。
フォント構造の仕様書
TrueTypeフォントの技術情報については、Microsoft Typography groupのサイトが詳しいです。 http://www.microsoft.com/typography/default.mspx
(正確には OpenTypeの)フォント構造の仕様は、http://www.microsoft.com/typography/otspec/default.htm に公開されています。今回問題になったCMAPテーブルの構造は、http://www.microsoft.com/typography/otspec/cmap.htm にあります。
ツール
本当に正しく読み込めているか確認するのに、フォント構造をダンプするツールが必要です。前述の MSのサイトに、いくつかツールが公開されていますが、その中の ttfdump というものが使えそうです。http://www.microsoft.com/typography/tools/tools.aspx
たとえば、以下を実行すると CMAPテーブルの内容を解析して表示してくれます。
ttfdump c:\windows\fonts\ipam.ttf -tcmap
CMAPの解読コードを書く
エラーが起きる過程をデバッガで追いかけると、TTCFontReader>>decodeCMapFmtTable: で、フォーマット12(Segmented Coverage 32bit)という形式のテーブルを処理できないために起こっていることがわかりました。フォント構造の仕様書をもとに読み込むコードを書いて見ます。
!TTCFontReader methodsFor: 'as yet unclassified' stamp: 'KR 10/19/2007 20:25'! decodeCmapFmtTable: entry | cmapFmt length cmap firstCode entryCount segCount segments offset code | cmapFmt _ entry nextUShort. ((cmapFmt = 0) or: [cmapFmt = 4] or: [cmapFmt = 6]) ifTrue: [ length _ entry nextUShort. entry skip: 2. "skip version"] ifFalse: [ entry skip: 2. "reserved" length _ entry nextULong. entry skip: 4. "language" ]. cmapFmt = 0 ifTrue: "byte encoded table" (既存コードと同じなので中略) cmapFmt = 4 ifTrue: "segment mapping to deltavalues" (既存コードと同じなので中略) cmapFmt = 6 ifTrue: "trimmed table" (既存コードと同じなので中略) cmapFmt = 12 ifTrue: "segmented coverage" [|groupCount groups | groupCount _ entry nextULong. groups _ Array new: groupCount. groups _ (1 to: groupCount) collect: [:e | Array new: 3]. 1 to: groupCount do: [:i | (groups at: i) at: 1 put: entry nextULong. "StartCharCode" (groups at: i) at: 2 put: entry nextULong. "endCharCode" (groups at: i) at: 3 put: entry nextULong. "startGlyphID" ]. groups inspect. self halt. "とりあえず読み込むところまで" ]. ^ nil! !
これで読み込んだ結果は、さきほどのttfdumpで表示した内容と一致することが確認できました。
Squeakでサポートするには?
JIS X0213:2004ということは、0xFFFF までのUCS-2の枠を超えて、UCS-4の文字コードを使うことになります。
実際、ttfdumpでIPAフォントのCMAPを見てみると、こんな感じです(抜粋)。
Char 0000FF9B -> Index 7444 Char 0000FF9C -> Index 7445 Char 0000FF9D -> Index 7446 Char 0000FF9E -> Index 7447 Char 0000FF9F -> Index 7448 9859. Char 0000FFE0 -> Index 82 Char 0000FFE1 -> Index 83 9860. Char 0000FFE2 -> Index 120 9861. Char 0000FFE3 -> Index 18 9862. Char 0000FFE4 -> Index 6965 9863. Char 0000FFE5 -> Index 80 9864. Char 0002000B -> Index 8202 9865. Char 00020089 -> Index 9460 9866. Char 000200A2 -> Index 9470 9867. Char 000200A4 -> Index 9473 9868. Char 000201A2 -> Index 9481 9869. Char 00020213 -> Index 9497 9870. Char 0002032B -> Index 9539 9871. Char 00020371 -> Index 9548 9872. Char 00020381 -> Index 9546 (中略) 10161. Char 0002A6B2 -> Index 11895
Squeakのフォント関係のオブジェクト構造を見てみると、UCS-2の16bitのコードをそのままテーブルのインデックスに使っていることがわかります。ですからまずUCS-4をサポートできるようにしなくてはなりません。ただし、上のダンプでもわかるように、UTF32のサイズのテーブルにしてしまうと、中身がすかすかになり非常にメモリ効率が悪いので、スパースなテーブル構造を考えないといけません。
ただ、仮にデータ構造ができたとしても、http://ja.wikipedia.org/wiki/JIS_X_0213 にも書かれているように、グリフ置換という特別な機能を実装しないと文字を表示できません。
freetype2のプラグインを作ればここまでできるかもしれませんが、あまりにも敷居が高すぎるので、当面現状のTrueType関係のオブジェクト構造はあまり変更しなくてよいよう、フォーマット12のcmapからUCS-2の範囲に限定したグリフを取り扱えるようにすることを目標としたいと思います。