Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[upTeX] JIS-encoded TFM #149

Closed
aminophen opened this issue Oct 15, 2022 · 22 comments
Closed

[upTeX] JIS-encoded TFM #149

aminophen opened this issue Oct 15, 2022 · 22 comments

Comments

@aminophen
Copy link
Member

aminophen commented Oct 15, 2022

upTeX で内部コードに依らず min10 や jis のような「文字コード JIS なレガシーな TFM」を使える状態にしておくと,pTeX から upTeX への乗り換えを進める上で良いのではないかと思ったのでメモしておきます。

  • [1] 内部コードは uptex 固定にしてしまいたいけど,min10 のような JIS-encoded な TFM/VF を使いたい人のために「DVI 文字コードを JIS にする/Unicode にする」を選ぶプリミティブを新設する
  • [2] 組版時に使う TFM も JIS-encoded か Unicode かを(完璧ではないにせよ)文字コード範囲から自動判定して内部で \toucs する(判定失敗対策で \jfont/\tfont プリミティブでの読込時にエンコード矯正できる機能も追加)

単純に [1] だけを実装しても [2] で DVI に書き込むコードと実在の TFM の文字コードが不一致だと破綻するので,順番としては以下の方が良いのかもしれません。

  • [A1] 組版時に \jfont/\tfont で読み込む段階でエンコード矯正するための \font [in <encoding>] <control sequence><equals><file name><at clause> という書式を導入する。
    • この書式が使われた場合は,メトリック情報を記憶する段階で内部コードに合うように toUCS(fromJIS()) あるいは toJIS(fromUCS()) し,変換できない文字は無視する。
    • 新書式を使わない場合に TFM の文字コード範囲から JIS-encoded か Unicode かを(完璧ではないにせよ)自動判定しても良いかもしれない。
  • [A2] DVI 出力時には,エンコード矯正が行われた TFM については set2set3 での出力時に元のエンコードに戻して書き込む。
    • 変換できない文字は無視する。

実装案は作れそうなので,やってみます。


なお,これを実現すれば upLaTeX に JY1 / JT1 をエミュレートする機能を乗せることもできるかもしれません。これは upTeX 本体実装を作った後に考えます。

@t-tk
Copy link
Collaborator

t-tk commented Oct 15, 2022

うーーん
ざっと読んだ限りの印象では、あまりに複雑すぎて私は乗り気にならない感じです。

現状、upTeXの実装では、内部コードが upTeX のとき、
upTeXの内部バッファは kcatcode(5bit) + UTF32もどき(24bit) になっていて
内部バッファから dvi に書き込む際に toDVI() でUTF32もどき(24bit) (最大 0xFFFFFF, 本来のUTF32は32bitで最大 0x001FFFFF) にしています。
で、この関数は文字コード 0x1FFFFF以下の場合は素通ししているだけなので、
pTeXの内部バッファの和文文字コードの範囲 0x2020..0x7F7F もtoDVI()はそのまま使えます。
またupTeXエンジンから出力後、DVI以降(dviware)は、フォント名と文字コードは常にセットで管理されているのでupTeXの文字コード(UTF32もどき)とpTeXの文字コード(JIS)が同じdviファイルに混在していても安全に処理できます。
それに加え、TeXエンジン内部のもともとの考え方として、フォント名と文字コードのセットがきちんと管理できていれば文字コードの混在は厭わないという思想に思えます。
なのであまり複雑にせずとも対応できそうな気がします。入力側の手当てをどうするのかが課題になりそうですが。

ただ、kcatcodeとかglueとかの文字コードの対応関係は内部UCS(UTF32もどき)と内部JISでは別物なのは確かです。
今回のご提案はそこをprimitiveで切り替えたいということでしょうか?

@aminophen
Copy link
Member Author

今回のご提案はそこをprimitiveで切り替えたいということでしょうか?

はい,例えば

