日本語用OpenTypeフォントについて

日本語用OpenTypeフォントには、(恐らく)最低限以下のテーブルが必要です。

テーブル名|内容
:--|:--
head|ヘッダー
hhea|横書き用ヘッダー
maxp|種々の最大値
OS/2|基本情報(内部)
name|基本情報(外部)
cmap|グリフとコードポイントの対応表
post|PostScript用情報
CFF|グリフデータ
GDEF|合字などの定義
GPOS|字の表示位置
GSUB|グリフの置き換え用データ
hmtx|横書き用メトリックデータ
vhea|縦書き用ヘッダー
vmtx|縦書き用メトリックデータ
DSIG|電子署名

fonttoolsを導入してttxファイルを覗いている前提で話を勧めます。
詳しい情報は[規格](https://docs.microsoft.com/en-us/typography/opentype/spec/)を読んでください。
##head
基本的に`ttx`で元に戻すときに自動で再計算されます。
##hhea
###tableVersion
`value="0x00010000"`になっていればOKです。
###ascent/descent
グリフごとのベースラインからの上/下への距離の最大値です。
###advamceWidthMax
`hmtx`テーブルで宣言されるグリフの幅の最大値です。
###minLeftSideBearing
`hmtx`テーブルで`lsb=""`と宣言される数値の最大値です。
###minRightSideBearing
`lsb`と似たようなものです。`Min(aw - lsb - (xMax - xMin))`で定義されます。
###xMaxExtent
`Max(lsb + (xMax - xMin))`で定義されます。
###caretSlopeRise/caretSlopeRun
縦書き用にそれぞれ1, 0である必要があります。
###caretOffset
斜体(Slanted)でない限り0です。
###reserved0/1/2/3/metricDataFormat
現状では全て0です。
###numberOfHMetrics
詳細不明
##maxp
CFFを使うフォントは`tableVersion`を`0x5000`に、`numGlyphs`をグリフ数にしておいてください。
##OS/2
すみません。よくわかりませんでした。
[規格書](https://docs.microsoft.com/en-us/typography/opentype/spec/os2)を読んでください。
大量の情報が含まれているので、分かったところから追記していきます。
###Version
OS/2テーブルのバージョンです。4か5であれば恐らく問題ありません。
バージョンによってこのテーブルに必要な情報が変わりますが、この記事ではとりあえずバージョン4に必要なものを網羅することを目標とします。
###xAvgCharWidth
非ゼロ幅グリフ全ての幅の平均です。
何のためにこんな情報があるんでしょうか。

###usWeightClass
フォントのウェイトを表します。1以上1000以下の数値が与えられ、数字が大きいほど太いことを示します。
100~900までは100刻みでよく見るThin, Extra-Light, Light,...と対応しています。つまり通常は400です。
###usWidthClass
フォントの幅を表します。1以上9以下の数値が与えられ、数字が大きいほど幅が広いことを示します。5が基準(100%)になります。
###fsType
最下位4bitでフォントの埋め込みや編集に関する制限を規定します。この4bitの値は0, 2, 4, 8のいずれかを取ります。
下から9個目のビットが1の場合はフォントのサブセット化が禁止であることを、10個目が1の場合は埋め込まれたビットマップフォントのみ埋め込み可能であることを示します。
###ySubscriptXSize/ySubscriptYSize
文字を下付きにする時のグリフの幅と高さを規定します。
###ySubscriptXOffset/ySubscriptYOffset
文字を下付きにする時のグリフの表示位置のオフセットを規定します。
###ySuperscriptXSize/ySuperscriptYSize
`ySubscriptXSize`及び`ySubscriptYSize`と同様です。上付き文字に関する情報です。
###ySuperscriptXOffset/ySuperscriptYOffset
`ySubscriptXOffset`及び`ySubscriptYOffset`と同様です。上付き文字に関する情報です。
###yStrikeoutSize
打ち消し線のサイズを表します。`post`テーブルの情報と関連しているようです。
###yStrikeoutPosition
打ち消し線の表示位置です。baselineの高さからの差分で表されます。
###sFamilyClass
[こちらの規定](https://docs.microsoft.com/en-us/typography/opentype/spec/ibmfc)に従って、フォントのクラスを規定します。
###ulUnicodeRange1/2/3/4
Unicodeのどのブロックの文字を含んでいるかを表します。この4つで1セットの128bitの情報です。
あるブロックのに対応していればそこのビットが1で、そうでなければ0になります。何をもって対応していると見做すかは製作者側に委ねられているようです。
ビットとブロックの対応表は[こちら](https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ulunicoderange1-bits-031ulunicoderange2-bits-3263ulunicoderange3-bits-6495ulunicoderange4-bits-96127)です。
###achVendID
フォントのベンダーを表します。
###usFirstCharIndex/usLastCharIndex
フォントに収録されている文字の範囲を表します。ほとんどのフォントは半角空白文字を含むため、`usFirstCharIndex`は32であることが多いです。
どちらにおいても、65535以上である場合は全て65535とします。
###sTypoAscender/sTypoDescender
`hhea`テーブルの`Ascent`, `Descent`とほぼ同様です。
###ulCodePageRange1/2
フォントが対応しているコードページを表します。対応表は[ここ](https://docs.microsoft.com/en-us/typography/opentype/spec/os2#ulcodepagerange1-bits-031ulcodepagerange2-bits-3263)です。
###sxHeight/sCapHeight
恐らくx`(U+0078)`およびH`(U+0048)`にあたるグリフの最高点のベースラインからの高さです。
###usDefaultChar
フォントが対応していない文字が与えられた時に表示するグリフのIDを規定します。普通は0だと思います。
###usBreakChar
単語を分かち書きするときの区切りにあたる文字のUnicodeにおける符号を規定します。普通は32だと思います。
##name
フォント名やバージョン情報がOS, 言語などの情報とともに記述されています。詳細は省略します。
##cmap
`<cmap_format_4 platformID="0" platEncID="3" language="0">`と
`<cmap_format_4 platformID="3" platEncID="1" language="0">`の2種類、同じデータを用意しておけば一応は問題ありませんが、漢字にしっかりと対応させようとする場合は問題があります。`platformID`, `platEncID`, `language`に関しては省略します。対応するOSやコード表などを定義します。
`cmap_format_n`の`n`によっていろいろ変わってきますが、主要なものだけ解説します。
###format 0
256グリフまで対応付けができます。
`<map code="0x20" name="space"/>`のように記述します。
###format 4
UnicodeのBMPをサポートします。
`<map code="0x20" name="space"/>`のように記述します。
###format 12
UnicodeのSMPをサポートします。
ヘッダーが`<cmap_format_12 platformID="" platEncID="" format="12" reserved="0" length="" language="" nGroups="">`となっています。
`length`にはテーブル内のグリフ数*12+16が、`nGroups`にはテーブル内のグリフ数が入ります。
`<map code="0x20" name="space"/>`のように記述します。
###format 14
異体字セレクタを使った場合のグリフを宣言します。ヘッダーは`<cmap_format_14 platformID="" platEncID="">`であり、`language`は必要ありません。
`<map uv="0x30" uvs="0xfe00" name="StrokeZero"/>`のように記述します。
`uv`が元グリフのコードポイント、`uvs`が使用する異体字セレクタのコードポイントです。`name`は省略できる場合があります。恐らく、省略した場合`uv`に割り当てられたグリフがそのまま使用されます。
##post
省略します。
##CFF
[解説記事](https://qiita.com/Niccori250km/items/43d490db38198c08779e)を別に書いたので見てください。
##GDEF
`Version`は`0x00010000`にしておいてください。
`GlyphClassDef`における`ClassDef`の値は次の通りです。

クラス|説明
:--|:--
1|単一の文字(空白を含む)
2|合字
3|マーク
4|グリフのパーツ

他のテーブルについてはまだ知りません。
##GPOS
カーニングなどを宣言できます。
##GSUB
そこそこ複雑な構造をしています。規格書を読んだり規約をきちんと確認した上でリバースエンジニアリングしたりいじり回したりして慣れましょう。
とりあえず`FeatureTag`に関して、`vert`が縦書き用グリフへの置換(捨て仮名等の仮名文字は`vkna`)、`liga`が合字を示します。`vrt2`に`vert`と同じデータを入れておくと良いらしいです。[こちら](https://docs.microsoft.com/en-us/typography/opentype/spec/featurelist)で全てのフィーチャの一覧が見られます。[Wikipedia](https://en.m.wikipedia.org/wiki/List_of_typographic_features)も参考になるかもしれません。ただし、ソフトによって対応状況が大きく異なります。
また、`LookupType`によって以下の通り置換の種類を決定します。

LookupType|説明
:--|:--
1|1つのグリフを1つのグリフに置換
2|1つのグリフを複数のグリフに置換
3|1つのグリフを複数のグリフのうちの1つに置換
4|複数のグリフを1つのグリフに置換
5|文脈によって1つ以上のグリフを置換
6|Chained Contextによって1つ以上のグリフを置換
7|拡張置換
8|6の逆転版(?)

また、`LookupType`の番号によって、元のグリフと置換後のグリフの指定方法が異なります。

##hmtx
`<mtx name="[name]" width="[width]" lsb="[leftsidebearing]"/>`の羅列です。`name`はグリフ名、`width`はグリフ幅、`lsb`はグリフの左端のx座標です。
##vhea
`hhea`の縦書き版です。[こちらのプログラム](https://github.com/En3-HCl/CharStringParser/)でCFFから生成できます。
というか多分これ、ちょっといじれば`hhea`と`hmtx`も生成できると思います。極稀に`hmtx`の`lsb`を全て0で出力してくるプログラムがあるので、必要なら試す価値もあると思います。
##vmtx
`htmx`の縦書き版です。`vhea`と同じく、CFFから生成できます。
`tsb`は`OS/2`テーブルにある`sTypoAscender`からの値となります。
##DSIG
規格書を読んでもよくわかりませんでした。その手の人(?)に聞きましょう。恐らく、電子署名です。
##その他
`SVG`テーブルにSVGファイルを突っ込んだり、`MATH`テーブルに数式組版用データを突っ込んだり、`JSTF`テーブルとか`VORG`テーブルとかで組版の微修正用のデータを突っ込んだりできるみたいです。
規格に則って一通りのデータを揃えたフォントがあったら良かったのに