実際には$\emptyset$を返す.
\enditem
-\beginsection main loop その1: $\mibox{head}(\mibox{Np})$が和文文字の場合
+\vfill\eject
+\beginsection main loop
-これは,次の3つの場合でおこる:
-\item \IT{Np.id}が\IT{id\_jglyph}の場合(本当に和文文字)
-\item \IT{Np.id}が\IT{id\_pbox}で,$\mibox{head}(\mibox{Np})$が和文文字の場合
-\item \IT{Np.id}が\IT{id\_hlist}で,$\mibox{head}(\mibox{Np})$が和文文字の場合
-\enditem
-前2つの場合は,$\mibox{head}(\mibox{Np})$は処理対象のリスト中に現れる本当の\IT{glyph\_node}である.
-一方,最後の場合では,$\mibox{head}(\mibox{Np})$はリスト中にあるhboxの中身(の最初)に出現する\IT{glyph\_node}である.
+\beginparagraph 一覧表
-そのため,挿入される和文処理グルーの種類については,前2つと最後の場合とで扱いを異なったものとしている:
-$$
-\vbox{\hsize=0.85\hsize\bf
-hboxの外側の文字と内側の文字の間の空白では,|\kanjiskip|, |\xkanjiskip|の量の計算では両方の文字の情報を使うが,
-JFM由来のグルーでは内側の文字の情報は使われない.}
+\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
\beginparagraph 挿入されるglue/kernの種類
-\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{Nq}→&id\_jglyph&&&id\_hlist 非文字\cr
-\IT{Np}↓&id\_pbox 和&id\_hlist 和&$\mibox{head}(\mibox{Nq})$\rm: 欧文&id\_box\_like&id\_glue&id\_kern\cr
-\noalign{\vskip.25em\hrule\vskip.25em}
-id\_jglyph&\rm E${}+{}$(M→K)&{\rm $\rm O_A$→$\rm K$}&{\rm $\rm O_A$→X}&$\rm O_A^*$&$\rm O_A$&$\rm O_A^+$\cr
-id\_pbox 和&\rm E${}+{}$(M→K)&{\rm $\rm O_A$→$\rm K$}&{\rm $\rm O_A$→X}&$\rm O_A^*$&$\rm O_A$&$\rm O_A^+$\cr
-id\_hlist 和&\rm E${}+{}$($\rm O_B$→$\rm K$)&{\rm K}${}^+$&{\rm X}${}^+$&---&---&---\cr
-}}$$
-挿入されるglue/kernの種別を表にすると上のようになる.最後の1つ以外は,挿入される位置は\IT{Np.first}の直前であり,
-以降「右側の空白」と呼ぶ.
+前節の表にある空白の種類についての解説を行う.
+
+\item E: \IT{Nq}が行末にきたとき,
+\IT{Nq}と行末の間に入る空白 (kern).挿入位置は\IT{Nq.last}の直後.
+\itemitem JFMでは「文字コード|'lineend'|の文字」との間に入るkern量として設定できる.
+\itemitem 右空白がkernであるときは挿入されない.
+\itemitem この種類のkernが挿入される時,右空白は自然長がEの分だけ引かれる.
+
+
\item M: \IT{Nq}と\IT{Np}の間に入るJFM由来のglue/kern.
-\IT{Nq}, \IT{Np}の間で|\inhibitglue|を発行した場合は抑止される.
-\itemitem 両方の塊で使われているJFMが(サイズもこめて)等しかったら量の決定は容易い.
+\itemitem \IT{Nq}, \IT{Np}の間で|\inhibitglue|を発行した場合,挿入は抑止される.
+\itemitem 両方の塊で使われているJFMが(サイズもこめて)等しい場合は,両者で使われている
+JFMの情報をそのまま利用できるので,量の決定は容易い.
\itemitem そうでなければ,まず
$$
\vcenter{\halign{\hfil$#:={}$&(\inhibitglue#\inhibitglue)\cr
-gb&\IT{Nq}と「文字コードが|'diffmet'|の文字」との間に入るglue/kern.\cr
-ga&「文字コードが|'diffmet'|の文字」と\IT{Np}との間に入るglue/kern.\cr
+gb&\IT{Nq}と「文字コードが|'diffmet'|の文字」との間に入るglue/kern\cr
+ga&「文字コードが|'diffmet'|の文字」と\IT{Np}との間に入るglue/kern\cr
}}
$$
-として2つの量を計算.少なくとも片方が$\emptyset$の場合は,もう片方の値を用いる.
+として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}$であれば,
+\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|の自動挿入が無効」
- ($\mibox{Nq.auto\_xspc}\vee \mibox{Np.auto\_xspc}=\bot$) ならば,長さ0のglueを挿入する.
-\itemitem \mibox{Nq}内の文字が「直後への|\xkanjiskip|挿入が無効」という指定
-($\hbox{\sf alxspmode}\ge 2$)であるか,
-\mibox{Np}内の文字が「直前への|\xkanjiskip|挿入が無効」という指定
-($\hbox{\sf jaxspmode}\ge 2$)であるならば,長さ0のglueを挿入する.
+\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|であれば,
-JFMに指定されている|\xkanjiskip|の量を用いる.
+$\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|の指定で抑止される.
-\item E: \IT{Nq}が行末にきたとき,\IT{Nq}と行末の間に入る空白 (kern).挿入位置は\IT{Nq.last}の直後.
-\itemitem JFMでは「文字コード|'lineend'|の文字」との間に入るkern量として設定できる.
-\itemitem 右側の空白がkernであるときは挿入されない.
-\itemitem この種のkernが挿入される時,右側の空白は自然長がEの分だけ引かれる.
\enditem
-あと,注として,
-
-\item 「→」は,左側の種類(例えばM)のglue/kernは$\emptyset$であった場合,右側の種類(例えばK)のglueを挿入することを示す.
-\item ${}^*$, ${}^+$は,penalty処理時のバリエーションを表す.次の節では,上添字なしの場合のpenaltyの処理について述べる.
-\enditem
\beginparagraph penaltyまわりの処理
\Bigl[\node{\hbox{M, K, X他}}_{3,\,5,\,6}\Bigr]
\node{\mibox{Np}}
$$
-このような状況下で,禁則処理に関係するpenaltyの挿入処理は,原則として(上ほど優先度高):
-\item $\#\mibox{Bp}\ge 1$の場合,{\bf 全ての}\IT{Bp}の元$p$~(penalty)に対して,
-$$p.\mibox{penalty}\mathrel{+}=\mibox{Nq.post}+\mibox{Np.pre}.$$
-\itemitem
-全ての\IT{Bp}の元に対して行うのは,実際にはどのpenaltyの位置で行分割が行われるかわからないからである.
-\itemitem $\mibox{Nq.id}=\mibox{id\_hlist}$の場合には,\IT{Nq.post}は0と扱われる.
-$\mibox{Np.id}=\mibox{id\_hlist}$の場合も同様.
-
-\item $\#\mibox{Bp}=0$かつ$\mibox{Nq.post}+\mibox{Np.pre}=:a\neq 0$,
-さらに「右側の空白がkernでない」場合:
-$p.\mibox{penalty}=a$であるpenalty~$p$を作成し,
-それを(M, K他のglue挿入前に)\IT{Np.first}の直前に挿入する.
-つまり,この場合,
-$$
-\longrightarrow\cdots\longrightarrow\node{\np a}
-\Bigl[\node{\hbox{M, K, X他}}_{3,\,5,\,6}\Bigr]
-\node{\mibox{Np}}
-$$
-となる.
-\item $\#\mibox{Bp}=0$かつ${\rm E}\neq 0$(かつ右側の空白がglue)の場合:同様に新たなpenaltyを作る.\hfil\break
-(Eの位置で改行可能にしたいので)
-\item つまり,$\#\mibox{Bp}=0$であったとき,新たなpenaltyを作らないのは,
-${\rm E}=0$かつ$a=0$の場合に限る.
+禁則処理に関係するpenaltyの挿入処理は,以下に述べるところ部分は共通の動作である.
+
+\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
-なお,penalty値の計算では,$+10000$は正の無限大,$-10000$は負の無限大として扱っている.
-そのため,通常の加減算で絶対値が10000を越えたら,その分はカットしている.
-あと,$(10000)+(-10000)=0$としている.また,\IT{Nq.post}, \IT{Np.pre}が$\emptyset$の場合は,
-それぞれ0として扱う.
+$\#\mibox{Bp}=0$の場合が,penalty挿入の3種類の方法「normal」「always」「suppress」で
+異なる部分である:
-\medskip\noindent{\bf バリエーションについて}\quad
-前節の表に出てきた${}^*$, ${}^+$では,上の原則から以下の点が変更されている.
-変更点は,いずれも$\#\mibox{Bp}=0$の場合に関するところのみである:
-
-\item ${}^*$: \IT{Nq}と\IT{Np}の間での行分割を常に可能とするため,
-右側の空白($\rm O_A$)が$\emptyset$の場合であっても新たなpenaltyを作る.
+\item {\bf「normal」の場合:}
+次の場合に,$p.\mibox{penalty}=a$であるpenalty~$p$を作成し,
+それを(M, K他のglue挿入前に)\IT{Np.first}の直前に挿入する:
+$$
+\hbox{左空白(E)が存在しているか,$a\neq 0$かつ右空白がkernである.}
+$$
+\item {\bf「always」の場合:}
+この場合は,\IT{Nq}, \IT{Np}の間で常に行分割可能にしたいので,挿入する条件は以下のようになる:
+$$
+\hbox{左空白(E)が存在しているか,右空白がglueでない(つまり,kernか未定義のとき).}
+$$
-\item ${}^+$: このとき,\IT{Nq}と\IT{Np}の間での行分割は元々不可能である.
-Lua\TeX-ja では,そのような場合を「わざわざ行分割可能に」することはしない.そのため,
-\itemitem 右側の空白がglueの場合は,値が10000のpenaltyを作成する.
-\itemitem 右側の空白が$\emptyset$かkernの場合は,新たにpenaltyを作ることはしない.
+\item {\bf「suppress」の場合:}このとき,\IT{Nq}と\IT{Np}の間での行分割は元々不可能である.
+Lua\TeX-ja では,そのような場合を「わざわざ行分割可能に」することはしない.
+つまり,右空白がglueであるとき,その直前に|\penalty 10000|を挿入する.
\enditem
\beginparagraph いくつかの例:未完
\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
見本として,|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'|)のみの対応.
\item {\bf 和文処理グルーの挿入: |pre_linebreak_filter|, |hpack_filter| callbacks}
-動作については,{\tt jfmglue.pdf}(未完)を参照.
+å\8b\95ä½\9cã\81®è©³ç´°ã\81«ã\81¤ã\81\84ã\81¦ã\81¯ï¼\8c{\tt jfmglue.pdf}ï¼\88æ\9cªå®\8cï¼\89ã\82\92å\8f\82ç\85§ï¼\8e
\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,
local ltjc = luatexja.charrange
local ltjs = luatexja.stack
local ltjj = luatexja.jfmglue
+local ltjf = luatexja.jfont
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 PACKED = 2
local KINSOKU = 3
local KANJI_SKIP = 6
local XKANJI_SKIP = 7
local PROCESSED = 8
+local IC_PROCESSED = 9
local BOXBDD = 15
------------------------------------------------------------------------
------------------------------------------------------------------------
--- 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
- 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)
------------------------------------------------------------------------
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]
+ met_tb = ltjf.font_metric_table[p.font]
+ t = ltjf.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'
s = base .. ' ' .. print_scaled(p.kern) .. 'pt'
if p.subtype==2 then
s = s .. ' (for accent)'
- elseif has_attr(p, attr_icflag)==ITALIC then
+ elseif has_attr(p, attr_icflag)==IC_PROCESSED then
s = s .. ' (italic correction)'
+ -- 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
-- callbacks
+
luatexbase.add_to_callback('pre_linebreak_filter',
function (head,groupcode)
return main_process(head, true, tex.textdir)
- end,'ltj.pre_linebreak_filter',2)
+ 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, dir)
return main_process(head, false, dir)
- end,'ltj.hpack_filter',2)
+ end,'ltj.hpack_filter',
+ luatexbase.priority_in_callback('hpack_filter',
+ 'luaotfload.hpack_filter') + 1)
dofile(path)
end
require('lualibs')
- ltj.loadlua('luatexja-rmlgbm.lua')
- % For Ryumin-Light and GothicBBB-Medium.
+
+
}
+\RequireLuaModule{luatexja.rmlgbm} % For Ryumin-Light and GothicBBB-Medium.
\RequireLuaModule{luatexja.charrange}
-\directlua{
- ltj.loadlua('luatexja-jfont.lua')}
+\RequireLuaModule{luatexja.jfont}
\RequireLuaModule{luatexja.stack}
+\RequireLuaModule{luatexja.pretreat}
\RequireLuaModule{luatexja.inputbuf}
\RequireLuaModule{luatexja.jfmglue}
\directlua{
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{luatexja.jfmglue.create_inhibitglue_node()}}
+++ /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
-
+++ /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')
--
luatexbase.provides_module({
name = 'luatexja.jfmglue',
- date = '2011/06/09',
- version = '0.1',
+ 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)
-local ltjb = luatexja.base
-local ltjs = luatexja.stack
+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 KANJI_SKIP = 6
local XKANJI_SKIP = 7
local PROCESSED = 8
+local IC_PROCESSED = 9
local BOXBDD = 15
local kanji_skip
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)
+ 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
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)==ITALIC then
+ elseif has_attr(p, attr_icflag)==IC_PROCESSED then
p = node_next(p); pid = p.id
end
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
- Np.last = lp; lp = node_next(lp)
+ 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>=KINSOKU and lpa~=BOXBDD do
+ 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()
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 -- elseif lpa>=KINSOKU then
+ 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
- lp = node_next(lp)
+ set_attr_icflag_processed(lp); lp = node_next(lp)
elseif lpi == id_penalty then
- table.insert(Bp, lp); Bp[0] = Bp[0] + 1; lp = node_next(lp)
+ 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
- lp = node_next(lp)
+ 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; lp = node_next(lp); check_next_ickern(); return
+ 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
- --if lpa == PACKED then
- -- Np.id = id_jglyph
- -- for q in node.traverse_id(id_glyph, lp.head) do
- -- Np.nuc = q; break
- -- end
+ 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; lp = node_next(lp)
- while lp.id~=id_math do lp = node_next(lp) end; break
+ 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
- lp = node_next(node_next(node_next(lp))); Np.nuc = lp
+ 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
end
end
end
- Np.last = lp; Np.id = lpi; lp = node_next(lp)
+ set_attr_icflag_processed(lp); Np.last = lp; Np.id = lpi; lp = node_next(lp)
end
-- extract informations from Np
local function set_np_xspc_jachar(c,x)
Np.class = has_attr(x, attr_jchar_class)
Np.char = c
- local z = ltj.font_metric_table[x.font]
+ local z = ltjf.font_metric_table[x.font]
Np.size= z.size
- Np.met = ltj.metrics[z.jfm]
+ Np.met = ltjf.metrics[z.jfm]
Np.var = z.var
- Np.pre = ltjs.get_penalty_table('pre', c, 0, ltj.box_stack_level)
- Np.post = ltjs.get_penalty_table('post', c, 0, ltj.box_stack_level)
+ 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
else
Np.lend = 0
end
- y = ltjs.get_penalty_table('xsp', c, 3, ltj.box_stack_level)
+ 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)
x = node_tail(x.components); c = x.char
end
end
- Np.pre = ltjs.get_penalty_table('pre', c, 0, ltj.box_stack_level)
- Np.post = ltjs.get_penalty_table('post', c, 0, ltj.box_stack_level)
+ 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, ltj.box_stack_level)
+ 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)
real_insert(0, g)
end
-- \jcharwidowpenalty 挿入予定箇所更新
- if ltjs.get_penalty_table('kcat', Np.char, 0, ltj.box_stack_level)%2~=1 then
+ if ltjs.get_penalty_table('kcat', Np.char, 0, ltjp.box_stack_level)%2~=1 then
widow_Np = Np; widow_Bp = Bp
end
end
Bp = widow_Bp; Np = widow_Np
if Np then
handle_penalty_normal(0,
- ltjs.get_penalty_table('jwp', 0, 0, ltj.box_stack_level))
+ ltjs.get_penalty_table('jwp', 0, 0, ltjp.box_stack_level))
end
else
-- the current list is the contents of a hbox
end
handle_list_tail()
-- adjust attr_icflag
- for p in node.traverse(head) do
- local a = has_attr(p, attr_icflag) or 0
- if a==0 then set_attr(p, attr_icflag, PROCESSED) end
- end
tex.attribute[attr_icflag] = -(0x7FFFFFFF)
return head
end
-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
.. 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
+ 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 }
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 },
\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
↑文字クラスが変わらないので幅も変わらない.
\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
\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
-%#! 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<20 % <= 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.584
-% 10: 5.209s 5.523
+% 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