先日からHarfBuzzとずっと格闘してる。
難しいけどコーディングはDEEPなのですごくエキサイティングだ。
結論からいうと、openframeworksにおいてのカーニングについてはHarfBuzzとFreeTypeの相性が抜群なので、
ofTrueTypeFontUC にちょっと手を加えるだけで 日本語のプロポーショナル(palt)については対応出来た。
やりたい機能である、混合フォントについては
bool loadSubFont(string filename,float sizeRate=1.0f, float baseLineRate=1.0f ,int unicodeRangeStart=0x0000,int unicodeRangeEnd=0x0000);
みたいな感じでサブフォントをunicodeレンジに対して追加できるようにしてみた。
unicodeレンジを指定しない場合は後で読み込まれたフォントで上書きするイメージ。
最初に日本語フォントを呼んで LATENフォントを読めば 対応文字のみ LATENフォントで表示ができる。
ついでにいうとこのクラスはTextureつくっちゃうのでオンスレッドで動作できないので
(アウトライン)パスをスレッドでガンガン呼び出して使いたいのでofImageに習ってbUseTextureみたいなフラグもつけた。
で、次はレンダリング時の改行制御だ。これについては、1つ外側のレベルの話だ。
ICUとかを導入するのが筋っぽいんだけど大げさすぎるので簡単に実装してみた。
(というかパス通し疲れた・・・)
各文字要素(クラスタ)に対して、こんなかんじで改行可能かどうかをマーキングしていく。
breakable=__CharsNotEOL.find(src[i])==string::npos &&
(isCJK(src[i])||(i<len-1?isCJK(src[i+1]):true)||__CharsBreakable.find(src[i])!=string::npos) &&
(i<len-1? __CharsNotSOL.find(src[i+1])==string::npos :true);
日本語にしてみると、
・行末禁則文字でない
かつ(&&)
・CJK文字である または(||) 次の文字がCJK文字である または(||) 区切り文字である
かつ(&&)
・次の文字が行頭禁則文字ではない
場合は改行可能(笑)
概ねこんなかんじだと思う。
後は禁則文字セットなどを充実しておけばわりとちゃんと動きそう。
マーキングだけしたら、実際の改行判断はレンダリング部分でやる(次回)。
どんどん日本語限定仕様になっていく気がするな・・・。
ちなみにちょっと手を加えれば縦書きに対応できる。
と、いろいろ順調だったんだけど、なんかharfbuzzのclusterが
ちょいちょいおかしい値を返してきて壮大に位置がずれるのである・・・。
調べたらどうやら ligature だ。これは盲点だった。
ちゃんとunicode文字コードで用意されてるんですねー。
hb_feature_tでligaをoffってみたらちゃんと(っていうか若干重なって)表示された。
が、全く美しくないので次はligatureに対応しなくてはならない。
レンダリング freetypeに依存しすぎ&合成フォントしてるしで大改修が必要である・・・。
\(^o^)/オワ・・・