[61] GSUB
はグリフの置き換えを、
GPOS
はグリフの位置調整に関する情報を記述する
OpenType フォントの表です。
[104]
JSTF
は justification のためのグリフの置き換えや位置調整に関する情報を記述する
OpenType フォントの表です。
[5]
GSUB
にはグリフの置き換えのための対応表データが入っていて、
GPOS
にはグリフの利用に関係する座標等のデータが入っています。
[4]
GSUB
,
GPOS
とも似たような構造になっています。
末端のデータ等細部が微妙に違っているので注意が必要です。
[62] どちらも、 まず対象となる用字系と言語系について、 それに関わる機能がいくつかあって、 機能における lookup がいくつかあり、 その lookup に条件と処理が書かれているという構造です。
[105]
JSTF
は対象となる用字系と言語系について、
適用可能な調整がいくつかあるという構造です。
JSTF
も
lookup を参照したり、含めたりできますが、
GSUB
や GPOS
とは構造が違います。
[58] 表示処理全体の中での位置は文字のレンダリング参照。
[85]
GSUB
の
lookup の条件に一致した場合はグリフ(列)をグリフ(列)に置き換えることになります。
このときどれがどれに変化したかはある程度追跡できる
(元のグリフ(列)を得た大元の文字列との対応関係を知れる)
必要があります。
[81]
GPOS
の
lookup の条件に一致した場合に行うべき処理や
JstfMax lookup の解釈は、
グリフ位置決定を参照。
[159]
shaping において連なりに分割してから処理されるために、
用字系が違うと
GSUB
が適用されないことがあるようです。
[8]
GSUB
表,
GPOS
表は用字系や言語系に対して適用可能な機能を記述できます。
[59] 機能に対して、実施されるべき操作を lookup として記述できます。
[46]
GSUB
表,
GPOS
表には同じタグの機能を複数個含められます。
用字系や言語系に対してどの機能を適用するかを選択できますから、
同じ機能でも用字系と言語系に合わせて違う lookup
が適用されるようにできます。
[144] lookup にはグリフ列の一部分について一致するかしないかの条件と、 一致した場合に行うグリフ(列)置換またはグリフの位置調整を記述できます。
[145]
GSUB
表と GPOS
表では、
それぞれの LookupList
内に任意個含められます。
>>103
[146] LookupList
中の lookup の出現順序 (索引) は、
... に使われます。
[151]
JSTF
表では、
各提案に行を長くする用と短くする用で各1つまで含められます。
>>103
[152]
同じ lookup と呼ばれますが、
GSUB
表ではグリフ(列)の置換の記述のため、
GPOS
表ではグリフの位置調整の記述のため、
と少し構造が違います。
一致条件の部分が同じような意味、同じような構造でも、
lookupType
が両者で違っています。
[63]
GSUB
や GPOS
を適用するには、
用字系, 言語系, 機能から利用する
lookup
を決定します。
[64]
複数の lookup を適用する場合、
適用順序は
LookupList
の出現順とします。
>>12, >>67, >>1
1つの
lookup
でグリフ列を先頭から末尾まで処理し、
次の
lookup
へと進みます。
>>67, >>1
ただし
GSUB
lookupType
8
はグリフ列の末尾から先頭に向かって処理します。
>>1
[65]
フォント開発者は、
複数の機能を同時適用するときの相互作用を考慮して
LookupList
中の lookup の順序を決められます。
1つの機能に複数の lookup
を結びつけることが出来ますから、
サンドイッチ式の適用も記述できます。
[68] 同時に複数の機能を適用する場合、 それらの lookup の和集合を使います。 >>67 つまり重複した lookup があるときは、1回分だけ適用されます。
[69] なお、機能ごとに異なる部分グリフ列にのみ適用することができます。 >>67
[70] 同じ lookup で異なる部分グリフ列に適用されるべきときはどうなるのでしょう。 適用対象のグリフも和集合になるのでしょうか。
[78] lookup には、 一致条件 (と一致時の挙動) を記述する部分表を1個以上含められます。 >>77, >>1
[79]
各部分表はいくつかの種類があって、
substFormat
や
posFormat
によって区別されます。
どの形式によるかは記述方法の違いによるストレージ効率で選べます。
部分表ごとに違う形式も選べるので、
都合に応じて区分できます。
>>77, >>1
部分表の構成の違いは lookup の挙動には直接影響しません。
[80] とある入力が1つの lookup に含まれる複数の条件に一致することは、 明確には認められても禁止されてもいないようです。 その場合の挙動も不明です。 どんな入力にも高々1回だけ一致するようにするべきと思われます。
[13] lookup
は,
lookupType
と
substFormat
にもよりますが、
グリフの列の一致条件を3通り記述できます。すなわち、
[14] 入力のグリフ列は、指定された処理が施される対象となります。
[15] 後戻りは入力の直前、 先読みは入力の直後にあるべきグリフ列で、 一致するかどうかの判断には使いますが、 処理の対象にはなりません。
[16] 一致した場合、入力の次のグリフに進んで一致するかどうかの検査を繰り返します >>67, >>77。 先読み列があれば、その先頭からということになります。
[17]
ただし、
GPOS
の lookupType
2
は2つのグリフの組に対して値を設定するもので、
常に2つのグリフが入力となるのですが、
第2グリフに与えられた値がないときには、
その次の処理の入力は前の処理の第2グリフからとなります。
>>67, >>72, >>77
[71] 先読みと後戻りが一致するグリフは、 機能の適用対象となるグリフでなくても構いません。 >>67
[19]
入力の第2のグリフ以降先読みの最後のグリフまでの各グリフの前、
あるいは後戻りの各グリフの後には、
特定の種類のグリフがあったとしても、
一致判定においては無視する場合があります。
その条件は
lookup
の
lookupFlag
で記述されます。
lookupFlag
の
IGNORE_BASE_GLYPHS
(ビット1)
が指定されている場合、
GDEF
表のグリフ級定義で 1 (基底) とされたグリフは無視します。
>>1lookupFlag
の
IGNORE_LIGATURES
(ビット2)
が指定されている場合、
GDEF
表のグリフ級定義で 2 (合字) とされたグリフは無視します。
>>1lookupFlag
の
IGNORE_MARKS
(ビット3)
が指定されている場合、
GDEF
表のグリフ級定義で 3 (マーク) とされたグリフは無視します。
>>1lookupFlag
の
IGNORE_MARKS
が指定されていない場合、lookupFlag
の
USE_MARK_FILTERING_SET
(ビット4)
が指定されている場合、
lookup の markFilteringSet
を参照します。
>>1lookupFlag
の
USE_MARK_FILTERING_SET
が指定されていない場合、[34] マーク系の機能が3つあります。 アラビア文字のように前後の文字との位置関係によってグリフを変化させつつ、 主たるグリフに付随するマークは合字化の判定で適宜無視したりしなかったり、 といった条件を記述するために用意されているようです。
[35] マーク添付級とマークグリフ集合は似たような機能ですが、 マークグリフ集合の方が記述能力が高い (複雑) です。 マークグリフ集合の方が後から追加された機能です。 マーク添付級だけでは不十分ということで追加されたのでしょうか。
[36]
グリフ級に基づく無視は
GSUB
lookupType
6 と共にしばしば使われているようです。
lookupType
6
では一致した入力列に更に他の lookup
を適用することになりますが、
このとき入力列の何番目の位置のグリフであるかに依存して適用する
lookup
を決めます
(seqLookupRecords
)。
何番目であるかには、無視されたグリフを算入しません。
従って無視されたグリフの有無でどの lookup がどのグリフに適用されるかは変化しませんし、
無視されたグリフには lookup が適用されません。
ただし一致した入力列のグリフに対して lookup
を適用するときに、その lookup が前後の条件を記述していれば、
無視されたグリフの有無がその結果に影響を与える可能性はあります。
[37]
GSUB
lookupType
4 (複数のグリフの列から1つの合字への置き換え)
での利用も禁止されているわけではありませんが、
その意味するところは定かではありません。
無視して読み飛ばしたグリフも含めて入力列の全体が置き換えられるべきなのでしょうか?
[54]
GPOS
lookupType
2 (グリフの組に対する位置調整)
での利用も禁止されているわけではありませんが、
どう適用されるべきなのか明確ではありません。
第1グリフは適用対象のグリフの範囲が指定されますが、
第2グリフは任意(すべて)のグリフが対象となり得ますから、
読み飛ばしとの相互作用をどうするべきか、
処理結果にいくつかの解釈が存在し得ます。
[56]
GPOS
lookupType
4, 5, 6
は付加するマークグリフと基底グリフ, 合字グリフ,
基底となるマークグリフとの位置関係を調整するものです。
入力は付加しようとするマークグリフです >>77。
GPOS
lookupType
4
(Mark-to-Base Attachment Positioning, MarkBasePos)
では、
マークグリフに対し、
グリフ列を遡って基底グリフを探さなければなりません。
>>77GPOS
lookupType
5
(Mark-to-Ligature Attachment Positioning, MarkLigPos)
では、
マークグリフに対し、
グリフ列を遡って合字グリフを探さなければなりません。
>>77GPOS
lookupType
6
(Mark-to-Mark Attachment Positioning, MarkMarkPos)
では、
付加するマークグリフ mark1 に対し、
グリフ列を遡って基底となるマークグリフ mark2
を探します。
>>77[88]
6 では lookupFlag
に応じてマークグリフ mark2 を探します。
>>77
[87] 4 と 5 も読み飛ばしとの相互作用がどう扱われるのが想定される挙動なのか不明瞭です。
[31]
入力列,
先読み列,
後戻り列として指定できるグリフの列の長さ (グリフの数)
には上限が規定されていません。
表に於いて個数を表す値が uint16
なので、
216 - 1 が構造上の上限となります。
無視して読み飛ばすグリフの個数にも上限が規定されていません。
[32] 実際の自然言語の記述に使うためのフォントでそこまで長いものが必要にはなり得ませんから、 それよりずっと小さな、しかし十分大きな個数で探索を打ち切るような実装が普通でしょうし、 それをしないで杜撰に実装するとセキュリティーの問題にもなり得ます。
[33] 実際上どれくらいの長さが必要なのでしょうかね。 16個では少し心もとない気がします。 128個だと過大な気がします。
[51]
GSUB
lookupType
5 は lookupType
6 に容易に書き換えられるようです。
5 の利用例が少ないのは 5 の機能では不十分な場合が多いのでしょう。
[55]
GPOS
はカーニングで
2
が使われていることが多いようです。
GPOS
lookupType
1, 2 しか対応していない実装もあります。
[47] lookup は機能から参照されて適用されるものと、 他の lookup から参照されるものとがあります。
[48]
入れ子の lookup は
GSUB
lookupType
1 が多いですが、
2 の例もあります。
[49]
仕様書には入れ子にできる lookupType
の制限は特にないようですが、
どれも適用できるのか不安感はあります。
[52]
GSUB
lookupType
4, substFormat
1
を使った事例があります。
このとき入力の複数の隣接したグリフが合字化された1つのグリフに置き換えられることがあります。
[53]
もしその場合に入力列側で無視されるグリフが間に挟まっていたらどう処理されるべきなのか、
入れ子の lookup で使われる sequenceIndex
が指すのが合字化により消失するグリフのときどう処理されるべきなのか、
よくわかりません。
[50]
実装によっては
GSUB
lookupType
1, substFormat
2
しか対応していないこともあるようです。
[57] 入れ子の lookup と >>17 の挙動の関係も若干不明瞭です。 入れ子の lookup でも適用される旨が仕様書には書かれている >>72 のですが、どういうイメージなのでしょう。
[74] 入れ子を二重以上深くできるのか不明です。仕様書では特に禁止はしていませんが。
[154]
JstfMax lookup は GPOS
lookup の lookupType
のうち contextual positioning lookups 以外を使えます。 >>103
つまり入れ子に lookup するものは認められていないようです。
(指定された場合にどう処理するべきなのかは不明。)
[6]
GSUB
,
GPOS
とも必須の表ではなく、
不要なフォントには入っていません。
どちらかだけのフォントもあります。
[7]
といっても使わないで済むのは欧米や東アジアの昔ながらの簡易的な表示に使うフォントくらいのものです。
それ以外の地域で使われる文字の多くは
GSUB
や GPOS
の機能が必要です。
欧米や東アジアの文字も、カーニングや縦書きや合字など、
高品質
(現在の計算機環境では標準的に実現されているレベルも含む。)
な文字のレンダリングにはそうした機能が必要となります。
GSUB
代替グリフの選択[90]
GSUB
の lookup (群) を適応する処理は、
原則的に入力が1つのグリフ列、
出力も1つのグリフ列です。
[91]
ただし一部の lookupType
(を使う一部の機能)
は、 GSUB
lookup の適用結果に複数の候補を示すことが出来ます。
[92] 複数の結果になるのが最後の lookup なら複数通りの最終出力の可能性があり得ますし、 最後でない lookup ならそれ以降の lookup で最終出力の違いが更に広がっていく可能性があります。 1つのグリフ列中にそのような箇所が複数あれば、 最終出力はそれぞれの選択のすべての組合せ分あり得ることになります。
[94] OpenType 仕様書の機能タグ登録簿の記述によれば、 そうした機能は DTP ソフトウェアの編集画面などにグリフごとに他の選択肢を表示して、 利用者に適切なものを選ばせることが想定されているようです。
[95] 1度限りの印刷なら選んで終わりで済みますが、 情報交換や長期保存のためには選択結果を恒久的に固定する方法が必要となります。
[99] どちらもフォントの改訂などで構造が変わってしまうと指していたグリフが変わってしまうリスクはあります。 もっともフォントの改訂はどのグリフも前のものとの「同一性」が保たれる保証はないので、 あまり気にしても仕方がないかもしれません。互換性を気にするフォント開発者なら気を使ってくれるはずです。 それが期待できないならフォントを埋め込むなど、 利用フォント含め転送・保存するしかありません。
[155] IllustratorとInDesignでaaltのルールが異なる件 - 帰ってきた💫Unicode刑事〔デカ〕リターンズ, https://moji-memo.hatenablog.jp/entry/20070720/1184917140
Illustratorの「aalt 0」って、InDesignで言うところの「aalt 1」(CID順で1番目の異体字)のことだと思うのだが、なぜ別のルールを採用しているのだろう。
JSTF
の調整[106] justification は期待される行長と実際の行の内容の長さの関係を調整する処理です。 グリフ間のスペース量を加減したり、グリフを合字グリフに置き換えたりします。
[107]
JSTF
にはそのフォントに適した調整方法と調整量の提案を何段階かに分けて記述できます
>>103。
文字のレンダリングの際にはこれを参照してそのフォントに適した
justification を実装できます。
OpenType は具体的な justification の手法までは規定していません。
行長をもっと減らしたいとき、増やしたいときにどのグリフをどうすればいいかを取得できますが、
もっと増やしたい、減らしたいという判断は別途行わないといけません。
[108]
JSTF
には、 用字系と言語系に対して、
適用可能な提案のリストが含まれます。
リスト中の各提案は、 priority level (影響の小さい順、「悪くない」順)
に並べて格納します。
適用時には、初めの提案から順に必要な提案まで適用していきます。
>>103
[126] 各提案には次のデータを含められます。 >>103
GSUB
で有効にする lookup 群GSUB
で無効にする lookup 群GPOS
で有効にする lookup 群GPOS
で無効にする lookup 群GSUB
で有効にする lookup 群GSUB
で無効にする lookup 群GPOS
で有効にする lookup 群GPOS
で無効にする lookup 群[135] GSUB
や GPOS
の lookup は、
それぞれの表 の LookupList
におけるindexにより指定します。
>>103
[143]
JstfMax lookup (justify lookup) は
JSTF
表に直接記述します。
>>103
[111] 提案を適用した調整は、次のようにします。 >>103
[125] 実際には1つの行はフォントや書字方向が違う複数の連なりで構成されているかもしれませんし、 機能はすべて同時に適用するのではなく shaping 過程で複数回に分けて適用されたり、グリフ列の一部分のみに適用されたりするのでしょうから、 ここに示した手順群がそのまま実行できるとは限りません。 追い込みや追い出しのため連なりを再構成する場合もあるかもしれません。 HTML の子要素が行内の箱になって含まれる場合のように、 連なり以外のオブジェクトが行に入っていること、 そのオブジェクト内部の構造も再構成に影響してくることがあります。
[161]
実際の手順群の構成は shaping の設計や justification
周りのアルゴリズムに依存します。
しかし JSTF
の指定の適用に関わる部分だけを眺めれば、
およそこのような手順群に要約できるものと考えられます。
[153] JstfMax lookup で設定された値の利用についてはグリフ位置決定を参照。
[109]
JSTF
には用字系ごとに拡張子グリフのリストも指定できます。
justification の処理では各提案の他にこのグリフも使えます。
>>103
[10] 各 feature の利用例は font feature 参照。
[9]
Nishiki-teki
は
GSUB
,
GPOS
ともに
script
が多数あって、
langSysRecords
をも複数使っています。
また
GSUB
,
GPOS
ともに同じ feature tag の別の feature list item があります。
[45] >>42
GSUB
1, 2; 3, 1
GPOS
1, 1; 1, 2; 9, 1 (2, 1)
[44] โครงการอักษรอีสาน, , https://linux.thai.net/~thep/esaan-scripts/
GSUB
2, 1; 4, 1; 5, 2; 6, 1; 6, 2
(入れ子の lookup が 2, 1; 4, 1)
GPOS
4, 1; 6, 1
[41] Ken Lunde 小林剣さんはTwitterを使っています: 「Rendering 김일성, 김정일 & 김정은 via the #OpenType 'ccmp' GSUB feature using chaining contextual substitutions. 🇰🇵 🤔 #KPS9566 #UTC154 @DPRK_News https://t.co/Fi41NOsWsQ」 / Twitter, 午前11:42 · 2018年1月7日 , https://twitter.com/ken_lunde/status/949833681354375168
[157] 正確實現簡轉繁字型, 三日月綾香, , https://ayaka.shn.hk/s2tfont/hant/
[158] >>157 簡体字から繁体字への変換に GSUB
+ trad
を使う。
[160] Yu Gothic UIに text-spacing-trim を適用するとバグる, https://zenn.dev/inaniwaudon/scraps/f224417d4c51ee
[166] フォントでTUT-Code - にせねこメモ, https://nixeneko.hatenablog.com/entry/2015/12/03/000000
[11] opentype-layout/proposals at master · OpenType/opentype-layout · GitHub, https://github.com/OpenType/opentype-layout/tree/master/proposals
[38] Spec for Thai OpenType Creation, , https://linux.thai.net/~thep/th-otf/
[3] GSUB テーブル (1) - ScriptList, https://aznote.jakou.com/prog/opentype/17_gsub1.html
[164] OpenTypeフォントでFizzBuzz(その2) - にせねこメモ, https://nixeneko.hatenablog.com/entry/2015/05/10/234628