GPOS テーブル
「GPOS テーブル」には、グリフの位置を調整するデータが格納されています。
構造的にはほぼ GSUB テーブルと同じで、LookupList のサブテーブルが GPOS 固有のフォーマットとなっています。
GSUB と同じです。
構造的にはほぼ GSUB テーブルと同じで、LookupList のサブテーブルが GPOS 固有のフォーマットとなっています。
テーブルデータ
uint16 majorVersion | メジャーバージョン = 1 |
---|---|
uint16 minorVersion | マイナーバージョン = 0 or 1 |
Offset16 scriptListOffset | ScriptList テーブルへのオフセット位置。 (GPOS テーブルの先頭を 0 とする) |
Offset16 featureListOffset | FeatureList テーブルへのオフセット位置 |
Offset16 lookupListOffset | LookupList テーブルへのオフセット位置 |
ver 1.1 の場合、以下が続く | |
Offset32 featureVariationsOffset | FeatureVariations テーブルへのオフセット位置。 0 の場合あり。 |
GSUB と同じです。
プログラム (1)
まずは ScriptList、FeatureList、LookupList の一覧を表示してみます。
>> 23a_gpos_list.c
Feature Tag には、GPOS 用のタグが設定されています。
(GSUB と GPOS の両方で使われるタグもあります)
>> 23a_gpos_list.c
... == 'hani' == <LangSys> [default] requiredFeatureIndex: 65535 (5,19,33,47,61,75,89,) -- LangSysRecord ['JAN '] -- <LangSys> requiredFeatureIndex: 65535 (6,20,34,48,62,76,90,) ... ---- FeatureList ---- [0] 'halt' | 2, [1] 'halt' | 2, .. [42] 'vert' | 0,1, .. [97] 'vpal' | 7, ---- LookupList ---- ==== [0] ==== {Lookup} lookupType <1> | lookupFlag:0x0000 | subTableCount:1 # {SubTable} format <1> ...
Feature Tag には、GPOS 用のタグが設定されています。
(GSUB と GPOS の両方で使われるタグもあります)
Feature Tag
GPOS で使われる主な Feature Tag は、以下の通りです。
vert | 縦書きグリフの配置 |
---|---|
halt | (横書き) 全角幅→半角幅 |
vhal | (縦書き) 全角高さ→半角高さ |
palt | (横書き) 等幅→プロポーショナル |
vpal | (縦書き) 等幅→プロポーショナル |
kern | (横書き) グリフ間の余白調整 |
vkrn | (縦書き) グリフ間の余白調整 |
mark | マークグリフの配置 |
mkmk | マークグリフを他のマークに対して配置 |
LookupType
GPOS では、LookupType の意味が GSUB とは異なります。
1 | Single adjustment | 単一グリフの位置調整 |
---|---|---|
2 | Pair adjustment | ペアグリフの位置調整 |
3 | Cursive attachment | cursive (筆記体) グリフの接続 |
4 | MarkToBase attachment | ベースグリフとマークグリフの接続 |
5 | MarkToLigature attachment | 合字グリフとマークグリフの接続 |
6 | MarkToMark attachment | マークグリフとマークグリフの接続 |
7 | Context positioning | コンテキストの1つ以上のグリフの配置 |
8 | Chained Context positioning | 連鎖したコンテキストの1つ以上のグリフの配置 |
9 | Extension positioning | Offset32 の位置にサブテーブルを置く |
プログラム (2)
先にプログラムの方を紹介しておきます。
各 LookupType のデータは以降で解説します。
>> 23b_gpos_type1.c
GPOS の LookupList から、LookupType 1・2・9 のデータを表示するプログラムです。
「output.txt」に出力します。
各 LookupType のデータは以降で解説します。
>> 23b_gpos_type1.c
GPOS の LookupList から、LookupType 1・2・9 のデータを表示するプログラムです。
「output.txt」に出力します。
共通テーブル
Lookup サブテーブルで使われる共通のテーブルデータです。
ValueRecord
グリフ位置を調整するためのデータです。
各項目はオプションであり、対応するフラグ (valueFormat) が ON の場合のみ、データが格納されています。
各項目はオプションであり、対応するフラグ (valueFormat) が ON の場合のみ、データが格納されています。
int16 xPlacement | bit 0 | x 位置の調整値 (デザイン単位) |
---|---|---|
int16 yPlacement | bit 1 | y 位置の調整値 |
int16 xAdvance | bit 2 | (水平レイアウト) advance の x 位置調整 |
int16 yAdvance | bit 3 | (垂直レイアウト) advance の y 位置調整 |
Offset16 xPlaDeviceOffset | bit 4 | (非可変フォント時) Device テーブルへのオフセット位置。 (可変フォント時) VariationIndex テーブルへのオフセット位置。 一つ上の親テーブルの先頭を 0 とする。 0 の場合あり。 |
Offset16 yPlaDeviceOffset | bit 5 | - |
Offset16 xAdvDeviceOffset | bit 6 | - |
Offset16 yAdvDeviceOffset | bit 7 | - |
Anchor
接続する位置の情報。
Format 1
uint16 anchorFormat | フォーマット番号 = 1 |
---|---|
int16 xCoordinate | x の値 (デザイン単位) |
int16 yCoordinate | y の値 (デザイン単位) |
Format 2
uint16 anchorFormat | フォーマット番号 = 2 |
---|---|
int16 xCoordinate | x の値 (デザイン単位) |
int16 yCoordinate | y の値 (デザイン単位) |
uint16 anchorPoint | 輪郭線の座標のインデックス |
Format 3
uint16 anchorFormat | フォーマット番号 = 3 |
---|---|
int16 xCoordinate | x の値 (デザイン単位) |
int16 yCoordinate | y の値 (デザイン単位) |
Offset16 xDeviceOffset | (非可変フォント時) Device テーブルへのオフセット位置。 (可変フォント時) VariationIndex テーブルへのオフセット位置。 Anchor テーブルの先頭を 0 とする。0 の場合あり。 |
Offset16 yDeviceOffset | Y 方向 |
LookupType 1 (単一グリフの調整)
LookupType 1 の場合の Lookup サブテーブルです。
単一のグリフの調整を行います。
サブテーブルのフォーマットは、2種類あります。
Coverage テーブルでグリフを検索し、ValueRecord の値で位置を調整します。
「halt」は、横書きにおいて、全角幅のグリフを半角幅に調整します。
かっこの場合は、左に余白があるため、xPlacement でグリフの x 位置を -500 し、xAdvance で、次のグリフへの x 移動距離を -500 します。
単一のグリフの調整を行います。
サブテーブルのフォーマットは、2種類あります。
Coverage テーブルでグリフを検索し、ValueRecord の値で位置を調整します。
Format 1
すべてのグリフに対して同じ値を使います。uint16 posFormat | フォーマット番号 = 1 |
---|---|
Offset16 coverageOffset | Coverage テーブルへのオフセット位置。 (サブテーブルの先頭を 0 とする) |
uint16 valueFormat | ValueRecord のフォーマットフラグ値 |
ValueRecord valueRecord | すべてのグリフに適用する調整値 |
Format 2
各グリフごとに ValueRecord が定義されています。uint16 posFormat | フォーマット番号 = 2 |
---|---|
Offset16 coverageOffset | Coverage テーブルへのオフセット位置 |
uint16 valueFormat | ValueRecord のフォーマットフラグ値 |
uint16 valueCount | 配列の数。 Coverage テーブルのグリフ数と一致している。 |
ValueRecord valueRecords[valueCount] | ValueRecord の配列 |
出力例
▼ 'halt' [1404] (〈) U+3008 [xPlacement:-500, xAdvance:-500, ] [1406] (《) U+300A [xPlacement:-500, xAdvance:-500, ] [1408] (「) U+300C [xPlacement:-500, xAdvance:-500, ] [1410] (『) U+300E [xPlacement:-500, xAdvance:-500, ] [1412] (【) U+3010 [xPlacement:-500, xAdvance:-500, ] .. [1397] (、) U+3001 [xAdvance:-500, ] [1398] (。) U+3002 [xAdvance:-500, ]
「halt」は、横書きにおいて、全角幅のグリフを半角幅に調整します。
かっこの場合は、左に余白があるため、xPlacement でグリフの x 位置を -500 し、xAdvance で、次のグリフへの x 移動距離を -500 します。
LookupType 2 (二つのグリフの位置調整) - format 1
LookupType 2 では、ペアとなる二つのグリフの調整を行います。
サブテーブルのフォーマットは、2種類あります。
まずは Format 1 から。
「kern」は、横書き用のカーニングです。
特定のペアの2文字が並んでいる場合、グリフ間の余白を調整します。
「/#」の2文字の場合は、「/」の幅を -21 します。
「//」の2文字の場合は、最初の「/」の幅を -82 します。
サブテーブルのフォーマットは、2種類あります。
まずは Format 1 から。
Format 1
Coverage テーブルでペアの最初のグリフを検索し、PairSet のリストから2番目のグリフを検索。
PairValueRecord の2つの ValueRecord で各グリフの位置を調整します。
▼ PairSet
▼ PairValueRecord
PairValueRecord の2つの ValueRecord で各グリフの位置を調整します。
uint16 posFormat | フォーマット番号 = 1 |
---|---|
Offset16 coverageOffset | Coverage テーブルへのオフセット位置。 ペアの最初のグリフを探すためのデータ。 |
uint16 valueFormat1 | 最初のグリフの ValueRecord フォーマットフラグ値。 0 の場合あり。 |
uint16 valueFormat2 | 2番目のグリフの ValueRecord フォーマットフラグ値。 0 の場合あり。 |
uint16 pairSetCount | 配列の数 |
Offset16 pairSetOffsets[pairSetCount] | PairSet テーブルへのオフセット位置。 (サブテーブルの先頭を 0 とする) ペアの最初のグリフの Coverage index に対応している。 ペアの最初のグリフに対応する、2番目のグリフと調整値のデータ。 |
▼ PairSet
uint16 pairValueCount | 配列の数 |
---|---|
PairValueRecord pairValueRecords[pairValueCount] | PairValueRecord の配列 |
▼ PairValueRecord
uint16 secondGlyph | ペアの2番目のグリフ ID |
---|---|
ValueRecord valueRecord1 | 最初のグリフの調整値 (フラグが 0 なら空) |
ValueRecord valueRecord2 | 2番目のグリフの調整値 (フラグが 0 なら空) |
出力例
▼ 'kern' [16] (/) U+002F + [4] (#) U+0023 (1)[xAdvance:-21, ] + [16] (/) U+002F (1)[xAdvance:-82, ] + [55] (V) U+0056 (1)[xAdvance:13, ] + [81] (p) U+0070 (1)[xAdvance:-19, ]
「kern」は、横書き用のカーニングです。
特定のペアの2文字が並んでいる場合、グリフ間の余白を調整します。
「/#」の2文字の場合は、「/」の幅を -21 します。
「//」の2文字の場合は、最初の「/」の幅を -82 します。
LookupType 2 - format 2
「LookupType 2」の「format 2」です。
少々複雑なので、format 1 とは分けました。
ペアとなる各グリフを任意のクラスに定義して、各クラスのグリフをペアとして適用させます。
▼ Class1Record
▼ Class2Record
少々複雑なので、format 1 とは分けました。
ペアとなる各グリフを任意のクラスに定義して、各クラスのグリフをペアとして適用させます。
Format 2
uint16 posFormat | フォーマット番号 = 2 |
---|---|
Offset16 coverageOffset | Coverage テーブルへのオフセット位置。 ペアの最初のグリフを探すためのデータ。 |
uint16 valueFormat1 | 最初のグリフの ValueRecord フォーマットフラグ値。 0 の場合あり。 |
uint16 valueFormat2 | 2番目のグリフの ValueRecord フォーマットフラグ値。 0 の場合あり。 |
Offset16 classDef1Offset | 最初のグリフの ClassDef テーブルへのオフセット位置。 (サブテーブルの先頭を 0 とする) ペアの最初の各グリフのクラスを定義する。 クラスが定義されていないグリフはすべて class = 0 とする。 |
Offset16 classDef2Offset | 2番目のグリフの ClassDef テーブルへのオフセット位置 |
uint16 class1Count | 最初のグリフのクラスの数 (class = 0 を含む)。 1〜9 のクラス番号が定義されていたら、10 となる。 |
uint16 class2Count | 2番目のグリフのクラスの数 (class = 0 を含む) |
Class1Record class1Records[class1Count] | Class1Record の配列。 ペアの最初の各クラスのデータ。 |
▼ Class1Record
Class2Record class2Records[class2Count] | Class2Record の配列。 ペアの2番目の各クラスのデータ。 |
---|
▼ Class2Record
ValueRecord valueRecord1 | 最初のグリフの ValueRecord。空の場合あり。 |
---|---|
ValueRecord valueRecord2 | 2番目のグリフの ValueRecord。空の場合あり。 |
ClassDef
GDEF でも使われるテーブルです。
指定された範囲のグリフを、指定したクラスに定義します。
クラス値は「1〜」の任意の数値で、クラスが定義されていないグリフは、すべて class = 0 となります。
▼ ClassRangeRecord
指定された範囲のグリフを、指定したクラスに定義します。
クラス値は「1〜」の任意の数値で、クラスが定義されていないグリフは、すべて class = 0 となります。
Format 1
「startGlyphID 〜 startGlyphID + glyphCount - 1」のグリフ ID に、クラス値の配列から値を割り当てます。uint16 classFormat | フォーマット番号 = 1 |
---|---|
uint16 startGlyphID | classValueArray の最初のグリフ ID |
uint16 glyphCount | 配列の数 |
uint16 classValueArray[glyphCount] | 各グリフの、クラス値の配列 |
Format 2
指定範囲のグリフ ID に、同じクラス値を割り当てます。uint16 classFormat | フォーマット番号 = 2 |
---|---|
uint16 classRangeCount | 配列の数 |
ClassRangeRecord classRangeRecords[classRangeCount] | ClassRangeRecord の配列。 startGlyphID の小さい順に並んでいる。 |
▼ ClassRangeRecord
uint16 startGlyphID | 範囲の最初のグリフ ID |
---|---|
uint16 endGlyphID | 範囲の最後のグリフ ID |
uint16 class | 範囲のグリフに適用されるクラス値 |
使い方
まず、Coverage テーブルから、ペアの最初のグリフを探します。
次に、classDef1Offset のオフセット位置にある ClassDef テーブルから、ペアの最初のグリフのクラス値を取得します。
Coverage テーブルに存在して、ClassDef テーブルに存在しないグリフの場合は、class = 0 となります。
なお、クラス値は、このサブテーブルでのみ意味のある値であり、任意の数字を設定することができます。
次に、classDef2Offset のオフセット位置にある ClassDef テーブルから、ペアの2番目のグリフを検索し、クラス値を取得します。
各グリフのクラス値を「class1」「class2」とした場合、
class1Records[class1] の位置の class2Records[class2] から、ValueRecord を取得します。
class1Records・class2Records の配列は、class = 0 のデータも含んでいるので、クラス値をそのまま添字として使います。
次に、classDef1Offset のオフセット位置にある ClassDef テーブルから、ペアの最初のグリフのクラス値を取得します。
Coverage テーブルに存在して、ClassDef テーブルに存在しないグリフの場合は、class = 0 となります。
なお、クラス値は、このサブテーブルでのみ意味のある値であり、任意の数字を設定することができます。
次に、classDef2Offset のオフセット位置にある ClassDef テーブルから、ペアの2番目のグリフを検索し、クラス値を取得します。
各グリフのクラス値を「class1」「class2」とした場合、
class1Records[class1] の位置の class2Records[class2] から、ValueRecord を取得します。
class1Records・class2Records の配列は、class = 0 のデータも含んでいるので、クラス値をそのまま添字として使います。
出力例
## Coverage ## [4] (#) U+0023 [7] (&) U+0026 [16] (/) U+002F [32] (?) U+003F [33] (@) U+0040 ... ## classDef1Offset: 39494 classDef2Offset: 39732 class1Count: 40 class2Count: 68 ## ClassDef 1 ## [4] (#) U+0023 <class 30> [7] (&) U+0026 <class 17> [16] (/) U+002F <class 35> [32] (?) U+003F <class 32> [33] (@) U+0040 <class 18> ... ## ClassDef 2 ## [3] (") U+0022 <class 14> [8] (') U+0027 <class 14> [9] (() U+0028 <class 11> [10] ()) U+0029 <class 12> [11] (*) U+002A <class 17> [13] (,) U+002C <class 36> [14] (‑) U+2011 <class 10> ... ## class1[0] + class2[0] | (1)[xAdvance:0, ] class1[0] + class2[1] | (1)[xAdvance:-63, ] class1[0] + class2[2] | (1)[xAdvance:-10, ] class1[0] + class2[3] | (1)[xAdvance:-38, ] class1[0] + class2[4] | (1)[xAdvance:-48, ]
LookupType 3 (cursive グリフの接続)
「LookupType 3」のサブテーブルのフォーマットは1つのみです。
アルファベットが流れるように繋がっている cursive (筆記体) フォントにおいて、
前のグリフの出口ポイントと、次のグリフの入口ポイントを接続させることで、グリフを繋げるためのデータです。
ただし、グリフ間の余白調整ならカーニングでも出来ますし、GPOS を使わないとグリフが繋がらないような設計だと、対応しているソフトウェアが限られてくるため、あまり実用的ではありません。
LookupType 3 を使っているフォントはあまりないと思うので、フォーマットのみ解説しておきます。
▼ EntryExitRecord
アルファベットが流れるように繋がっている cursive (筆記体) フォントにおいて、
前のグリフの出口ポイントと、次のグリフの入口ポイントを接続させることで、グリフを繋げるためのデータです。
ただし、グリフ間の余白調整ならカーニングでも出来ますし、GPOS を使わないとグリフが繋がらないような設計だと、対応しているソフトウェアが限られてくるため、あまり実用的ではありません。
LookupType 3 を使っているフォントはあまりないと思うので、フォーマットのみ解説しておきます。
uint16 posFormat | フォーマット番号 = 1 |
---|---|
Offset16 coverageOffset | Coverage テーブルへのオフセット位置 |
uint16 entryExitCount | 配列の数 |
EntryExitRecord entryExitRecord[entryExitCount] | EntryExitRecord の配列 |
▼ EntryExitRecord
Offset16 entryAnchorOffset | 入口の Anchor テーブルへのオフセット位置。 (サブテーブルの先頭を 0 とする) 0 の場合あり。 |
---|---|
Offset16 exitAnchorOffset | 出口の Anchor テーブルへのオフセット位置。 (サブテーブルの先頭を 0 とする) 0 の場合あり。 |
LookupType 9 (Offset32)
GSUB の LookupType 7 と同じで、サブテーブルを Offset32 の位置に置くためのデータです。
uint16 posFormat | フォーマット番号 = 1 |
---|---|
uint16 extensionLookupType | 実体の LookupType 値 |
Offset32 extensionOffset | 実体のサブテーブルへのオフセット位置。 (このサブテーブルの先頭を 0 とする) |