BASE テーブル

BASE テーブル
「BASE テーブル」には、ベースラインの情報が格納されています。
また、各言語グリフごとの最小/最大範囲も含まれている場合があります。

異なる言語のグリフを同じ行に並べる時に、特定の言語のベースラインに合わせることができます。

また、この情報を使うことで、「仮想ボディ」と「平均字面」の枠を求めることができます。
ベースラインについて
フォントのグリフは、基本的に Y = 0 をベースラインとして座標が置かれているので、普通に描画する分には、BASE テーブルの情報は特に必要はありません。

DTP などで、特定のベースラインに合わせて文字を揃えたい場合などに使います。
テーブルデータ
uint16メジャーバージョン = 1
uint16マイナーバージョン = 0 or 1
Offset16 horizAxisOffset水平レイアウト用の Axis テーブルへのオフセット位置。
BASE テーブルの先頭を 0 とする。
データがない場合、0。
値はすべて Y 方向。
Offset16 vertAxisOffset垂直レイアウト用の Axis テーブルへのオフセット位置。
データがない場合、0。
値はすべて X 方向。
ver 1.1 の場合、以下が続く
Offset32 itemVarStoreOffsetItem Variation Store テーブルへのオフセット位置。
データがない場合、0。

Axis
Offset16 baseTagListOffsetBaseTagList テーブルへのオフセット位置。
Axis テーブルの先頭を 0 とする。
データがない場合、0。
Offset16 baseScriptListOffsetBaseScriptList テーブルへのオフセット位置

BaseTagList
フォントのすべてのベースラインの識別子。

uint16 baseTagCountタグの数。0 の場合あり。
Tag baselineTags[baseTagCount]ベースライン識別子。数値順に並んでいる。

▼ ベースライン識別子
hangぶら下がりベースライン。
チベット語などで、文字が下にぶら下がっているような水平線。
縦書き時は、時計回りに90度回転。
icfb平均字面の下端。
縦書き時は、左端。
icft平均字面の上端。
縦書き時は、右端。
ideo仮想ボディの下端。
縦書き時は、左端 (※ ベースラインは 0 に設定する)
idtp仮想ボディの上端。
縦書き時は、右端 (※ 推奨値: unitsPerEm)
math数式の中心。
縦書き時は、時計回りに90度回転した中心。
romn欧文のベースライン。
縦書き時は、時計回りに90度回転 (横書き用)

BaseScriptList
言語ごとのリスト。

uint16 baseScriptCountBaseScriptRecord の数
BaseScriptRecord [baseScriptCount]BaseScriptRecord の配列。タグの数値順に並んでいる。

BaseScriptRecord
Tag baseScriptTag識別子 (Script タグ)
Offset16 baseScriptOffsetBaseScript テーブルへのオフセット位置。
BaseScriptList の先頭を 0 とする。

BaseScript
1つの言語のベースラインと最小/最大エクステントのデータ。

Offset16 baseValuesOffsetBaseValue テーブルへのオフセット位置。
(デフォルトのベースラインデータ)
BaseScript の先頭を 0 とする。
データがない場合、0。
Offset16 defaultMinMaxOffsetデフォルトの MinMax テーブルへのオフセット位置。
データがない場合、0。
uint16 baseLangSysCountBaseLangSysRecord の数。
デフォルトのデータのみの場合は、0。
BaseLangSysRecord []言語固有のデータが必要な場合、BaseLangSysRecord の配列。
タグの数値順に並んでいる。

BaseLangSysRecord
Tag baseLangSysTag言語システムの識別子
Offset16 minMaxOffsetMinMax テーブルへのオフセット位置。
(BaseScript の先頭を 0 とする)

BaseValue
ベースラインのデータ。

uint16 defaultBaselineIndexデフォルトとなるベースラインのインデックス番号。
BaseTagList のインデックス値。
uint16 baseCoordCount以下の配列の数
Offset16 baseCoords[]BaseCoord テーブルへのオフセット位置。
BaseValue の先頭を 0 とする。

BaseTagList のタグの数だけ存在し、各ベースライン位置の値が格納されている。

MinMax
Offset16 minCoord最小値を定義した BaseCoord テーブルへのオフセット位置。
(MinMax の先頭を 0 とする)。
0 の場合あり。
Offset16 maxCoord最大値を定義した BaseCoord テーブルへのオフセット位置。
0 の場合あり。
uint16 featMinMaxCountFeatMinMaxRecord の数
FeatMinMaxRecord []FeatMinMaxRecord の配列。タグの数値順に並んでいる。

FeatMinMaxRecord
Tag featureTableTagFeature タグ
Offset16 minCoord最小値を定義した BaseCoord テーブルへのオフセット位置。
(MinMax の先頭を 0 とする)。
0 の場合あり。
Offset16 maxCoord最大値を定義した BaseCoord テーブルへのオフセット位置。
0 の場合あり。
BaseCoord
ベースラインの座標値、または最小/最大エクステント値。

format 1
uint16 baseCoordFormatフォーマット番号 = 1
int16 coordinateX or Y 値 (デザイン単位)

format 2
uint16 baseCoordFormatフォーマット番号 = 2
int16 coordinateX or Y 値 (デザイン単位)
uint16 referenceGlyphグリフID
uint16 baseCoordPoint参照グリフ上の輪郭点のインデックス