% 内部コード uptex で処理
\ifnum\jis"2121="3000 \else \expandafter\end \fi
\font\x=jis      \x あい)\inhibitglue\font\y=upjisr-h \y あい)\inhibitglue\end

のようなものが jis.tfm は JIS で,upjisr-h は Unicode であるという混在に対応できるようにということです。

背景としては,いずれ「内部コード EUC/SJIS な (u)pTeX」は LaTeX3 の激しい変更に耐えきれなくなり,内部 Unicode 一択になることが近い将来起こりうることを懸念しています。万が一そのようなことが起こっても,従来の pTeX 用の TFM を使い回すことができるようにという保険を作っておくのはどうか,と思い立ったので issue を立てました。

関連: texjporg/platex#98 (l3str-convert), #147 (l3regex), https://github.com/h20y6m/plexpl3/issues など。

@t-tk
Copy link
Collaborator

t-tk commented Oct 15, 2022

なるほど。LaTeX3が内部Unicode一択になった場合にも pTeX の TFM が動くエミュレーションという点が狙いということですね。

今のpTeXや「upTeXの内部EUC動作」の実装では、
[α] 入力がUTF-8だとしてもptexencが SJIS/EUC (8bit可変長)に変換後、入力バッファに突っ込み、
[β] さらに(u)pTeXエンジンの入り口で16bit JIS の内部コード(0x2020..0x7F7F) に変換
[γ] (u)pTeXエンジンは 16bit JISを前提にglueなどの処理
となっています。

私の理解では、
[α]のEUC/SJISをやめたい、
LaTeX3が内部Unicode化が進展した場合、[β]あたりまでUnicodeのままでいてくれた方がpLaTeXが追従しやすい、
[γ]のtfmの情報へのアクセスの時点でJISに変換できれば(u)pTeXの内部バッファがUnicodeでも大丈夫

ということでしょうか。

@aminophen
Copy link
Member Author

TeX users slack (texuser.slack.com) で今日から話をしているだけなので私もまだ考えがまとまっていませんが,概ねそのように考えています。以下のような「非互換な仕様変更」も想定しつつ,まずは「非互換な仕様変更には該当しない改良」に手をつけようというのが本件「pTeX の JIS-encoded TFM が動くエミュレーション」です。


〜 Slack を読んでいない方へ & アーカイブが 90 日で消えるので補足 〜

現状の LaTeX3 では regression test(大量に用意されたテストファイル入力 .lvt に対するログ .tlg を比較)の仕組みが (u)pTeX に対しては機能していません。

  • pTeX では高位ビットが現れるテストファイルの入力中断処理が仕込まれている
  • upTeX では regression-test.cfg で最初から \disablecjktoken している

その理由は恐らく

  • (u)pTeX が「和文(CJK)文字トークン」という独特の物が存在し,また文字コードが中途半端に 0--255 ではないこと(e.g.「`あ」できるのに「\catcode`あ」できない)

が理解されないためだと思われます。和文(CJK)文字トークンの catcode が 16〜18(19) であることも考慮されておらず「カテゴリーコードは 16 進 1 桁」を前提にしたインタフェースが構築されています(参考)。

