\setbox0=\hbox{\kern.5em$\mathstrut#1$\kern.5em}\dp0=0pt
\hbox{\vrule
$\vcenter{\hsize=\wd0\hrule\kern.5ex\copy0\kern.5ex\hrule}$%
- \vrule\kern.1em}}
+ \vrule\kern.1em}{}}
\def\nk{{\rm kern}\ }
\def\ng{{\rm glue}\ }
\def\np{{\rm penalty}\ }
本文書では,Lua\TeX-jaが(現時点において)和文処理に関わるglue/kernを
どのように挿入するかの内部処理について説明する.
+\bigskip
+{\large\bf\noindent これは仕様・内部処理の提案の1つにしかすぎません.最終的にこのようになる
+保証はどこにもありませんし,現時点でのLuaコードが本文書に従っている保証もありません.
+バグが混入している可能性も大きいです.}
+
\beginsection 予備知識
説明に入る前に,段落やhboxの中身は,\TeX の内部ではnode達による
\item 次のように,nodeがどのように連続しているかを表すことにする.
$$
-\node{a}\node{b}_{\rm I}\node{c}
+\node{a}\node{b}_{1}\node{c}
$$
-å\8f³ä¸\8bã\81«ã\81¤ã\81\84ã\81¦ã\81\84ã\82\8bæ·»å\97ã\81¯ï¼\8cLua\TeX-jaã\81«ã\81\8aã\81\84ã\81¦ã\81\9dã\81®nodeã\81®å½¹å\89²ã\82\92å\8cºå\88¥ã\81\99ã\82\8bã\81\9fã\82\81ã\81«ã\81¤ã\81\91ã\82\89ã\82\8cã\81\9f
-値(jtypeと呼ぼう)であり,次のようになっている.
+ä¸\8bæ·»å\97ã\81¯ï¼\8cLua\TeX-jaã\81«ã\81\8aã\81\84ã\81¦ã\81\9dã\81®nodeã\81®å½¹å\89²ã\82\92å\8cºå\88¥ã\81\99ã\82\8bã\81\9fã\82\81ã\81«ã\81¤ã\81\91ã\82\89ã\82\8cã\81\9f
+値(icflagと呼ぼう)であり,次のようになっている.
$$
\vbox{\halign{#:\ \hfil&#\hfil\quad&#:\ \hfil&#\hfil\cr
-I&イタリック補正由来のkern&
-T&|\[x]kanjiskip|に置換されうるkern\cr
-J&JFM由来のglue/kern&
-K&禁則処理用penalty\cr
-E&「行末」との間に入るkern&
-KS&|\kanjiskip|用glue\cr
-XS&|\xkanjiskip|用glue\cr
+1&イタリック補正由来のkern &
+2&幅補正のため,hboxにカプセル化された和文文字\cr
+3&禁則処理用penalty&
+4&JFM由来のglue/kern\cr
+5&「行末」との間に入るkern&
+6&|\kanjiskip|用glue\cr
+7&|\xkanjiskip|用glue&
+8&既に処理対象となったnode\cr
+15&リスト先頭/末尾に入るglue/kern/penalty\span\omit\span\cr
}}
$$
+和文処理グルーの挿入処理に一度通されたnodeは,みなicflagが3以上となることに注意.
+
+なお,上添字はnodeのsubtypeを表す.
\item {\sf jaxspmode}のようなサンセリフ体で,|\ltjsetparameter|で設定可能なパラメタ値を表す.
-\item タイプライタ体の|\kanjiskip|, |\xkanjiskip|は,それぞれ「和文間空白」「和欧文間空白」の意味で
-抽象的に用いている.
+\item タイプライタ体の|\kanjiskip|, |\xkanjiskip|は,
+それぞれ「和文間空白」「和欧文間空白」の意味で抽象的に用いている.
\item nil値は$\emptyset$と書く.
\enditem
-\beginsection JFM由来グルーの挿入 ({\tt luatexja-jfmglue.lua})
+\beginsection 方針など
+
+本バージョンにおいては,JFM由来グルーと|\[x]kanjiskip|の挿入は同じ段階で行われる.
+大雑把に言うと,
+$$
+\vbox{\hsize=0.85\hsize\bf 和文処理グルーの挿入処理では,以下は存在しないものとして扱われる:
+\item 「文字に付属する」アクセントやイタリック補正.
+\item 行中数式の内部.
+\item 実際の組版中には現れないinsertion, vadjust, mark, whatsit node達.
+\enditem}
+$$
+
+\beginparagraph 和文文字の「自然長」(JFMにおける{\tt width}の指定値)について
+
+p\TeX においては,和文文字の行頭と行末に自動的にglueやkernをおくことはできなかったことから,
+JFMにおける文字幅の意味は,
+$$
+\hbox{\vbox{\hsize=0.8\hsize \noindent
+「その文字が行頭におかれるときの,版面左端の位置」を左端,\hfill\break
+「その文字が行末におかれるときの,版面右端の位置」を右端としたときの幅}}
+$$
+というように,明確な意味があるものであった.例えば,乙部さんによるぶら下げ組パッケージ ({\tt burasage.lzh})
+においては,句読点類(「|,、.。|」の4文字)の文字幅は0.0となっている.
+
+一方,Lua\TeX-ja においては,和文文字が行末にきた場合,その文字と行末の間にkernを挿入することができる:
+例えば,前に挙げた4文字についてぶら下げ組をしたいのであれば,
-JFM由来グルーの処理は,「連続する2つのnodeの間に何を入れるか」という単位で行われる.
-そのため,
-\item node生成を伴わないもの(グループ境界,|\relax|等)は全て無視される.
-\item 一方,node生成を伴うものは全て「透過しない」.
-例えば,次のソースにおいて,閉じ括弧と開き括弧の間に入る物は,
-左と右とで異なる:
\begintt
-)( )\hbox{}(
+ [1701] = {
+ chars = { 'lineend' }
+ },
+ [42] = {
+ chars = { ',', '、', '.', '。' },
+ align = 'left', left = 0.0, down = 0.0,
+ width = 0.5, height = 0.88, depth = 0.12, italic=0.0,
+ kern = { [1701] = -0.5, ...}
+ }, ...
\endtt
-\item 「現在位置でのJFM由来グルーの挿入抑制」を行う|\inhibitglue|は,内部では専用のwhatsit node
-($\hbox{\tt subtype}=44$, \setbox0=\hbox{|user_id|}$\copy0=30111$)を作ること
-によって実装している.これらのnodeは,「現在位置で挿入しない」というフラグを立てるためだけ
-に存在するものであって,挿入処理中に全て削除される.
-\enditem
-以下,$q$, $p$を連続するnodeとする.
+のように,「文字|'lineend'|との間に負のkernをおく」ように指定すればよい.
+そのため,p\TeX と比較すると,JFMにおける|width|の指定値に絶対的な意味はあまりないことになる.
+{\small 行頭にもkern をおけるようにするかどうかは検討中である.}
-\beginparagraph 2つの和文文字の間
-この場合,グルー挿入に関係する量は次の通りである.これら3つの量の値によって,
-$q$と$p$の間に何が挿入されるかが決定される.これらの記号は他の場合にも用いる.
-\item $g$: JFMで指定された,$q$と$p$の間に入るglue/kern.
-JFMで規定されていないときは$\emptyset$と書こう.
-両ノードで使われているJFMが異なる時の$g$の決定方法は,後に記述する.
-\item $w$: JFMで指定された,「$q$の直後で改行が行われた場合,
-$q$と行末の間に入るカーン量」の値.
+\beginparagraph グルーの挿入単位「塊」
-また,$g-w$で,$g$の自然長を$w$だけ減算したglue/kernを表すことにする($g$がglueならばこのnodeはglue,$g$がkernならばkern).
+和文処理グルーの挿入処理は,
+ごく大雑把にいうと,「連続する2つのnodeの間に何を挿入するか」の繰り返しである.
+実際の挿入処理は,「隣り合った2つの『塊』\IT{Nq}, \IT{Np}の間に何を入れるか」を
+単位として行われる.
-\item $P$: $q$に対する行末禁則用ペナルティ (post-break penalty) と,
-$p$に対する行頭禁則用ペナルティ (pre-break penalty) との和.どちらも
-設定されていないときは0となる.
-\enditem
-なお,間に|\inhibitglue|による指定があった場合,$g=\emptyset$, $w=0$として処理される.
+\medskip\noindent{\bf 定義}\quad
+「{\bf 塊}」(\IT{Nn}などで表す)とは,次の4つのいずれかの条件を満たすnode(達のリスト)
+のことである:
+\enum icflagが3以上15未満であるnode達の連続からなるリスト.
-設計方針としては,
-\item JFM由来で入るものがkernの場合,この場所では行分割は許さない.
-\item そうでない場合,(penaltyの値$P$があるが)この場所での行分割は可能である.
-\enditem
-である.さて,次が実際の場合わけである:
-
-\enum $w\neq 0$, $g=\emptyset$のとき
-$$\ncount=0
-\node{q}
-\node{\nk w}_{\rm E}
-\node{\np P}_{\rm K}
-\node{\nk{-w}}_{\rm T}
-\node{p}
-$$
-この$\node{\nk{-w}}_{\rm T}$は,
-「$q$と$p$の間で行分割されないときは間に何のglue/kernもないように見える」ために
-挿入されたものである.次のステップで|\[x]kanjiskip|の挿入が行われる時に,このnodeは
-|\[x]kanjiskip|用のglueに置換される.
-
-\enum $w\neq 0$, $g\neq\emptyset$のとき:
-$$\ncount=0
-\node{q}
-\node{\nk w}_{\rm E}
-\node{\np P}_{\rm K}
-\node{g-w}_{\rm J}
-\node{p}
-$$
+このようなnode達は,既に組み上がったhboxを|\unpackage|により解体したときに発生する.
+一度和文処理グルーの挿入処理が行われているため,二重の処理を防ぐためにこうして1つの塊を構成させている.
-\enum $w=0$, $g$: kernのとき
-$$\ncount=0
-\node{q}
-\node{g}_{\rm J}
-\node{p}
+なお,icflagが15であるnodeは,処理中に発見されしだい削除される
+(hboxの先頭や末尾に挿入されたglue/kern/penaltyであるので,
+本来の「段落/hboxの中身に適宜グルーを挿入する」という目的を考えると存在すべきでない).
+\enum 数式開始を表す\IT{math\_node}から始まる文中数式を表すnodeのリスト:
$$
-
-\enum $w=0$, $g$: glueのとき
-$$\ncount=0
-\node{q}
-\node{\np P}_{\rm K}
-\node{g}_{\rm J}
-\node{p}
+ \node{\hbox{数式境界(開始)}}
+ \longrightarrow\hbox{(この間,行中数式が続く)}
+ \node{\hbox{数式境界(終了)}}
$$
-
-\enum $w=0$, $g=\emptyset$, $P\neq 0$のとき
-$$\ncount=0
-\node{q}
-\node{\np P}_{\rm K}
-\node{p}
+\enum \IT{glyph\_node}~$p$と,それと切り離すことが望ましくないと考えられるnode達:
$$
-
-\enum $w=0$, $g=\emptyset$, $P=0$のとき
-$$\ncount=0
-\node{q}
-\node{p}
+ \Bigl[\node{\nk\hskip-.5em}^2
+ \node{\hbox{アクセント文字}}
+ \node{\nk\hskip-.5em}^2\Bigr]
+ \node{p}
+ \Bigl[\node{\nk\hskip-.5em}_1\Bigr]
$$
-\enditem
+但し,これには$p$が${\rm icflag}=2$のhboxである場合も含む.%
+{\small ←この場合の処理は実はおこらない?}
+\enum {\bf 以下のどれにもあてはまらない}node~$p$:
+\itemitem 組版結果からは消えてしまう,\IT{ins\_node},
+\IT{mark\_node}, \IT{adjust\_node}, \IT{whatsit\_node}.
+\itemitem penalty(←但し,挿入処理の過程で値が変更されることはある)
-なお,両ノードで使われているJFMが異なる時の$g$の決定方法であるが,
-\enum $g_{\rm L}$を,$q$に使用されているJFMにおける,「$q$と文字|'diffmet'|」の間に
-入るglue/kernの値とする.
-\enum $g_{\rm R}$を,$p$に使用されているJFMにおける,「文字|'diffmet'|と$p$」の間に
-入るglue/kernの値とする.
-\enum 両方から,実際に入る$g$の値を計算する.
-\itemitem $g_L$, $g_R$の少なくとも片方が$\emptyset$のときは,$\emptyset$でない方を
-そのまま採用する.
-\itemitem 両方とも$\emptyset$でない場合は,|differentjfm|の値にそって$g$の値を計算する.
\enditem
-\beginparagraph 和文文字と(和文文字,kern以外のnode)の間
-
-「和文文字の間」の場合に対して,以下が異なる:
-\item $g$は,$q$に使用されているJFMにおける,「$q$と文字|'jcharbdd'|」の間に
-入るglue/kernの値である.
-\item $p$が{\bf penaltyでない場合}は,いつもこの位置で行分割できるようにするため,
-case~6 ($w$, $P=0$, $g=\emptyset$) の場合にも,$q$と$p$の間には
-0という値のpenaltyが入る.即ち,次のようになる.
-$$\ncount=0
-\node{q}
-\node{\np 0}_{\rm K}
-\node{p}
-$$
-\enditem
+\medskip\noindent{\bf 記号}\quad
+\IT{Bp}で,塊\IT{Nq}と塊\IT{Np}の間にある\IT{penalty\_node}達の配列を表す.
-\beginparagraph (和文文字,kern以外のnode)と和文文字の間
-この場合も,基本的には「和文文字の間」と似ているが,以下が異なる:
-\item $g$は,$p$のJFMにおける,「文字|'jcharbdd'|と$p$」の間に
-入るglue/kernの値である.
-\item 常に$w=0$である.
-\item いつもこの位置で行分割できるようにするため,
-case~6 ($w$, $P=0$, $g=\emptyset$) の場合にも,$q$と$p$の間には
-0という値のpenaltyが入る.
-\enditem
+\beginsection 挿入処理の大枠
-即ち,次の3通りになる.
-\enum $g$: kernのとき
-$$\ncount=0
-\node{q}
-\node{g}_{\rm J}
-\node{p}
-$$
+\beginparagraph 「塊」の保持するデータ
-\enum $g$: glueのとき
-$$\ncount=0
-\node{q}
-\node{\np P}_{\rm K}
-\node{g}_{\rm J}
-\node{p}
-$$
+「塊」\IT{Np}は,内部では少なくとも次の要素を持ったテーブルとして表される:
-\enum $g=\emptyset$のとき
-$$\ncount=0
-\node{q}
-\node{\np P}_{\rm K}
-\node{p}
-$$
+\item \IT{.first}: \IT{Np}の先頭のnode.
+\item \IT{.nuc}: \IT{Np}の「核」となるnode.
+\itemitem 1., 2.によるものである場合,$\mibox{Np.nuc}=\mibox{Np.first}$.
+\item \IT{.last}: \IT{Np}の最後のnode.
+\item \IT{.id}: \IT{Np}の種類を表す値.
+\itemitem 1.によるものである場合,\IT{id\_pbox}(Pseudo BOXのつもり).
+\itemitem 3.によるものであり,$p$が和文文字だった場合,\IT{id\_jglyph}.
+\itemitem 4.によるものであり,$p$が垂直変位がnon-zeroなhbox,
+あるいはvbox, ruleだった場合,\IT{id\_box\_like}.
+\itemitem それ以外の場合,node~$p$の種別を表す数値$p.\mibox{id}$そのもの.
+(数値そのものだと使い勝手が悪いので,\IT{id\_glyph}, \IT{id\_glue}, \IT{id\_kern}などと
+別名を定義している)
\enditem
-\beginparagraph 和文文字とkernの間,kernと和文文字の間
-
-和文文字の後にkernが続いた場合,あるいはkernの後に和文文字が続いた場合,
-この間で行分割はできないものとしている.そのため,
-以下の3ケースに限られる:
-\enum $g$: kernのとき
-$$\ncount=0
-\node{q}
-\node{g}_{\rm J}
-\node{p}
-$$
-
-\enum $g$: glueのとき
-$$\ncount=0
-\node{q}
-\node{\np 10000}_{\rm K}
-\node{g}_{\rm J}
-\node{p}
-$$
-
-\enum $g=\emptyset$のとき
-$$\ncount=0
-\node{q}
-\node{p}
-$$
+\medskip\noindent{\bf 定義}\quad
+「\IT{Np}の中身の先頭」を意味する$\mibox{head}(\mibox{Np})$は,以下で定義される:
+
+\noindent{\small (説明の都合上作った記法で,Luaソース中にはこのような書き方はない)}
+
+\item \IT{Np.id}が\IT{id\_hlist}の場合:後に述べる{\tt check\_box}関数を用いて,
+hbox~\IT{Np.nuc}中の「最初のnode」「最後のnode」を求める.
+\item \IT{Np.id}が\IT{id\_pbox}の場合:\IT{id\_hlist}の場合とほぼ同様.
+\item $\mibox{Np}.\mibox{id}=\mibox{id\_glyph}$(欧文文字)の場合:
+\itemitem \IT{glyph\_node}~\IT{Np.nuc}が単一の文字を格納している(合字でない)場合は,\IT{Np.nuc}自身.
+\itemitem そうでない場合は,合字の構成要素の先頭→構成要素の先頭→……
+と再帰的に探索し,最後にたどり着いた\IT{glyph\_node}.
+\item $\mibox{Np}.\mibox{id}=\mibox{id\_disc}$ (discretionary break) の場合:
+\IT{disc\_node}は,
+\item $\mibox{Np}.\mibox{id}=\mibox{id\_jglyph}$(和文文字)の場合:\IT{Np.nuc}自身.
+\item $\mibox{Np}.\mibox{id}=\mibox{id\_math}$(数式境界)の場合:
+「文字コード$-1$の欧文文字」を仮想的に考え,それを$\mibox{head}(\mibox{Np})$とする.
+\item それ以外の場合:未定義.敢えて書けば$\mibox{head}(\mibox{Np}):=\emptyset$.
\enditem
-なお,ここでの$g$は,
-\item $q$がkernだった場合は,
-$p$のJFMにおける,「|'jcharbdd'|と$p$」の間に
-入るglue/kernの値.
-\item $p$がkernだった場合は,
-$q$のJFMにおける,「$q$と|'jcharbdd'|」の間に
-入るglue/kernの値.
+\noindent 同様にして,「\IT{Np}の中身の先頭」を意味する$\mibox{last}(\mibox{Np})$も定義され,
+「\IT{Np}は,先頭が$\mibox{head}(\mibox{Np})$,
+末尾が$\mibox{tail}(\mibox{Np})$であるような単語」のように
+考えることができる.
+
+\medskip\noindent{\bf 定義}\quad
+「\IT{glyph\_node}~$h$の情報を算出する」とは,
+$h\neq\emptyset$の時に,テーブル\IT{Np}に
+以下のような要素を追加することである:
+
+\item \IT{.pre}: $h$の文字コードに対する{\sf prebreakpenalty}パラメタの値
+\item \IT{.post}: $h$の文字コードに対する{\sf postbreakpenalty}パラメタの値
+\item \IT{.xspc\_before}, \IT{.xspc\_after}: $h$の前後に|\xkanjiskip|が挿入可能であるかの
+指定値(パラメタ{\sf jaxspmode}, {\sf alxspmode}由来)
+\item \IT{.auto\_xspc}: $h$での{\sf autoxspacing}パラメタの値
\enditem
-\beginparagraph 要検討の箇所
+$h$が和文文字を格納している場合は,さらに次の要素の追加作業も含む:
-私が推測するに,欧文では,
-\item 単語内ではフォントは変わらない;
-\item 単語内では,明示的に/ハイフネーションにより挿入されたdiscretionary break以外では
-行分割がおきない;
+\item \IT{.size}: $h$で使われている和文フォントのフォントサイズ.
+\item \IT{.met}, \IT{.var}: 使われているJFMの情報.
+\item \IT{.auto\_kspc}: {\sf autospacing}パラメタの値.
\enditem
-という事情があるため,TFM由来のkernや合字処理は(nodeを生成しないもの以外は)
-何も透過しないという状態になっているものと思われます.
-そのため,JFMグルー等の仕様を考える場合,欧文でいう「単語」に対応するようなものは
-何か,というのを考える必要があります.現実装では,素直に欧文の合字処理と同様のものであると考え,
-透過するnodeはない,という仕様にしています.
-しかし,|\[x]kanjiskip|の処理と共通にしてしまうというのも
-考え方によってはありかもしれません.
+\beginparagraph 全体図
-\bigskip
-\item {\bf イタリック補正のkernの周囲}
+\enum 変数類の初期化
+\itemitem 処理対象が段落の中身(後で行分割される)の場合:$\mibox{mode}\leftarrow\top$
+\itemT \IT{lp}(node走査用カーソル)の初期位置は,
+リスト先頭部にある|\parindent|由来のhboxや
+local paragraph($\Omega$由来)等の情報を格納するwhatsit nodeたちが終わった所
+(つまり,段落本来の先頭部分)となる.
+\itemT \IT{last}(リスト末尾のnode)も,リストの最後部に挿入される|\parfillskip|由来のglue%
+を指す.
+\itemitem
+処理対象がhboxの中身の場合:$\mibox{mode}\leftarrow\bot$
+\itemT \IT{lp}はリスト先頭.
+\itemT 番人として,リスト末尾にkernを挿入.\IT{last}はこのkernとなる.
-例えば,|jfm-ujis.lua|では,|'jcharbdd'|は文字クラス
-0であるため,今の実装では,\hfil\break
-「|)\/(|」という入力からは,次のnodeの並びを得る:
-\setbox1=\hbox{|\/|}%
-$$
-\vbox{\halign{$#$\hfil&$#$\hfil&$#$\hfil&$#$\hfil&$#$\hfil\cr
-\node{\hbox{)}}&\ncount=1
-\node{\np 10000}_{\rm K}&\ncount=1
-\node{\ng 0.5\z_{-0.5}}_{\rm J}\cr&\ncount=1
-\node{\nk \copy1}&\ncount=1
-\node{\np 10000}_{\rm K}&\ncount=1
-\node{\ng 0.5\z_{-0.5}}_{\rm J}&\ncount=1
-\node{\hbox{(}}\cr
-}}
-$$
-一方,イタリック補正をJFM由来グルーが透過するとしたならば,当然
-$$
-\node{\hbox{)}}
-\node{\nk \copy1}
-\node{\ng 0.5\z_{-0.5}}
-\node{\hbox{(}}
-$$
-となる(実際の組版イメージでは,
-「{\tenmini 斜め)}\hbox{}(」「{\tenmini 斜め)}(」).どちらにするか?
+\enum 先頭が\IT{lp}以降にある塊で,一番早いものを\IT{Np}にセットする.
+\itemitem 作業の途中で$\mibox{lp}=\mibox{last}$となったら,処理対象のリストに塊はないので,8.へ.
+\itemitem そうでなければ,$\mibox{head}(\mibox{Np})$の情報を算出しておく.
+\itemitem 本段階終了後,\IT{lp}は\IT{Np.last}の次のnodeとなる.
+\enum ({\tt handle\_list\_head})
+リストに最初に出てくる塊\IT{Np}が求まったので,リスト「先頭」とこの塊との間に和文処理グルーを挿入.
-\item {\bf penaltyの周囲}
+\enum 今の塊\IT{Np}と,その次の塊の間に入る和文処理グルーを求めるため,
+一旦$\mibox{Nq}\leftarrow \mibox{Np}$として待避させ,次の塊\IT{Np}を探索する.
+\itemitem 作業の途中で$\mibox{lp}=\mibox{last}$となったら,\IT{Nq}がリスト中最後の塊であるので,
+7.へ.
+\itemitem そうでなければ,$\mibox{head}(\mibox{Np})$の情報を算出しておく.
+\itemitem 本段階終了後,\IT{lp}は\IT{Np.last}の次のnodeとなる.
-これも,例えば次の設定の下では,「|)\penalty1701(|」からは以下を得る:
-\itemitem 「)」と行末の間に$-0.5\z$だけkernを入れる.
-\itemitem 「)」「(」の行頭/行末禁則用penaltyの値はどれも1000.
-$$
-\vbox{\halign{$#$\hfil&$#$\hfil&$#$\hfil&$#$\hfil&$#$\hfil\cr
-\node{\hbox{)}}&\ncount=1
-\node{\nk {-0.5}\z}_{\rm E}&\ncount=1
-\node{\np 1000}_{\rm K}&\ncount=1
-\node{\ng 1\z_{-0.5}}_{\rm J}\cr
-&\ncount=1\node{\np 1701}&\ncount=1
-\node{\np 1000}_{\rm K}&\ncount=1
-\node{\ng 0.5\z_{-0.5}}_{\rm J}&\ncount=1
-\node{\hbox{(}}\cr}}
-$$
-\leftskip2\zw
-例えばpenaltyを合算することとした場合,上の入力例では本来「)」「(」の間に
-1701のpenaltyがあるのだから,
-$$
-\vbox{\halign{$#$\hfil&$#$\hfil&$#$\hfil&$#$\hfil&$#$\hfil&$#$\hfil\cr
-\node{\hbox{)}}&\ncount=1
-\node{\nk {-0.5}\z}_{\rm E}&\ncount=1
-\node{\np 3701}_{\rm K}&\ncount=1
-\node{\ng 0.5\z_{-0.5}}_{\rm J}&\ncount=1
-\node{\hbox{(}}\cr
-\node{\hbox{)}}&\ncount=1
-\node{\nk {-0.5}\z}_{\rm E}&\ncount=1
-\node{\np 3701}_{\rm K}&\ncount=1
-\node{\ng 1\z_{-0.5}}_{\rm J}&\ncount=1
-\node{\ng 0.5\z_{-0.5}}_{\rm J}&\ncount=1
-\node{\hbox{(}}\cr
-}}
-$$
-のどちらか(上はpenaltyを透過する場合,下は透過しない場合)にするのが
-良いと思われます.
+\enum \IT{Nq}と\IT{Np}の間に和文処理グルーを挿入する.\IT{Np.id}による場合分けを行う.
+「main loop その\nobreak1,~2」を参照のこと.
+\enum \IT{Np}が単一の文字ではない{\small (合字など)}可能性がある以下の場合において,
+$\mibox{tail}(\mibox{Np})$の情報を算出する.終わったら,再びループに入るため,4.へ.
-\item {\bf discretionary breakの取り扱い}
-discretionary break (\IT{disc\_node})は,行分割時の行末の内容<pre>,
-行頭の内容<post>,それに行分割しないときの内容<no_break>の3つをリストの形で
-持っている.|linebreak.w|を見る限り,Lua\TeX でも<pre>, <post>, <no_break>の
-中身にはglueやpenaltyを許容していないようだ.
+\itemitem \IT{id\_glyph}(欧文文字)のとき
+\itemitem \IT{id\_disc} (discretionary break) のとき
+\itemitem \IT{id\_hlist}のとき
+\itemitem \IT{id\_pbox}のとき
-現行の実装では,<pre>, <post>, <no_break>のどれも,和文フォントへの置換の
-段階からして行われていない(だから中身は全部欧文扱いとなる).
-{\small 単純にサボっていました|^^;|}
-<pre>, <post>, <no_break>の中身にglueやpenaltyが許容されないことから,
-これらに対する和文用処理の方法として,次の2種類が挙げられる.
-私は前者で良いのではないかと思っているのだが…….
-\itemitem (現行のまま)discretionary breakの中身に和文文字はないものと想定する.
-例えば<pre>の中身に和文文字を入れたい場合は,<pre>の中身全体を
-必ずhboxで括ることとする.
-\itemitem 「glueを挿入」を全部「自然長だけを取り出したkernを挿入」に置き換え,
-普段の和文処理グルー挿入処理を流用する.
+\enum ({\tt handle\_list\_tail})
+リストの最後にある塊\IT{Nq}が求まったので,この塊とリスト「末尾」の間に和文処理グルーを挿入.
-
-\item {\bf 数式の取り扱い}
-
-まだ数式中に和文文字が(hboxでカプセル化されることなく)出現することは想定していない.
-実用的にはそれでも十分だと思うが,もしp\TeX のように単に
-\begintt
-$aあa$
-\endtt
-などと書いても和文文字が
-出力されるようにするとなれば,「数式リストから変換されてできた水平リストでは,
-和文処理グルーの挿入処理を無効とする」ようにしないといけないだろう.
+\enum $\mibox{mode}=\bot$の場合,番人となるkernを1.において挿入したので,その番人を削除する.
\enditem
-\beginsection {\tt \char"5C[x]kanjiskip}の挿入%"
-
-現実装の|\[x]kanjiskip|の挿入の方針として,
-\item JFMグルーが挿入されていないところに「標準の空き量」として挿入する.
-\item 実際の段落/hboxの内容に即して,組版イメージの見た目に関係のないところは透過する.
-\enditem
+\beginsection リスト先頭・末尾の処理と「boxの内容」
-\beginparagraph 処理の概要
+\beginparagraph リスト先頭の処理 ({\tt handle\_list\_head})
-|\[x]kanjiskip|挿入処理では,次の3つのnodeを用いている.
-$$\ncount=0
-\node{\IT{nr}}\longrightarrow\cdots
-\node{\IT{nq}}\longrightarrow\cdots
-\node{\IT{np}}
-$$
-\item \IT{nr}と\IT{np}の間に|\[x]kanjiskip|を挿入しようとする.
-\item 実際にnodeの形で挿入しようとする場所は$\it nq$の直後である.
-\item \IT{nr}, \IT{nq}は異なるnodeとは限らない.
-\item {\bf \IT{np}はリストの先頭から末尾までループで渡る.}その過程で
-\IT{nr}, \IT{nq}を適宜更新し,実際のnode挿入処理を行っている.
-\item 厳密には,コード中では\IT{nr}という変数は使っていない.代わりに使われているのは,
-\itemitem $\mibox{insert\_skip}\in \{\mibox{no\_skip},
- \mibox{after\_schar}, \mibox{after\_wchar}\}$:
-「node \IT{nr}」の種類を表す:
-\itemT \IT{no\_skip}: 「node \IT{nr}」の後ろ(\IT{nr}と\IT{np}の間)に
-|\[x]kanjiskip|が入ることはない.
-\itemT \IT{after\_schar}: 「node \IT{nr}」を,欧文文字(の入った\IT{glyph\_node})であり,
-かつ{\sf alxspmode}パラメータの指定により「\IT{nr}の後ろに|\xkanjiskip|の挿入を許可する」ようなものとみなす.
-\itemT \IT{after\_wchar}: 「node \IT{nr}」を和文文字(の入った\IT{glyph\_node})とみなす.
-\itemitem \IT{nrc}: 「node \IT{nr}の文字コード」を表す.
-\itemitem \IT{nrf\/}: 「\IT{nr}のフォント」を表す.
-\itemitem $\mibox{nr\_spc}[1]$: 「node \IT{nr}」における
-{\sf autospacing}(|\kanjiskip|の自動挿入を行うか否か)の設定値.
-\itemitem $\mibox{nr\_spc}[2]$: 「node \IT{nr}」における
-{\sf autoxspacing}(|\xkanjiskip|の自動挿入を行うか否か)の設定値.
-
-\medskip\leftskip=2\zw\noindent
-\IT{nrc}, \IT{nrf}の値は,$\mibox{insert\_skip}=\mibox{after\_wchar}$のときのみ用いられる.
-$\mibox{insert\_skip}=\mibox{no\_skip}$のときには,それだけで情報は十分であるから,
-\IT{nr\_spc}, \IT{nq}の値も用いられない.
+次の場合に,
+\IT{Np}で使われているのと同じJFMを使った「文字コードが{\tt 'boxbdd'}の文字」と
+\IT{Np}との間に入るglue/kernを,\IT{Np.first}の直前に挿入する:
+\item $\mibox{Np.id}=\mibox{id\_jglyph}$(和文文字)
+\item $\mibox{Np.id}=\mibox{id\_pbox}$であり,$\mibox{head}(\mibox{Np})$が和文文字であるとき.
\enditem
-
-ループの中で,以下の場合には\IT{nr}は変化せず,$\IT{nq}\leftarrow \IT{np}$となる.
-つまり,これらのnodeに対して|\[x]kanjiskip|は透過する:
-\item \IT{np}がpenaltyの場合
-\item \IT{np}が$\hbox{\tt subtype}=0$のkern(TFM由来)の場合.
-\item \IT{np}が$\hbox{\tt subtype}=1$のkern(つまり,明示的kernかイタリック補正由来)であって,jtypeが
$$
-\hbox{I (イタリック補正),E(行末との間),T(一時的)}
+\vcenter{\halign{$\mibox{mode}=#$:\qquad\hfil&$#$\hfil\cr
+\bot&\node{\kern-1em}\,\hbox{(リスト先頭)}\longrightarrow\cdots\node{g}_{15}
+\node{\mibox{Np}}\cr
+\top&\node{\hbox{{\tt\char92 parindent}由来hbox}}\longrightarrow\cdots
+\Bigl[\node{\np 10000}_{15}\Bigr]\node{g}_{15}\node{\mibox{Np}}\cr
+}}
$$
-であった場合.後者2つはJFMグルーの挿入で入るものなので,
-ユーザは「イタリック補正は透過」と考えればよい.
-
-\item \IT{np}がinsertion, mark, |\vadjust|, whatsitのnodeである場合.
-これらは水平リストからは消え去る運命にある.
-\enditem
+ここで,$g$がglueかつ$\mibox{mode}=\top$かつ$\#\mibox{Bp}=0$のときのみ,|\parindent|由来のhboxの直後で改行されることを防ぐために
+$g$の直前にpenaltyを挿入する.{\small
+($\#\mibox{Bp}$が1以上の場合は,|\parindent|と\IT{Np}の間にある
+penaltyのため,\IT{Np}の直前での改行が起こり得る状態となっているので,
+特にそれを抑制することもしない)\inhibitglue}.
-\beginparagraph \IT{np}が文字 (\IT{glyph\_node}) の場合
-
-この場合がやはり一番基本となる.
-\enum $\mibox{insert\_skip}=\mibox{after\_schar}$, \IT{np}: 和文文字の場合
-
-前に書いたように,「node \IT{nr}」は(直後に|\xkanjiskip|の挿入が許可されている)欧文文字と
-みなされている.
-そのため,「node \IT{nr}」と\IT{np}の間に|\xkanjiskip|の入る条件は以下である.
-\itemitem 文字\IT{np}に対する{\sf jaxspmode}パラメータの指定において
-「直前への|\xkanjiskip|の挿入が許可」されている.
-\itemitem 「node \IT{nr}における」{\sf autoxspacing}パラメタの値 ($\mibox{nr\_spc}[2]$) か,
-\IT{np}における{\sf autoxspacing}の値の少なくとも一方が真である.
-
-\medskip\leftskip=2\zw\noindent
-まず,実際に入る|\xkanjiskip|の量$g$を次の方法で決定する:
-\itemitem {\sf xkanjiskip}パラメータの自然長が|\maxdimen|でない場合,
-{\sf xkanjiskip}パラメータの値をそのまま採用する.
-\itemitem {\sf xkanjiskip}パラメータの自然長が|\maxdimen|の場合は,
-\IT{np}で使われているJFMに設定されている|\xkanjiskip|の量を用いる.
-\itemitem 上の2つのどれでもない場合,fallbackとして0を用いる.
-
-{\bf 要検討}:既にJFMグルー挿入処理で和欧文間の行分割は可能としているので
-0を挿入する意味はない?
-
-\medskip\leftskip=2\zw\noindent
-次にこのようにして決定された$g$を実際に挿入する:
-\itemitem ほとんどの場合,$g$の値をもつglueを\IT{nq}の直後に挿入する.
-$$\ncount=0
-\node{\mibox{nr}}\longrightarrow\cdots
-\node{\mibox{nq}}\node{\ng g}_{\rm XS}\longrightarrow\cdots
-\node{\mibox{np}}
-$$
-\itemitem \IT{np}の直前が${\rm jtype}={\rm T}$なnodeの場合,そのnodeに
-$g$の分だけ自然長/伸び/縮み量を加算する.
-$$\ncount=0
-\vbox{\halign{$#$\hfil\cr
-\node{\mibox{nr}}\longrightarrow\cdots
-\node{\mibox{nq}}\longrightarrow\cdots
-\node{\ng h}_{\rm T}
-\node{\mibox{np}}\cr
-\hfil\Downarrow\cr
-\vadjust{\bigskip}
-\node{\mibox{nr}}\longrightarrow\cdots
-\node{\mibox{nq}}\longrightarrow\cdots
-\node{\ng g+h}_{\rm XS}
-\node{\mibox{np}}\cr
-\node{\mibox{nr}}\longrightarrow\cdots
-\node{\mibox{nq}}\longrightarrow\cdots
-\node{\nk k}_{\rm T}
-\node{\mibox{np}}\cr
-\hfil\Downarrow\cr
-\node{\mibox{nr}}\longrightarrow\cdots
-\node{\mibox{nq}}\longrightarrow\cdots
-\node{\ng g+k}_{\rm XS}
-\node{\mibox{np}}\cr
-}}
-$$
+\beginparagraph リスト末尾の処理 ({\tt handle\_list\_tail})
-\medskip\leftskip=2\zw\noindent
-最後に,次のループに移るために,次の処理を行う:
-\itemitem
-$\mibox{nq}\leftarrow \mibox{np}$,
-$\mibox{nr\_spcの設定}$,
-$\mibox{nrf}\leftarrow \mibox{np}.\mibox{font}$,
-$\mibox{nrc}\leftarrow \mibox{np}.\mibox{char}$
-\itemitem $\mibox{np}\leftarrow \mibox{next\/}(\mibox{np})$
-\itemitem $\mibox{insert\_skip}\leftarrow \mibox{after\_wchar}$
-
-\enum $\mibox{insert\_skip}=\mibox{after\_wchar}$, \IT{np}: 欧文文字の場合
-
-前に書いたように,「node \IT{nr}」は和文文字とみなされている.
-そのため,「node \IT{nr}」と\IT{np}の間に|\xkanjiskip|の挿入が起こるための条件は
-次の3条件が満たされていることである:
-\itemitem \IT{nrc}番の和文文字に対する{\sf jaxspmode}パラメータの設定で,
-「直後への|\xkanjiskip|挿入」が許可されている.
-\itemitem \IT{np}の文字{\small(もし\IT{np}が合字であれば,合字の構成要素の最初の文字)}%
-に対する{\sf alxspmode}パラメータの設定で,
-「直前への|\xkanjiskip|挿入」が許可されている.
-\itemitem \IT{nr}における{\sf autoxspacing}パラメタの値 ($\mibox{nr\_spc}[2]$) か,
-「node \IT{nr}」における{\sf autoxspacing}の値の少なくとも一方が真である.
-
-\medskip\leftskip=2\zw\noindent
-この後,実際に|\xkanjiskip|の量を計算し,nodeの形で実際に挿入するところは,
-量の決定のところで\IT{np}の代わりに\IT{nrf}を用いる以外は同じである.
-最後の,次のループに移るための処理では,次が行われる.
-\itemitem
-$\mibox{nq}\leftarrow \mibox{np}$,
-$\mibox{nrc}\leftarrow \mibox{np}.\mibox{char}$,
-$\mibox{nr\_spcの設定}$
-\itemitem $\mibox{np}\leftarrow \mibox{next\/}(\mibox{np})$
-\itemitem \IT{insert\_skip}の設定.
-
-$\mibox{insert\_skip}\leftarrow \mibox{after\_schar}$となるのは,
-\IT{np}の文字{\small(もし\IT{np}が合字であれば,合字の構成要素の末尾の文字)}%
-における{\sf alxspmode}パラメータの設定で,
-「直後への|\xkanjiskip|挿入」が許可されている場合である.
-そうでないときは,$\mibox{insert\_skip}\leftarrow \mibox{no\_skip}$となる.
-
-\enum $\mibox{insert\_skip}=\mibox{after\_wchar}$, \IT{np}: 和文文字の場合
-
-この場合は|\xkanjiskip|の代わりに|\kanjiskip|を挿入することとなる.
-{\sf jaxspmode}, {\sf alxspmode}のように「直前/直後への|\kanjiskip|挿入許可の制御」
-を行うパラメータは存在しない.「{\sf autospacing}で自動挿入が禁止される」とマニュアルでは言っているが,
-それは{\bf 挿入する|\kanjiskip|の量を一時的に0にしているだけで,
-「node \IT{nr}」と\IT{np}の間には
-常に|\kanjiskip|が入ることには変わりはない}ことに注意.
+この場合,\IT{mode}の値により処理が全く異なる.
-\medskip
-実際に入る|\kanjiskip|の量$g$は次の方法で決定される:
-\itemitem \IT{nr}における{\sf autospacing}の値 ($\mibox{nr\_spc}[1]$) か,
-\IT{np}における{\sf autospacing}の値が共に偽なら,$g=0$.
-\itemitem {\sf kanjiskip}パラメータの自然長が|\maxdimen|でない場合,
-{\sf kanjiskip}パラメータの値をそのまま採用する.
-\itemitem {\sf xkanjiskip}パラメータの自然長が|\maxdimen|の場合は,
-\IT{np}で使われているJFMに設定されている|\kanjiskip|の量を用いる:
-\itemT 「node \IT{nr}」で使用されているJFMと,\IT{np}で使用されているJFMそれぞれに
-|\kanjiskip|の値が設定されている場合,…….
-
-\itemitem 上の3つのどれでもない場合,fallbackとして0を用いる.
+\noindent{\bf A: \IT{mode}が偽である場合.}
+この場合はリストはhboxの中身だから,行分割はおこり得ない.
+リスト先頭の処理と同様に,
+次の場合に
+\IT{Nq}と「文字コードが{\tt 'boxbdd'}の文字」と
+の間に入るglue/kernを,\IT{Nq.last}の直後に挿入する:
+\item $\mibox{Nq.id}=\mibox{id\_jglyph}$(和文文字)
+\item $\mibox{Nq.id}=\mibox{id\_pbox}$であり,$\mibox{tail}(\mibox{Nq})$が和文文字であるとき.
\enditem
+$$
+\node{\mibox{Nq}}\node{g}_{15}\longrightarrow\cdots\node{\nk\hbox{(番人)}}
+$$
+上の番人は,次のstepで除去されるのだった.
\medskip
-$g$を実際に挿入するところは,今の場合も1.の場合と変わらない.
-次のループに移るために\IT{nq}等の設定処理も,1.と同じである.
+\noindent{\bf B: \IT{mode}が真である場合.}
-\beginparagraph \IT{np}がhboxの場合
+この場合,段落の末尾には常に|\penalty 10000|と|\parfillskip|由来のグルーが存在する.
+そのため,上のように「文字コードが{\tt 'boxbdd'}の文字」との空白を考えるのではなく,
+まず,\IT{Nq}が行末にきたときに行末との間に入る空白$w$を代わりに挿入する.
+\item $\mibox{Nq.id}=\mibox{id\_jglyph}$(和文文字)
+\item $\mibox{Nq.id}=\mibox{id\_pbox}$であり,$\mibox{tail}(\mibox{Nq})$が和文文字であるとき.
+\enditem
+$$
+\node{\mibox{Nq}}\node{\nk w}_{15}\node{\np10000}\longrightarrow\cdots
+\node{\ng (\hbox{\tt\char92 parfillskip})}
+$$
+次に,|\jcharwidowpenalty|の挿入処理を行う→省略.
-|\[x]kanjiskip|は,垂直変位が0である(即ち,|\raise|, |\lower|により上下に移動されていない)
-hboxの境界を跨ぐ.
+\beginparagraph box内の「最初/最後の文字」の検索 ({\tt check\_box})
-\enum hbox内の「最初のnode」\IT{first\_char}と「最後のnode」\IT{last\_char}を探索する.
-この探索は,次を透過する:
-\itemitem 垂直変位が0であるhboxの境界(但し,空hboxは透過しない).
-\itemitem insertion, mark, |\vadjust|, whatsit, penalty用のnode.
-\itemitem 「最初のnode」「最後のnode」それぞれにいえることだが,文字 (\IT{glyph\_node}) でない場合は
-\IT{first\_char},~\IT{last\_char}はそれぞれ$\emptyset$となる.
+「hboxの中の文字と外の文字の間に」|\kanjiskip|, |\xkanjiskip|の挿入を行えるようにするため,
+{\tt check\_box}関数ではhbox内の「最初のnode」「最後のnode」の検索を行う.
-\medskip\leftskip=2\zw\noindent
-前者の具体例として,例えば,次の入力を考える.
-\begintt
-あ\hbox{a}い\hbox{\hbox{}b\hbox{}}う\hbox{}cえ\hbox{\hbox{d}}お
-\endtt
-すると,
-$$
-\vbox{\halign{#の間のhbox\hfil\quad $\longrightarrow$\quad
-&$\mibox{first\_char}=\hbox{#}$,\ \hfil
-&$\mibox{last\_char}=\hbox{#}$\hfil\cr
-1.\ 「あ」「い」&「a」&「a」\cr
-2.\ 「い」「う」&$\emptyset$&$\emptyset$\cr
-3.\ 「う」「c」&$\emptyset$&$\emptyset$\cr
-4.\ 「え」「お」&「d」&「d」\cr
-}}
-$$%$
-となる.
-
-\enum \IT{np}の前に|\[x]kanjiskip|を挿入するか否か,あるいは実際に挿入する量の決定は,
-\IT{first\_char}に対しての処理をそのまま適用する.つまり,上の例では
-\itemitem 「あ」と「a」の間に|\xkanjiskip|が挿入されることから,「あ」とhbox 1.の間には|\xkanjiskip|が挿入される.
-\itemitem 「い」とhbox 2.の間には|\xkanjiskip|が挿入されない.
-
-\enum 同様に,\IT{np}の後ろに|\[x]kanjiskip|を挿入するか否かは,
-文字\IT{last\_char}の後ろに対してどうなるかの値を用いる.上の例では,
-\itemitem 「a」と「い」の間に|\xkanjiskip|が挿入されることから,hbox 1.と「い」の間には|\xkanjiskip|が挿入される.
-\itemitem hbox 2.と「う」の間には|\xkanjiskip|が挿入されない.
-\medskip\leftskip=2\zw\noindent
-次のループに進むための設定も,node~\IT{last\_char}における値をもとに行う.
+\item 以下のnodeは検索から除外される:
+\itemitem 組版結果からは消えてしまう,\IT{ins\_node},
+\IT{mark\_node}, \IT{adjust\_node}, \IT{whatsit\_node}, penalty.
+\itemitem (box中身の先頭/末尾に入っている)icflagが7のglue/kern/penalty.
+\itemitem アクセント部とイタリック補正.
+\item \IT{hlist\_node}~$q$に出会ったら,$q$の垂直変位量が0である限り,検索は$q$の内部も進む.以下同文.
+\item 検索して得られた「最初のnode」「最後のnode」がそれぞれ\IT{glyph\_node}でなければ,
+実際には$\emptyset$を返す.
\enditem
-以上より,項目1.で与えられた入力では,次の出力が得られる:
-$$
-\hbox{あ\hbox{a}い\hbox{\hbox{}b\hbox{}}う\hbox{}cえ\hbox{\hbox{d}}お}
-$$
-{\bf 要検討:}空のhboxは跨がないようにしているのは,次の2つを使い分けられるようにするため:
-\item JFMグルー挿入の抑止:|\inhibitglue|
-\item 全ての和文処理グルー挿入の抑止:
-|\inhibitglue\hbox{}\inhibitglue|
+\vfill\eject
+\beginsection main loop
+
+\beginparagraph 一覧表
+
+\IT{Nq}, \IT{Np}の種類別に挿入されるglue/kernの種別を表にすると次のようになる.
+
+\def\;{\hskip0.25em}\ltjsetparameter{jacharrange={+1}}
+\def\gkf#1#2#3#4#5{$\vcenter{\small\rm\halign{\hbox to 1em{\hss##\hss}\;\vrule&%
+\hbox to 3em{\hss##\hss}&\vrule\;\hbox to 1em{\hss##\hss}\cr
+#1\mathstrut&\omit\hfil #2\span\omit\cr\noalign{\hrule}#3\strut\cr}}$}
+\setbox1=\hbox{\gkf{E}{M→K}{○}{nor}{○}}
+\setbox2=\hbox to 0.4pt{\vrule height\dimexpr \ht1+0.5em\relax depth \dimexpr \dp1\relax}
+$$\def\:{\hskip0.5em}\lineskiplimit=\maxdimen\lineskip=0pt
+\vcenter{\halign{\hfil#\hfil\hskip1em\copy2%
+\:&\:\hfil#\hfil\:&\:\hfil#\hfil\:&\:\hfil#\hfil\:&\:\hfil#\hfil%
+\:&\:\hfil#\hfil\:&\:\hfil#\hfil\:&\:\hfil#\hfil\:&\:\hfil#\hfil\cr
+\raise0.5em\hbox{$\vcenter{\hbox{\IT{Nq}→}\smallskip\hbox{\IT{Np}↓}}$}%
+&和文1&和文2&欧文&箱&id\_glue&id\_kern\cr
+\noalign{\hrule}
+和文1&
+\gkf{E}{M→K}{○}{nor}{○}&
+\gkf{}{$\rm O_A$→K}{×}{nor}{○}&
+\gkf{}{$\rm O_A$→X}{○}{nor}{○}&
+\gkf{}{$\rm O_A$}{---}{all}{○}&
+\gkf{}{$\rm O_A$}{---}{nor}{○}&
+\gkf{}{$\rm O_A$}{---}{sup}{○}\cr
+和文2&
+\gkf{E}{$\rm O_B$→K}{○}{nor}{×}&
+\gkf{}{K}{×}{sup}{×}&
+\gkf{}{X}{○}{sup}{×}\cr
+欧文&
+\gkf{E}{$\rm O_B$→X}{○}{nor}{○}&
+\gkf{}{X}{○}{sup}{×}\cr
+箱&\gkf{E}{$\rm O_B$}{○}{alw}{---}\cr
+\IT{id\_glue}&\gkf{E}{$\rm O_B$}{○}{nor}{---}\cr
+\IT{id\_kern}&\gkf{E}{$\rm O_B$}{○}{sup}{---}\cr
+}}$$
+
+\item {\bf 項目名}\quad 表1行目の\IT{Nq}の種類について説明する.\IT{Np}についても同様.
+\itemitem 「和文1」:リスト中に直接出現している和文文字.
+\itemT $\mibox{Nq.id}=\mibox{id\_jglyph}$であったとき.
+\itemT $\mibox{Nq.id}=\mibox{id\_pbox}$かつ$\mibox{last}(\mibox{Nq})$が和文文字であったとき.
+\itemitem 「和文2」:リスト内にあるhboxの中身として出現した和文文字.すなわち,
+$\mibox{Nq.id}=\mibox{id\_hlist}$かつ
+$\mibox{last}(\mibox{Nq})$が和文文字であったとき.
+\itemitem 「欧文」:$\mibox{last}(\mibox{Nq})$が欧文文字であったとき.即ち,
+\itemT リスト中に直接出現しているとき($\mibox{Nq.id}=\mibox{id\_jglyph}$ or~%
+$\mibox{Nq.id}=\mibox{id\_pbox}$かつ$\mibox{last}(\mibox{Nq})$が欧文文字).
+\itemT $\mibox{Nq.id}=\mibox{id\_hlist}$かつ
+$\mibox{last}(\mibox{Nq})$が欧文文字であったとき.
+\itemT $\mibox{Nq.id}=\mibox{id\_math}$であったとき.
+\itemitem 「箱」:前後に和文処理グルーが挿入されない用なbox状のnode.
+\itemT $\mibox{Nq.id}=\mibox{id\_list}$かつ
+$\mibox{last}(\mibox{Nq})$が文字でなかった(未定義)だったとき.
+\itemT $\mibox{Nq.id}=\mibox{id\_box\_like}$のとき.
+\itemitem 「\IT{id\_glue}」:そのまま,$\mibox{Nq.id}=\mibox{id\_glue}$であったとき.
+\itemitem 「\IT{id\_kern}」:そのまま,$\mibox{Nq.id}=\mibox{id\_kern}$であったとき.
+
+\item 表中の各セルは,それぞれ次のような内容を表している:
+$$\vcenter{\rm\halign{\hbox to 3em{\hss#\hss}\;\vrule&%
+\hbox to 3.5em{\hss#\hss}&\vrule\;\hbox to 3em{\hss#\hss}\cr
+左空白\mathstrut&\omit\hfil 右空白\span\omit\cr\noalign{\hrule}L&P取扱\strut&R\cr}}$$
+
+\itemitem 「左空白」:\IT{Nq}の直後に挿入される空白の種類.空欄は,何も入らないことを表す.
+\itemitem 「右空白」:\IT{Np}の直前に挿入される空白の種類.
+
+なお,「A→B」は,まずAの種類のglue/kernを調べ,それが未定義ならば,
+Bの種類のglue/kernを採用することを示している.このとき,矢印の右側に入る空白%
+(K, X)はいつでも定義されていることに注意.
+
+\itemitem 「P取扱」:\IT{Nq}と\IT{Np}の間に入る禁則用ペナルティの取扱の方法を表す.
+\IT{Nq}と\IT{Np}の間で常に行分割を許すかに伴い,
+{\bf nor}mal, {\bf alw}ays, {\bf sup}pressの3種類がある.
+\itemitem 「L」「R」:禁則用ペナルティの挿入処理において,
+\IT{Nq.post}~(L)や\IT{Np.pre}~(R)の値を実際に活用するかどうかを示す.値は次の3種類:
+$$
+\hbox{○(利用する),×(利用せず,0として扱う),---(未定義のため0扱い)}$$
\enditem
-なお,\IT{np}の垂直変位が0でない場合は,\IT{np}の前後への|\[x]kanjiskip|の挿入は行われない
-(即ち,$\mibox{insert\_skip}\leftarrow\mibox{no\_skip}$となる).
+\beginparagraph 挿入されるglue/kernの種類
-\beginparagraph \IT{np}がkernの場合
+前節の表にある空白の種類についての解説を行う.
-前に書いたように,|subtype|が0のkern(TFM由来)や,|subtype|が1であってもjtypeがI, E,~Tのkernは
-挿入処理を透過してしまうので,今問題にしているのはそうでない場合である.
+\item E: \IT{Nq}が行末にきたとき,
+\IT{Nq}と行末の間に入る空白 (kern).挿入位置は\IT{Nq.last}の直後.
+\itemitem JFMでは「文字コード|'lineend'|の文字」との間に入るkern量として設定できる.
+\itemitem 右空白がkernであるときは挿入されない.
+\itemitem この種類のkernが挿入される時,右空白は自然長がEの分だけ引かれる.
-\item $\hbox{\tt subtype}=1$の場合.
-挿入処理で透過されないのは
-jtypeがない(明示的kern)か,jtypeがJ(JFM由来グルー)という2つの場合であるが,
-いずれの場合も,\IT{np}の周囲には|\[x]kanjiskip|の挿入は行われない.そのため,次ループのために
-行われる処理は,$\mibox{insert\_skip}\leftarrow\mibox{no\_skip}$,
-$\mibox{np}\leftarrow\mibox{next}(\mibox{np})$だけである.
-
-\item $\hbox{\tt subtype}=2$(|\accent|由来)の場合.
-
-\IT{np}はリストの先頭から走査されていることから,\IT{np}に続くnodeの並びは
-$$\ncount=0
-\node{\mibox{np}=\nk\!\!}
-\node{\hbox{アクセント文字}}
-\node{\nk\!\!}
-\node{\hbox{アクセントのつく文字}}
+\item M: \IT{Nq}と\IT{Np}の間に入るJFM由来のglue/kern.
+\itemitem \IT{Nq}, \IT{Np}の間で|\inhibitglue|を発行した場合,挿入は抑止される.
+\itemitem 両方の塊で使われているJFMが(サイズもこめて)等しい場合は,両者で使われている
+JFMの情報をそのまま利用できるので,量の決定は容易い.
+\itemitem そうでなければ,まず
$$
-となっている.p\TeX-3.2と同様に,Lua\TeX-jaでは|\[x]kanjiskip|挿入処理で
-アクセント文字は無視することにしている.そのため,
-\IT{nq}は変化せず,次回のループで処理対象となる\IT{np}は
-$\mibox{np}\leftarrow
-\mibox{next\/}(\mibox{next\/}(\mibox{next\/}(\mibox{np})))$となる.
+\vcenter{\halign{\hfil$#:={}$&(\inhibitglue#\inhibitglue)\cr
+gb&\IT{Nq}と「文字コードが|'diffmet'|の文字」との間に入るglue/kern\cr
+ga&「文字コードが|'diffmet'|の文字」と\IT{Np}との間に入るglue/kern\cr
+}}
+$$
+として2つの量を計算.少なくとも片方が未定義の場合は,もう片方の値を用いる.
+そうでなければ,両者の値から自然長,伸び量,縮み量ごとに計算
+(方法として,平均,和,大きい方,小さい方)を行い,それによって得られたglue/kernを採用する.
+\item K: |\kanjiskip|を表すglueを挿入($\emptyset$にはならない).
+\itemitem 両方の塊において「|\kanjiskip|の自動挿入が無効」
+ ($\mibox{Nq.auto\_kspc}\vee \mibox{Np.auto\_kspc}=\bot$) ならば,長さ0のglueを挿入する.
+\itemitem {\sf kanjiskip}パラメタの自然長が$\hbox{\tt\char92maxdimen}=(2^{30}-1)\,{\rm sp}$で
+あれば,
+JFMに指定されている|\kanjiskip|の量を用いる.\IT{Nq}, \IT{Np}で使われているJFMが異なった時の処理は,
+Mの場合と同じである.
+\itemitem 上のどれにも当てはまらなければ,{\sf kanjiskip}パラメタで表される量のglueを挿入する.
+\item X: |\xkanjiskip|を表すglueを挿入($\emptyset$にはならない).
+\itemitem 次のいずれかの場合には,|\xkanjiskip|は長さ0のglueとなる:
+\itemT 両方の塊において,「|\xkanjiskip|の自動挿入が無効」という指定
+($\mibox{Nq}.\mibox{auto\_xspc}\vee \mibox{Np}.\mibox{auto\_xspc}=\bot$)
+がされていた場合.
+\itemT \IT{Nq}内の文字について「直後への|\xkanjiskip|挿入が無効」であった場合,即ち
+$\hbox{\sf alxspmode}\ge 2$(欧文)か$\hbox{\sf jaxspmode}\equiv0\pmod2$(和文).
+\itemT \IT{Np}内の文字について「直前への|\xkanjiskip|挿入が無効」であった場合,即ち
+$\hbox{\sf alxspmode}\equiv0\pmod2$(欧文)か$\hbox{\sf jaxspmode}\ge2$(和文).
+\itemitem {\sf xkanjiskip}パラメタの自然長が|\maxdimen|であれば,
+$\mibox{last}(\mibox{Nq})$, $\mibox{head}(\mibox{Np})$の片方が和文文字であるので,
+そこで使われているJFMで指定されている|\xkanjiskip|の量を用いる
+(JFMで指定されていなければ長さ0のglueと見なされる).
+\itemitem 上のどれにも当てはまらなければ,{\sf xkanjiskip}パラメタで表される量のglueを挿入する.
+\item $\rm O_B$: \IT{Nq}と「文字コードが|'jcharbdd'|の文字」との間に入るglue.
+Mのバリエーションと考えればよく,同じように|\inhibitglue|の指定で抑止される.
+\item $\rm O_A$: 「文字コードが|'jcharbdd'|の文字」と\IT{Np}との間に入るglue.
+Mのバリエーションと考えればよく,同じように|\inhibitglue|の指定で抑止される.
\enditem
-\beginparagraph \IT{np}が数式境界 (\IT{math\_node})の場合
-
-数式境界は,便宜的に「文字コードが$-1$である文字」とみなして内部で処理している.
-\beginparagraph その他の場合
+\beginparagraph penaltyまわりの処理
-以上に出てきていないnode(vbox, rule, discretionary break, glue, margin\_kern)の
-周囲には|\[x]kanjiskip|の挿入は行われない.
-
-\beginsection JFM由来グルーとの関係の例
+隣り合った塊\IT{Nq}, \IT{Np}の間には,集合\IT{Bp}で表される0個以上のpenaltyがあるのだった:
+$$
+\node{\mibox{Nq}}
+\Bigl[\node{\hbox{E}}_4\Bigr]
+\longrightarrow\cdots
+\hbox{(penaltyある可能性あり)}\cdots
+\Bigl[\node{\hbox{M, K, X他}}_{3,\,5,\,6}\Bigr]
+\node{\mibox{Np}}
+$$
+禁則処理に関係するpenaltyの挿入処理は,以下に述べるところ部分は共通の動作である.
-最後に,今まで説明した,JFM由来グルーと|\[x]kanjiskip|の処理によって,実際にどのようにnodeの
-並びが変わるかをいくつかの例で示す.上付きで$*$がついているnodeは,値が0だと挿入されないことを示す.
+\medskip
+$\#\mibox{Bp}\ge 1$の場合には,{\bf 全ての}\IT{Bp}の元$p$~(penalty)に対して次を行う:
+$$p.\mibox{penalty}\mathrel{+}=a,\qquad a:=\mibox{Nq.post}+\mibox{Np.pre}.$$
+\item
+全ての\IT{Bp}の元に対して行うのは,
+実際にはどのpenaltyの位置で行分割が行われるかがわからないからである.
+\item 数ページ前の表で,左下が「×」 or 「---」となっていた場合は,上の計算式において
+\IT{Nq.post}は0と扱われる.右下が「×」 or 「---」なら,\IT{Np.pre}が0と扱われる.
+\item penalty値の計算では,$+10000$は正の無限大,$-10000$は負の無限大として扱っている.
+そのため,$a$の計算や$p.\mibox{penalty}$への加算代入のところでは,
+通常の加減算で絶対値が10000を越えたら分はカットし,さらに$(10000)+(-10000)=0$としている.
+\enditem
+$\#\mibox{Bp}=0$の場合が,penalty挿入の3種類の方法「normal」「always」「suppress」で
+異なる部分である:
-\item {\bf 例1: 2つの連続する和文文字の間}
-\setbox1=\hbox{|\kanjiskip|}
-$$\ncount=0
-\vbox{\halign{$#$\hfil\cr
-\node{\hbox{和文文字}}\node{\hbox{和文文字}}
-\cr
-\hfil\Downarrow\cr
-\vadjust{\bigskip}
-\node{\hbox{和文文字}}
-\node{\nk w}_{\rm E}^*
-\node{\np P}^*\longrightarrow
-\left\{\vcenter{%
-\halign{$#$\hfil\cr
-\ncount=0\node{{\rm glue/kern}\ g+w}_{\rm J}\cr
-\ncount=0\node{\copy1+w}_{\rm KS}\cr
-}}\right\}
-\node{\hbox{和文文字}}\cr
-}}
+\item {\bf「normal」の場合:}
+次の場合に,$p.\mibox{penalty}=a$であるpenalty~$p$を作成し,
+それを(M, K他のglue挿入前に)\IT{Np.first}の直前に挿入する:
$$
-
-\item {\bf 例2: 和文文字と欧文文字の間}
-\setbox1=\hbox{|\xkanjiskip|}
-$$\ncount=0
-\vbox{\halign{$#$\hfil\cr
-\node{\hbox{和文文字}}\node{\hbox{欧文文字}}
-\cr
-\hfil\Downarrow\cr
-\vadjust{\bigskip}
-\node{\hbox{和文文字}}
-\node{\nk w}_{\rm E}^*
-\node{\np P}\longrightarrow
-\left\{\vcenter{%
-\halign{$#$\hfil\cr
-\ncount=0\node{{\rm glue/kern}\ g+w}_{\rm J}\cr
-\ncount=0\node{\copy1+w}_{\rm XS}\cr
-}}\right\}^*
-\node{\hbox{欧文文字}}\cr
-}}
+\hbox{左空白(E)が存在しているか,$a\neq 0$かつ右空白がkernである.}
$$
-ここで,上の2つの例に出てきた記号の意味は次の通り:
-\itemitem $w$: 前側の和文文字と行末の間に入るkern量.
-\itemitem $g$: 2つの文字の間に入るglue/kern(JFM由来).
-\itemitem $P$: 2つの文字の禁則用penaltyの合計値.
-
-
-\par\vfill\eject
-\item {\bf 例3: 2つの和文文字の間にいくつかの「無視される」node達}
-\setbox1=\hbox{|\kanjiskip|}
-$$\ncount=0
-\vbox{\halign{$\relax#$\hfil&$\relax#$\hfil\cr
-\node{\hbox{和字}\ A}&
-\ncount=1\node{\nk i_A}_{\rm I}
-\longrightarrow \cdots
-\node{\np p_B}
-\node{\hbox{和字}\ B}
-\cr
-\span\Downarrow\cr
-\vadjust{\bigskip}
-% T
-\node{\hbox{和字}\ A}&
-\ncount=1\node{\nk w_A}_{\rm E}^*
-\node{\np P_A}_{\rm K}^*
-\node{\nk {-w_A}}_{\rm T}^*
-\node{\nk i_A}_{\rm I}
-\longrightarrow \cdots\cr
-&\ncount=1\node{\np p_B}
-\node{\np P_B}^*\longrightarrow
-\left\{\vcenter{%
-\halign{$#$\hfil\cr
-\ncount=0\node{{\rm glue/kern}\ g_B}_{\rm J}\cr
-\ncount=0\node{\copy1}_{\rm KS}\cr
-}}\right\}
-\node{\hbox{和字}\ B}\cr
-\span\hbox{or}\cr
-% T
-\node{\hbox{和字}\ A}&
-\ncount=1\node{\nk w_A}_{\rm E}^*
-\node{\np P_A}_{\rm K}^*
-\node{{\rm glue/kern}\ g_A-w_A}_{\rm J}
-\node{\nk i_A}_{\rm I}\cr
-&\ncount=1
-\longrightarrow \cdots
-\node{\np p_B}
-\node{\np P_B}
-\node{{\rm glue/kern}\ g_B}_{\rm J}^*
-\node{\hbox{和字}\ B}\cr
-}}
+\item {\bf「always」の場合:}
+この場合は,\IT{Nq}, \IT{Np}の間で常に行分割可能にしたいので,挿入する条件は以下のようになる:
$$
-ここで,
-\itemitem $w_A$: 和文文字$A$と行末の間に入るkern量.
-\itemitem $P_A$: 和文文字$A$の行末禁則用penalty.
-\itemitem $g_A$: 和文文字$A$と|'jcharbdd'|との間に入るglue/kern.
-\itemitem $P_B$: 和文文字$B$の行頭禁則用penalty.
-\itemitem $g_B$: |'jcharbdd'|と和文文字$B$の間に入るglue/kern.
+\hbox{左空白(E)が存在しているか,右空白がglueでない(つまり,kernか未定義のとき).}
+$$
+
+\item {\bf「suppress」の場合:}このとき,\IT{Nq}と\IT{Np}の間での行分割は元々不可能である.
+Lua\TeX-ja では,そのような場合を「わざわざ行分割可能に」することはしない.
+つまり,右空白がglueであるとき,その直前に|\penalty 10000|を挿入する.
\enditem
+\beginparagraph いくつかの例:未完
+
+\beginsection main loop その2: その他の場合
+
+\setbox1=\hbox{hp}\setbox2=\hbox to 0.4pt{\vrule height\dimexpr \ht1+0.25em\relax depth \dimexpr \dp1+0.25em\relax}
+$$\def\:{\hskip0.5em}\lineskiplimit=\maxdimen\lineskip=0pt
+\vcenter{\halign{\hfil\IT{#}\hfil\hskip1em\copy2%
+\:&\:\hfil\IT{#}\hfil\:&\:\hfil\IT{#}\hfil\:&\:\hfil\IT{#}\hfil\:&\:\hfil\IT{#}\hfil%
+\:&\:\hfil\IT{#}\hfil\:&\:\hfil\IT{#}\hfil\:&\:\hfil\IT{#}\hfil\:&\:\hfil\IT{#}\hfil\cr
+\IT{Np}→&&id\_hlist 非文字\cr
+\IT{Nq}↓&$\mibox{head}(\mibox{Nq})$\rm: 欧文&id\_box\_like&id\_glue&id\_kern\cr
+\noalign{\vskip.25em\hrule\vskip.25em}
+id\_jglyph&\rm E${}+{}$({\rm $\rm O_B$→X})&\rm E${}+\rm O_B^*$&\rm E${}+\rm O_B$&\rm E${}+\rm O_B^+$\cr
+id\_pbox 和&\rm E${}+{}$({\rm $\rm O_B$→X})&\rm E${}+\rm O_B^*$&\rm E${}+\rm O_B$&\rm E${}+\rm O_B^+$\cr
+id\_hlist 和&\rm X${}^+$&---&---&---\cr
+他&---&---&---&---\cr
+}}$$
\end
\def\XyM{X\kern-.30em\smash{\raise.50ex\hbox{\UPSILON}}\kern-.30em{M}}%
\def\XyMTeX{\XyM\kern-.1em\TeX}%
-
% main matter
\centerline{\big Lua\TeX-jaパッケージ}\bigskip
\centerline{\large\the\year/\the\month/\the\day}\medskip
ほげほげ){\gt (ふがふが}
\endtt
\item 欧文や和文のベースライン補正が可能.
-\item p\TeX とある程度コマンド名が互換.
+\item p\TeX とある程度コマンド名が互換ではあるが,{\bf 内部動作についてはp\TeX との100\%互換は
+目指していません{\small (p\TeX で不自然なところがあれば,積極的に改める)\inhibitglue}}.
\enditem
\beginparagraph 制限
\beginparagraph ファイル構成
-
-\item {\tt luatexja-core.sty}:
-コア部分.拡張子は{\tt sty}であるが,この単一のファイルでplain \TeX と\LaTeX 両方に
-対応するように設計する方針である.しかし,
-{\bf 現時点で\LaTeX での使用は全く考慮されていない.}
-\item {\tt luatexja-core.lua}: コア部分に使われるLuaコード.
-\item {\tt luatexja-jfont.lua}: 和文フォント定義部のLuaコード.
-\item {\tt luatexja-xkanji.lua}: |\[x]kanjiskip|自動挿入処理のLuaコード.
-\item {\tt luatexja-rmlgbm-data.lua}: 非埋込和文フォント用のデータ(小塚明朝Pr6N R由来).
-\item {\tt luatexja-rmlgbm.lua}: 非埋込和文フォント (Ryumin-Light etc.) 定義部.
-\item {\tt mk-rmlgbm-data.tex}: {\tt luatexja-rmlgbm-data.lua}作成用スクリプト
+\item {\tt src/}: 核となる\TeX ソースとLuaコードはこのディレクトリ内に入っている.
+\itemitem \TeX 用スタイルファイル達
+\itemT {\tt luatexja.sty}: 利用者はこのファイルを読み込む.
+拡張子は{\tt sty}であるが,plain \TeX と\LaTeX 両方に対応させる方針である.しかし,
+{\bf 現時点で\LaTeX での使用は考慮されていない.}
+\itemT {\tt luatexja-core.sty}:
+\itemT {\tt luatexja-base.sty}:
+\itemT {\tt luatexja-cctbreg.sty}:
+\itemT {\tt luatexja-compat.sty}: p\TeX 互換用primitive(|\euc|, |\kansuji|)定義部.
+\itemT {\tt luatexja-compat-ptex.sty}:
+\itemT {\tt luatexja-plain.sty}:
+\itemT {\tt luatexja-kinsoku.tex}: 禁則用ペナルティ等のパラメータを書いたファイル.
+{\tt ukinsoku.tex} (in up\TeX-0.30) から自動生成されたもの.
+
+\itemT {\tt mk-rmlgbm-data.tex}: {\tt luatexja-rmlgbm-data.lua}作成用スクリプト
{\small(小塚明朝を{\tt luaotfload}で読み込んだ時のキャッシュが必要)\inhibitglue}.
-\item {\tt luatexja-kinsoku.tex}: 禁則用ペナルティ等のパラメータを書いたファイル.
-下のファイルによって{\tt ukinsoku.tex} (in up\TeX-0.30) から自動生成されたもの.
-\item {\tt jfm-ujis.lua}: up\TeX-0.30の{\tt ujis.tfm}ベースのメトリックサンプル.
-\item {\tt jfm-mono.lua}: 「全文字が全角幅」のメトリックサンプル.
+
+\itemitem Luaコード達(旧フォーマット)
+\itemT {\tt luatexja-core.lua}: コア部分に使われるLuaコード.
+\itemT {\tt luatexja-rmlgbm-data.lua}: 非埋込和文フォント用のデータ(小塚明朝Pr6N R由来).
+\itemT {\tt jfm-ujis.lua}: up\TeX-0.30の{\tt ujis.tfm}ベースのメトリックサンプル.
+\itemT {\tt jfm-mono.lua}: 「全文字が全角幅」のメトリックサンプル.
+
+\itemitem Luaコード達(新フォーマット,{\tt src/luatexja/}以下)
+
+\itemT {\tt base.lua}
+\itemT {\tt compat.lua}: p\TeX 互換用primitive(|\euc|, |\kansuji|)実装部.
+\itemT {\tt jisx0208.lua}: |\euc|等で使うJIS~X~0208→Unicode変換表.
+\itemT {\tt infomute.lua}
+\itemT {\tt jfont.lua}: 和文フォント定義部のLuaコード.
+\itemT {\tt rmlgbm.lua}: 非埋込和文フォント (Ryumin-Light etc.) 定義用コード.
+\itemT {\tt jfmglue.lua}: 和文処理に伴う空白の挿入処理部.
+\itemT {\tt tangle.lua}
+\itemT {\tt charrange.lua}: 「和文文字の範囲」管理部.
+\itemT {\tt debug.lua}
+\itemT {\tt inputbuf.lua}: 「和文文字直後の改行」処理用.
+\itemT {\tt stack.lua}: Lua\TeX-ja スタック管理システム.
\enditem
\beginsection 使用方法
大雑把に言うと,plain \TeX の状況で,以下のようにすればよい.
\begintt
-\input luatexja-core.sty % ←マクロ本体を読み込み
+\input luatexja.sty % ←マクロ本体を読み込み
\jfont\tenipam={file:ipam.ttf:jfm=ujis} at 13.5\jQ
\tenipam\parindent=1\zw
\globaljfont<font>={<font_name>:<features>} <size> % global に定義
\endtt
-
\item {\bf <font_name> の指定について}\par\noindent
内部でluaotfloadパッケージを読み込んでいる.大きくわけて,以下の4種類がある.
このうち,前の2つはluaotfloadパッケージの機能である.
見本として,|jfm-ujis.lua|を入れてある.
\begintt
-ltj.define_jfm {
+luatexja.jfont.define_jfm {
dir = 'yoko', zw = 1.0, zh = 1.0,
[0] = {
align = 'left', left = 0.0, down = 0.0,
}
\endtt
-全体は,「関数|ltj.define_jfm|にテーブルを引数として与える」という構造になっている.
+全体は,「関数|luatexja.jfont.define_jfm|にテーブルを引数として与える」という構造になっている.
以下に,テーブルの中身を述べる.
\item |dir|: 組方向を指定する.将来的にはいずれ縦組(|'tate'|)を実装したいが,
現時点では横組(|'yoko'|)のみの対応.
\beginsection 互換用命令(書きかけ)
{\tt luatexja-compat.sty}を読み込むことで,次が追加.
-\item |\euc|, |\jis|, |\sjis|, |\kuten|, |\ucs|: up\TeX と同じ動作.
+\item |\euc|, |\jis|, |\sjis|, |\kuten|, |\ucs|:
+それぞれEUC-JP,ISO-2022-JP,Shift-JIS,区点コードからUnicodeへの変換を行う.
+JIS~X~0208→Unicodeへの変換テーブルとしては,up\TeX-0.30で用いられているものを利用している.
\item |\kansuji|
-\item |kansujichar={<num>, <char>}| key in |\ltjsetparameter|.
+\item |kansujichar={<num>, <char>}|~key in |\ltjsetparameter|.
\enditem
\item {\bf (luaotfloadパッケージによるグリフ置換等の処理はこの位置で)}
-\item {\bf JFM由来glue/kernの挿入: |pre_linebreak_filter|, |hpack_filter| callbacks}
-
-ここで,JFMに由来する和文文字間のglue/kernを挿入する.
-基本的には連続する和文文字(を表すnode)間に挿入するが,
-\itemitem 水平ボックスの先頭/末尾,段落の先頭/末尾には「文字コード|'boxbdd'|の文字」があると
-見做して空白を挿入する.
-\itemitem 和文文字とそうでないもの(欧文文字,ボックス等)の間に関しては,
-和文文字でない方は「文字コード|'jcharbdd'|の文字」であると見做す.
-\itemitem フォントの異なる2つの和文文字においても,
-両者のフォントのJFMとsizeが一致した場合は,
-挿入処理においては「同じフォント」であるかのように扱う.
-\itemitem そうでない場合は,両者の間に「文字コード|'diffmet'|の文字」があると見做して,
-両和文文字からそれぞれglue/kern |gb|, |ga|を計算し,そこから実際に入るglue/kernを
-計算している(|\ltjsetparameter|中の|differentjfm|キーを参照).
-\itemitem もうちょっと詳しく書くと,本処理前において,和文文字を表す
-2つの連続した|glyph_node| $Q$, $P$の間には,次のnode達が挿入される:
-$$
- \ldots,\ Q,\ (\hbox{|\kern|}\ w\,{\rm pt}),\ (\hbox{|\penalty|}\ p),\
-(\hbox{|\kern|}\ (k-w)\,{\rm pt})
-,\ P,\ \ldots
-$$
-上に書いた全てのnodeが挿入されるとは限らず,また4つめのkernもglueに変わる可能性がある.
-上に出てきた量の意味は次の通りである:
-\itemT $w$: $Q$が行末にきたときに,行末からどれだけずらすかを指定した量.
-\itemT $p$: $Q$の行末禁則用penaltyと$P$の行頭禁則用penaltyの合計値.ウィドウ防止用の
-|\jcharwidowpenalty|が挿入される時は,値はここに加算される.
-\itemT |\kern| $k$: 本来の$Q$と$P$の間に入る空き(glueであることも).
-$w$のために自然長を補正している.
-
-\item {\bf |kanjiskip|, |xkanjiskip|の挿入: |pre_linebreak_filter|, |hpack_filter| callbacks}
-
-p\TeX の|adjust_hlist| procedureとほぼ同様の処理を用いて,
-和文間glue |kanjiskip|や和欧文間glue |xkanjiskip|を
-挿入する.
-\itemitem 数式境界 (|math_node|) との間に|xkanjiskip|を自動挿入するかの決定は,
-p\TeX では数字{\tt 0}との間に挿入するかどうかで判定していたが,Lua\TeX-jaでは
-「文字コード$-1$の文字」で判定している.
-\itemitem 合字の周囲の空白挿入については,構成要素の文字列を通じて判断している.例えば,
-「漢ffi字」という文字列に対して,
-\itemT 「漢」と「ffi」間の空白挿入:「漢」と「f」間に入るかで判断
-\itemT 「ffi」と「字」間の空白挿入:「i」と「字」間に入るかで判断
+\item {\bf 和文処理グルーの挿入: |pre_linebreak_filter|, |hpack_filter| callbacks}
+
+動作の詳細については,{\tt jfmglue.pdf}(未完)を参照.
\item {\bf ベースライン補正: |pre_linebreak_filter|, |hpack_filter| callbacks}
-ltj.define_jfm {
+luatexja.jfont.define_jfm {
dir = 'yoko',
zw = 1.0, zh = 1.0,
-ltj.define_jfm {
+luatexja.jfont.define_jfm {
dir = 'yoko',
zw = 1.0, zh = 1.0,
--- /dev/null
+\DeclareKanjiEncodingDefaults{}{}
+\DeclareErrorKanjiFont{JY3}{mc}{m}{n}{10}
+\DeclareYokoKanjiEncoding{JY3}{}{}
+\DeclareKanjiSubstitution{JY3}{mc}{m}{n}
+%JT3
+
+\newcommand\mcdefault{mc}
+\newcommand\gtdefault{gt}
+\newcommand\kanjiencodingdefault{JY3}
+\newcommand\kanjifamilydefault{\mcdefault}
+\newcommand\kanjiseriesdefault{\mddefault}
+\newcommand\kanjishapedefault{\updefault}
+\kanjiencoding{JY3}
+
+\DeclareKanjiFamily{JY3}{mc}{}
+\DeclareFontShape{JY3}{mc}{m}{n}{<-> psft:Ryumin-Light:jfm=ujis}{}
+\DeclareKanjiFamily{JY3}{gt}{}
+\DeclareFontShape{JY3}{gt}{m}{n}{<-> psft:GothicBBB-Medium:jfm=ujis}{}
+\DeclareFontShape{JY3}{mc}{bx}{n}{<->ssub*gt/m/n}{}
+
+%fontencoding{JT3}\selectfont
+\fontencoding{JY3}\selectfont
+\DeclareTextFontCommand{\textmc}{\mcfamily}
+\DeclareTextFontCommand{\textgt}{\gtfamily}
+\DeclareOldFontCommand{\mc}{\normalfont\mcfamily}{}
+\DeclareOldFontCommand{\gt}{\normalfont\gtfamily}{}
+
+\endinput
--- /dev/null
+%%
+%% luatexja-latex-fonts.sty: derived from plfonts.dtx in pLaTeX.
+%%
+\makeatletter
+\let\k@encoding\@empty
+\let\ck@encoding\@empty
+% LuaTeX-ja uses JY3 and JT3 encodings.
+\def\cy@encoding{JY3}\def\ct@encoding{JT3}
+
+
+\let\k@family\@empty
+\let\k@series\@empty
+\let\k@shape\@empty
+\def\curr@kfontshape{\k@encoding/\k@family/\k@series/\k@shape}
+\def\rel@fontshape{\f@encoding/\f@family/\f@series/\f@shape}
+\newdimen\Cht
+\newdimen\cht
+\newdimen\Cdp
+\newdimen\cdp
+\newdimen\Cwd
+\newdimen\cwd
+\newdimen\Cvs
+\newdimen\cvs
+\newdimen\Chs
+\newdimen\chs
+\newdimen\cHT
+%\let\afont\font
+\def\inlist@#1#2{%
+ \def\in@@##1<#1>##2##3\in@@{%
+ \ifx\in@##2\in@false\else\in@true\fi}%
+ \in@@#2<#1>\in@\in@@}
+\def\fam@elt{\noexpand\fam@elt}
+\def\enc@elt{\noexpand\enc@elt}
+\def\fenc@list{\enc@elt<OML>\enc@elt<T1>\enc@elt<OT1>\enc@elt<OMS>%
+ \enc@elt<OMX>\enc@elt<TS1>\enc@elt<U>}
+\let\kenc@list\@empty
+\let\kyenc@list\@empty
+\let\ktenc@list\@empty
+\def\kfam@list{\fam@elt<mc>\fam@elt<gt>}
+\def\ffam@list{\fam@elt<cmr>\fam@elt<cmss>\fam@elt<cmtt>%
+ \fam@elt<cmm>\fam@elt<cmsy>\fam@elt<cmex>}
+\let\notkfam@list\ffam@list
+\let\notffam@list\kfam@list
+\newbox\tstrutbox
+\newbox\zstrutbox
+\def\strut{\relax
+ \ifydir
+ \ifmmode\copy\strutbox\else\unhcopy\strutbox\fi
+ \else
+ \ifmmode\copy\tstrutbox\else\unhcopy\tstrutbox\fi
+ \fi}
+\def\tstrut{\relax\hbox{\tate
+ \ifmmode\copy\tstrutbox\else\unhcopy\tstrutbox\fi}}
+\def\zstrut{\relax\hbox{\tate
+ \ifmmode\copy\zstrutbox\else\unhcopy\zstrutbox\fi}}
+\def\DeclareFontEncoding{%
+ \begingroup
+ \nfss@catcodes
+ \expandafter\endgroup
+ \DeclareFontEncoding@}
+\def\DeclareFontEncoding@#1#2#3{%
+ \expandafter
+ \ifx\csname T@#1\endcsname\relax
+ \def\cdp@elt{\noexpand\cdp@elt}%
+ \xdef\cdp@list{\cdp@list\cdp@elt{#1}%
+ {\default@family}{\default@series}%
+ {\default@shape}}%
+ \expandafter\let\csname#1-cmd\endcsname\@changed@cmd
+ \def\enc@elt{\noexpand\enc@elt}%
+ \xdef\fenc@list{\fenc@list\enc@elt<#1>}%
+ \else
+ \@font@info{Redeclaring font encoding #1}%
+ \fi
+ \global\@namedef{T@#1}{#2}%
+ \global\@namedef{M@#1}{\default@M#3}%
+ \xdef\LastDeclaredEncoding{#1}%
+ }
+\def\DeclareKanjiEncoding#1{%
+ \@latex@warning{%
+ The \string\DeclareKanjiEncoding\space is obsoleted command. Please use
+ \MessageBreak
+ the \string\DeclareTateKanjiEncoding\space for `Tate-kumi' encoding, and
+ \MessageBreak
+ the \string\DeclareYokoKanjiEncoding\space for `Yoko-kumi' encoding.
+ \MessageBreak
+ I treat the `#1' encoding as `Yoko-kumi'.}
+ \DeclareYokoKanjiEncoding{#1}%
+}
+\def\DeclareYokoKanjiEncoding{%
+ \begingroup
+ \nfss@catcodes
+ \expandafter\endgroup
+ \DeclareYokoKanjiEncoding@}
+\def\DeclareYokoKanjiEncoding@#1#2#3{%
+ \expandafter
+ \ifx\csname T@#1\endcsname\relax
+ \def\cdp@elt{\noexpand\cdp@elt}%
+ \xdef\cdp@list{\cdp@list\cdp@elt{#1}%
+ {\default@k@family}{\default@k@series}%
+ {\default@k@shape}}%
+ \expandafter\let\csname#1-cmd\endcsname\@changed@kcmd
+ \def\enc@elt{\noexpand\enc@elt}%
+ \xdef\kyenc@list{\kyenc@list\enc@elt<#1>}%
+ \xdef\kenc@list{\kenc@list\enc@elt<#1>}%
+ \else
+ \@font@info{Redeclaring KANJI (yoko) font encoding #1}%
+ \fi
+ \global\@namedef{T@#1}{#2}%
+ \global\@namedef{M@#1}{\default@KM#3}%
+ }
+\def\DeclareTateKanjiEncoding{%
+ \begingroup
+ \nfss@catcodes
+ \expandafter\endgroup
+ \DeclareTateKanjiEncoding@}
+\def\DeclareTateKanjiEncoding@#1#2#3{%
+ \expandafter
+ \ifx\csname T@#1\endcsname\relax
+ \def\cdp@elt{\noexpand\cdp@elt}%
+ \xdef\cdp@list{\cdp@list\cdp@elt{#1}%
+ {\default@k@family}{\default@k@series}%
+ {\default@k@shape}}%
+ \expandafter\let\csname#1-cmd\endcsname\@changed@kcmd
+ \def\enc@elt{\noexpand\enc@elt}%
+ \xdef\ktenc@list{\ktenc@list\enc@elt<#1>}%
+ \xdef\kenc@list{\kenc@list\enc@elt<#1>}%
+ \else
+ \@font@info{Redeclaring KANJI (tate) font encoding #1}%
+ \fi
+ \global\@namedef{T@#1}{#2}%
+ \global\@namedef{M@#1}{\default@KM#3}%
+ }
+\@onlypreamble\DeclareKanjiEncoding
+\@onlypreamble\DeclareYokoKanjiEncoding
+\@onlypreamble\DeclareYokoKanjiEncoding@
+\@onlypreamble\DeclareTateKanjiEncoding
+\@onlypreamble\DeclareTateKanjiEncoding@
+\def\DeclareKanjiEncodingDefaults#1#2{%
+ \ifx\relax#1\else
+ \ifx\default@KT\@empty\else
+ \@font@info{Overwriting KANJI encoding scheme text defaults}%
+ \fi
+ \gdef\default@KT{#1}%
+ \fi
+ \ifx\relax#2\else
+ \ifx\default@KM\@empty\else
+ \@font@info{Overwriting KANJI encoding scheme math defaults}%
+ \fi
+ \gdef\default@KM{#2}%
+ \fi}
+\let\default@KT\@empty
+\let\default@KM\@empty
+\@onlypreamble\DeclareKanjiEncodingDefaults
+\def\DeclareFontFamily#1#2#3{%
+ \@ifundefined{T@#1}%
+ {\@latex@error{Encoding scheme `#1' unknown}\@eha}%
+ {\edef\tmp@item{{#2}}%
+ \expandafter\expandafter\expandafter
+ \inlist@\expandafter\tmp@item\expandafter{\ffam@list}%
+ \ifin@ \else
+ \def\fam@elt{\noexpand\fam@elt}%
+ \xdef\ffam@list{\ffam@list\fam@elt<#2>}%
+ \fi
+ \def\reserved@a{#3}%
+ \global
+ \expandafter\let\csname #1+#2\expandafter\endcsname
+ \ifx \reserved@a\@empty
+ \@empty
+ \else \reserved@a
+ \fi
+ }%
+}
+\def\DeclareKanjiFamily#1#2#3{%
+ \@ifundefined{T@#1}%
+ {\@latex@error{KANJI Encoding scheme `#1' unknown}\@eha}%
+ {\edef\tmp@item{{#2}}%
+ \expandafter\expandafter\expandafter
+ \inlist@\expandafter\tmp@item\expandafter{\kfam@list}%
+ \ifin@ \else
+ \def\fam@elt{\noexpand\fam@elt}%
+ \xdef\kfam@list{\kfam@list\fam@elt<#2>}%
+ \fi
+ \def\reserved@a{#3}%
+ \global
+ \expandafter\let\csname #1+#2\expandafter\endcsname
+ \ifx \reserved@a\@empty
+ \@empty
+ \else \reserved@a
+ \fi
+ }%
+}
+\def\DeclareKanjiSubstitution#1#2#3#4{%
+ \expandafter\ifx\csname T@#1\endcsname\relax
+ \@latex@error{KANJI Encoding scheme `#1' unknown}\@eha
+ \else
+ \begingroup
+ \def\reserved@a{#1}%
+ \toks@{}%
+ \def\cdp@elt##1##2##3##4{%
+ \def\reserved@b{##1}%
+ \ifx\reserved@a\reserved@b
+ \addto@hook\toks@{\cdp@elt{#1}{#2}{#3}{#4}}%
+ \else
+ \addto@hook\toks@{\cdp@elt{##1}{##2}{##3}{##4}}%
+ \fi}%
+ \cdp@list
+ \xdef\cdp@list{\the\toks@}%
+ \endgroup
+ \global\@namedef{D@#1}{\def\default@family{#2}%
+ \def\default@series{#3}%
+ \def\default@shape{#4}}%
+ \fi}
+\def\DeclareErrorKanjiFont#1#2#3#4#5{%
+ \xdef\error@kfontshape{%
+ \noexpand\expandafter\noexpand\split@name\noexpand\string
+ \expandafter\noexpand\csname#1/#2/#3/#4/#5\endcsname
+ \noexpand\@nil}%
+ \gdef\default@k@family{#2}%
+ \gdef\default@k@series{#3}%
+ \gdef\default@k@shape{#4}%
+ \global\let\k@family\default@k@family
+ \global\let\k@series\default@k@series
+ \global\let\k@shape\default@k@shape
+ \gdef\f@size{#5}%
+ \gdef\f@baselineskip{#5pt}}
+\@onlypreamble\DeclareKanjiSubstitution
+\@onlypreamble\DeclareErrorKanjiFont
+\def\DeclareFixedFont#1#2#3#4#5#6{%
+ \begingroup
+ \math@fontsfalse
+ \every@math@size{}%
+ \fontsize{#6}\z@
+ \edef\tmp@item{{#2}}%
+ \expandafter\expandafter\expandafter
+ \inlist@\expandafter\tmp@item\expandafter{\kyenc@list}%
+ \ifin@
+ \usekanji{#2}{#3}{#4}{#5}%
+ \global\let#1\getjfont
+ \else
+ %\expandafter\expandafter\expandafter
+ %\inlist@\expandafter\tmp@item\expandafter{\ktenc@list}%
+ %\ifin@
+ % \usekanji{#2}{#3}{#4}{#5}%
+ % \let\font\tfont
+ %\else
+ \useroman{#2}{#3}{#4}{#5}%
+ \global\expandafter\let\expandafter#1\the\font
+ %\fi
+ \fi
+ \endgroup
+ }
+\def\reDeclareMathAlphabet#1#2#3{%
+ \edef#1{\noexpand\protect\expandafter\noexpand\csname%
+ \expandafter\@gobble\string#1\space\space\endcsname}%
+ \edef\@tempa{\expandafter\@gobble\string#2}%
+ \edef\@tempb{\expandafter\@gobble\string#3}%
+ \edef\@tempc{\string @\expandafter\@gobbletwo\string#2}%
+ \ifx\@tempc\@tempa%
+ \edef\@tempa{\expandafter\@gobbletwo\string#2}%
+ \edef\@tempb{\expandafter\@gobbletwo\string#3}%
+ \fi
+ \expandafter\edef\csname\expandafter\@gobble\string#1\space\space\endcsname%
+ {\noexpand\DualLang@mathalph@bet%
+ {\expandafter\noexpand\csname\@tempa\space\endcsname}%
+ {\expandafter\noexpand\csname\@tempb\space\endcsname}%
+ }%
+}
+\@onlypreamble\reDeclareMathAlphabet
+\def\DualLang@mathalph@bet#1#2{%
+ \relax\ifmmode
+ \ifx\math@bgroup\bgroup% 2e normal style (\mathrm{...})
+ \bgroup\let\DualLang@Mfontsw\DLMfontsw@standard
+ \else
+ \ifx\math@bgroup\relax% 2e two letter style (\rm->\mathrm)
+ \let\DualLang@Mfontsw\DLMfontsw@oldstyle
+ \else
+ \bgroup\let\DualLang@Mfontsw\DLMfontsw@standard
+ \fi
+ \fi
+ \else
+ \let\DualLang@Mfontsw\@firstoftwo
+ \fi
+ \DualLang@Mfontsw{#1}{#2}%
+}
+\def\DLMfontsw@standard#1#2#3{#1{#2{#3}}\egroup}
+\def\DLMfontsw@oldstyle#1#2{#1\relax\@fontswitch\relax{#2}}
+\def\DLMfontsw@oldlfont#1#2{#1\relax#2\relax}
+\def\all@shape{all}%
+\def\DeclareRelationFont#1#2#3#4#5#6#7#8{%
+ \def\rel@shape{#4}%
+ \ifx\rel@shape\@empty
+ \global
+ \expandafter\def\csname rel@#1/#2/#3/all\endcsname{%
+ \romanencoding{#5}\romanfamily{#6}%
+ \romanseries{#7}}%
+ \else
+ \global
+ \expandafter\def\csname rel@#1/#2/#3/#4\endcsname{%
+ \romanencoding{#5}\romanfamily{#6}%
+ \romanseries{#7}\romanshape{#8}}%
+ \fi
+}
+\def\SetRelationFont#1#2#3#4#5#6#7#8{%
+ \def\rel@shape{#4}%
+ \ifx\rel@shape\@empty
+ \expandafter\def\csname rel@#1/#2/#3/all\endcsname{%
+ \romanencoding{#5}\romanfamily{#6}%
+ \romanseries{#7}}%
+ \else
+ \expandafter\def\csname rel@#1/#2/#3/#4\endcsname{%
+ \romanencoding{#5}\romanfamily{#6}%
+ \romanseries{#7}\romanshape{#8}}%
+ \fi
+}
+\newif\if@knjcmd
+\def\userelfont{\@knjcmdtrue}
+\DeclareRobustCommand\selectfont{%
+ \let\tmp@error@fontshape\error@fontshape
+ \let\error@fontshape\error@kfontshape
+ \edef\tmp@item{{\k@encoding}}%
+ \expandafter\expandafter\expandafter
+ \inlist@\expandafter\tmp@item\expandafter{\kyenc@list}%
+ \ifin@
+ \let\cy@encoding\k@encoding
+ \edef\ct@encoding{\csname t@enc@\k@encoding\endcsname}%
+ \else
+ \expandafter\expandafter\expandafter
+ \inlist@\expandafter\tmp@item\expandafter{\ktenc@list}%
+ \ifin@
+ \let\ct@encoding\k@encoding
+ \edef\cy@encoding{\csname y@enc@\k@encoding\endcsname}%
+ \else
+ \@latex@error{KANJI Encoding scheme `\k@encoding' unknown}\@eha
+ \fi
+ \fi
+ %\let\font\tfont
+ %\let\k@encoding\ct@encoding
+ %\xdef\font@name{\csname\curr@kfontshape/\f@size\endcsname}%
+ %\pickup@font
+ %\font@name
+ \let\k@encoding\cy@encoding
+ \xdef\font@name{\csname\curr@kfontshape/\f@size\endcsname}%
+ \pickup@jfont
+ \font@name
+ \expandafter\def\expandafter\k@encoding\tmp@item
+ \kenc@update
+ \let\error@fontshape\tmp@error@fontshape
+ \if@knjcmd \@knjcmdfalse
+ \expandafter\ifx
+ \csname rel@\k@encoding/\k@family/\k@series/\k@shape\endcsname\relax
+ \expandafter\ifx
+ \csname rel@\k@encoding/\k@family/\k@series/all\endcsname\relax
+ \else
+ \csname rel@\k@encoding/\k@family/\k@series/all\endcsname
+ \fi
+ \else
+ \csname rel@\k@encoding/\k@family/\k@series/\k@shape\endcsname
+ \fi
+ \fi
+ %\let\font\afont
+ \xdef\font@name{\csname\curr@fontshape/\f@size\endcsname}%
+ \pickup@font
+ \font@name
+ \enc@update
+ \ifx\f@linespread\baselinestretch \else
+ \set@fontsize\baselinestretch\f@size\f@baselineskip
+ \fi
+ \size@update}
+\def\KanjiEncodingPair#1#2{\@namedef{t@enc@#1}{#2}\@namedef{y@enc@#2}{#1}}
+\KanjiEncodingPair{JY3}{JT3}
+\def\set@fontsize#1#2#3{%
+ \@defaultunits\@tempdimb#2pt\relax\@nnil
+ \edef\f@size{\strip@pt\@tempdimb}%
+ \@defaultunits\@tempskipa#3pt\relax\@nnil
+ \edef\f@baselineskip{\the\@tempskipa}%
+ \edef\f@linespread{#1}%
+ \let\baselinestretch\f@linespread
+ \def\size@update{%
+ \baselineskip\f@baselineskip\relax
+ \baselineskip\f@linespread\baselineskip
+ \normalbaselineskip\baselineskip
+ \adjustbaseline
+ \setbox\strutbox\hbox{%\yoko
+ \vrule\@width\z@
+ \@height.7\baselineskip \@depth.3\baselineskip}%
+ \setbox\tstrutbox\hbox{%\tate
+ \vrule\@width\z@
+ \@height.5\baselineskip \@depth.5\baselineskip}%
+ \setbox\zstrutbox\hbox{%\tate
+ \vrule\@width\z@
+ \@height.7\baselineskip \@depth.3\baselineskip}%
+ \let\size@update\relax}}
+\newbox\adjust@box
+\newdimen\adjust@dimen
+\def\adjustbaseline{%
+ \setbox\adjust@box\hbox{\ltjsetparameter{yjabaselineshift=\z@}あ}%
+ \cht\ht\adjust@box
+ \cdp\dp\adjust@box
+ \cwd\wd\adjust@box
+ \cvs\normalbaselineskip
+ \chs\cwd
+ \cHT\cht \advance\cHT\cdp
+ % \iftdir
+ % \setbox\adjust@box\hbox{\tbaselineshift\z@ M}%
+ % \adjust@dimen\ht\adjust@box
+ % \advance\adjust@dimen\dp\adjust@box
+ % \advance\adjust@dimen-\cHT
+ % \divide\adjust@dimen\tw@
+ % \advance\adjust@dimen\cdp
+ % \advance\adjust@dimen-\dp\adjust@box
+ % \tbaselineshift\adjust@dimen
+ % \fi
+ }
+\DeclareRobustCommand\romanencoding[1]{%
+ \expandafter\ifx\csname T@#1\endcsname\relax
+ \@latex@error{Encoding scheme `#1' unknown}\@eha
+ \else
+ \edef\f@encoding{#1}%
+ \ifx\cf@encoding\f@encoding
+ \let\enc@update\relax
+ \else
+ \let\enc@update\@@enc@update
+ \fi
+ \fi
+}
+\DeclareRobustCommand\kanjiencoding[1]{%
+ \expandafter\ifx\csname T@#1\endcsname\relax
+ \@latex@error{KANJI Encoding scheme `#1' unknown}\@eha
+ \else
+ \edef\k@encoding{#1}%
+ \ifx\ck@encoding\k@encoding
+ \let\kenc@update\relax
+ \else
+ \let\kenc@update\@@kenc@update
+ \fi
+ \fi
+}
+\DeclareRobustCommand\fontencoding[1]{%
+ \edef\tmp@item{{#1}}%
+ \expandafter\expandafter\expandafter
+ \inlist@\expandafter\tmp@item\expandafter{\kenc@list}%
+ \ifin@ \kanjiencoding{#1}\else\romanencoding{#1}\fi}
+\def\@@kenc@update{%
+ \default@KT
+ \csname T@\k@encoding\endcsname
+ \csname D@\k@encoding\endcsname
+ \let\kenc@update\relax
+ \let\ck@encoding\k@encoding
+ \edef\tmp@item{{\k@encoding}}%
+ \expandafter\expandafter\expandafter
+ \inlist@\expandafter\tmp@item\expandafter{\kyenc@list}%
+ \ifin@ \let\cy@encoding\k@encoding
+ \else
+ \expandafter\expandafter\expandafter
+ \inlist@\expandafter\tmp@item\expandafter{\ktenc@list}%
+ \ifin@ \let\ct@encoding\k@encoding
+ \else
+ \@latex@error{KANJI Encoding scheme `\k@encoding' unknown}\@eha
+ \fi
+ \fi
+}
+\let\kenc@update\relax
+\def\@changed@kcmd#1#2{%
+ \ifx\protect\@typeset@protect
+ \@inmathwarn#1%
+ \expandafter\ifx\csname\ck@encoding\string#1\endcsname\relax
+ \expandafter\ifx\csname ?\string#1\endcsname\relax
+ \expandafter\def\csname ?\string#1\endcsname{%
+ \TextSymbolUnavailable#1%
+ }%
+ \fi
+ \global\expandafter\let
+ \csname\cf@encoding \string#1\expandafter\endcsname
+ \csname ?\string#1\endcsname
+ \fi
+ \csname\ck@encoding\string#1%
+ \expandafter\endcsname
+ \else
+ \noexpand#1%
+ \fi}
+\newif\if@notkfam
+\newif\if@notffam
+\newif\if@tempswz
+\DeclareRobustCommand\romanfamily[1]{\edef\f@family{#1}}
+\DeclareRobustCommand\kanjifamily[1]{\edef\k@family{#1}}
+\DeclareRobustCommand\fontfamily[1]{%
+ \edef\tmp@item{{#1}}%
+ \@notkfamfalse
+ \@notffamfalse
+ \expandafter\expandafter\expandafter
+ \inlist@\expandafter\tmp@item\expandafter{\kfam@list}%
+ \ifin@ \edef\k@family{#1}%
+ \else
+ \expandafter\expandafter\expandafter
+ \inlist@\expandafter\tmp@item\expandafter{\notkfam@list}%
+ \ifin@ \@notkfamtrue
+ \else
+ \@tempswzfalse
+ \def\fam@elt{\noexpand\fam@elt}%
+ \message{(I search kanjifont definition file:}%
+ \def\enc@elt<##1>{\message{.}%
+ \edef\reserved@a{\lowercase{\noexpand\IfFileExists{##1#1.fd}}}%
+ \reserved@a{\@tempswztrue}{}\relax}%
+ \kenc@list
+ \message{)}%
+ \if@tempswz
+ \edef\k@family{#1}%
+ \else
+ \@notkfamtrue
+ \xdef\notkfam@list{\notkfam@list\fam@elt<#1>}%
+ \fi
+ \fi\fi
+ \expandafter\expandafter\expandafter
+ \inlist@\expandafter\tmp@item\expandafter{\ffam@list}%
+ \ifin@ \edef\f@family{#1}\else
+ \expandafter\expandafter\expandafter
+ \inlist@\expandafter\tmp@item\expandafter{\notffam@list}%
+ \ifin@ \@notffamtrue \else
+ \@tempswzfalse
+ \def\fam@elt{\noexpand\fam@elt}%
+ \message{(I search font definition file:}%
+ \def\enc@elt<##1>{\message{.}%
+ \edef\reserved@a{\lowercase{\noexpand\IfFileExists{##1#1.fd}}}%
+ \reserved@a{\@tempswztrue}{}\relax}%
+ \fenc@list
+ \message{)}%
+ \if@tempswz
+ \edef\f@family{#1}%
+ \else
+ \@notffamtrue
+ \xdef\notffam@list{\notffam@list\fam@elt<#1>}%
+ \fi
+ \fi\fi
+ \if@notkfam\if@notffam
+ \edef\k@family{#1}\edef\f@family{#1}%
+ \fi\fi}
+\DeclareRobustCommand\romanseries[1]{\edef\f@series{#1}}
+\DeclareRobustCommand\kanjiseries[1]{\edef\k@series{#1}}
+\DeclareRobustCommand\fontseries[1]{\kanjiseries{#1}\romanseries{#1}}
+\DeclareRobustCommand\romanshape[1]{\edef\f@shape{#1}}
+\DeclareRobustCommand\kanjishape[1]{\edef\k@shape{#1}}
+\DeclareRobustCommand\fontshape[1]{\kanjishape{#1}\romanshape{#1}}
+\def\usekanji#1#2#3#4{%
+ \kanjiencoding{#1}\kanjifamily{#2}\kanjiseries{#3}\kanjishape{#4}%
+ \selectfont\ignorespaces}
+\def\useroman#1#2#3#4{%
+ \romanencoding{#1}\romanfamily{#2}\romanseries{#3}\romanshape{#4}%
+ \selectfont\ignorespaces}
+\def\usefont#1#2#3#4{%
+ \edef\tmp@item{{#1}}%
+ \expandafter\expandafter\expandafter
+ \inlist@\expandafter\tmp@item\expandafter{\kenc@list}%
+ \ifin@ \usekanji{#1}{#2}{#3}{#4}%
+ \else\useroman{#1}{#2}{#3}{#4}%
+ \fi}
+\DeclareRobustCommand\normalfont{%
+ \kanjiencoding{\kanjiencodingdefault}%
+ \kanjifamily{\kanjifamilydefault}%
+ \kanjiseries{\kanjiseriesdefault}%
+ \kanjishape{\kanjishapedefault}%
+ \romanencoding{\encodingdefault}%
+ \romanfamily{\familydefault}%
+ \romanseries{\seriesdefault}%
+ \romanshape{\shapedefault}%
+ \selectfont\ignorespaces}
+\adjustbaseline
+\let\reset@font\normalfont
+\DeclareRobustCommand\mcfamily
+ {\not@math@alphabet\mcfamily\mathmc
+ \kanjifamily\mcdefault\selectfont}
+\DeclareRobustCommand\gtfamily
+ {\not@math@alphabet\gtfamily\mathgt
+ \kanjifamily\gtdefault\selectfont}
+\let\romanprocess@table\process@table
+\def\kanjiprocess@table{%
+ \kanjiencoding{\kanjiencodingdefault}%
+ \kanjifamily{\kanjifamilydefault}%
+ \kanjiseries{\kanjiseriesdefault}%
+ \kanjishape{\kanjishapedefault}%
+}
+\def\process@table{%
+ \romanprocess@table
+ \kanjiprocess@table
+}
+\@onlypreamble\romanprocess@table
+\@onlypreamble\kanjiprocess@table
+\DeclareTextCommandDefault{\textunderscore}{%
+ \leavevmode\kern.06em
+ %\iftdir\raise-\tbaselineshift\fi
+ \vbox{\hrule\@width.3em}}
+
+\let\extract@afont\extract@font
+\def\pickup@jfont{%
+ \expandafter \ifx \font@name \relax
+ \let\extract@font\extract@jfont
+ \define@newfont
+ \let\extract@font\extract@afont
+ \fi
+ \let\getjfont\font@name}
+
+\def\extract@jfont{%
+ \get@external@font
+ \expandafter\globaljfont\font@name\external@font\relax
+ \font@name\global\zw=\zw\global\zh=\zh
+ \csname \f@encoding+\f@family\endcsname
+ \csname\curr@fontshape\endcsname}
+
+\endinput
%% Load Lua modules.
\RequireLuaModule{luatexja.base}
\RequireLuaModule{luatexja.tangle}
-\RequireLuaModule{luatexja.charrange}
-\RequireLuaModule{luatexja.stack}
-\RequireLuaModule{luatexja.inputbuf}
-
%%------------------ Tiny helpers
%% Registers
-local ltjb = luatexja.base
-local ltjc = luatexja.charrange
-local ltjs = luatexja.stack
+require('lualibs')
+require('luatexja.rmlgbm'); local ltjr = luatexja.rmlgbm -- must be 1st
+require('luatexja.base'); local ltjb = luatexja.base
+require('luatexja.charrange'); local ltjc = luatexja.charrange
+require('luatexja.jfont'); local ltjf = luatexja.jfont
+require('luatexja.inputbuf'); local ltji = luatexja.inputbuf
+require('luatexja.jfmglue'); local ltjj = luatexja.jfmglue
+require('luatexja.pretreat'); local ltjp = luatexja.pretreat
+require('luatexja.stack'); local ltjs = luatexja.stack
+require('luatexja.setwidth'); local ltjw = luatexja.setwidth
local node_type = node.type
local node_new = node.new
local attr_jchar_class = luatexbase.attributes['ltj@charclass']
local attr_curjfnt = luatexbase.attributes['ltj@curjfnt']
local attr_yablshift = luatexbase.attributes['ltj@yablshift']
-local attr_ykblshift = luatexbase.attributes['ltj@ykblshift']
local attr_icflag = luatexbase.attributes['ltj@icflag']
-local lang_ja_token = token.create('ltj@japanese')
-local lang_ja = lang_ja_token[2]
-
---
-local ljfm_find_char_class = ltj.int_find_char_class
-
-
local ITALIC = 1
-local TEMPORARY = 2
-local FROM_JFM = 3
-local KINSOKU = 4
+local PACKED = 2
+local KINSOKU = 3
+local FROM_JFM = 4
local LINE_END = 5
local KANJI_SKIP = 6
local XKANJI_SKIP = 7
-local PACKED = 8
+local PROCESSED = 8
+local IC_PROCESSED = 9
+local BOXBDD = 15
------------------------------------------------------------------------
-- naming:
return out
end
--- return true if and only if p is a Japanese character node
-local function is_japanese_glyph_node(p)
- return p and (p.id==id_glyph)
- and (p.font==has_attr(p,attr_curjfnt))
-end
-
function math.two_add(a,b) return a+b end
function math.two_average(a,b) return (a+b)/2 end
elseif k == 'autoxspacing' then
tex.write(tex.getattribute('ltj@autoxspc'))
elseif k == 'differentjfm' then
- if ltj.ja_diffmet_rule == math.max then
+ if luatexja.jfmglue.diffmet_rule == math.max then
tex.write('large')
- elseif ltj.ja_diffmet_rule == math.min then
+ elseif luatexja.jfmglue.diffmet_rule == math.min then
tex.write('small')
- elseif ltj.ja_diffmet_rule == math.two_average then
+ elseif luatexja.jfmglue.diffmet_rule == math.two_average then
tex.write('average')
- elseif ltj.ja_diffmet_rule == math.two_add then
+ elseif luatexja.jfmglue.diffmet_rule == math.two_add then
tex.write('both')
else -- This can't happen.
tex.write('???')
if c<0 or c>216 then
ltjb.package_error('luatexja',
'invalid character range number (' .. c .. ')',
- {'A character range number should be in the range 0..216,',
- 'So I changed this one to zero.'})
+ 'A character range number should be in the range 0..216,\n'..
+ 'So I changed this one to zero.')
c=0
end
tex.write(ltjc.get_range_setting(c))
if c<0 or c>0x10FFFF then
ltjb.package_error('luatexja',
'bad character code (' .. c .. ')',
- {'A character number must be between -1 and 0x10ffff.',
- "(-1 is used for denoting `math boundary')",
- 'So I changed this one to zero.'})
+ 'A character number must be between -1 and 0x10ffff.\n'..
+ "(-1 is used for denoting `math boundary')\n"..
+ 'So I changed this one to zero.')
c=0
end
if k == 'prebreakpenalty' then
if ltj.isglobal=='global' then tex.sprint('\\global') end
end
-
-------------------------------------------------------------------------
--- MAIN PROCESS STEP 1: replace fonts (prefix: main1)
-------------------------------------------------------------------------
-ltj.box_stack_level = 0
--- This is used in Step 2 (JFM glue/kern) and Step 3 (\[x]kanjiskip).
-
-local function main1_suppress_hyphenate_ja(head)
- for p in node.traverse_id(id_glyph, head) do
- if ltjc.is_ucs_in_japanese_char(p) then
- local v = has_attr(p, attr_curjfnt)
- if v then
- p.font = v
- node.set_attribute(p, attr_jchar_class,
- ljfm_find_char_class(p.char, ltj.font_metric_table[v].jfm))
- end
- v = has_attr(p, attr_ykblshift)
- if v then
- node.set_attribute(p, attr_yablshift, v)
- else
- node.unset_attribute(p, attr_yablshift)
- end
- if p.subtype%2==1 then p.subtype = p.subtype - 1 end
- p.lang=lang_ja
- end
- end
- lang.hyphenate(head)
- return head
-end
-
--- mode: true iff this function is called from hpack_filter
-local function main1_set_box_stack_level(head, mode)
- local box_set = false
- local p = head
- local cl = tex.currentgrouplevel + 1
- while p do
- if p.id==id_whatsit and p.subtype==sid_user and p.user_id==30112 then
- local g = p
- if mode and g.value==cl then box_set = true end
- head, p = node.remove(head, g)
- else p = node_next(p)
- end
- end
- if box_set then
- ltj.box_stack_level = tex.getcount('ltj@@stack') + 1
- else
- ltj.box_stack_level = tex.getcount('ltj@@stack')
- end
- if not head then -- prevent that the list is null
- head = node_new(id_kern); head.kern = 0; head.subtype = 1
- end
- return head
-end
-
--- CALLBACKS
-luatexbase.add_to_callback('hpack_filter',
- function (head)
- return main1_set_box_stack_level(head, true)
- end,'ltj.hpack_filter_pre',1)
-luatexbase.add_to_callback('pre_linebreak_filter',
- function (head)
- return main1_set_box_stack_level(head, false)
- end,'ltj.pre_linebreak_filter_pre',1)
-luatexbase.add_to_callback('hyphenate',
- function (head,tail)
- return main1_suppress_hyphenate_ja(head)
- end,'ltj.hyphenate')
-
-
-------------------------------------------------------------------------
--- MAIN PROCESS STEP 4: width of japanese chars (prefix: main4)
-------------------------------------------------------------------------
-
--- TeX's \hss
-local function main4_get_hss()
- local hss = node_new(id_glue)
- local fil_spec = node_new(id_glue_spec)
- fil_spec.width = 0
- fil_spec.stretch = 65536
- fil_spec.stretch_order = 2
- fil_spec.shrink = 65536
- fil_spec.shrink_order = 2
- hss.spec = fil_spec
- return hss
-end
-
-local function main4_set_ja_width(head)
- local p = head
- local met_tb, t, s, g, q, a, h
- local m = false -- is in math mode?
- while p do
- local v=has_attr(p,attr_yablshift) or 0
- if p.id==id_glyph then
- p.yoffset = p.yoffset-v
- if is_japanese_glyph_node(p) then
- met_tb = ltj.font_metric_table[p.font]
- t = ltj.metrics[met_tb.jfm]
- s = t.char_type[has_attr(p,attr_jchar_class)]
- if s.width ~= 'prop' and
- not(s.left==0.0 and s.down==0.0 and s.align=='left'
- and round(s.width*met_tb.size)==p.width) then
- -- must be encapsuled by a \hbox
- head, q = node.remove(head,p)
- p.next = nil
- p.yoffset=round(p.yoffset-met_tb.size*s.down)
- p.xoffset=round(p.xoffset-met_tb.size*s.left)
- if s.align=='middle' or s.align=='right' then
- h = node_insert_before(p, p, main4_get_hss())
- else h=p end
- if s.align=='middle' or s.align=='left' then
- node_insert_after(h, p, main4_get_hss())
- end
- g = node_hpack(h, round(met_tb.size*s.width), 'exactly')
- g.height = round(met_tb.size*s.height)
- g.depth = round(met_tb.size*s.depth)
- node.set_attribute(g, attr_icflag, PACKED)
- if q then
- head = node_insert_before(head, q, g)
- else
- head = node_insert_after(head, node.tail(head), g)
- end
- p = q
- else p=node_next(p)
- end
- else p=node_next(p)
- end
- elseif p.id==id_math then
- m=(p.subtype==0); p=node_next(p)
- else
- if m then
- if p.id==id_hlist or p.id==id_vlist then
- p.shift=p.shift+v
- elseif p.id==id_rule then
- p.height=p.height-v; p.depth=p.depth+v
- end
- end
- p=node_next(p)
- end
- end
-return head
-end
-
-- main process
-- mode = true iff main_process is called from pre_linebreak_filter
-local function main_process(head, mode)
+local function main_process(head, mode, dir)
local p = head
- p = ltj.int_insert_jfm_glue(p,mode)
- p = ltj.int_insert_kanji_skip(p)
- p = main4_set_ja_width(p)
+ p = ltjj.main(p,mode)
+ p = ltjw.set_ja_width(p, dir)
return p
end
local k = debug_depth
local s
local pt=node_type(p.id)
+ local base = debug_depth .. string.format('%X', has_attr(p,attr_icflag) or 0)
+ .. ' ' .. pt .. ' ' .. p.subtype
if pt == 'glyph' then
- print_fn(debug_depth.. ' GLYPH ', p.subtype, utf.char(p.char), p.font)
+ s = base .. ' ' .. utf.char(p.char) .. ' ' .. tostring(p.font)
+ .. ' (' .. print_scaled(p.height) .. '+'
+ .. print_scaled(p.depth) .. ')x' .. print_scaled(p.width)
+ print_fn(s)
elseif pt=='hlist' then
- s = debug_depth .. ' hlist ' .. p.subtype
- .. '(' .. print_scaled(p.height) .. '+' .. print_scaled(p.depth) .. ')x'
- .. print_scaled(p.width)
+ s = base .. '(' .. print_scaled(p.height) .. '+'
+ .. print_scaled(p.depth) .. ')x' .. print_scaled(p.width)
if p.glue_sign >= 1 then
s = s .. ' glue set '
if p.glue_sign == 2 then s = s .. '-' end
for i = 2, p.glue_order do s = s .. 'l' end
end
end
+ if has_attr(p, attr_icflag, PACKED) then
+ s = s .. ' (packed)'
+ end
print_fn(s)
local q = p.head
debug_depth=debug_depth.. '.'
end
debug_depth=k
elseif pt == 'glue' then
- s = debug_depth.. ' glue ' .. p.subtype
- .. ' ' .. print_spec(p.spec)
- if has_attr(p, attr_icflag)==TEMPORARY then
- s = s .. ' (might be replaced)'
- elseif has_attr(p, attr_icflag)==FROM_JFM then
+ s = base .. ' ' .. print_spec(p.spec)
+ if has_attr(p, attr_icflag)==FROM_JFM then
s = s .. ' (from JFM)'
elseif has_attr(p, attr_icflag)==KANJI_SKIP then
s = s .. ' (kanjiskip)'
end
print_fn(s)
elseif pt == 'kern' then
- s = debug_depth.. ' kern ' .. p.subtype
- .. ' ' .. print_scaled(p.kern) .. 'pt'
- if has_attr(p, attr_icflag)==ITALIC then
+ s = base .. ' ' .. print_scaled(p.kern) .. 'pt'
+ if p.subtype==2 then
+ s = s .. ' (for accent)'
+ elseif has_attr(p, attr_icflag)==IC_PROCESSED then
s = s .. ' (italic correction)'
- elseif has_attr(p, attr_icflag)==TEMPORARY then
- s = s .. ' (might be replaced)'
+ -- elseif has_attr(p, attr_icflag)==ITALIC then
+ -- s = s .. ' (italic correction)'
elseif has_attr(p, attr_icflag)==FROM_JFM then
s = s .. ' (from JFM)'
elseif has_attr(p, attr_icflag)==LINE_END then
end
print_fn(s)
elseif pt == 'penalty' then
- s = debug_depth.. ' penalty ' .. tostring(p.penalty)
+ s = base .. ' ' .. tostring(p.penalty)
if has_attr(p, attr_icflag)==KINSOKU then
s = s .. ' (for kinsoku)'
end
print_fn(s)
elseif pt == 'whatsit' then
- s = debug_depth.. ' whatsit ' .. tostring(p.subtype)
+ s = base .. ' subtype: ' .. tostring(p.subtype)
if p.subtype==sid_user then
s = s .. ' user_id: ' .. p.user_id .. ' ' .. p.value
else
end
print_fn(s)
else
- print_fn(debug_depth.. ' ' .. node.type(p.id), p.subtype)
+ print_fn(base)
end
p=node_next(p)
end
-- callbacks
+
luatexbase.add_to_callback('pre_linebreak_filter',
function (head,groupcode)
- return main_process(head, true)
- end,'ltj.pre_linebreak_filter',2)
+ return main_process(head, true, tex.textdir)
+ end,'ltj.pre_linebreak_filter',
+ luatexbase.priority_in_callback('pre_linebreak_filter',
+ 'luaotfload.pre_linebreak_filter') + 1)
luatexbase.add_to_callback('hpack_filter',
- function (head,groupcode,size,packtype)
- return main_process(head, false)
- end,'ltj.hpack_filter',2)
+ function (head,groupcode,size,packtype, dir)
+ return main_process(head, false, dir)
+ end,'ltj.hpack_filter',
+ luatexbase.priority_in_callback('hpack_filter',
+ 'luaotfload.hpack_filter') + 1)
texio.write_nl("("..path..")")
dofile(path)
end
- require('lualibs')
- ltj.loadlua('luatexja-rmlgbm.lua')
- % For Ryumin-Light and GothicBBB-Medium.
- ltj.loadlua('luatexja-jfont.lua')
ltj.loadlua('luatexja-core.lua')
- ltj.loadlua('luatexja-jfmglue.lua')
- ltj.loadlua('luatexja-xkanji.lua')
}
%%%%%%%% Redefine \/
%\let\ltj@ic=\/ \protected\def\/{{\ltj@icflag=1\ltj@ic}}
-\protected\def\/{\directlua{ltj.ext_append_italic()}}
+\protected\def\/{\directlua{luatexja.jfont.append_italic()}}
%%%%%%%% \jfont\CS={...:...;jfm=metric;...}, \globaljfont
-\protected\def\jfont{\afterassignment\ltj@@jfont\directlua{ltj.ext_jfontdefX(false)}}
+\protected\def\jfont{\afterassignment\ltj@@jfont\directlua{luatexja.jfont.jfontdefX(false)}}
\protected\def\globaljfont{%
- \afterassignment\ltj@@jfont\directlua{ltj.ext_jfontdefX(true)}}
-\def\ltj@@jfont{\directlua{ltj.ext_jfontdefY()}}
+ \afterassignment\ltj@@jfont\directlua{luatexja.jfont.jfontdefX(true)}}
+\def\ltj@@jfont{\directlua{luatexja.jfont.jfontdefY()}}
%%%%%%%% \inhibitglue
-\protected\def\inhibitglue{\directlua{ltj.ext_create_inhibitglue_node()}}
+\protected\def\inhibitglue{\directlua{luatexja.jfmglue.create_inhibitglue_node()}}
%%%%%%%% \ltjdefcharrange<name>{100-200,3000-,5000,...}
\protected\def\ltjdefcharrange#1#2{%
\define@choicekey*+[ltj]{japaram}{differentjfm}[\ltj@temp\ltj@tempr]%
{large,small,average,both}{%
\ifcase\ltj@tempr
- \directlua{ltj.ja_diffmet_rule = math.max}\or
- \directlua{ltj.ja_diffmet_rule = math.min}\or
- \directlua{ltj.ja_diffmet_rule = math.two_average}\or
- \directlua{ltj.ja_diffmet_rule = math.two_add}
+ \directlua{luatexja.jfmglue.diffmet_rule = math.max}\or
+ \directlua{luatexja.jfmglue.diffmet_rule = math.min}\or
+ \directlua{luatexja.jfmglue.diffmet_rule = math.two_average}\or
+ \directlua{luatexja.jfmglue.diffmet_rule = math.two_add}
\fi
}{\ltj@PackageError{luatexja}{invalid argument `#1' for `differentjfm'}{%
Argument for `differentjfm' must be one of `large', `small', `average',^^J%
+++ /dev/null
-------------------------------------------------------------------------
--- MAIN PROCESS STEP 2: insert glue/kerns from JFM (prefix: none)
-------------------------------------------------------------------------
-
-local ltjs = luatexja.stack
-
-local node_type = node.type
-local node_new = node.new
-local node_remove = node.remove
-local node_prev = node.prev
-local node_next = node.next
-local has_attr = node.has_attribute
-local set_attr = node.set_attribute
-local node_insert_before = node.insert_before
-local node_insert_after = node.insert_after
-local round = tex.round
-
-local id_penalty = node.id('penalty')
-local id_glyph = node.id('glyph')
-local id_glue_spec = node.id('glue_spec')
-local id_glue = node.id('glue')
-local id_kern = node.id('kern')
-local id_hlist = node.id('hlist')
-local id_whatsit = node.id('whatsit')
-local sid_user = node.subtype('user_defined')
-
-local TEMPORARY = 2
-local FROM_JFM = 3
-local KINSOKU = 4
-local LINE_END = 5
-
-
-local attr_jchar_class = luatexbase.attributes['ltj@charclass']
-local attr_curjfnt = luatexbase.attributes['ltj@curjfnt']
-local attr_icflag = luatexbase.attributes['ltj@icflag']
--- attr_icflag: 1: kern from \/, 2: 'lineend' kern from JFM
-
---
-local ljfm_find_char_class = ltj.int_find_char_class
-
--- arithmetic with penalty.
--- p += e
-local function add_penalty(p,e)
- local i = p
- if i>=10000 then
- if e<=-10000 then i = 0 end
- elseif i<=-10000 then
- if e>=10000 then i = 0 end
- else
- i = i + e
- if i>=10000 then i = 10000
- elseif i<=-10000 then i = -10000 end
- end
- return i
-end
-
--- return true if and only if p is a Japanese character node
-local function is_japanese_glyph_node(p)
- return (p.id==id_glyph) and (p.font==has_attr(p,attr_curjfnt))
-end
-
--- EXT: for \inhibitglue
-function ltj.ext_create_inhibitglue_node()
- local g=node_new(id_whatsit, sid_user)
- g.user_id=30111; g.type=100; g.value=1; node.write(g)
-end
-
--- In the beginning of a hlist created by line breaking, there are the followings:
--- - a hbox by \parindent
--- - a whatsit node which contains local paragraph materials.
--- When we insert jfm glues, we ignore these nodes.
-local function is_parindent_box(p)
- if p.id==id_hlist then
- return (p.subtype==3)
- -- hlist (subtype=3) is a box by \parindent
- elseif p.id==id_whatsit then
- return (p.subtype==node.subtype('local_par'))
- end
-end
-
-local function find_size_metric(px)
- if is_japanese_glyph_node(px) then
- return { ltj.font_metric_table[px.font].size,
- ltj.font_metric_table[px.font].jfm, ltj.font_metric_table[px.font].var }
- else
- return nil
- end
-end
-
-local function new_jfm_glue(size,mt,bc,ac)
--- mt: metric key, bc, ac: char classes
- local g=nil
- local z = ltj.metrics[mt].char_type[bc]
- if z.glue and z.glue[ac] then
- local h = node_new(id_glue_spec)
- h.width = round(size*z.glue[ac][1])
- h.stretch = round(size*z.glue[ac][2])
- h.shrink = round(size*z.glue[ac][3])
- h.stretch_order=0; h.shrink_order=0
- g = node_new(id_glue)
- g.subtype = 0; g.spec = h
- elseif z.kern and z.kern[ac] then
- g = node_new(id_kern)
- g.subtype = 1; g.kern = round(size*z.kern[ac])
- end
- return g
-end
-
--- Insert jfm glue: main routine
--- local variables
-local p
-local q = nil -- the previous node of p
-local q_post -- the postbreakpenalty of q
-local ps, qs
-local widow_node -- 最後の「句読点扱いでない」和文文字
-local widow_bp -- 挿入位置 (a penalty)
-local last -- the sentinel
-local chain = false -- is q a Japanese character?
-local ihb_flag = false -- is \inhibitglue specified?
-local head -- the head of current list
-local mode -- true iff insert_jfm_glue is called from pre_linebreak_filter
-
--- initialize (insert the sentinel, etc.)
-local function init_var()
- p = head; q = nil; widow_node = nil; widow_bp = nil
- chain = false; ihb_flag = false;
- if mode then
- while p and is_parindent_box(p) do p=node_next(p) end
- last=node.tail(head)
- if last and last.id==id_glue and last.subtype==15 then
- last=node.prev(last)
- while (last and last.id==id_penalty) do last=node.prev(last) end
- end
- if last then last=node_next(last) end
- else -- 番人を挿入
- last=node.tail(head); local g = node_new('kern')
- node_insert_after(head, last, g); last = g
- end
-end
-
--- Insert JFM glue before the first node (which is a Japanese glyph node)
-local function ins_gk_head()
- if is_japanese_glyph_node(p) then
- ps = find_size_metric(p)
- local g = new_jfm_glue(ps[1], ps[2],
- ljfm_find_char_class('boxbdd',ps[2]),
- has_attr(p,attr_jchar_class))
- if g then
- set_attr(g, attr_icflag, FROM_JFM)
- head = node_insert_before(head, p, g)
- end
- q_post = ltjs.get_penalty_table('post', p.char, 0, ltj.box_stack_level); chain = true
- elseif p.id==id_glyph then
- q_post = ltjs.get_penalty_table('post', p.char, 0, ltj.box_stack_level)
- end
- qs = ps; q = p; p = node_next(p)
-end
-
--- The real insertion process is handled in this procedure.
-local function real_insert(g, w, pen, always_penalty_ins)
- -- g: glur/kern from JFM
- -- w: the width of kern that will be inserted between q and the end of a line
- -- pen: penalty
- -- always_penalty_ins: true iff we insert a penalty,
- -- for the linebreak between q and p.
- if w~=0 then
- if not g then
- g = node_new(id_kern); g.kern = -w; g.subtype = 1
- set_attr(g, attr_icflag, TEMPORARY)
- -- this g might be replaced by \[x]kanjiskip in step 3.
- else
- set_attr(g, attr_icflag, FROM_JFM)
- if g.id==id_kern then w=0
- else g.spec.width = round(g.spec.width - w)
- end
- end
- end
- if w~=0 then
- local h = node_new(id_kern)
- set_attr(h, attr_icflag, LINE_END)
- h.kern = w; h.subtype = 0; node_insert_before(head, p, h)
- elseif g then
- set_attr(g, attr_icflag, FROM_JFM)
- if g.id==id_kern then
- pen=0; always_penalty_ins = false
- end
- end
- if w~=0 or pen~=0 or ((not g) and always_penalty_ins) then
- local h = node_new(id_penalty)
- h.penalty = pen; set_attr(h, attr_icflag, KINSOKU)
- node_insert_before(head, p, h)
- end
- if g then
- node_insert_before(head, p, g);
- end
-end
-
--- This is a variant of real_insert (the case which a kern is related)
-local function real_insert_kern(g)
- if g then
- if g.id==id_glue then
- local h = node_new(id_penalty)
- h.penalty = 10000; set_attr(h, attr_icflag, KINSOKU)
- node_insert_before(head, p, h)
- end
- set_attr(g, attr_icflag, FROM_JFM)
- node_insert_before(head, p, g)
- end
-end
-
-ltj.ja_diffmet_rule = math.two_average
-
-local function calc_ja_ja_aux(gb,ga)
- if not gb then
- return ga
- else
- if not ga then return gb end
- local k = node.type(gb.id) .. node.type(ga.id)
- if k == 'glueglue' then
- -- 両方とも glue.
- gb.spec.width = round(ltj.ja_diffmet_rule(gb.spec.width, ga.spec.width))
- gb.spec.stretch = round(ltj.ja_diffmet_rule(gb.spec.stretch,ga.spec.shrink))
- gb.spec.shrink = -round(ltj.ja_diffmet_rule(-gb.spec.shrink, -ga.spec.shrink))
- return gb
- elseif k == 'kernkern' then
- -- 両方とも kern.
- gb.kern = round(ltj.ja_diffmet_rule(gb.kern, ga.kern))
- return gb
- elseif k == 'kernglue' then
- -- gb: kern, ga: glue
- ga.spec.width = round(ltj.ja_diffmet_rule(gb.kern,ga.spec.width))
- ga.spec.stretch = round(ltj.ja_diffmet_rule(ga.spec.stretch, 0))
- ga.spec.shrink = -round(ltj.ja_diffmet_rule(-ga.spec.shrink, 0))
- return ga
- else
- -- gb: glue, ga: kern
- gb.spec.width = round(ltj.ja_diffmet_rule(ga.kern, gb.spec.width))
- gb.spec.stretch = round(ltj.ja_diffmet_rule(gb.spec.stretch, 0))
- gb.spec.shrink = -round(ltj.ja_diffmet_rule(-gb.spec.shrink, 0))
- return gb
- end
- end
-end
-
--- Calc the glue between two Japanese characters
-local function calc_ja_ja_glue()
- if ihb_flag then return nil
- elseif table.are_equal(qs,ps) then
- return new_jfm_glue(ps[1],ps[2],
- has_attr(q,attr_jchar_class),
- has_attr(p,attr_jchar_class))
- else
- local g = new_jfm_glue(qs[1],qs[2],
- has_attr(q,attr_jchar_class),
- ljfm_find_char_class('diffmet',qs[2]))
- local h = new_jfm_glue(ps[1],ps[2],
- ljfm_find_char_class('diffmet',ps[2]),
- has_attr(p,attr_jchar_class))
- return calc_ja_ja_aux(g,h)
- end
-end
-
-local function ins_gk_any_JA()
- ps = find_size_metric(p)
- if chain then -- (q,p): JA-JA
- local g = calc_ja_ja_glue()
- local w = 0; local x = ljfm_find_char_class('lineend', qs[2])
- if (not ihb_flag) and x~=0 then
- local h = ltj.metrics[qs[2]].char_type[has_attr(q, attr_jchar_class)]
- if h.kern and h.kern[x] then w = round(qs[1]*h.kern[x]) end
- end
- q_post = add_penalty(q_post, ltjs.get_penalty_table('pre', p.char, 0, ltj.box_stack_level))
- real_insert(g, w, q_post, false)
- elseif q.id==id_glyph then -- (q,p): AL-JA
- local g = nil
- if not ihb_flag then
- g = new_jfm_glue(ps[1], ps[2],
- ljfm_find_char_class('jcharbdd',ps[2]),
- has_attr(p,attr_jchar_class))
- end
- q_post = add_penalty(q_post, ltjs.get_penalty_table('pre', p.char, 0, ltj.box_stack_level))
- real_insert(g, 0, q_post, true)
- elseif q.id==id_kern then -- (q,p): kern-JA
- local g = nil
- if not ihb_flag then
- g = new_jfm_glue(ps[1], ps[2],
- ljfm_find_char_class('jcharbdd',ps[2]),
- has_attr(p,attr_jchar_class))
- end
- real_insert_kern(g)
- else
- local g = nil
- if not ihb_flag then
- g = new_jfm_glue(ps[1], ps[2],
- ljfm_find_char_class('jcharbdd',ps[2]),
- has_attr(p,attr_jchar_class))
- end
- real_insert(g, 0, q_post, true)
- end
- q, qs, q_post = p, ps, ltjs.get_penalty_table('post', p.char, 0, ltj.box_stack_level)
- if ltjs.get_penalty_table('kcat', p.char, 0, ltj.box_stack_level)%2~=1 then
- widow_node = p
- end
- p = node_next(p); chain = true
-end
-
-local function ins_gk_JA_any()
- -- the case (q,p): JA-JA is treated in ins_gk_any_JA()
- local g = nil
- if not ihb_flag then
- g = new_jfm_glue(qs[1], qs[2],
- has_attr(q,attr_jchar_class),
- ljfm_find_char_class('jcharbdd',qs[2]))
- end
- if p.id==id_glyph then -- (q,p): JA-AL
- local w = 0; local x = ljfm_find_char_class('lineend', qs[2])
- if (not ihb_flag) and x~=0 then
- local h = ltj.metrics[qs[2]].char_type[has_attr(q,attr_jchar_class)]
- if h.kern and h.kern[x] then w = round(qs[1]*h.kern[x]) end
- end
- q_post = add_penalty(q_post, ltjs.get_penalty_table('pre', p.char, 0, ltj.box_stack_level))
- real_insert(g, w, q_post, true)
- elseif p.id==id_kern then -- (q,p): JA-kern
- real_insert_kern(g)
- else
- local w = 0; local x = ljfm_find_char_class('lineend', qs[2])
- if (not ihb_flag) and x~=0 then
- local h = ltj.metrics[qs[2]].char_type[has_attr(q,attr_jchar_class)]
- if h.kern and h.kern[x] then w = round(qs[1]*h.kern[x]) end
- end
- if p.id~=penalty then
- real_insert(g, w, q_post, true)
- else
- real_insert(g, w, q_post, false)
- end
- end
- chain = false; q, qs, q_post = p, nil, 0; p = node_next(p)
-end
-
--- Insert JFM glue after thr last node
-local function ins_gk_tail()
- local g
- if is_japanese_glyph_node(p) then
- if mode then
- local w = 0; local x = ljfm_find_char_class('lineend', qs[2])
- if (not ihb_flag) and x~=0 then
- local h = ltj.metrics[qs[2]].char_type[has_attr(q,attr_jchar_class)]
- if h.kern and h.kern[x] then w = round(qs[1]*h.kern[x]) end
- end
- if w~=0 then
- g = node_new(id_kern); g.subtype = 0; g.kern = w
- set_attr(g, attr_icflag, LINE_END)
- node_insert_before(head, last, g)
- end
- end
- end
-end
-
-local function add_widow_penalty()
- -- widoe_node: must be
- if not widow_node then return end
- local a = node_prev(widow_node)
- local i = has_attr(a, attr_icflag) or 0
- local wp = ltjs.get_penalty_table('jwp', 0, 0, ltj.box_stack_level)
- if i==4 then
- a.penalty=add_penalty(a.penalty, wp)
- elseif i>=2 then
- local b = node_prev(a)
- if i==4 then
- b.penalty=add_penalty(b.penalty, wp)
- else
- local g = node_new(id_penalty)
- g.penalty = wp; head = node_insert_before(head,a,g)
- end
- else
- local g = node_new(id_penalty)
- g.penalty = wp; head = node_insert_before(head,widow_node,g)
- end
-end
-
--- Finishing: add \jcharwidowpenalty or remove the sentinel
-local function finishing()
- if mode then
- -- Insert \jcharwidowpenalty
- add_widow_penalty()
- else
- head = node_remove(head, last)
- end
-end
-
--- The interface
-function ltj.int_insert_jfm_glue(ahead, amode)
- if not ahead then return ahead end
- head = ahead; mode = amode; init_var();
- while p~=last and p.id==id_whatsit and p.subtype==sid_user and p.user_id==30111 do
- local g = p; p = node_next(p); ihb_flag = true; head, p = node.remove(head, g)
- end
- if p~=last then ins_gk_head() else finishing() return head end
- while p~=last do
- if p.id==id_whatsit and p.subtype==sid_user and p.user_id==30111 then
- local g = p; p = node_next(p)
- ihb_flag = true; head, p = node.remove(head, g)
- else
- if is_japanese_glyph_node(p) then -- p: JAchar
- ins_gk_any_JA()
- elseif chain then -- q: JAchar
- ins_gk_JA_any()
- else
- q, qs, q_post = p, nil, 0; p = node_next(p)
- end
- ihb_flag = false
- end
- end
- ins_gk_tail(); finishing(); return head
-end
-
+\ltj@tempcnta="0%"
+\loop\ifnum\ltj@tempcnta<"100%"
+ \ltjsetparameter{alxspmode={\ltj@tempcnta,0}}%
+ \advance\ltj@tempcnta by1
+\repeat
+
+\ltj@tempcnta=`\0%"
+\loop\ifnum\ltj@tempcnta<`\:%"
+ \ltjsetparameter{alxspmode={\ltj@tempcnta,3}}%
+ \advance\ltj@tempcnta by1
+\repeat
+
+\ltj@tempcnta=`\A%"
+\loop\ifnum\ltj@tempcnta<`\[%"
+ \ltjsetparameter{alxspmode={\ltj@tempcnta,3}}%
+ \advance\ltj@tempcnta by1
+\repeat
+
+\ltj@tempcnta=`\a%"
+\loop\ifnum\ltj@tempcnta<`\{%"
+ \ltjsetparameter{alxspmode={\ltj@tempcnta,3}}%
+ \advance\ltj@tempcnta by1
+\repeat
+
+\ltj@tempcnta="2000%"
+\loop\ifnum\ltj@tempcnta<"2070%"
+ \ltjsetparameter{kcatcode={\ltj@tempcnta,1}}%
+ \advance\ltj@tempcnta by1
+\repeat
+
+\ltj@tempcnta="3000%"
+\loop\ifnum\ltj@tempcnta<"3040%"
+ \ltjsetparameter{kcatcode={\ltj@tempcnta,1}}%
+ \advance\ltj@tempcnta by1
+\repeat
+
+\ltj@tempcnta="FF00%"
+\loop\ifnum\ltj@tempcnta<"FFF0%"
+ \ltjsetparameter{kcatcode={\ltj@tempcnta,1}}%
+ \advance\ltj@tempcnta by1
+\repeat
+
%
% 行頭、行末禁則パラメータ
%
--- /dev/null
+%
+% luatexja-latex.sty
+%
+
+%! これは外から読まれない
+%% Avoid multiple loading.
+\csname luatexjalatexLoaded\endcsname
+\edef\ltj@latex@AtEnd{%
+\endlinechar=\the\endlinechar
+\relax}
+\endlinechar=-1 %
+\def\luatexjalatexLoaded{\endinput}
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{luatexja-latex}[2011/08/01 v0.1]
+
+\endlinechar=13
+
+
+%%% patch for LaTeX (similar to plfonts.dtx)
+\input{lltjfont.sty}
+\input{lltjdefs.sty}
+
+%%% parameter
+
+\ltjsetparameter{kanjiskip=0pt plus 0.4pt minus 0.4pt,
+ xkanjiskip=.25\zw plus 1pt minus 1pt,
+ autospacing, autoxspacing, jacharrange={-1},
+ yalbaselineshift=0pt, yjabaselineshift=0pt,
+ jcharwidowpenalty=500, differentjfm=average
+}
+
+\input luatexja-kinsoku.tex
+
+%%------------------ all done
+\ltj@latex@AtEnd
+\endinput
+%% EOF
jcharwidowpenalty=500, differentjfm=average
}
-\ltj@tempcnta="0%"
-\loop\ifnum\ltj@tempcnta<"100%"
- \ltjsetparameter{alxspmode={\ltj@tempcnta,0}}%
- \advance\ltj@tempcnta by1
-\repeat
-
-\ltj@tempcnta=`\0%"
-\loop\ifnum\ltj@tempcnta<`\:%"
- \ltjsetparameter{alxspmode={\ltj@tempcnta,3}}%
- \advance\ltj@tempcnta by1
-\repeat
-
-\ltj@tempcnta=`\A%"
-\loop\ifnum\ltj@tempcnta<`\[%"
- \ltjsetparameter{alxspmode={\ltj@tempcnta,3}}%
- \advance\ltj@tempcnta by1
-\repeat
-
-\ltj@tempcnta=`\a%"
-\loop\ifnum\ltj@tempcnta<`\{%"
- \ltjsetparameter{alxspmode={\ltj@tempcnta,3}}%
- \advance\ltj@tempcnta by1
-\repeat
-
-\input luatexja-kinsoku.tex
-
-\ltj@tempcnta="2000%"
-\loop\ifnum\ltj@tempcnta<"2070%"
- \ltjsetparameter{kcatcode={\ltj@tempcnta,1}}%
- \advance\ltj@tempcnta by1
-\repeat
-
-\ltj@tempcnta="3000%"
-\loop\ifnum\ltj@tempcnta<"3040%"
- \ltjsetparameter{kcatcode={\ltj@tempcnta,1}}%
- \advance\ltj@tempcnta by1
-\repeat
-
-\ltj@tempcnta="FF00%"
-\loop\ifnum\ltj@tempcnta<"FFF0%"
- \ltjsetparameter{kcatcode={\ltj@tempcnta,1}}%
- \advance\ltj@tempcnta by1
-\repeat
-%\endinput
-%! ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
-
%%------------------ all done
\ltj@plain@AtEnd
\endinput
+++ /dev/null
-------------------------------------------------------------------------
--- MAIN PROCESS STEP 3: insert \xkanjiskip (prefix: none)
-------------------------------------------------------------------------
-local ltjs = luatexja.stack
-
-local node_type = node.type
-local node_new = node.new
-local node_prev = node.prev
-local node_next = node.next
-local node_copy = node.copy
-local has_attr = node.has_attribute
-local set_attr = node.set_attribute
-local node_insert_before = node.insert_before
-local node_insert_after = node.insert_after
-local node_hpack = node.hpack
-local round = tex.round
-
-local id_penalty = node.id('penalty')
-local id_glyph = node.id('glyph')
-local id_glue = node.id('glue')
-local id_glue_spec = node.id('glue_spec')
-local id_kern = node.id('kern')
-local id_hlist = node.id('hlist')
-local id_ins = node.id('ins')
-local id_mark = node.id('mark')
-local id_adjust = node.id('adjust')
-local id_math = node.id('math')
-local id_whatsit = node.id('whatsit')
-
-local attr_icflag = luatexbase.attributes['ltj@icflag']
-local attr_autospc = luatexbase.attributes['ltj@autospc']
-local attr_autoxspc = luatexbase.attributes['ltj@autoxspc']
-local attr_curjfnt = luatexbase.attributes['ltj@curjfnt']
-local max_dimen = 1073741823
-
-local ITALIC = 1
-local TEMPORARY = 2
-local FROM_JFM = 3
-local KINSOKU = 4
-local LINE_END = 5
-local KANJI_SKIP = 6
-local XKANJI_SKIP = 7
-local PACKED = 8
-
-local kanji_skip
-local xkanji_skip
-
--- (glyph_node nr) ... (node nq) <GLUE> ,,, (node np)
-local np, nq, nrc, nrf
-local np_spc, nr_spc
-local no_skip = 0
-local after_schar = 1
-local after_wchar = 2 -- nr is a Japanese glyph_node
-local insert_skip = no_skip
-local head
-
-local function is_japanese_glyph_node(p)
- return p and (p.id==id_glyph)
- and (p.font==has_attr(p,attr_curjfnt))
-end
-
-local function get_zero_glue()
- local g = node_new(id_glue_spec)
- g.width = 0; g.stretch_order = 0; g.stretch = 0
- g.shrink_order = 0; g.shrink = 0
- return g
-end
-
-local function skip_table_to_spec(n)
- local g = node_new(id_glue_spec)
- local st = ltjs.get_skip_table(n, ltj.box_stack_level)
- g.width = st.width; g.stretch = st.stretch; g.shrink = st.shrink
- g.stretch_order = st.stretch_order; g.shrink_order = st.shrink_order
- return g
-end
-
-local function add_glue_spec(g,h)
- -- g := g + h
- g.width = g.width + h.width
- if g.stretch_order<h.stretch_order then
- g.stretch_order = h.stretch_order
- g.stretch = h.stretch
- elseif g.stretch_order==h.stretch_order then
- g.stretch = g.stretch + h.stretch
- end
- if g.shrink_order<h.shrink_order then
- g.shrink_order = h.shrink_order
- g.shrink = h.shrink
- elseif g.shrink_order==h.shrink_order then
- g.shrink = g.shrink + h.shrink
- end
-end
-
--- lowest part of \xkanjiskip
-local function get_xkanji_skip_from_jfm(pf)
- if pf then
- local px = { ltj.font_metric_table[pf].size,
- ltj.font_metric_table[pf].jfm }
- local i = ltj.metrics[px[2]].xkanjiskip
- if i then
- return { round(i[1]*px[1]), round(i[2]*px[1]), round(i[3]*px[1]) }
- else return nil
- end
- else return nil
- end
-end
-
-local function insert_xkanjiskip_node(q, f, p)
- if nr_spc[2] or np_spc[2] then
- local g = node_new(id_glue); g.subtype = 0
- if xkanji_skip.width==max_dimen then -- use xkanjiskip from JFM
- local gx = node_new(id_glue_spec)
- gx.stretch_order = 0; gx.shrink_order = 0
- local ak = get_xkanji_skip_from_jfm(f)
- if ak then
- gx.width = ak[1]; gx.stretch = ak[2]; gx.shrink = ak[3]
- else gx = get_zero_glue() -- fallback
- end
- g.spec = gx
- else g.spec=node_copy(xkanji_skip)
- end
- local h = node_prev(p)
- if h and has_attr(h, attr_icflag)==TEMPORARY then
- if h.id==id_kern then
- g.spec.width = g.spec.width + h.kern
- set_attr(g,attr_icflag,XKANJI_SKIP)
- node_insert_after(head, q, g)
- head = node.remove(head, h)
- node.free(h)
- else
- add_glue_spec(h.spec, g.spec)
- node.free(g.spec); node.free(g)
- end
- else
- set_attr(g,attr_icflag,XKANJI_SKIP)
- node_insert_after(head, q, g)
- end
- end
-end
-
-local function insert_ascii_kanji_xkskip(q, p)
- if ltjs.get_penalty_table('xsp', p.char, 3, ltj.box_stack_level)<=1 then return end
- insert_xkanjiskip_node(q, p.font, p)
-end
-
-local function insert_kanji_ascii_xkskip(q, p)
- local g = true
- local c = p.char
- while p.components and p.subtype
- and math.floor(p.subtype/2)%2==1 do
- p = p.components; c = p.char
- end
- if ltjs.get_penalty_table('xsp', c, 3, ltj.box_stack_level)%2 == 1 then
- if ltjs.get_penalty_table('xsp', nrc, 3, ltj.box_stack_level)%2 == 0 then g = false end
- else g = false
- end
- if g then insert_xkanjiskip_node(q, nrf, p) end
-end
-
-local function set_insert_skip_after_achar(p)
- local c = p.char
- while p.components and p.subtype
- and math.floor(p.subtype/2)%2 == 1 do
- p=node.tail(p.components); c = p.char
- end
- if ltjs.get_penalty_table('xsp', c, 3, ltj.box_stack_level)>=2 then
- insert_skip = after_schar
- else
- insert_skip = no_skip
- end
-end
-
--- lowest part of \kanjiskip
-local function get_kanji_skip_from_jfm(pf)
- if pf then
- local px = { ltj.font_metric_table[pf].size,
- ltj.font_metric_table[pf].jfm }
- local i = ltj.metrics[px[2]].kanjiskip
- if i then
- return { round(i[1]*px[1]), round(i[2]*px[1]), round(i[3]*px[1]) }
- else return nil
- end
- else return nil
- end
-end
-
-local function insert_kanji_skip(ope, p)
- local g = node_new(id_glue); g.subtype=0
- if nr_spc[1] or np_spc[1] then
- if kanji_skip.width==max_dimen then -- use kanjiskip from JFM
- local gx = node_new(id_glue_spec);
- gx.stretch_order = 0; gx.shrink_order = 0
- local bk = get_kanji_skip_from_jfm(nrf)
- local ak = get_kanji_skip_from_jfm(p.font)
- if bk then
- if ak then
- gx.width = round(ltj.ja_diffmet_rule(bk[1], ak[1]))
- gx.stretch = round(ltj.ja_diffmet_rule(bk[2], ak[2]))
- gx.shrink = -round(ltj.ja_diffmet_rule(-bk[3], -ak[3]))
- else
- gx.width = bk[1]; gx.stretch = bk[2]; gx.shrink = bk[3]
- end
- elseif ak then
- gx.width = ak[1]; gx.stretch = ak[2]; gx.shrink = ak[3]
- else gx = get_zero_glue() -- fallback
- end
- g.spec = gx
- else g.spec=node_copy(kanji_skip)
- end
- else g.spec = get_zero_glue()
- end
- local h = node_prev(p)
- if h and has_attr(h, attr_icflag)==TEMPORARY then
- if h.id==id_kern then
- g.spec.width = g.spec.width + h.kern
- head = node.remove(head, h)
- node.free(h)
- set_attr(g,attr_icflag,KANJI_SKIP)
- ope(head, p, g)
- else
- add_glue_spec(h.spec, g.spec)
- node.free(g.spec); node.free(g)
- end
- else
- set_attr(g,attr_icflag,KANJI_SKIP)
- ope(head, p, g)
- end
-end
-
--- When p is a glyph_node ...
-local function insks_around_char()
- if is_japanese_glyph_node(np) then
- if insert_skip==after_wchar then
- insert_kanji_skip(node_insert_before, np)
- elseif insert_skip==after_schar then
- insert_ascii_kanji_xkskip(nq, np)
- end
- insert_skip=after_wchar
- nrc = np.char; nrf = np.font; nr_spc = np_spc
- else
- if insert_skip==after_wchar then
- insert_kanji_ascii_xkskip(nq, np)
- end
- set_insert_skip_after_achar(np); nr_spc = np_spc
- end
- nq = np
-end
-
--- Return first and last glyph nodes in a hbox
-local first_char = nil
-local last_char = nil
-local find_first_char = nil
-local function check_box(box_ptr)
- local p = box_ptr; local found_visible_node = false
- if not p then
- find_first_char = false; first_char = nil; last_char = nil
- return true
- end
- while p do
- if p.id==id_glyph then
- repeat
- if find_first_char then
- first_char = p; find_first_char = false
- end
- last_char = p; found_visible_node = true; p=node_next(p)
- if not p then return found_visible_node end
- until p.id~=id_glyph
- end
- if p.id==id_hlist then
- if has_attr(p, attr_icflag)==PACKED then
- for q in node.traverse_id(id_glyph, p.head) do
- if find_first_char then
- first_char = q; find_first_char = false
- end
- last_char = q; found_visible_node = true
- end
- else
- if p.shift==0 then
- if check_box(p.head) then found_visible_node = true end
- else if find_first_char then
- find_first_char = false
- else
- last_char = nil
- end
- end
- end
- elseif p.id==id_ins or p.id==id_mark
- or p.id==id_adjust or p.id==id_whatsit
- or p.id==id_penalty then
- p=p
- else
- found_visible_node = true
- if find_first_char then
- find_first_char = false
- else
- last_char = nil
- end
- end
- p = node_next(p)
- end
- return found_visible_node
-end
-
--- When np is a hlist_node ...
-local function insks_around_hbox()
- if np.shift==0 then
- find_first_char = true; first_char = nil; last_char = nil
- if check_box(np.head) then
- -- first char
- if is_japanese_glyph_node(first_char) then
- nrc = first_char.char; nrf = first_char.font
- if insert_skip==after_schar then
- insert_ascii_kanji_xkskip(nq, first_char)
- elseif insert_skip==after_wchar then
- np_spc = { has_attr(first_char, attr_autospc)==1,
- has_attr(first_char, attr_autoxspc)==1 }
- insert_kanji_skip(node_insert_before, np)
- end
- insert_skip = after_wchar
- elseif first_char then
- if insert_skip==after_wchar then
- insert_kanji_ascii_xkskip(nq, first_char)
- end
- set_insert_skip_after_achar(first_char)
- end
- -- last char
- if is_japanese_glyph_node(last_char) then
- insert_skip = after_wchar
- nrc = last_char.char; nrf = last_char.font
- nr_spc = { has_attr(last_char, attr_autospc)==1,
- has_attr(last_char, attr_autoxspc)==1 }
- if is_japanese_glyph_node(node_next(np)) then
- insert_kanji_skip(node_insert_after, np)
- end
- elseif last_char then
- set_insert_skip_after_achar(last_char)
- nr_spc = { has_attr(last_char, attr_autospc)==1,
- has_attr(last_char, attr_autoxspc)==1 }
- else insert_skip = no_skip
- end
- else insert_skip = no_skip
- end
- else insert_skip = no_skip
- end
- nq = np
-end
-
--- When np is a penalty ...
-local function insks_around_penalty()
- nq = np
-end
-
--- When np is a kern ...
---
-local function insks_around_kern()
- if np.subtype==1 then -- \kern or \/
- local i = has_attr(np, attr_icflag)
- if not i or i==FROM_JFM then -- \kern
- insert_skip = no_skip
- elseif i==ITALIC or i==LINE_END or i==TEMPORARY then
- nq = np
- end
- elseif np.subtype==2 then
- -- (np = kern from \accent) .. (accent char) .. (kern from \accent) .. (glyph)
- np = node_next(node_next(np))
- else -- kern from TFM
- nq = np
- end
-end
-
--- When np is a math_node ...
-local function insks_around_math()
- local g = { char = -1 }
- if (np.subtype==0) and (insert_skip==after_wchar) then
- insert_kanji_ascii_xkskip(nq, g)
- insert_skip = no_skip
- else
- nq = np; set_insert_skip_after_achar(g); nr_spc = np_spc
- end
-end
-
-function ltj.int_insert_kanji_skip(ahead)
- kanji_skip=skip_table_to_spec('kanjiskip')
- xkanji_skip=skip_table_to_spec('xkanjiskip')
- head = ahead
- np = head; nq = nil; insert_skip = no_skip
- while np do
- np_spc = { (has_attr(np, attr_autospc)==1),
- (has_attr(np, attr_autoxspc)==1) }
- if np.id==id_glyph then
- repeat
- np_spc = { has_attr(np, attr_autospc)==1,
- has_attr(np, attr_autoxspc)==1 }
- insks_around_char(); np=node_next(np)
- until (not np) or np.id~=id_glyph
- else
- if np.id==id_hlist then
- insks_around_hbox()
- elseif np.id==id_penalty then
- insks_around_penalty()
- elseif np.id==id_kern then
- insks_around_kern()
- elseif np.id==id_math then
- insks_around_math()
- elseif np.id==id_ins or np.id==id_mark
- or np.id==id_adjust or np.id==id_whatsit then
- -- do nothing
- np = np
- else
- -- rule, disc, glue, margin_kern
- insert_skip = no_skip
- end
- np = node_next(np)
- end
- end
- return head
-end
\ No newline at end of file
module('luatexja.charrange', package.seeall)
local err, warn, info, log = luatexbase.errwarinf(_NAME)
-local ltjb = luatexja.base
+require('luatexja.base'); local ltjb = luatexja.base
local floor = math.floor
local has_attr = node.has_attribute
module('luatexja.compat', package.seeall)
local err, warn, info, log = luatexbase.errwarinf(_NAME)
-local ltjb = luatexja.base
-local ltjs = luatexja.stack
+require('luatexja.base'); local ltjb = luatexja.base
+require('luatexja.stack'); local ltjs = luatexja.stack
-- \kuten, \jis, \euc, \sjis, \ucs, \kansuji
function to_kansuji(num)
module('luatexja.inputbuf', package.seeall)
local err, warn, info, log = luatexbase.errwarinf(_NAME)
-local ltjc = luatexja.charrange
+require('luatexja.charrange'); local ltjc = luatexja.charrange
local node_new = node.new
local id_glyph = node.id('glyph')
--- /dev/null
+--
+-- luatexja/jfmglue.lua
+--
+luatexbase.provides_module({
+ name = 'luatexja.jfmglue',
+ date = '2011/06/27',
+ version = '0.2',
+ description = 'Insertion process of JFM glues and kanjiskip',
+})
+module('luatexja.jfmglue', package.seeall)
+local err, warn, info, log = luatexbase.errwarinf(_NAME)
+
+require('luatexja.base'); local ltjb = luatexja.base
+require('luatexja.stack'); local ltjs = luatexja.stack
+require('luatexja.jfont'); local ltjf = luatexja.jfont
+require('luatexja.pretreat'); local ltjp = luatexja.pretreat
+
+local node_type = node.type
+local node_new = node.new
+local node_remove = node.remove
+local node_prev = node.prev
+local node_next = node.next
+local node_copy = node.copy
+local node_tail = node.tail
+local node_free = node.free
+local has_attr = node.has_attribute
+local set_attr = node.set_attribute
+local node_insert_before = node.insert_before
+local node_insert_after = node.insert_after
+local round = tex.round
+
+local id_glyph = node.id('glyph')
+local id_hlist = node.id('hlist')
+local id_vlist = node.id('vlist')
+local id_rule = node.id('rule')
+local id_ins = node.id('ins')
+local id_mark = node.id('mark')
+local id_adjust = node.id('adjust')
+local id_disc = node.id('disc')
+local id_whatsit = node.id('whatsit')
+local id_math = node.id('math')
+local id_glue = node.id('glue')
+local id_kern = node.id('kern')
+local id_penalty = node.id('penalty')
+
+local id_glue_spec = node.id('glue_spec')
+local id_jglyph = node.id('glyph') + 256
+local id_box_like = node.id('hlist') + 256
+local id_pbox = node.id('hlist') + 512
+local sid_user = node.subtype('user_defined')
+
+local ITALIC = 1
+local PACKED = 2
+local KINSOKU = 3
+local FROM_JFM = 4
+local LINE_END = 5
+local KANJI_SKIP = 6
+local XKANJI_SKIP = 7
+local PROCESSED = 8
+local IC_PROCESSED = 9
+local BOXBDD = 15
+
+local kanji_skip
+local xkanji_skip
+
+local attr_jchar_class = luatexbase.attributes['ltj@charclass']
+local attr_curjfnt = luatexbase.attributes['ltj@curjfnt']
+local attr_icflag = luatexbase.attributes['ltj@icflag']
+local attr_autospc = luatexbase.attributes['ltj@autospc']
+local attr_autoxspc = luatexbase.attributes['ltj@autoxspc']
+local max_dimen = 1073741823
+
+
+
+-------------------- Helper functions
+
+local function find_char_class(c,m)
+ return m.chars[c] or 0
+end
+
+local function get_zero_glue()
+ local g = node_new(id_glue_spec)
+ g.width = 0; g.stretch_order = 0; g.stretch = 0
+ g.shrink_order = 0; g.shrink = 0
+ return g
+end
+
+local function skip_table_to_spec(n)
+ local g = node_new(id_glue_spec)
+ local st = ltjs.get_skip_table(n, ltjp.box_stack_level)
+ g.width = st.width; g.stretch = st.stretch; g.shrink = st.shrink
+ g.stretch_order = st.stretch_order; g.shrink_order = st.shrink_order
+ return g
+end
+
+-- penalty 値の計算
+local function add_penalty(p,e)
+ if p.penalty>=10000 then
+ if e<=-10000 then p.penalty = 0 end
+ elseif p.penalty<=-10000 then
+ if e>=10000 then p.penalty = 0 end
+ else
+ p.penalty = p.penalty + e
+ if p.penalty>=10000 then p.penalty = 10000
+ elseif p.penalty<=-10000 then p.penalty = -10000 end
+ end
+ return
+end
+
+-- 「異なる JFM」の間の調整方法
+diffmet_rule = math.two_average
+function math.two_add(a,b) return a+b end
+function math.two_average(a,b) return (a+b)/2 end
+
+-------------------- idea
+-- 2 node の間に glue/kern/penalty を挿入する.
+-- 基本方針: char node q と char node p の間
+
+-- Np: 「p を核とする塊」
+-- first: 最初の node,nuc: p,last: 最後の node
+-- id: 核 node の種類
+-- Nq: 「q を核とする塊」
+-- 実際の glue は Np.last, Nq.first の間に挿入される
+-- Bp: Np.last, Nq.first の間の penalty node 達の配列
+
+-- 核の定義:
+-- node x が non-char node のときは,x のみ
+-- x が char_node のときは,
+-- - x が \accent の第二引数だったとき
+-- [kern2 kern y kern2] x の 3 node が核に加わる
+-- - x の直後に \/ 由来 kern があったとき
+-- その \/ 由来の kern が核に加わる
+-- p, q の走査で無視するもの:
+-- ins, mark, adjust, whatsit, penalty
+--
+-- Nq.last .. + .. Bp.first .... Bp[last] .... * .. Np.first
+-- +: kern from LINEEND はここに入る
+-- *: jfm glue はここに入る
+
+local head -- the head of current list
+local last -- the last node of current list
+local lp -- 外側での list 走査時のカーソル
+
+local Np, Nq, Bp
+local widow_Bp, widow_Np -- \jcharwidowpenalty 挿入位置管理用
+
+local ihb_flag -- JFM グルー挿入抑止用 flag
+ -- on: \inhibitglue 指定時,hlist の周囲
+
+-------------------- hlist 内の文字の検索
+
+local first_char, last_char, find_first_char
+
+local function check_box(box_ptr, box_end)
+ local p = box_ptr; local found_visible_node = false
+ if not p then
+ find_first_char = false; first_char = nil; last_char = nil
+ return true
+ end
+ while p and p~=box_end do
+ local pid = p.id
+ if pid==id_kern then
+ if p.subtype==2 then
+ p = node_next(node_next(node_next(p))); pid = p.id
+ elseif has_attr(p, attr_icflag)==IC_PROCESSED then
+ p = node_next(p); pid = p.id
+ end
+ end
+ if pid==id_glyph then
+ repeat
+ if find_first_char then
+ first_char = p; find_first_char = false
+ end
+ last_char = p; found_visible_node = true; p=node_next(p)
+ if (not p) or p==box_end then return found_visible_node end
+ until p.id~=id_glyph
+ end
+ if pid==id_hlist then
+ if has_attr(p, attr_icflag)==PACKED then
+ for q in node.traverse_id(id_glyph, p.head) do
+ if find_first_char then
+ first_char = q; find_first_char = false
+ end
+ last_char = q; found_visible_node = true; break
+ end
+ else
+ if p.shift==0 then
+ if check_box(p.head, nil) then found_visible_node = true end
+ else if find_first_char then
+ find_first_char = false
+ else
+ last_char = nil
+ end
+ end
+ end
+ elseif not (pid==id_ins or pid==id_mark
+ or pid==id_adjust or pid==id_whatsit
+ or pid==id_penalty) then
+ found_visible_node = true
+ if find_first_char then
+ find_first_char = false
+ else
+ last_char = nil
+ end
+ end
+ p = node_next(p)
+ end
+ return found_visible_node
+end
+
+-------------------- Np の計算と情報取得
+-- calc next Np
+local function set_attr_icflag_processed(p)
+ local a = has_attr(p, attr_icflag) or 0
+ if a<=1 then set_attr(p, attr_icflag, PROCESSED) end
+end
+
+local function check_next_ickern()
+ if lp.id == id_kern and has_attr(lp, attr_icflag)==ITALIC then
+ set_attr(lp, attr_icflag, IC_PROCESSED); Np.last = lp; lp = node_next(lp)
+ else Np.last = Np.nuc end
+end
+
+local function calc_np_pbox()
+ Np.first = lp; Np.id = id_pbox
+ lpa = KINSOKU -- dummy
+ while lp~=last and lpa>=PACKED and lpa~=BOXBDD do
+ Np.nuc = lp; lp = node_next(lp); lpa = has_attr(lp, attr_icflag) or 0
+ end
+ check_next_ickern()
+end
+
+local function calc_np()
+ -- We assume lp = node_next(Np.last)
+ local pBp = Bp; local lpi, lpa
+ Nq = Np; Bp = {}; Bp[0] = 0; Np = {}; ihb_flag = false
+ while true do
+ lpi = lp.id; lpa = has_attr(lp, attr_icflag) or 0
+ if lp==last then Np = nil; return
+ elseif lpa>=PACKED then
+ if lpa == BOXBDD then
+ local lq = node_next(lp)
+ head = node_remove(head, lp); lp = lq
+ else calc_np_pbox(); return end -- id_pbox
+ elseif lpi == id_ins or lpi == id_mark or lpi == id_adjust then
+ set_attr_icflag_processed(lp); lp = node_next(lp)
+ elseif lpi == id_penalty then
+ table.insert(Bp, lp); Bp[0] = Bp[0] + 1
+ set_attr_icflag_processed(lp); lp = node_next(lp)
+ elseif lpi == id_whatsit then
+ if lp.subtype==sid_user and lp.user_id==30111 then
+ local lq = node_next(lp)
+ head = node_remove(head, lp); lp = lq; ihb_flag = true
+ else
+ set_attr_icflag_processed(lp); lp = node_next(lp)
+ end
+ else -- a `cluster' is found
+ Np.first = lp
+ if lpi == id_glyph then -- id_[j]glyph
+ if lp.font == has_attr(lp, attr_curjfnt) then Np.id = id_jglyph
+ else Np.id = id_glyph end
+ Np.nuc = lp; set_attr_icflag_processed(lp)
+ lp = node_next(lp); check_next_ickern(); return
+ elseif lpi == id_hlist then -- hlist
+ Np.last = lp; Np.nuc = lp; set_attr_icflag_processed(lp)
+ if lp.shift~=0 then Np.id = id_box_like
+ else Np.id = lpi end
+ lp = node_next(lp); return
+ elseif lpi == id_vlist or lpi == id_rule then -- id_box_like
+ Np.nuc = lp; Np.last = lp; Np.id = id_box_like; break
+ elseif lpi == id_math then -- id_math
+ Np.nuc = lp
+ while lp.id~=id_math do
+ set_attr_icflag_processed(lp); lp = node_next(lp)
+ end; break
+ elseif lpi == id_kern and lp.subtype==2 then -- id_kern
+ set_attr_icflag_processed(lp); lp = node_next(lp)
+ set_attr_icflag_processed(lp); lp = node_next(lp)
+ set_attr_icflag_processed(lp); lp = node_next(lp)
+ set_attr_icflag_processed(lp); Np.nuc = lp
+ if lp.font == has_attr(lp, attr_curjfnt) then Np.id = id_jglyph
+ else Np.id = id_glyph end
+ lp = node_next(lp); check_next_ickern(); return
+ else -- id_disc, id_glue, id_kern
+ Np.nuc = lp; break
+ end
+ end
+ end
+ set_attr_icflag_processed(lp); Np.last = lp; Np.id = lpi; lp = node_next(lp)
+end
+
+-- extract informations from Np
+-- We think that "Np is a Japanese character" if Np.met~=nil,
+-- "Np is an alphabetic character" if Np.pre~=nil,
+-- "Np is not a character" otherwise.
+
+-- 和文文字のデータを取得
+local function set_np_xspc_jachar(c,x)
+ Np.class = has_attr(x, attr_jchar_class)
+ Np.char = c
+ local z = ltjf.font_metric_table[x.font]
+ Np.size= z.size
+ Np.met = ltjf.metrics[z.jfm]
+ Np.var = z.var
+ Np.pre = ltjs.get_penalty_table('pre', c, 0, ltjp.box_stack_level)
+ Np.post = ltjs.get_penalty_table('post', c, 0, ltjp.box_stack_level)
+ z = find_char_class('lineend', Np.met)
+ local y = Np.met.char_type[Np.class]
+ if y.kern and y.kern[z] then
+ Np.lend = round(Np.size*y.kern[z])
+ else
+ Np.lend = 0
+ end
+ y = ltjs.get_penalty_table('xsp', c, 3, ltjp.box_stack_level)
+ Np.xspc_before = (y>=2)
+ Np.xspc_after = (y%2==1)
+ Np.auto_kspc = (has_attr(x, attr_autospc)==1)
+ Np.auto_xspc = (has_attr(x, attr_autoxspc)==1)
+end
+
+-- 欧文文字のデータを取得
+local ligature_head = 1
+local ligature_tail = 2
+local function set_np_xspc_alchar(c,x, lig)
+ if c~=-1 then
+ if lig == ligature_head then
+ while x.components and x.subtype and math.floor(x.subtype/2)%2==1 do
+ x = x.components; c = x.char
+ end
+ else
+ while x.components and x.subtype and math.floor(x.subtype/2)%2==1 do
+ x = node_tail(x.components); c = x.char
+ end
+ end
+ Np.pre = ltjs.get_penalty_table('pre', c, 0, ltjp.box_stack_level)
+ Np.post = ltjs.get_penalty_table('post', c, 0, ltjp.box_stack_level)
+ else
+ Np.pre = 0; Np.post = 0
+ end
+ Np.met = nil
+ local y = ltjs.get_penalty_table('xsp', c, 3, ltjp.box_stack_level)
+ Np.xspc_before = (y%2==1)
+ Np.xspc_after = (y>=2)
+ Np.auto_xspc = (has_attr(x, attr_autoxspc)==1)
+end
+
+-- Np の情報取得メインルーチン
+local function extract_np()
+ local x = Np.nuc
+ if Np.id == id_jglyph then
+ set_np_xspc_jachar(x.char, x)
+ elseif Np.id == id_glyph then
+ set_np_xspc_alchar(x.char, x, ligature_head)
+ elseif Np.id == id_hlist then
+ find_first_char = true; first_char = nil; last_char = nil
+ if check_box(x.head, nil) then
+ if first_char then
+ if first_char.font == has_attr(first_char, attr_curjfnt) then
+ set_np_xspc_jachar(first_char.char,first_char)
+ else
+ set_np_xspc_alchar(first_char.char,first_char, ligature_head)
+ end
+ end
+ end
+ elseif Np.id == id_pbox then -- mikann
+ find_first_char = true; first_char = nil; last_char = nil
+ if check_box(Np.first, node_next(Np.last)) then
+ if first_char then
+ if first_char.font == has_attr(first_char, attr_curjfnt) then
+ set_np_xspc_jachar(first_char.char,first_char)
+ else
+ set_np_xspc_alchar(first_char.char,first_char, ligature_head)
+ end
+ end
+ end
+ elseif Np.id == id_disc then
+ find_first_char = true; first_char = nil; last_char = nil
+ if check_box(x.replace, nil) then
+ if first_char then
+ if first_char.font == has_attr(first_char, attr_curjfnt) then
+ set_np_xspc_jachar(first_char.char,first_char)
+ else
+ set_np_xspc_alchar(first_char.char,first_char, ligature_head)
+ end
+ end
+ end
+ elseif Np.id == id_math then
+ set_np_xspc_alchar(-1, x)
+ end
+end
+
+-- change the information for the next loop
+-- (will be done if Np is an alphabetic character or a hlist)
+local function after_hlist()
+ if last_char then
+ if last_char.font == has_attr(last_char, attr_curjfnt) then
+ set_np_xspc_jachar(last_char.char,last_char, ligature_after)
+ else
+ set_np_xspc_alchar(last_char.char,last_char, ligature_after)
+ end
+ else
+ Np.pre = nil; Np.met = nil
+ end
+end
+local function after_alchar()
+ local x = Np.nuc
+ set_np_xspc_alchar(x.char,x, ligature_after)
+end
+
+
+-------------------- 最下層の処理
+
+local function lineend_fix(g)
+ if g and g.id==id_kern then
+ Nq.lend = 0
+ elseif Nq.lend and Nq.lend~=0 then
+ if not g then
+ g = node_new(id_kern); g.subtype = 1
+ g.kern = -Nq.lend; set_attr(g, attr_icflag, LINEEND)
+ elseif g.id==id_kern then
+ g.kern = g.kern - Nq.lend
+ else
+ g.spec.width = g.spec.width - Nq.lend
+ end
+ end
+ return g
+end
+
+-- change penalties (or create a new penalty, if needed)
+local function handle_penalty_normal(post, pre, g)
+ local a = (pre or 0) + (post or 0)
+ if Bp[0] == 0 then
+ if (a~=0 and not(g and g.id==id_kern)) or (Nq.lend and Nq.lend~=0) then
+ local p = node_new(id_penalty)
+ if a<-10000 then a = -10000 elseif a>10000 then a = 10000 end
+ p.penalty = a
+ head = node_insert_before(head, Np.first, p)
+ Bp[1] = p; Bp[0] = 1; set_attr(p, attr_icflag, KINSOKU)
+ end
+ else for i, v in ipairs(Bp) do add_penalty(v,a) end
+ end
+end
+
+local function handle_penalty_always(post, pre, g)
+ local a = (pre or 0) + (post or 0)
+ if Bp[0] == 0 then
+ if not (g and g.id==id_glue) or (Nq.lend and Nq.lend~=0) then
+ local p = node_new(id_penalty)
+ if a<-10000 then a = -10000 elseif a>10000 then a = 10000 end
+ p.penalty = a
+ head = node_insert_before(head, Np.first, p)
+ Bp[1] = p; Bp[0] = 1; set_attr(p, attr_icflag, KINSOKU)
+ end
+ else for i, v in ipairs(Bp) do add_penalty(v,a) end
+ end
+end
+
+local function handle_penalty_suppress(post, pre, g)
+ local a = (pre or 0) + (post or 0)
+ if Bp[0] == 0 then
+ if g and g.id==id_glue then
+ local p = node_new(id_penalty)
+ p.penalty = 10000; head = node_insert_before(head, Np.first, p)
+ Bp[1] = p; Bp[0] = 1; set_attr(p, attr_icflag, KINSOKU)
+ end
+ else for i, v in ipairs(Bp) do add_penalty(v,a) end
+ end
+end
+
+-- 和文文字間の JFM glue を node 化
+local function new_jfm_glue(Nn, bc, ac)
+-- bc, ac: char classes
+ local g = nil
+ local z = Nn.met.char_type[bc]
+ if z.glue and z.glue[ac] then
+ local h = node_new(id_glue_spec)
+ h.width = round(Nn.size*z.glue[ac][1])
+ h.stretch = round(Nn.size*z.glue[ac][2])
+ h.shrink = round(Nn.size*z.glue[ac][3])
+ h.stretch_order=0; h.shrink_order=0
+ g = node_new(id_glue)
+ g.subtype = 0; g.spec = h
+ elseif z.kern and z.kern[ac] then
+ g = node_new(id_kern)
+ g.subtype = 1; g.kern = round(Nn.size*z.kern[ac])
+ end
+ if g then set_attr(g, attr_icflag, FROM_JFM) end
+ return g
+end
+
+-- Nq.last (kern w) .... (glue/kern g) Np.first
+local function real_insert(w, g)
+ if w~=0 then
+ local h = node_new(id_kern)
+ set_attr(h, attr_icflag, LINE_END)
+ h.kern = Nq.lend; h.subtype = 1
+ head = node_insert_after(head, Nq.last, h)
+ end
+ if g then
+ head = node_insert_before(head, Np.first, g)
+ Np.first = g
+ end
+end
+
+-------------------- 和文文字間空白量の決定
+
+-- get kanjiskip
+local function get_kanji_skip_from_jfm(Nn)
+ local i = Nn.met.kanjiskip
+ if i then
+ return { round(i[1]*Nn.size), round(i[2]*Nn.size), round(i[3]*Nn.size) }
+ else return nil
+ end
+end
+local function get_kanjiskip()
+ local g = node_new(id_glue)
+ if Np.auto_kspc or Nq.auto_kspc then
+ if kanji_skip.width == max_dimen then
+ local gx = node_new(id_glue_spec);
+ gx.stretch_order = 0; gx.shrink_order = 0
+ local bk = get_kanji_skip_from_jfm(Nq)
+ local ak
+ if (Np.met==Nq.met) and (Nq.size==Np.size) and (Nq.var==Np.var) then
+ ak = nil
+ else
+ ak = get_kanji_skip_from_jfm(Np)
+ end
+ if bk then
+ if ak then
+ gx.width = round(diffmet_rule(bk[1], ak[1]))
+ gx.stretch = round(diffmet_rule(bk[2], ak[2]))
+ gx.shrink = -round(diffmet_rule(-bk[3], -ak[3]))
+ else
+ gx.width = bk[1]; gx.stretch = bk[2]; gx.shrink = bk[3]
+ end
+ elseif ak then
+ gx.width = ak[1]; gx.stretch = ak[2]; gx.shrink = ak[3]
+ else gx = get_zero_glue() -- fallback
+ end
+ g.spec = gx
+ else g.spec=node_copy(kanji_skip) end
+ else
+ local gx = get_zero_glue()
+ g.spec = gx
+ end
+ set_attr(g, attr_icflag, KANJI_SKIP)
+ return g
+end
+
+local function calc_ja_ja_aux(gb,ga)
+ if not gb then
+ return ga
+ else
+ if not ga then return gb end
+ local k = node.type(gb.id) .. node.type(ga.id)
+ if k == 'glueglue' then
+ -- 両方とも glue.
+ gb.spec.width = round(diffmet_rule(gb.spec.width, ga.spec.width))
+ gb.spec.stretch = round(diffmet_rule(gb.spec.stretch,ga.spec.shrink))
+ gb.spec.shrink = -round(diffmet_rule(-gb.spec.shrink, -ga.spec.shrink))
+ node_free(ga)
+ return gb
+ elseif k == 'kernkern' then
+ -- 両方とも kern.
+ gb.kern = round(diffmet_rule(gb.kern, ga.kern))
+ node_free(ga)
+ return gb
+ elseif k == 'kernglue' then
+ -- gb: kern, ga: glue
+ ga.spec.width = round(diffmet_rule(gb.kern,ga.spec.width))
+ ga.spec.stretch = round(diffmet_rule(ga.spec.stretch, 0))
+ ga.spec.shrink = -round(diffmet_rule(-ga.spec.shrink, 0))
+ node_free(gb)
+ return ga
+ else
+ -- gb: glue, ga: kern
+ gb.spec.width = round(diffmet_rule(ga.kern, gb.spec.width))
+ gb.spec.stretch = round(diffmet_rule(gb.spec.stretch, 0))
+ gb.spec.shrink = -round(diffmet_rule(-gb.spec.shrink, 0))
+ node_free(ga)
+ return gb
+ end
+ end
+end
+
+local function calc_ja_ja_glue()
+ if ihb_flag then return nil
+ elseif (Nq.size==Np.size) and (Nq.met==Np.met) and (Nq.var==Np.var) then
+ return new_jfm_glue(Nq, Nq.class, Np.class)
+ else
+ local g = new_jfm_glue(Nq, Nq.class,
+ find_char_class('diffmet',Nq.met))
+ local h = new_jfm_glue(Np, find_char_class('diffmet',Np.met),
+ Np.class)
+ return calc_ja_ja_aux(g,h)
+ end
+end
+
+-------------------- 和欧文間空白量の決定
+
+-- get xkanjiskip
+local function get_xkanji_skip_from_jfm(Nn)
+ local i = Nn.met.xkanjiskip
+ if i then
+ return { round(i[1]*Nn.size), round(i[2]*Nn.size), round(i[3]*Nn.size) }
+ else return nil
+ end
+end
+local function get_xkanjiskip(Nn)
+ local g = node_new(id_glue)
+ if Nq.xspc_after and Np.xspc_before and (Nq.auto_xspc or Np.auto_xspc) then
+ if xkanji_skip.width == max_dimen then
+ local gx = node_new(id_glue_spec);
+ gx.stretch_order = 0; gx.shrink_order = 0
+ local bk = get_xkanji_skip_from_jfm(Nn)
+ if bk then
+ gx.width = bk[1]; gx.stretch = bk[2]; gx.shrink = bk[3]
+ else gx = get_zero_glue() -- fallback
+ end
+ g.spec = gx
+ else g.spec=node_copy(xkanji_skip) end
+ else
+ local gx = get_zero_glue()
+ g.spec = gx
+ end
+ set_attr(g, attr_icflag, XKANJI_SKIP)
+ return g
+end
+
+
+-------------------- 隣接した「塊」間の処理
+
+local function get_OA_skip()
+ if not ihb_flag then
+ return new_jfm_glue(Np, find_char_class('jcharbdd',Np.met), Np.class)
+ else return nil
+ end
+end
+local function get_OB_skip()
+ if not ihb_flag then
+ return new_jfm_glue(Nq, Nq.class, find_char_class('jcharbdd',Nq.met))
+ else return nil
+ end
+end
+
+-- (anything) .. jachar
+local function handle_np_jachar()
+ local g = nil
+ if Nq.id==id_jglyph or (Nq.id==id_pbox and Nq.met) then
+ g = calc_ja_ja_glue() or get_kanjiskip() -- M->K
+ g = lineend_fix(g)
+ handle_penalty_normal(Nq.post, Np.pre, g); real_insert(Nq.lend, g)
+ elseif Nq.met then -- Nq.id==id_hlist
+ g = get_OA_skip() or get_kanjiskip() -- O_A->K
+ handle_penalty_normal(0, Np.pre, g); real_insert(0, g)
+ elseif Nq.pre then
+ g = get_OA_skip() or get_xkanjiskip(Np) -- O_A->X
+ handle_penalty_normal(Nq.post, Np.pre, g); real_insert(0, g)
+ else
+ g = get_OA_skip() -- O_A
+ if Nq.id==id_glue then handle_penalty_normal(0, Np.pre, g)
+ elseif Nq.id==id_kern then handle_penalty_suppress(0, Np.pre, g)
+ else handle_penalty_always(0, Np.pre, g)
+ end
+ real_insert(0, g)
+ end
+ -- \jcharwidowpenalty 挿入予定箇所更新
+ if ltjs.get_penalty_table('kcat', Np.char, 0, ltjp.box_stack_level)%2~=1 then
+ widow_Np = Np; widow_Bp = Bp
+ end
+end
+
+-- jachar .. (anything)
+local function handle_nq_jachar()
+ local g = nil
+ if Np.pre then
+ g = get_OB_skip() or get_xkanjiskip(Nq) -- O_B->X
+ g = lineend_fix(g)
+ handle_penalty_normal(Nq.post, Np.pre, g); real_insert(Nq.lend, g)
+ else
+ g = get_OB_skip(); g = lineend_fix(g) -- O_B
+ if Np.id==id_glue then handle_penalty_normal(Nq.post, 0, g)
+ elseif Np.id==id_kern then handle_penalty_suppress(Nq.post, 0, g)
+ else handle_penalty_always(Nq.post, 0, g)
+ end
+ real_insert(Nq.lend, g)
+ end
+end
+
+-- (anything) .. (和文文字で終わる hlist)
+local function handle_np_ja_hlist()
+ local g = nil
+ if Nq.id==id_jglyph or (Nq.id==id_pbox and Nq.met) then
+ g = get_OB_skip() or get_kanjiskip() -- O_B->K
+ g = lineend_fix(g)
+ handle_penalty_normal(Nq.post, 0, g); real_insert(Nq.lend, g)
+ elseif Nq.met then -- Nq.id==id_hlist
+ g = get_kanjiskip() -- K
+ handle_penalty_suppress(0, 0, g); real_insert(0, g)
+ elseif Nq.pre then
+ g = get_xkanjiskip(Np) -- X
+ handle_penalty_suppress(0, 0, g); real_insert(0, g)
+ end
+end
+
+-- (和文文字で終わる hlist) .. (anything)
+local function handle_nq_ja_hlist()
+ local g = nil
+ if Np.pre then
+ g = get_xkanjiskip(Nq) -- X
+ handle_penalty_suppress(0, 0, g); real_insert(0, g)
+ end
+end
+
+-------------------- 開始・終了時の処理
+
+-- リスト末尾の処理
+local function handle_list_tail()
+ Np = Nq
+ if mode then
+ -- the current list is to be line-breaked:
+ if Np.id == id_jglyph or (Np.id==id_pbox and Np.met) then
+ if Np.lend~=0 then
+ g = node_new(id_kern); g.subtype = 0; g.kern = Np.lend
+ set_attr(g, attr_icflag, BOXBDD)
+ node_insert_after(head, Np.last, g)
+ end
+ end
+ -- Insert \jcharwidowpenalty
+ Bp = widow_Bp; Np = widow_Np
+ if Np then
+ handle_penalty_normal(0,
+ ltjs.get_penalty_table('jwp', 0, 0, ltjp.box_stack_level))
+ end
+ else
+ -- the current list is the contents of a hbox
+ if Np.id == id_jglyph or (Np.id==id_pbox and Np.met) then
+ local g = new_jfm_glue(Np, Np.class, find_char_class('boxbdd',Np.met))
+ if g then
+ set_attr(g, attr_icflag, BOXBDD)
+ head = node_insert_after(head, Np.last, g)
+ end
+ end
+ head = node_remove(head, last) -- remove the sentinel
+ end
+end
+
+-- リスト先頭の処理
+local function handle_list_head()
+ if Np.id == id_jglyph or (Np.id==id_pbox and Np.met) then
+ local g = new_jfm_glue(Np, find_char_class('boxbdd',Np.met), Np.class)
+ if g then
+ set_attr(g, attr_icflag, BOXBDD)
+ if g.id==id_glue and Bp[0]==0 then
+ local h = node_new(id_penalty)
+ h.penalty = 10000; set_attr(h, attr_icflag, BOXBDD)
+ end
+ head = node_insert_before(head, Np.first, g)
+ end
+ end
+end
+
+-- initialize
+local function init_var()
+ lp = head; widow_Bp = nil; widow_Np = nil
+ kanji_skip=skip_table_to_spec('kanjiskip')
+ xkanji_skip=skip_table_to_spec('xkanjiskip')
+ if mode then
+ -- the current list is to be line-breaked:
+ -- hbox from \parindent is skipped.
+ while lp and (lp.id==id_whatsit or ((lp.id==id_hlist) and (lp.subtype==3))) do
+ lp=node_next(lp) end
+ last=node.tail(head)
+ else
+ -- the current list is the contents of a hbox:
+ -- insert a sentinel
+ last=node.tail(head); local g = node_new(id_kern)
+ node_insert_after(head, last, g); last = g
+ end
+end
+
+-------------------- 外部から呼ばれる関数
+
+-- main interface
+function main(ahead, amode)
+ if not ahead then return ahead end
+ head = ahead; mode = amode; init_var(); calc_np()
+ if Np then
+ extract_np(); handle_list_head()
+ if Np.id==id_glyph then after_alchar()
+ elseif Np.id==id_hlist or Np.id==id_pbox or Np.id==id_disc then after_hlist()
+ end
+ else
+ if not mode then head = node_remove(head, last) end
+ return head
+ end
+ calc_np()
+ while Np do
+ extract_np()
+ -- 挿入部
+ if Np.id == id_jglyph then
+ handle_np_jachar()
+ elseif Np.met then
+ if Np.id==id_hlist then handle_np_ja_hlist()
+ else handle_np_jachar() end
+ elseif Nq.met then
+ if Nq.id==id_hlist then handle_nq_ja_hlist()
+ else handle_nq_jachar() end
+ end
+ -- Np の後処理
+ if Np.id==id_glyph then after_alchar()
+ elseif Np.id==id_hlist or Np.id==id_pbox or Np.id==id_disc then after_hlist()
+ end
+ calc_np()
+ end
+ handle_list_tail()
+ -- adjust attr_icflag
+ tex.attribute[attr_icflag] = -(0x7FFFFFFF)
+ return head
+end
+
+-- \inhibitglue
+function create_inhibitglue_node()
+ local g=node_new(id_whatsit, sid_user)
+ g.user_id=30111; g.type=100; g.value=1; node.write(g)
+end
+
+-- TODO: 二重挿入の回避
-local ltjb = luatexja.base
-local ltjc = luatexja.charrange
+--
+-- luatexja/jfont.lua
+--
+luatexbase.provides_module({
+ name = 'luatexja.jfont',
+ date = '2011/06/27',
+ version = '0.1',
+ description = 'Loader for Japanese fonts',
+})
+module('luatexja.jfont', package.seeall)
+
+require('luatexja.base'); local ltjb = luatexja.base
+require('luatexja.charrange'); local ltjc = luatexja.charrange
local node_new = node.new
local has_attr = node.has_attribute
local ITALIC = 1
------------------------------------------------------------------------
--- LOADING JFM (prefix: ljfm)
+-- LOADING JFM
------------------------------------------------------------------------
-ltj.metrics={} -- this table stores all metric informations
-ltj.font_metric_table={} -- [font number] -> jfm_name, jfm_var, size
+metrics={} -- this table stores all metric informations
+font_metric_table={} -- [font number] -> jfm_name, jfm_var, size
local jfm_file_name, jfm_var
local defjfm_res
-function ltj.define_jfm(t)
+function define_jfm(t)
local real_char -- Does current character class have the 'real' character?
if t.dir~='yoko' then
defjfm_res= nil; return
defjfm_res= t
end
-local function ljfm_find_char_class(c,m)
+function find_char_class(c,m)
-- c: character code, m
- if not ltj.metrics[m] then return 0 end
- return ltj.metrics[m].chars[c] or 0
+ if not metrics[m] then return 0 end
+ return metrics[m].chars[c] or 0
end
-ltj.int_find_char_class = ljfm_find_char_class
-local function ljfm_load_jfont_metric()
+local function load_jfont_metric()
if jfm_file_name=='' then
ltjb.package_error('luatexja',
'no JFM specified',
"The JFM 'ujis' will be used for now."})
jfm_file_name='ujis'
end
- for j,v in ipairs(ltj.metrics) do
+ for j,v in ipairs(metrics) do
if v.name==jfm_file_name then return j end
end
ltj.loadlua('jfm-' .. jfm_file_name .. '.lua')
if defjfm_res then
defjfm_res.name = jfm_file_name
- table.insert(ltj.metrics,defjfm_res)
- return #ltj.metrics
+ table.insert(metrics, defjfm_res)
+ return #metrics
else
return nil
end
------------------------------------------------------------------------
--- LOADING JAPANESE FONTS (prefix: ljft)
+-- LOADING JAPANESE FONTS
------------------------------------------------------------------------
local cstemp
-- EXT
-function ltj.ext_jfontdefX(g)
+function jfontdefX(g)
local t = token.get_next()
cstemp=token.csname_name(t)
if g then ltj.is_global = '\\global' else ltj.is_global = '' end
end
-- EXT
-function ltj.ext_jfontdefY() -- for horizontal font
- local j = ljfm_load_jfont_metric()
+function jfontdefY() -- for horizontal font
+ local j = load_jfont_metric()
local fn = font.id(cstemp)
local f = font.fonts[fn]
if not j then
ltjb.package_error('luatexja',
"bad JFM `" .. jfm_file_name .. "'",
- {'The JFM file you specified is not valid JFM file.',
- 'So defining Japanese font is cancelled.'})
+ 'The JFM file you specified is not valid JFM file.\n'..
+ 'So defining Japanese font is cancelled.')
tex.sprint(ltj.is_global .. '\\expandafter\\let\\csname '
.. cstemp .. '\\endcsname=\\relax')
return
end
- ltj.font_metric_table[fn]={}
- ltj.font_metric_table[fn].jfm=j
- ltj.font_metric_table[fn].size=f.size
- ltj.font_metric_table[fn].var=jfm_var
+ font_metric_table[fn]={}
+ font_metric_table[fn].jfm=j
+ font_metric_table[fn].size=f.size
+ font_metric_table[fn].var=jfm_var
tex.sprint(ltj.is_global .. '\\protected\\expandafter\\def\\csname '
.. cstemp .. '\\endcsname'
.. '{\\csname ltj@curjfnt\\endcsname=' .. fn
- .. ' \\zw=' .. round(f.size*ltj.metrics[j].zw) .. 'sp'
- .. '\\zh=' .. round(f.size*ltj.metrics[j].zh) .. 'sp\\relax}')
+ .. ' \\zw=' .. round(f.size*metrics[j].zw) .. 'sp'
+ .. '\\zh=' .. round(f.size*metrics[j].zh) .. 'sp\\relax}')
end
-- extract jfm_file_name and jfm_var
-local function ljft_extract_metric(name)
+local function extract_metric(name)
local basename=name
local tmp = utf.sub(basename, 1, 5)
jfm_file_name = ''; jfm_var = ''
-- replace fonts.define.read()
local ljft_dr_orig = fonts.define.read
function fonts.define.read(name, size, id)
- ljft_extract_metric(name)
+ extract_metric(name)
-- In the present imple., we don't remove "jfm=..." from name.
return ljft_dr_orig(name, size, id)
end
------------------------------------------------------------------------
-- EXT: italic correction
-function ltj.ext_append_italic()
+function append_italic()
local p = tex.nest[tex.nest.ptr].tail
if p and p.id==id_glyph then
local f = p.font
g.subtype = 1; node.set_attribute(g, attr_icflag, ITALIC)
if ltjc.is_ucs_in_japanese_char(p) then
f = has_attr(p, attr_curjfnt)
- local j = ltj.font_metric_table[f]
- local c = ljfm_find_char_class(p.char, j.jfm)
- g.kern = round(j.size * ltj.metrics[j.jfm].char_type[c].italic)
+ local j = font_metric_table[f]
+ local c = find_char_class(p.char, j.jfm)
+ g.kern = round(j.size * metrics[j.jfm].char_type[c].italic)
else
g.kern = font.fonts[f].characters[p.char].italic
end
--- /dev/null
+--
+-- luatexja/pretreat.lua
+--
+luatexbase.provides_module({
+ name = 'luatexja.pretreat',
+ date = '2011/06/27',
+ version = '0.1',
+ description = '',
+})
+module('luatexja.pretreat', package.seeall)
+local err, warn, info, log = luatexbase.errwarinf(_NAME)
+
+require('luatexja.charrange'); local ltjc = luatexja.charrange
+require('luatexja.jfont'); local ltjf = luatexja.jfont
+require('luatexja.stack'); local ltjs = luatexja.stack
+
+local has_attr = node.has_attribute
+local set_attr = node.set_attribute
+local unset_attr = node.unset_attribute
+local node_remove = node.remove
+local node_next = node.next
+
+local id_glyph = node.id('glyph')
+local id_whatsit = node.id('whatsit')
+local sid_user = node.subtype('user_defined')
+
+local attr_jchar_class = luatexbase.attributes['ltj@charclass']
+local attr_curjfnt = luatexbase.attributes['ltj@curjfnt']
+local attr_yablshift = luatexbase.attributes['ltj@yablshift']
+local attr_ykblshift = luatexbase.attributes['ltj@ykblshift']
+
+local lang_ja_token = token.create('ltj@japanese')
+local lang_ja = lang_ja_token[2]
+
+------------------------------------------------------------------------
+-- MAIN PROCESS STEP 1: replace fonts
+------------------------------------------------------------------------
+box_stack_level = 0
+-- This is used in jfmglue.lua.
+
+local function suppress_hyphenate_ja(head)
+ for p in node.traverse_id(id_glyph, head) do
+ if ltjc.is_ucs_in_japanese_char(p) then
+ local v = has_attr(p, attr_curjfnt)
+ if v then
+ p.font = v
+ set_attr(p, attr_jchar_class,
+ ltjf.find_char_class(p.char, ltjf.font_metric_table[v].jfm))
+ end
+ v = has_attr(p, attr_ykblshift)
+ if v then
+ set_attr(p, attr_yablshift, v)
+ else
+ unset_attr(p, attr_yablshift)
+ end
+ if p.subtype%2==1 then p.subtype = p.subtype - 1 end
+ p.lang=lang_ja
+ end
+ end
+ lang.hyphenate(head)
+ return head
+end
+
+-- mode: true iff this function is called from hpack_filter
+function set_box_stack_level(head, mode)
+ local box_set = false
+ local p = head
+ local cl = tex.currentgrouplevel + 1
+ for p in node.traverse_id(id_whatsit, head) do
+ if p.subtype==sid_user and p.user_id==30112 then
+ local g = p
+ if mode and g.value==cl then box_set = true end
+ head, p = node_remove(head, g); break
+ end
+ end
+ if box_set then
+ box_stack_level = tex.getcount('ltj@@stack') + 1
+ else
+ box_stack_level = tex.getcount('ltj@@stack')
+ end
+ return head
+end
+
+-- CALLBACKS
+luatexbase.add_to_callback('hpack_filter',
+ function (head)
+ return set_box_stack_level(head, true)
+ end,'ltj.hpack_filter_pre',1)
+luatexbase.add_to_callback('pre_linebreak_filter',
+ function (head)
+ return set_box_stack_level(head, false)
+ end,'ltj.pre_linebreak_filter_pre',1)
+luatexbase.add_to_callback('hyphenate',
+ function (head,tail)
+ return suppress_hyphenate_ja(head)
+ end,'ltj.hyphenate')
+--
+-- luatexja/rmlgbm.lua
+--
+luatexbase.provides_module({
+ name = 'luatexja.rmlgbm',
+ date = '2011/06/27',
+ version = '0.1',
+ description = 'Definitions of non-embedded Japanese fonts',
+})
+module('luatexja.rmlgbm', package.seeall)
+local err, warn, info, log = luatexbase.errwarinf(_NAME)
+
local rmlgbm_data = require('luatexja-rmlgbm-data')
local cache_chars = { [655360] = rmlgbm_data.characters }
--- /dev/null
+--
+-- luatexja/setwidth.lua
+--
+luatexbase.provides_module({
+ name = 'luatexja.setwidth',
+ date = '2011/06/28',
+ version = '0.1',
+ description = '',
+})
+module('luatexja.setwidth', package.seeall)
+local err, warn, info, log = luatexbase.errwarinf(_NAME)
+
+require('luatexja.base'); local ltjb = luatexja.base
+require('luatexja.jfont'); local ltjf = luatexja.jfont
+
+local node_type = node.type
+local node_new = node.new
+local node_tail = node.tail
+local node_next = node.next
+local has_attr = node.has_attribute
+local set_attr = node.set_attribute
+local node_insert_before = node.insert_before
+local node_insert_after = node.insert_after
+local round = tex.round
+
+local id_glyph = node.id('glyph')
+local id_kern = node.id('kern')
+local id_hlist = node.id('hlist')
+local id_vlist = node.id('vlist')
+local id_rule = node.id('rule')
+local id_math = node.id('math')
+
+local attr_jchar_class = luatexbase.attributes['ltj@charclass']
+local attr_curjfnt = luatexbase.attributes['ltj@curjfnt']
+local attr_yablshift = luatexbase.attributes['ltj@yablshift']
+local attr_icflag = luatexbase.attributes['ltj@icflag']
+
+local PACKED = 2
+
+local met_tb = {}
+local char_data = {}
+local head
+
+-- return true if and only if p is a Japanese character node
+local function is_japanese_glyph_node(p)
+ return p.font==has_attr(p, attr_curjfnt)
+end
+
+local function capsule_glyph(p, dir)
+ local h, box, q, fwidth, fheight, fdepth
+ p.xoffset= p.xoffset - round(met_tb.size*char_data.left)
+ if char_data.width ~= 'prop' then
+ fwidth = round(char_data.width*met_tb.size)
+ else fwidth = p.width end
+ fheight = round(met_tb.size*char_data.height)
+ fdepth = round(met_tb.size*char_data.depth)
+ if p.width ~= fwidth or p.height ~= fheight or p.depth ~= fdepth then
+ local y_shift = - p.yoffset + (has_attr(p,attr_yablshift) or 0)
+ p.yoffset = -round(met_tb.size*char_data.down)
+ head, q = node.remove(head, p)
+ local total = fwidth - p.width
+ if total == 0 then
+ h = p; p.next = nil
+ else
+ h = node_new(id_kern); h.subtype = 0
+ if char_data.align=='left' then
+ h.kern = total; p.next = h; h = p
+ elseif char_data.align=='right' then
+ h.kern = total; p.next = nil; h.next = p
+ elseif char_data.align=='middle' then
+ h.kern = round(total/2); p.next = h
+ h = node_new(id_kern); h.subtype = 0
+ h.kern = total - round(total/2); h.next = p
+ end
+ end
+ box = node_new(id_hlist);
+ box.width = fwidth; box.height = fheight; box.depth = fdepth
+ box.glue_set = 0; box.glue_order = 0; box.head = h
+ box.shift = y_shift; box.dir = dir or 'TLT'
+ set_attr(box, attr_icflag, PACKED)
+ if q then
+ head = node_insert_before(head, q, box)
+ else
+ head = node_insert_after(head, node_tail(head), box)
+ end
+ return q
+ else
+ p.yoffset = p.yoffset - (has_attr(p, attr_yablshift) or 0) - round(met_tb.size*char_data.down)
+ return node_next(p)
+ end
+end
+
+function set_ja_width(ahead, dir)
+ local p = ahead; head = ahead
+ local m = false -- is in math mode?
+ while p do
+ if p.id==id_glyph then
+ if is_japanese_glyph_node(p) then
+ met_tb = ltjf.font_metric_table[p.font]
+ char_data = ltjf.metrics[met_tb.jfm].char_type[has_attr(p, attr_jchar_class)]
+ p = capsule_glyph(p, dir)
+ else
+ p.yoffset = p.yoffset - (has_attr(p,attr_yablshift) or 0); p = node_next(p)
+ end
+ elseif p.id==id_math then
+ m = (p.subtype==0); p = node_next(p)
+ else
+ if m then
+ if p.id==id_hlist or p.id==id_vlist then
+ p.shift = p.shift + (has_attr(p,attr_yablshift) or 0)
+ elseif p.id==id_rule then
+ local v = has_attr(p,attr_yablshift) or 0
+ p.height = p.height - v; p.depth = p.depth + v
+ end
+ end
+ p = node_next(p)
+ end
+ end
+ -- adjust attr_icflag
+ tex.attribute[attr_icflag] = -(0x7FFFFFFF)
+ return head
+end
module('luatexja.stack', package.seeall)
local err, warn, info, log = luatexbase.errwarinf(_NAME)
-local ltjb = luatexja.base
+require('luatexja.base'); local ltjb = luatexja.base
local node_new = node.new
local id_whatsit = node.id('whatsit')
-ltj.define_jfm {
+luatexja.jfont.define_jfm {
dir = 'yoko2',
zw = 1.0, zh = 1.0,
-ltj.define_jfm {
+luatexja.jfont.define_jfm {
dir = 'yoko',
zw = 1.0, zh = 1.0,
-ltj.define_jfm {
+luatexja.jfont.define_jfm {
dir = 'yoko',
zw = 1.0, zh = 1.0,
kanjiskip = { 0.1, 0.04, 0.05 },
width = 1.0, height = 0.88, depth = 0.12, italic=0.0,
kern = { [8] = -1.41 , [2] = 2.0}
},
+ [51] = {
+ chars = { 'か' },
+ align = 'left', left = 0.0, down = 0.0,
+ width = 1.0, height = 0.88, depth = 0.12, italic=0.0,
+ kern = { [199] = 0.85 },
+ },
[2] = {
chars = { 'ア' },
},
[99] = {
chars = { 'jcharbdd' },
- align = 'left', left = 0.0, down = 0.0,
- width = 1.0, height = 0.88, depth = 0.12, italic=0.0,
glue = { [11] = { 1.41, 0, 0} },
kern = { [21] = 2.0, }
},
+ [199] = {
+ chars = { 'boxbdd' },
+ glue = { [51] = { 1.03, 0, 0} , [1] = { 0.94, 0.23, 0.45 }},
+ },
[8] = {
chars = { 'lineend' },
- align = 'left', left = 0.0, down = 0.0,
- width = 1.0, height = 0.88, depth = 0.12, italic=0.0,
}
}
\input luatexja-core.sty
\jfont\jisninety={file:ipaexm.ttf:script=latn;+jp90;jfm=ujis}
+\jfont\jisfour={file:ipaexm.ttf:script=latn;+jp04;jfm=ujis}
\jfont\jisexpt={file:ipaexm.ttf:script=latn;+expt;jfm=ujis}
\jfont\jishwid={file:ipaexm.ttf:script=latn;+hwid;jfm=ujis}
%\font\tmihwid={file:ipaexm.ttf:script=latn;+hwid}
{\tentt jp90} feature: 辻→{\jisninety 辻}
+{\tentt jp04} feature: 辻→{\jisfour 辻}
+
{\tentt hwid} feature: アイウエ→{\jishwid アイウエ}\hfil\break
↑文字クラスが変わらないので幅も変わらない.
%#! lualatex
\documentclass{article}
+\usepackage{luatexja}
+
+\makeatletter
+% from jsclasses
+\def\@setfontsize#1#2#3{%
+ \ifx\protect\@typeset@protect
+ \let\@currsize#1%
+ \fi
+ \fontsize{#2}{#3}\selectfont
+ \ifdim\parindent>\z@
+ \parindent=1\zw
+ \fi
+ \ltjsetparameter{kanjiskip={0\zw plus .1\zw minus .01\zw}}%
+ \@tempskipa=\ltjgetparameter{xkanjiskip}%
+ \ifdim\@tempskipa>\z@
+ \ltjsetparameter{xkanjiskip={0.25em plus 0.15em minus 0.06em}}%
+ \fi}
+
+\begin{document}
+\section{NFSS2}
+
+◆あいうえおabcかきく{\gt かきくa{\bf uyあ}いう}
+
+{\ltjsetparameter{xkanjiskip=0pt}イタリック補正\textit{f}◆\par}
+
+\DeclareFixedFont{\dr}{JY3}{gt}{m}{n}{12}
+あいうえおpqr{\dr かaiu}きく){\bf (漢字}
+
+\section{fontspec}
+
+かいてない
+\end{document}
+
+
+%%%%%%%%%%%%%%%%%%%%% OLD TEST
+\documentclass{article}
\usepackage{fontspec,pdftexcmds}
\input luatexja-core.sty
% \unkern がないとうなくいかない
\tracingonline=1\scrollmode\showboxdepth=10000\showboxbreadth=10000\showlists
-\end{document}
\ No newline at end of file
+\end{document}
\def\dumplist#1{\par\noindent\leavevmode
\hbox to 0.2\hsize{\copy#1\hss}%
\vbox{\hsize=0.6\hsize\sixtt\baselineskip=7.2pt\sixgt\let\\=\relax
-\directlua{ltj.ext_show_node_list(tex.getbox(#1).head, '\\par', tex.print)}\hrule}}
+\directlua{ltj.ext_show_node_list(tex.getbox(#1).head, '\\par ', tex.print)}\hrule}}
+
+%\tracingonline=1\tracingoutput=1\showboxdepth=3\showboxbreadth=100
\head{JA--JA (penなし)}
\setbox0=\hbox{\rmlh え\hbox{}}\dumplist0
+\setbox0=\hbox{\rmlh あ\hbox{ア}}\dumplist0
+
+\setbox0=\hbox{\rmlh あ\hbox{a}}\dumplist0
+
+\setbox0=\hbox{\rmlh い\hbox{a}}\dumplist0
+
\head{hbox--JA (penなし)}
\setbox0=\hbox{\rmlh \hbox{}あ}\dumplist0
\setbox0=\hbox{\rmlh \hbox{}う}\dumplist0
-\head{JA--penalty (penなし)} TODO: この場合の挙動はこれで良いか?
-
-\setbox0=\hbox{\rmlh あ\penalty567}\dumplist0
-
-\setbox0=\hbox{\rmlh い\penalty567}\dumplist0
-
-\setbox0=\hbox{\rmlh う\penalty567}\dumplist0
-
-\setbox0=\hbox{\rmlh え\penalty567}\dumplist0
-
-\head{penalty--JA (penなし)} TODO: この場合の挙動はこれで良いか?
-
-\setbox0=\hbox{\rmlh \penalty567あ}\dumplist0
-
-\setbox0=\hbox{\rmlh \penalty567い}\dumplist0
-
-\setbox0=\hbox{\rmlh \penalty567う}\dumplist0
-
{\vfill\eject%
\ltjsetparameter{prebreakpenalty={`(,123}}
\ltjsetparameter{postbreakpenalty={`あ,123}}
-\ltjsetparameter{postbreakpenalty={`い,123}}
+\ltjsetparameter{prebreakpenalty={`い,571}, postbreakpenalty={`い,123}}
\ltjsetparameter{postbreakpenalty={`う,123}}
\ltjsetparameter{postbreakpenalty={`え,123}}
\ltjsetparameter{postbreakpenalty={`お,123}}
\setbox0=\hbox{\rmlh aう}\dumplist0
+\head{JA--hbox (penあり)}
+
+\setbox0=\hbox{\rmlh あ\hbox{ア}}\dumplist0
+
+\setbox0=\hbox{\rmlh あ\hbox{a}}\dumplist0
+
+\setbox0=\hbox{\rmlh い\hbox{a}}\dumplist0
+
+\setbox0=\hbox{\rmlh \hbox{(}い\hbox{)}}\dumplist0
+
\head{italic correction}
\setbox0=\hbox{\it f\/(\/あ}\dumplist0
{\ltjsetparameter{alxspmode={`x,postonly}}
\setbox0=\hbox{\rmlh まx}\dumplist0}
-\head{kanjiskip from JFM/autoxspacing (EN--JA)}
+\head{xkanjiskip from JFM/autoxspacing (EN--JA)}
\setbox0=\hbox{\rmlh xま}\dumplist0
\setbox0=\hbox{\rmlh x\naxspc ま}\dumplist0
\setbox0=\hbox{\rmlh あ\penalty1701\penalty1701\penalty1701お}
\dumplist0
-\setbox0=\hbox{\tenrm あ\/\v{A}あ}
+\head{その他: italic correction and accents}
+
+\setbox0=\hbox{\tenrm あ\/j}
+\dumplist0
+\setbox0=\hbox{\tenrm\rmlh れ\v{A})}
+\dumplist0
+
+\head{その他: box boundary}
+
+\setbox0=\hbox{\rmlh かあか}
+\dumplist0
+\setbox0=\hbox{a\setbox3=\hbox{\rmlh かあか}\unhbox3a}
+\dumplist0
+\setbox0=\hbox{a\setbox3=\hbox{\rmlh か}\box3a}
\dumplist0
+\setbox0=\hbox{\rmlh き\hbox{か}き\hbox{き}き}
+\dumplist0
+
+{\ltjsetparameter{postbreakpenalty={`あ,1000},prebreakpenalty={`あ,1000}}
+\setbox0=\hbox{あ\hbox{(}あ\setbox3=\hbox{(}\unhbox3あ}
+\dumplist0}
+
\end
-%#! time luatex test05-speed.tex
+%#! time luatex "\count300=40\input test05-speed.tex"
\input luatexja-core.sty
\newcount\cnt\newcount\cnta
-\cnt=0
+\cnt=0\output={\deadcycles=0\setbox2000=\box255}
\long\def\loop#1\repeat{\def\body{#1}\iterate}
-\loop\ifnum\cnt<10 % <= this value
+\loop\ifnum\cnt<\count300 % <= this value
\cnta=0 \message{\the\cnt:}\par
{\loop\ifnum\cnta<500 あ.「い,うえお・か(き)く)(けこ\advance\cnta1\repeat}
\advance\cnt1
\end
% real time:
-% 20: 9.950s
-% 10: 5.209s
+% 40: 17.453
+% 30: 13.254
+% 20: 8.771
+% 10: 4.927
% env: C2D E7300, Mem 4GB, LuaTeX 0.71.0pre, Gentoo amd64 unstable
\ No newline at end of file
--- /dev/null
+%#!luatex
+\input luatexja.sty
+
+\def\gbox#1{\noindent\setbox0=\hbox{\d#1}
+ \vrule height 0.2pt depth 0.2pt width \dimexpr \wd0+10pt\relax
+ \kern\dimexpr -\wd0-5pt\relax\vrule height\ht0 depth \dp0\hbox{\copy0}%
+ \vrule height\ht0 depth \dp0\relax}
+\font\d=cmr17 at 20pt
+\baselineskip=40pt
+
+\jfont\sixgt={psft:GothicBBB-Medium:jfm=ujis} at 6pt
+\font\sixtt=cmtt10 at 6pt
+\def\dumplist#1{\par\noindent\leavevmode
+\hbox to 0.2\hsize{\copy#1\hss}%
+\vbox{\hsize=0.6\hsize\sixtt\baselineskip=7.2pt\sixgt\let\\=\relax
+\directlua{ltj.ext_show_node_list(tex.getbox(#1).head, '\\par ', tex.print)}\hrule}}
+
+\ltjsetparameter{yalbaselineshift=0pt,yjabaselineshift=0pt}
+\setbox0=\hbox{\d Hy}\dumplist0
+
+\ltjsetparameter{yalbaselineshift=-10pt}\gbox{Hy}
+\ltjsetparameter{yalbaselineshift=-0pt}\gbox{Hy}
+\ltjsetparameter{yalbaselineshift=10pt}\gbox{Hy}
+\ltjsetparameter{yalbaselineshift=20pt}\gbox{Hy}
+
+\jfont\f=psft:Ryumin-Light:jfm=ujis at 20pt\f
+\ltjsetparameter{yalbaselineshift=0pt,yjabaselineshift=0pt}
+\setbox0=\hbox{\f あ}\dumplist0
+
+\ltjsetparameter{yjabaselineshift=-10pt}\gbox{あ}
+\ltjsetparameter{yjabaselineshift=0pt}\gbox{あ}
+\ltjsetparameter{yjabaselineshift=10pt}\gbox{あ}
+\ltjsetparameter{yjabaselineshift=20pt}\gbox{あ}
+
+\jfont\f=name:IPAMincho:jfm=ujis at 20pt\f
+\ltjsetparameter{yalbaselineshift=0pt,yjabaselineshift=0pt}
+\setbox0=\hbox{\f あ}\dumplist0
+
+\ltjsetparameter{yjabaselineshift=-10pt}\gbox{あ}
+\ltjsetparameter{yjabaselineshift=0pt}\gbox{あ}
+\ltjsetparameter{yjabaselineshift=10pt}\gbox{あ}
+\ltjsetparameter{yjabaselineshift=20pt}\gbox{あ}
+
+\end