GSUB テーブル
「GSUB テーブル」には、縦書きグリフへの変換や、合字への変換など、単一または複数のグリフを、別のグリフに置き換えるためのデータが格納されています。
グリフは、「グリフ ID からグリフ ID」への変換となります。
文字を描画する際は、以下の順番で処理を行っていきます。
GSUB テーブルは、それぞれのデータが細かいテーブルに分かれているため、目的のデータを取得するためには、少々手間が掛かります。
まずは、GSUB テーブルのフォーマットと、文字体系/言語の情報である「ScriptList テーブル」を説明します。
グリフは、「グリフ ID からグリフ ID」への変換となります。
文字を描画する際は、以下の順番で処理を行っていきます。
- cmap で文字コードからグリフ ID を取得
- GSUB でグリフを置き換え
- GPOS で位置を調整
GSUB テーブルは、それぞれのデータが細かいテーブルに分かれているため、目的のデータを取得するためには、少々手間が掛かります。
まずは、GSUB テーブルのフォーマットと、文字体系/言語の情報である「ScriptList テーブル」を説明します。
テーブルデータ
uint16 majorVersion | メジャーバージョン = 1 |
---|---|
uint16 minorVersion | マイナーバージョン = 0 or 1 |
Offset16 scriptListOffset | ScriptList テーブルへのオフセット位置。 (GSUB の先頭を 0 とする) |
Offset16 featureListOffset | FeatureList テーブルへのオフセット位置 |
Offset16 lookupListOffset | LookupList テーブルへのオフセット位置 |
ver 1.1 の場合、以下が続く | |
Offset32 featureVariationsOffset | FeatureVariations テーブルへのオフセット位置 |
各テーブルの説明
ScriptList | 文字体系や言語の情報がある。 各言語ごとに、必要となる FeatureList のインデックス番号を取得するためのテーブル。 |
---|---|
FeatureList | 縦書きや合字など、置き換えの種類ごとに、必要な LookupList のインデックス値が格納されている |
LookupList | 対象のグリフを検索して、置き換えるためのデータ |
FeatureVariations | 可変フォント用 |
ScriptList テーブル
ここには、フォントに含まれる文字体系や言語の情報が格納されています。
言語によって置き換えるグリフが異なる場合があるため、まずはここで文字体系や言語を検索し、選択します。
ただ、複数の言語の情報が格納されていたとしても、実際にはすべての言語で同じデータが得られる場合も多いです。
(CJK フォントなど、複数の言語のグリフが含まれているようなフォントは除く)
最終的に必要となるのは、「FeatureList のインデックス番号」です。
言語によって置き換えるグリフが異なる場合があるため、まずはここで文字体系や言語を検索し、選択します。
ただ、複数の言語の情報が格納されていたとしても、実際にはすべての言語で同じデータが得られる場合も多いです。
(CJK フォントなど、複数の言語のグリフが含まれているようなフォントは除く)
ScriptList
uint16 scriptCount | 配列の数 |
---|---|
ScriptRecord scriptRecords[scriptCount] | ScriptRecord の配列。 scriptTag のアルファベット順に並んでいる。 |
ScriptRecord
Tag scriptTag | 文字体系の識別子。 タグ一覧は、OpenType 仕様書の 「OpenType Layout Tag Registry」>「Script tags」にあります。 'DFLT' = デフォルト 'latn' = ローマ字 'hani' = CJK (中国語/日本語/韓国語) 'kana' = ひらがな/カタカナ 'cyrl' = キリル文字 'grek' = ギリシャ文字 |
---|---|
Offset16 scriptOffset | Script テーブルへのオフセット位置。 (ScriptList の先頭を 0 とする) |
Script
Offset16 defaultLangSys | デフォルトの LangSys テーブルへのオフセット位置。 (Script の先頭を 0 とする) 0 の場合あり。 LangSysRecord に当てはまる言語がない場合や、言語による動作の違いがない場合に使う。 |
---|---|
uint16 langSysCount | 配列の数 (defaultLangSys は除く)。 言語固有の動作がない場合は、0。 |
LangSysRecord langSysRecords[langSysCount] | LangSysRecord の配列。 langSysTag のアルファベット順に並んでいる。 |
LangSysRecord
Tag langSysTag | 言語の識別子。 タグ一覧は、仕様書の「Language tags」にあります。 「3文字+スペース」の形となっています。 'JAN ' = 日本語 |
---|---|
Offset16 langSysOffset | LangSys テーブルへのオフセット位置。 (Script の先頭を 0 とする) |
LangSys
Offset16 lookupOrder | 0 (予約) |
---|---|
uint16 requiredFeatureIndex | この言語システムに必須な FeatureList のインデックス。 必要なければ 0xFFFF。 |
uint16 featureIndexCount | 配列の数 (requiredFeatureIndex は除く) |
uint16 featureIndices[featureIndexCount] | FeatureList テーブルのインデックス番号 (0〜) の配列。 任意の順番で並んでいる。 |
最終的に必要となるのは、「FeatureList のインデックス番号」です。
プログラム
>> 17_gsub_script.c
GSUB の ScriptList の一覧を表示するプログラムです。
(いずれもなければ「DFLT」)
いくつかの日本語フォントを見てみたところ、基本的に上記の2つが存在する場合が多いですが、「kana」しかない場合や、「DFLT」がないものもありました。
[1] 使用したい文字体系を元に検索
ScriptRecord から、scriptTag が「'kana' か 'hani'」、なければ「DFLT」のデータを探します。
「DFLT」もない場合は、「latn」か、先頭のデータを選択します。
[2] LangSys テーブルを選択
LangSysRecord の langSysTag が「'JAN '」のデータを選択します。
LangSysRecord が存在しない、または目的のタグが存在しない場合は、defaultLangSys の位置のデータを使います。
[3] FeatureList のインデックス値を取得
LangSys テーブルにある、FeatureList のインデックス値を取得します。
この値を使って、FeatureList テーブル内を参照することになります。
GSUB の ScriptList の一覧を表示するプログラムです。
---- GSUB ---- version: 1.0 scriptListOffset: 10 featureListOffset: 1746 lookupListOffset: 9824 ---- Script List ---- scriptCount: 7 == ScriptRecord [0] == scriptTag: 'DFLT' scriptOffset: 44 ** Script ** defaultLangSys: 4 langSysCount: 0 <LangSys> [default] requiredFeatureIndex: 65535 featureIndexCount: 16 featureIndices: 0,37,74,111,148,185,222,259,296,333,370,442,479,516,555,594, ...
日本語フォント
日本語を対象としたい場合は、ScriptRecord の scriptTag が「kana」または「hani」のデータを使います。(いずれもなければ「DFLT」)
いくつかの日本語フォントを見てみたところ、基本的に上記の2つが存在する場合が多いですが、「kana」しかない場合や、「DFLT」がないものもありました。
実際の使い方
日本語を扱いたい場合の手順は、以下のようになります。[1] 使用したい文字体系を元に検索
ScriptRecord から、scriptTag が「'kana' か 'hani'」、なければ「DFLT」のデータを探します。
「DFLT」もない場合は、「latn」か、先頭のデータを選択します。
[2] LangSys テーブルを選択
LangSysRecord の langSysTag が「'JAN '」のデータを選択します。
LangSysRecord が存在しない、または目的のタグが存在しない場合は、defaultLangSys の位置のデータを使います。
[3] FeatureList のインデックス値を取得
LangSys テーブルにある、FeatureList のインデックス値を取得します。
この値を使って、FeatureList テーブル内を参照することになります。