iPhoneでのTrueTypeフォント縦書き処理がようやく25%くらいできたので、中間報告めいた感じで。半分もいってないのに中間…!

iPhoneでフォントを扱う場合、部長は CGFontRef を使ってます。他にUIFontというクラスがありますが…ttfファイルを読み込んで描画という場合はCGFontRefを使うんじゃなかろうかと。どーなの?

で、こんな感じで実装を進めとりますが、縦書きの場合は括弧や句読点をそのまま表示するとおかしな事になるので、ソフト側で90度回転したり専用処理で対応する必要がある。で、フォントによっては縦書き用のデータ(グリフ)を持ってる場合があるので、自前でデータにアクセスしてデータを引っ張り出す訳だ。

iPhoneでの実装はこんな感じになるのかな?
CGFontRef fontRef;               // あらかじめ初期化済み

CFDataRef gsubTable = CGFontCopyTableForTag(fontRef, 'GSUB');
if(gsubTable)
{
    // GSUBテーブルからデータを引き出す
}
else
{
    CFDataRef mortTable = CGFontCopyTableForTag(fontRef, 'mort');
    if(mortTable)
    {
        // mortテーブルからデータを引き出す
    }
}

iPhoneでもフォントデータの内部にアクセスするAPIが用意されてて楽。TrueType(OpenType)フォントの仕様を斜め読みでよいので頑張って読んどくと吉なんじゃないかと。ネットで見つかるのはほぼ…ていうか99.9%英文だけどね!日本語での文献があるならぜひ教えて欲しいくらいです。

実際のデータにアクセスする場合、まず以下のようにしてデータポインタを取得。
const UInt8* const bytes = CFDataGetBytePtr(gsubTable);

「const UInt8* const」ってとこがミソ。なんでかはココを読んどいてちょ。

あとは各型にあわせたAPIがあるのでそれを使う。
UInt16 value16 = OSReadBigInt16(bytes, 0);
UInt32 value32 = OSReadBigInt32(bytes, 2);

みたいな。エンディアン依存のデータの読み書きも、APIを知ってしまえば気持ちがかなり楽になる。特に部長、こなへんあやふやなんで…(汗)

で、最初に試したフォントはGSUBが無くてmortがあるタイプだったのでココを参考に実装をしてみた。だいたいこんな感じ。
NSMutableDictionary *subGlyph = [[NSMutableDictionary alloc] init];
const UInt8* const bytes = CFDataGetBytePtr(mortTable);
int num = OSReadBigInt16(bytes, 68);
for(int i = 0; i < num; i++)
{
    unichar glyph = OSReadBigInt16(bytes, 76 + i * 4);
    unichar chg = OSReadBigInt16(bytes, 78 + i * 4);
    [subGlyph setObject:[NSNumber numberWithInt:chg] forKey:[NSNumber numberWithInt:glyph]];
}

資料ナナメ読みの汚いコードですが…実際に検証するならこんな感じでオッケィ。mortテーブルには、(必要なぶんだけ)縦書きグリフへの変換テーブルが格納されとるので、変換元のグリフ値をキー値にして変換先のグリフ値をNSDictionaryを作ればよい。

あとは実際の表示の時にでも、
CGGlyph glyph;     // 描画しようとしてるグリフ値

NSNumber *number = [subGlyph objectForKey:[NSNumber numberWithInt:glyph]];
if(number != nil) glyph = [number intValue];

こうして縦書き用のグリフ値に変換してやればよろし。ただし、全てのグリフ値に対して縦書き用のグリフ値が用意されとる訳ではないのに注意。

photo01んで、実際に表示してみたのがこの画像。見事、括弧とか句読点が縦書き用のグリフになりました。悪くないでしょ?

「飛ばす」ボタンはアレです。実装しとるのはゲーム向け処理で、一文字ずつ表示しとるのを、一気に表示させる機能。

ちなみに半角文字って、自分で90度回転させなきゃならんのかしらん?とりあえずGSUBに対応させてから考えよう…。