format 3
uint16 baseCoordFormatフォーマット番号 = 3
int16 coordinateX or Y 値 (デザイン単位)
Offset16 deviceTable(非可変フォント時) Device テーブルへのオフセット位置
(可変フォント時) Variation Index テーブルへのオフセット位置

BaseCoord の先頭を 0 とする。
0 の場合あり。
プログラム
>> 22_base.c

BASE テーブルのデータを表示するプログラムです。

---- BASE ----

version: 1.0
horizAxisOffset: 8
vertAxisOffset: 74

==== Horz Axis ====

baseTagListOffset: 4
baseScriptListOffset: 22

-- BaseTagList --

'icfb'
'icft'
'ideo'
'romn'

-- BaseScriptRecord ['DFLT'] --

baseScriptOffset: 110

- BaseScript -

baseValuesOffset: 24
defaultMinMaxOffset: 0
baseLangSysCount: 0

- BaseValue -

defaultBaselineIndex: 2
baseCoordCount: 4

{BaseCoord} <'icfb'> format:1 | coordinate:-78
{BaseCoord} <'icft'> format:1 | coordinate:838
{BaseCoord} <'ideo'> format:1 | coordinate:-120
{BaseCoord} <'romn'> format:1 | coordinate:0

一番重要なのは、BaseTagList のベースラインタグと、BaseValue の各 BaseCoord です。

日本語フォントでは、「icfb」「icft」「ideo」「romn」の4つのベースラインタグがある場合が多いです。
欧文フォントでは、「ideo」「romn」の2つである場合が多いです。

BaseCoord の coordinate 値が、ベースラインの X or Y 座標となります。
Horz Axis では Y 座標、Vert Axis では X 座標となります。
ベースラインについて


ベースラインの座標値は、水平/垂直レイアウトともに、グリフの原点 (0, 0) を基準とした値です。

縦書きの場合は、グリフの中央を原点とした値ではなく、水平レイアウト時の原点からの X 座標です。
仮想ボディと平均字面


仮想ボディ (Ideographic Em-Box)」は、基本的に 1 em の枠になります。

平均字面 (Ideographic Character Face)」は、CJK フォントで使われます。
仮想ボディよりも小さく、仮想ボディから上下左右に等間隔で離れた正方形であることが推奨されています。

ベースラインを平均字面に合わせると、サイズの異なる日本語グリフを綺麗に揃えたりすることができます。
仮想ボディの求め方
ideoEmboxLeft = 0

if HorzAxis.ideo is defined:
    ideoEmboxBottom = HorzAxis.ideo

    if HorzAxis.idtp is defined:
        ideoEmboxTop = HorzAxis.idtp
    else:
        ideoEmboxTop = HorzAxis.ideo + head.unitsPerEm

    if VertAxis.idtp is defined:
        ideoEmboxRight = VertAxis.idtp
    else:
        ideoEmboxRight = head.unitsPerEm

    if VertAxis.ideo is defined and non-zero:
        ! Bad Value
else if CJK font:
    ideoEmboxBottom = OS/2.sTypoDescender
    ideoEmboxTop = OS/2.sTypoAscender
    ideoEmboxRight = head.unitsPerEm
else:
    ! 設定できない

仮想ボディは、BASE テーブルが存在すれば BASE の情報から、なければ 'OS/2' や 'hhea' テーブルの値で決定します。

しかし、ソフトウェアによっては、そもそも BASE テーブル自体を読み込まない場合もあるため、どちらの情報が使われても問題ないように、フォントの値を設定することが求められます。

よって、「hhea.ascender、OS/2.sTypoAscender、HorzAxis.idtp」
「hhea.descender、OS/2.sTypoDescender、HorzAxis.ideo」は、それぞれ同じ値を設定することが推奨されています。
平均字面の求め方
if HorizAxis.icfb is defined:
    icfBottom = HorizAxis.icfb
    margin = HorizAxis.icfb - ideoEmboxBottom

    if HorizAxis.icft is defined:
        icfTop = HorizAxis.icft
    else:
        icfTop = ideoEmboxTop - margin

    if VertAxis.icfb is defined:
        icfLeft = VertAxis.icfb
    else:
        icfLeft = margin

    if VertAxis.icft is defined:
        icfRight = VertAxis.icft
    else:
        icfRight = ideoEmboxRight - icfLeft
else:
    ! 設定できない

margin は、仮想ボディと平均字面の余白です。
「源ノ明朝」の場合は、以下のようになっています。

head.unitsPerEm     : 1000
OS/2.sTypoAscender  : 880
OS/2.sTypoDescender : -120
hhea.ascender       : 1151
hhea.descender      : -286

== BASE / horz ==

icfb : -78
icft : 838
ideo : -120
romn : 0

embox.top    : -120 + 1000 = 880
embox.bottom : -120
embox.left   : 0
embox.right  : 1000

== BASE / vert ==

icfb : 42
icft : 958
ideo : 0
romn : 120

icf.top    : 838
icf.bottom : -78
icf.left   : 42
icf.right  : 958
margin     : -78 - -120 = 42

margin は 42 で、
icf.top - icf.bottom + margin * 2 = embox width (1000)
icf.right - icf.left + margin * 2 = embox height (1000)
となっているため、平均字面は仮想ボディから上下左右ともに margin 分小さい枠となっています。