CharString手書きマニュアル

#はじめに
CFFテーブルのCharStrringは頑張れば読めます。[規格書](https://wwwimages2.adobe.com/content/dam/acom/en/devnet/font/pdfs/5177.Type2.pdf)を読めば読み方が書いてあります。ただし、規格書ではあくまでもOpen Typeフォントのデータそのもののことを書いていて、xml形式に書き直されたttxファイルを読むのには向いていないので、備忘録的なメモを残しておきます。

まず、CharStringは
`w? (hs* vs* cm* hm* mt subpath)? (mt subpath)* endchar`
という形式になっています。ただし、

||意味|
|--:|:--|
|w|(デフォルト幅と異なる場合のみ記述)|
|hs|水平方向のステム|
|vs|垂直方向のステム|
|cm|コントロールマスク|  
|hm|ヒントマスク|  
|mt|座標移動オペレータ|  
|subpath|輪郭線データ|

#ttxファイルの中身
ここからは実際のttxファイルの中身についてです。
まずはじめに、具体例を示します。
ちなみにこれは座標計算をした上で自力で書きました。


命令|内容
:--|:--
\<CharString name=”.notdef”\>|これから書くグリフ名の宣言  
-126 0 34 648 34 hstem|水平方向のステム(y=0, 34, 682, 716)  
34 204 34 vstem|垂直方向のステム(x=34, 238, 272)  
34 hmoveto|移動  
272 682 -272 hlineto|直線  
34 -87.92 rmoveto|移動  
84.09 -253.08 -84.09 -253.08 rlineto|直線  
17.91 -53.92 rmoveto|移動  
84.09 253.08 84.09 -253.08 rlineto|直線  
17.91 53.92 rmoveto|移動  
-84.09 253.08 84.09 253.08 rlineto|直線  
-17.91 53.92 rmoveto|移動  
-84.09 -253.08 -84.09 253.08 rlineto|直線  
endchar|終了命令  
\</CharString\>|
このテーブル内ではほぼ全ての座標が`x`, `y`について、それぞれの相対座標で表されています。また、ステム情報に関してのいくつかの例外を除き、全て逆ポーランド記法（後置記法）で書かれています。この2点が、CharStringを理解しにくくする主な要因です。
普通の人はちゃんとGUIのあるソフトで字形を見ながらいじるから読まないし読む意味もありませんが。

#命令
では、命令に触れていきます。以下、`x`, `y`は絶対座標、`dx`, `dy`は相対座標を示します。
##ヒント命令
ヒントとは、フォントを描画する際の精度を向上させるための仕組みです。簡単に言えば、水平/垂直な直線の`y`/`x`座標をフォントに記録しておき、描画時にそれを元にどのピクセルに表示するかを判断する仕組みです。詳しくは自分で調べてみてください。
ヒント情報には、`hstem`, `vstem`, `hstemhm`, `vstemhm`, `hintmask`, `cntrmask`の6種類が存在します。
###hstem, vstem
```y dy (dya dyb)* hstem
x dx (dxa dxb)* vstem```
水平, 垂直方向のステムを記述します。2つ1組で、ある輪郭線の上下, 左右を表します。
###hstemhm, vstemhm
```(y dy (dya dyb)* hstemhm)*
(x dx (dxa dxb)* vstemhm?)*```
ヒントマスクが存在する場合に、`hstem`と同様に使用されます。ただし、`hstemhm`の次の命令は`vstemhm`であり、その後、`hintmask`が記述されます。このとき、`vstemhm`は(文字列上)省略できます。
ただし、仕様上多数の引数を同時に記憶しておくことが出来ないので、複数回にわたってステム情報が与えられる場合があります。
`vstemhm`は、`hstem`に対する`hstemhm`と同様の役割を、`vstem`に対して持っています。ただし、この次の命令は`hintmask`となります。
###hintmask
`hintmask mask`
かなりの曲者です。他の命令群が後置記法であるのに対し、この命令は前置記法が採られています。`mask`に当たる部分は`0x`を頭に付けた16進数か、2進数で記述します。
2つ1組で書かれたステム情報をアクティベートするかどうかを、上位ビットから順に示していきます。ただし、桁数が2進数で8の倍数となるように、下位ビットを0で埋めるようにします。例えば、
```0 10 10 10 10 10 hstemhm
0 10 20 30 hintmask 10010000```
というように記述されている場合、1つめのhstem, 1つ目のvstemをアクティベートします。
###cntrmask
すみません。よくわかっていません。わかったら追記するかもしれません。
##移動命令
rで始まるものはx, y座標の両方を、hで始まるものはx座標のみを、vで始まるものはy座標のみを引数に取ります。また、パス命令群を切り離し、別の線として扱う役割も果たします。
###rmoveto, hmoveto, vmoveto
```dx dy rmoveto
dx hmoveto
dy vmoveto```
##パス命令
移動命令と同様に、r/h/vで始まります。
###rlineto, hlineto, vlineto
```(dx dy)+ rlineto
dx1 (dya dxb)* hlineto
(dxa dyb)+ hlineto
dy1 vlineto
(dya dxb)+ vlineto```
現在の座標から直線を引きます。
`hlineto`, `vlineto`は2個以上の引数を与えられた場合、水平線と垂直線を交互に引きます。
###rrcurveto
`(dxa dya dxb dyb dxc dyc)+ rrcurveto`
現在の座標(0,0), (dxa,dya), (dxb,dyb), (dxc,dyc)の4点によって定義されるベジェ曲線を引きます。
6引数で1組となり、2組目以降は(dxc,dyc)を始点とします。
###hhcurveto
`dy1? (dxa dxb dyb dxc)+ hhcurveto`
なんらかの`rrcurveto`命令と等価です。
###vvcurveto
`dx1? (dya dxb dyb dyc)+ vvcurveto`
なんらかの`rrcurveto`命令と等価です。
###hvcurveto
`dx1 dx2 dy2 dy3 (dya dxb dyb dxc dxd dxe dye dyf)* dxf? hvcurveto`
なんらかの`rrcurveto`命令と等価です。
###hvcurveto
`dx1 dx2 dy2 dy3 (dya dxb dyb dxc dxd dxe dye dyf)* dxf? hvcurveto`
なんらかの`rrcurveto`命令と等価です。
###vhcurveto
`dy1 dx2 dy2 dx3 (dxa dxb dyb dyc dyd dxe dye dxf)* dyf? vhcurveto`
なんらかの`rrcurveto`命令と等価です。
###rcurveline
`(dxa dya dxb dyb dxc dyc)+ dxd dyd rcurveline`  
`(dxa dya dxb dyb dxc dyc)+ rrcurveto
dxd dyd rlineto`
と等価です。
###rlinecurve
`(dxa dya)+ dxb dyb dxc dyc dxd dyd rlinecurve`  
`dxd dyd rlineto
(dxa dya dxb dyb dxc dyc)+ rrcurveto`
と等価です。
###flex
`dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 dx6 dy6 fd flex`
細かいカーブを記述します。基本的には
`dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 dx6 dy6 rrcurveto`
と等価ですが、描画時にfd/100ピクセルを下回った場合、直線として処理されます。
###hflex
`dx1 dx2 dy2 dx3 dx4 dx5 dx6 hflex`  
`dx1 0 dx2 dy2 dx3 0 dx4 0 dx5 dy2 dx6 50 flex`
と等価です。
###flex1
`dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 d6 flex1`  
`dx1 dy1 dx2 dy2 dx3 dy3 dx4 dy4 dx5 dy5 dx6 dy6 flex1`
`dx6`, `dy6`に入る数値は以下のようになります。
|dx1+dx2+dx3+dx4+dx5|>|dy1+dy2+dy3+dy4+dy5|
のとき、dx6=d6
それ以外のとき、dy6=d6
前者でのdy6、後者でのdx6は、y座標(x座標)が始点と同一になるように決定されます。
###hflex1
`dx1 dy1 dx2 dy2 dx3 dx4 dx5 dy5 dx6 hflex1` 
`dx1 dy1 dx2 dy2 dx3 0 dx4 0 dx5 dy5 dx6 dy6 50 flex`
と等価です。ただし、dy6=-(dy1+dy2+dy5)になります。
##endchar
`endchar`
その文字の全命令が終了したことを示します。引数は存在しません。
#サブルーチン
フォントサイズ縮小のために、予め命令を登録しておき、呼び出すことができます。
##callsubr, callgsubr
```subr# callsubr
grobalsubr# callgsubr```
`subr#`, `grobalsubr#`にサブルーチンバイアス((g)subrの要素数が1~1239個のとき107, 1240~33899個のとき1131, 33900個以上のとき32768)を足した番号のサブルーチンを呼び出します。
このとき、指定された番号のサブルーチンがそのまま展開されるため、例えば`hstem 255 64 vstem`が登録されたサブルーチンを呼び出すときは、`255 64 subr# callsubr`とすることで、`255 64 hstem 255 64 vstem`を表すことができます。
###return
サブルーチンにおけるendcharみたいなものです。