GSUBの実装
詳しくは、GitHubに上げた calendar.fea を参照されたい。
最初に年について400の剰余を計算する。
これは要するに、百の位以上の桁について4の剰余を計算すればよい。
4の剰余を表すための状態の数だけ状態に対応する数字のグリフを作成する。
数字 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
0 mod 4 |
00 |
10 |
20 |
30 |
40 |
50 |
60 |
70 |
80 |
90 |
1 mod 4 |
01 |
11 |
21 |
31 |
41 |
51 |
61 |
71 |
81 |
91 |
2 mod 4 |
02 |
12 |
22 |
32 |
42 |
52 |
62 |
72 |
82 |
92 |
3 mod 4 |
03 |
13 |
23 |
33 |
43 |
53 |
63 |
73 |
83 |
93 |
実際には zero_0mod4, one_0mod4, …, nine_0mod4, …, zero_3mod4, …, nine_3mod4 などという名前のグリフを用意した。
数字の並びについて、まず前に数字が続かないもの、つまり数字の最初の桁について置換をおこなう。3桁の数字の最初の文字について次のように置換をおこなう。
元の数字 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
置換先 |
00 |
11 |
22 |
33 |
40 |
51 |
62 |
73 |
80 |
91 |
これは lookup check_first_fig_mod4 で行っている。
次に、4の剰余の状態を持った数字の次に来る3つの数字のうちの1番目の数字について置換を行う。
つまり、
mod4の数字 普通の数字 普通の数字 普通の数字
という並びの時に太字にした“普通の数字”を対応するmod4の数字に置換する。
元の数字 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
前が剰余0か2の時の置換先 |
00 |
11 |
22 |
33 |
40 |
51 |
62 |
73 |
80 |
91 |
前が剰余1か3の時の置換先 |
02 |
13 |
20 |
31 |
42 |
53 |
60 |
71 |
82 |
93 |
これは lookup check_mod4 で行った。
これで年の400の剰余が求まった。
さて、次に、年の始まりの曜日と閏年かどうかの14状態を判定する。これは、その14状態に対応するスラッシュ“/”のグリフを用意し、年と月の間のスラッシュ“/”(あるいはハイフンでもいい)に対し置換を行うこととする。これはスラッシュの前3桁の数字について400通り(数字が2桁、1桁しかない場合を加えて499通り)の置換をずらずら列挙することになる。うっ頭が…。
これは lookup check_firstday_and_leapyear で実装した。気合、といった感じ。
状態をもつスラッシュのグリフ名は
slash_mon_leap
slash_tue_comm
などとした。(mon, tue, wed, thu, fri, sat, sun)×(leap, comm)
置換後、スラッシュが14の状態をもっている。閏年はl, 閏年でない年はnで示した。
スラッシュの14状態(一番左の列)に対して、後続する数字(一番上の行)によって次の表のようにカレンダーを表示する。表記したのはカレンダーに含まれる日数と開始曜日である。
|
01 |
02 |
03 |
04 |
05 |
06 |
07 |
08 |
09 |
10 |
11 |
12 |
日, n |
31日 |
28水 |
31水 |
30土 |
31月 |
30木 |
31土 |
31火 |
30金 |
31日 |
30水 |
31金 |
月, n |
31月 |
28木 |
31木 |
30日 |
31火 |
30金 |
31日 |
31水 |
30土 |
31月 |
30木 |
31土 |
火, n |
31火 |
28金 |
31金 |
30月 |
31水 |
30土 |
31月 |
31木 |
30日 |
31火 |
30金 |
31日 |
水, n |
31水 |
28土 |
31土 |
30火 |
31木 |
30日 |
31火 |
31金 |
30月 |
31水 |
30土 |
31月 |
木, n |
31木 |
28日 |
31日 |
30水 |
31金 |
30月 |
31水 |
31土 |
30火 |
31木 |
30日 |
31火 |
金, n |
31金 |
28月 |
31月 |
30木 |
31土 |
30火 |
31木 |
31日 |
30水 |
31金 |
30月 |
31水 |
土, n |
31土 |
28火 |
31火 |
30金 |
31日 |
30水 |
31金 |
31月 |
30木 |
31土 |
30火 |
31木 |
日, l |
31日 |
29水 |
31木 |
30日 |
31火 |
30金 |
31日 |
31水 |
30土 |
31月 |
30木 |
31土 |
月, l |
31月 |
29木 |
31金 |
30月 |
31水 |
30土 |
31月 |
31木 |
30日 |
31火 |
30金 |
31日 |
火, l |
31火 |
29金 |
31土 |
30火 |
31木 |
30日 |
31火 |
31金 |
30月 |
31水 |
30土 |
31月 |
水, l |
31水 |
29土 |
31日 |
30水 |
31金 |
30月 |
31水 |
31土 |
30火 |
31木 |
30日 |
31火 |
木, l |
31木 |
29日 |
31月 |
30木 |
31土 |
30火 |
31木 |
31日 |
30水 |
31金 |
30月 |
31水 |
金, l |
31金 |
29月 |
31火 |
30金 |
31日 |
30水 |
31金 |
31月 |
30木 |
31土 |
30火 |
31木 |
土, l |
31土 |
29火 |
31水 |
30土 |
31月 |
30木 |
31土 |
31火 |
30金 |
31日 |
30水 |
31金 |
14 × 12 = 168通り。一桁の数字にも対応するために126通りの置換を追加し計294通りになった。
これは lookup replace_calendar で行った。
さて、カレンダーを表示するのもいいけどせっかくなので何年何月ってのも表示させたい。
月については、事前に月を示す(JAN, FEB, などと表示される)グリフを用意しておき、グリフ幅0で、カレンダーのグリフの次にきたときに丁度いい位置に月の表示がくるように位置調整しておく。
これを、カレンダーのグリフに後続する2桁または1桁の数字に対して置換をおこなうことで、月の表示を可能にしている。
これは lookup replace_month で実装した。
最後に年の表示。数字をspacingなグリフにしてしまうと、並べるのは簡単だが、左側に空白ができてしまう。
という訳で、年の数字専用の幅0のグリフを用意しておき、GSUBで数字をそれらのグリフに置換し、その後GPOSのMarkToMark positioning (タグでいうと'mkmk')を使って位置調整することで年の数字を並べようと考えた。
さて、フォントが一応できたので動作を見てみる。
「文字」パネルプルダウンメニューから「欧文合字」をオンにすると……
やったー!
イラレではどうかな?OpenTypeパネルから欧文合字を有効にして……
あれー?
'mkmk'が効いてない。
もし'mark'は効くであれば、'mkmk'じゃなくても'mark'とGSUBによる置換で代用することはできるのだけれど。
今回は、GSUBだけである程度まで動くようにしておく。事前に位置をずらした数字を用意しておいて、GSUBで順番に置換する。5桁あれば十分だろう。それより大きい桁数は'mkmk'を有効にできる環境で使うようにしてもらう。
これによって年を表す数字のグリフが5倍に増える。
このあたりは lookup replace_year_10000, lookup replace_year によってGSUB置換を実装、さらに lookup STACK_YEAR を使って6桁以上の年の数字が右に並ぶようにした。