このような状況から (u)pTeX の後方互換性を放棄してでも 和文文字トークンの扱いならびに ptexenc の仕様 (#147) などを見直していく必要があるのではないか,ということを考えています。この大規模な話については別の場としましょう。

@aminophen
Copy link
Member Author

aminophen commented Oct 15, 2022

[A1] 組版時に \jfont/\tfont で読み込む段階でエンコード矯正するための \font [in <encoding>] <control sequence><equals><file name><at clause> という書式を導入する。
この書式が使われた場合は,メトリック情報を記憶する段階で内部コードに合うように toUCS(fromJIS()) あるいは toJIS(fromUCS()) し

ここまでは 'emulate_jfm' ブランチで出来た気がします。

変換できない文字は無視する
新書式を使わない場合に TFM の文字コード範囲から JIS-encoded か Unicode かを(完璧ではないにせよ)自動判定しても良いかもしれない

これについてはまだです。

次は

[A2] DVI 出力時には,エンコード矯正が行われた TFM については set2 や set3 での出力時に元のエンコードに戻して書き込む。変換できない文字は無視する。

に取り組みます。(まだ考えられていませんが,文字ノードを作る時に文字コード変換するので,恐らく「禁則ペナルティがどうなるか」「\jcharwidowpenalty」「\lastnodechar」についてはきちんとテストする必要があると思います)

@t-tk
Copy link
Collaborator

t-tk commented Oct 15, 2022

このissueの冒頭のご提案もかなり大規模な話と感じます。
どこかで区切ってupTeXに入れるにしても中途半端では禍根を残しそうで不安です。
もう少しここで議論を続けてみます。

上記[γ]で文字コードはUnicodeだがアクセス先のTFMはJISで見る、ということは仕様として可能とは思いますがかなり直感に反します。

\char"A7B5

は、
現在のpTeX(内部EUC)では、「0xA7B5 (U+0423) У Cyrillic Capital Letter U」
現在のupTeX(内部UCS)では、「U+A7B5 ꞵ Latin Small Letter Beta」
が出ます。新しいエミュレート版ではどちらが適切?

その理由は恐らく

  • (u)pTeX が「和文(CJK)文字トークン」という独特の物が存在し,また文字コードが中途半端に 0--255 ではないこと(e.g.「`あ」できるのに「\catcode`あ」できない)

が理解されない

思いつきですが、その対策として例えばupTeXの仕様の追加で
「catcodeが11で文字コードがある値(例えば0x2E00以上)より大きい場合は漢字トークンとみなす」
「catcodeが12で文字コードがある値より大きい場合はCJK記号トークンとみなす」
のようなものを用意し、それらに対しては
「`あ」できて「\catcode`あ」できてしかもCJKトークンである
という風にするのはいかがでしょうか?

@aminophen
Copy link
Member Author

文字コードはUnicodeだがアクセス先のTFMはJISで見る

現に pTeX は「エンジンの内部コード EUC/SJIS だけど TFM 読取や DVI 書出の文字コードは JIS」な訳ですから,ここでコード変換が起こるのは直感的であると思います。また,トークンの話についてはこれとは無関係なので issue を分けるつもりです。

ご提示の \char"A7B5 の例も,私の [A1] [A2] を行っても出力は何も変わりません。

  • pTeX(内部EUC) →「0xA7B5 (U+0423) У Cyrillic Capital Letter U」
  • upTeX(内部UCS) →「U+A7B5 ꞵ Latin Small Letter Beta」

のままです。もう少しわかりやすく [A1][A2] を例示すると,例えば \font in jis \X=min10 としたときに,普通に min10.tfm を読むのではなく,あたかも

手動で「現min10.tfm(JIS) →(ptftopl)→ 仮temp.pl →(uppltotf)→ 新min10.tfm(Unicode)」として得られる「新 min10.tfm」を読んだような状態

を作りたいということです。

@aminophen
Copy link
Member Author

[A2] DVI 出力時には,エンコード矯正が行われた TFM については set2 や set3 での出力時に元のエンコードに戻して書き込む。

これも 4baff60 にて完了。ということで次は

変換できない文字は無視

に取り組みます。

  • 内部 JIS で TFM 読取時の Unicode→JIS 変換:TFM に現れる変換不能な Unicode 文字は JIS 変換時に「文字コード 0 がタイプ T > 0」と解釈されるはず。しかし,内部 JIS のときに「文字コード 0 の和文文字」がアクセスされることはないので,余分なデータがあるというだけで実害はないかもしれない。念のため要確認。
  • 内部 Unicode で TFM 読取時の JIS→Unicode 変換:実用レベルで変換できない文字はないと思う。念のため ppltotf が扱える文字コード範囲が Unicode から溢れていないか要確認。

新書式を使わない場合に TFM の文字コード範囲から JIS-encoded か Unicode かを(完璧ではないにせよ)自動判定しても良いかもしれない
文字ノードを作る時に文字コード変換するので,恐らく「禁則ペナルティがどうなるか」「\jcharwidowpenalty」「\lastnodechar」についてはきちんとテストする必要がある

これらは時間かかりそうです。

@aminophen
Copy link
Member Author

禁則ペナルティがどうなるか
\lastnodechar

こちらは影響を受けないようです(ノードリストを作るタイミングでは未変換・それよりはるか後のDVI に書き出すタイミングで変換しているため)。


「catcodeが11で文字コードがある値(例えば0x2E00以上)より大きい場合は漢字トークンとみなす」
「catcodeが12で文字コードがある値より大きい場合はCJK記号トークンとみなす」

この特定の値については #135 からだと思いますが,あちらは「OFM に定義された最大の文字コード」だから良かったものの,今回のようなものには使えないように思います。(例えば 0xB7 (U+00B7) は uptex-fonts でも和文扱いを想定した中黒です)

@h-kitagawa
Copy link
Member

変換できない文字は無視する

017aeab で試してみました.例えば

\kcatcode"D8=16\relax
\font in jis\x=jis \x ó

のように文字コード JIS の TFM 下で JIS 範囲外の文字を使うと DVI には set2 0 が書かれますが,これで良いのかは検討の余地ありです.

@aminophen
Copy link
Member Author

文字コード JIS の TFM 下で JIS 範囲外の文字を使うと DVI には set2 0 が書かれます

確かにそのとおりで,これは

手動で「現jis.tfm(JIS) →(ptftopl)→ 仮jis.pl →(uppltotf)→ 新jis.tfm(Unicode)」として得られる「新 jis.tfm」を読んだような状態

とは違いますが,むしろ「範囲外の文字は出力できない」で良いと思っています。出力できないときにどうするのが良いかですが,思いつくのは以下でしょうか。

  • DVI に set2 0 を書く(現在 017aeab の挙動)
  • Missing character: There is no ^^a1 in font cmr10! を真似て破棄する

従来は JFM では「存在しない文字はない (\nullfont できない)」という仕様でしたので,前者のまま(豆腐を出力する)方が無難?

@t-tk
Copy link
Collaborator

t-tk commented Oct 16, 2022

catcode の話は、こちらの主題の JIS-encoded TFMのエミュレートの話とは別にissue を立てました。
[upTeX] catcodeが15以下のCJKトークン #150

@t-tk
Copy link
Collaborator

t-tk commented Oct 16, 2022

  • DVI に set2 0 を書く(現在 017aeab の挙動)
  • Missing character: There is no ^^a1 in font cmr10! を真似て破棄する

どちらでも適切といえると思いますが、私の好みでは後者です。(実装の手間は考えずに言っています)
今回のケースでは文字コード変換前は Unicode の範囲で正規の文字にもかかわらず変換漏れで出なくなった感じがして、事情はあるにせよ変換できないまま黙って豆腐を出力するのはよろしくないように思えます。
ただ、実装の手間が大変という理由から見送りでもいいようにも思います。

@h-kitagawa
Copy link
Member

  • DVI に set2 0 を書く(現在 017aeab の挙動)
  • Missing character: There is no ^^a1 in font cmr10! を真似て破棄する

DVI→PDF の過程で「実フォントに該当グリフはなかった」ではなく,TeX→DVI という実フォントに依存しない状況での変換漏れなので,「黙って豆腐」には違和感を覚えます.

U+XXXX は pTeX 用 JFM hogem では出力できませんので,豆腐(もしくは〓)に置き換えます.

みたいな警告を出すのに +1 です(ノード破棄もあまりしたくないなあ,という印象).

@h-kitagawa
Copy link
Member

U+XXXX は pTeX 用 JFM hogem では出力できませんので,豆腐(もしくは〓)に置き換えます.

みたいな警告

e1068d4 で入れました.

@aminophen
Copy link
Member Author

お二方ともコメントありがとうございます。確かに「黙って豆腐」は良くないですね。ノード破棄すると dvipdfmx で字が詰まってしまうのも気になりますので,破棄せずに警告 e1068d4 で良いと思います。ありがとうございます。

@aminophen
Copy link
Member Author

迷っていますが Missing character: There is no ^^a1 in font cmr10!\tracinglostchars によって出力制御できるようなので,試しに 66a0ed9 でやってみました。ノード破棄ではないので lost という名前が合っていない気がしますが,これだけのためにプリミティブを増やすのもどうかと思うのと,euptex では \tracinglostchars=3 にすると警告でなくエラーに出来る点は使えそうに思いました。ただし,警告が発するタイミングは Missing character ではノード生成時であるのに対し,非 JIS の方は \shipout でノードの DVI 出力時であることが異なります。

@aminophen
Copy link
Member Author

ee0a8c1\ptextracingfonts というプリミティブを追加してみました。pdfTeX の \pdftracingfonts と同じ書式でフォント名とサイズを表示(もちろん font expansion には非対応)し,

  • JFM の場合は YOKO/TATE の情報を表示
  • 明示的に in jis / in ucs が指定された場合は JIS/Unicode の情報を表示

としてみました。 テストケース: https://gist.github.com/aminophen/6715ae7fce5e03ddecccf06e7569682a

※ LuaTeX にも \tracingfonts があるけど LaTeX の \tracingfonts と衝突しているらしい

※ XeTeX の \XeTeXtracingfonts は読み込んだフォントの所在ディレクトリを返す別物らしい

@aminophen
Copy link
Member Author

aminophen commented Oct 17, 2022

c93a8f7 で \ptexfontname というのも実装してみました。\ptextracingfonts と共通のコードを利用して

  • 欧文フォントに対しては \fontname と類似だが,フォントサイズの表示は "... at ...pt" ではなく "[email protected]" にする
  • 和文フォントに対しては追加情報も出す。
    • 常に「横組か縦組か」を "/YOKO" または "/TATE" で表示(→ 和文フォントでは常に "/" が表示されることになるので「和文フォントかどうか」の判定にも使える)
    • 明示的にエンコード指定で読込まれていれば "+JIS" または "+Unicode" を表示

としました。これで,プログラミング的に「そのフォントが JIS コードと Unicode のどちらで DVI 出力されるか」を知ることができます。


なお "in jis" 及び "in ucs" による TFM 読込においては,新しい font identifier は発行されません。従って,同じ TFM を同じサイズで複数回読み込んだ場合は「最初のエンコード」が常に使われ,2回目以降でエンコード指定を変えても無視されます。

%#!ptex
\font\x=min10
\font in jis\y=min10 % => min10 は無指定時のエンコードのまま
\font in ucs\z=min10 % => min10 は無指定時のエンコードのまま
%#!ptex
\font in ucs\x=umin10
\font\y=umin10 % => umin10 は Unicode のまま
\font in jis\z=umin10 % => umin10 は Unicode のまま

参考:tex.web の @<If this font has already been loaded...@> を参照。ここではフォント (TFM) 名と読込サイズ (at) が同じフォントを読込済扱いしているが,ここに和文エンコード (JIS/Unicode) のチェックを追加していないため,このような挙動になる。(これで問題ないという判断)

@aminophen
Copy link
Member Author

ptex-manual の方も 'emulate_jfm_tracingfonts' ブランチで文書化してみました。

texjporg/ptex-manual@4e840e1

期待通りに動いているようです。

@aminophen
Copy link
Member Author

大丈夫そうなので,後ほどコミットします。結局追加したのは

  • \font [in jis/ucs] 書式
  • \tojis プリミティブ
  • \ptextracingfonts プリミティブ
  • \ptexfontname プリミティブ

の 4 点です。

@aminophen
Copy link
Member Author

r64800 問題があったら reopen しましょう。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants