Closed aminophen closed 4 years ago
とりあえず、jsclassesとotfの部分を“最小”にしてみた。
\documentclass[a4j]{jarticle}
\SetSymbolFont{mincho}{bold}{JY1}{mc}{bx}{n}%…(〠)
\usepackage{bm}
\usepackage{etoolbox}% for \csshow
\begin{document}
{\sffamily\gtfamily これはゴシック}
\csshow{JY1/gt/m/n/10}%==> \JY1/gt/m/n/10=select font goth10.
{\sffamily\gtfamily $\int$みたいな数学記号が見出しに入ると……}
\csshow{JY1/gt/m/n/10}%==> \JY1/gt/m/n/10=select font cmss10. (???)
{\sffamily\gtfamily やったー!明朝体になった!}
\end{document}
(〠)
の部分がotfに相当する部分だけど、この記述に問題があるとは思えない。
だから結局、「bmパッケージがpLaTeXでアレ」ということなんだと思う。
最新の pLaTeX2e 2020-02-02 でも状況は変わっていないので,調べてみました。
\tracingonline1
\tracingmacros1
\tracingassigns1
としてログを解析した結果,LaTeX カーネルの
\def\do@subst@correction{%
\xdef\subst@correction{%
\font@name
\global\expandafter\font
\csname \curr@fontshape/\f@size\endcsname
\noexpand\fontname\font % <= このせいで \jfont ではなく \font が読み出される!
\relax}%
\aftergroup\subst@correction
}
で定義された \subst@correction
が実行された瞬間に
subst@correction ->JY1/mc/bx/n/10 global font JY1/gt/m/n/10 fontname font relax
{reassigning scriptscriptfont256=JY1/mc/bx/n/10}
{globally changing JY1/gt/m/n/10=select font goth10}
{into JY1/gt/m/n/10=select font nullfont}
{globally changing JY1/gt/m/n/10=select font nullfont}
{into JY1/gt/m/n/10=select font cmss10}
として上書きされていることがわかりました。\font は代入時には「横 JFM なら \jfont (和文横),縦 JFMなら \tfont (和文縦)」にアサインしてくれますが,読出時には「現在の \font (欧文)」しか読み出せないので,至極当然です。
これをどうにかする手段はないだろうか? と考えると,一案として
\csname \curr@fontshape/\f@size\endcsname
~ \font@name
の実体を \if か何かで判定して,それと一致する \font / \jfont / \tfont を読み出すとすればいい気がします。しかし,「ある fontdef トークンが \font か \jfont か \tfont か」を判定する,しかも \xdef 内で使える完全展開可能な方法が思いつきません。
※ 展開可能性を無視すれば,私の TeX 言語力でも強引にある程度は判定できたのですが,fontdef トークンが上書きされるようなコーナーケースには対応できないと思います。
そこで pTeX に \ifjfont, \iftfont みたいなプリミティブを実装してみました (https://github.com/texjporg/tex-jp-build/commit/9f2687caf267886b7d775cd4d29f2e0c8a46f9b3) 。この開発版 pTeX を使うと,本件 issue を解決することができます:
[edit 2020-02-05 01:04] 勘違い:むしろ判定を \noexpand しないといけないことに気づきましたので,コメントと下のマクロを修正しました。
\makeatletter
\def\do@subst@correction{%
\xdef\subst@correction{%
\font@name
\global\expandafter\font
\csname \curr@fontshape/\f@size\endcsname
\noexpand\fontname
\noexpand\ifjfont\font@name\jfont\noexpand\else
\noexpand\iftfont\font@name\tfont\noexpand\else\font
\noexpand\fi\noexpand\fi
\relax}%
\aftergroup\subst@correction
}
\makeatother
pTeX へのリクエストは https://github.com/texjporg/tex-jp-build/pull/97 に送りました。
↑ マクロの展開や代入を解析した結果から「これで行けるんじゃないかな」というテキトーな発想で試してみたら,一時間くらいで一発通ってしまった,という程度のものです。bm パッケージや LaTeX カーネルが壊れないかは自信がないので,マズかったらご指摘ください。
上の方の ZR さんご提示のソースにもう少しコメントを付け足したもの:
% ダメになる例:ゴシックが明朝になる
% disablejfam なので数式内で漢字が使えない最小化
\documentclass[disablejfam]{jarticle}
\usepackage{ptrace}
% ssub でなく明示定義されていれば大丈夫
%\DeclareFontShape{JY1}{mc}{bx}{n}{<5> <7> <10> goth10}{}
\DeclareSymbolFont{mincho}{JY1}{mc}{m}{n}
\SetSymbolFont{mincho}{bold}{JY1}{mc}{bx}{n}%…(\UTF{3020})
\usepackage{bm}
\usepackage{etoolbox}% for \csshow
\begin{document}
% =======================
{\sffamily\gtfamily ゴシックGT}のはずなのに
\csshow{JY1/gt/m/n/10}%==> \JY1/gt/m/n/10=select font goth10.
数式
\setbox0=\hbox{$\empty$}%
が一度でも入ると
% 数式が使われた時に有効だった欧文ファミリに再定義されてしまう
\csshow{JY1/gt/m/n/10}%==> \JY1/gt/m/n/10=select font cmr10. (???)
{\sffamily\gtfamily 同じサイズは明朝体MCになる}
% =======================
% =======================
{\sffamily\gtfamily\Large 別のサイズは大丈夫GT}
{\Large
だが数式
\setbox0=\hbox{$\empty$}%
が一度でも入ると}
{\sffamily\gtfamily\Large 別のサイズも潰されるGT}
% =======================
\end{document}
そういえば LuaTeX-ja ではどうしていたんだっけ……と思い返すと,\curr@fontshape
から encoding を取り出し,それが和文エンコーディングか否か判定していたのでした.pLaTeX でも同じようなことができませんか?
% #1 の展開結果から encoding 部分をとりだし,それが和文用かどうかの結果を \ifin@ に代入
\def\ltj@@IsFontJapanese#1{%
\directlua{luatexja.jfont.is_kenc(string.match(
'\luatexluaescapestring{#1}', '[^/]+'))}}
\let\ltj@@al@do@subst@correction=\do@subst@correction
\def\do@subst@correction{%
\ltj@@IsFontJapanese{\curr@fontshape}\ifin@%
\ltj@@ja@do@subst@correction
\else
\ltj@@al@do@subst@correction
\fi
}
和文エンコーディングか否か
和文エンコーディングか否かは \kyenc@list
とか \ktenc@list
を見ればわかるので,確かに \font@name
の展開結果から encoding を取り出しさえすれば行けるかも…。
よく読むと
\curr@fontshape
から encoding を取り出し
なのですね。それで正しいのでしょうか。私の理解としては,「グループ内で実行された \font@name
が実際にどのフォントを変更したか」に応じて読出元を変えるために,てっきり \font@name
から取り出すものかと。
\font@name
からエンコーディングを取り出して和文横かどうかを判定してみました。これなら新しいプリミティブは不要ですね…。(e-TeX の機能を \scantokens 以外にも使えばもう少しきれいになりそうですが…)
{\escapechar-1\relax \xdef\pltx@macro{\string\macro:->}}
\expandafter\expandafter\expandafter\def
\expandafter\expandafter\expandafter\pltx@strip@macro
\expandafter\pltx@macro\expandafter#\expandafter1/#2\@nil{#1}
\def\pltx@parse@font@name{%
\xdef\tmp@@@item{\expandafter\expandafter\expandafter\pltx@strip@macro
\expandafter\meaning\expandafter\font@name\pltx@macro\@nil}%
{\everyeof{\noexpand}\endlinechar=-1\relax
\xdef\tmp@@@item{{\expandafter\scantokens\expandafter{\tmp@@@item}}}}%
}
\def\do@subst@correction{%
\xdef\subst@correction{%
\font@name
\noexpand\pltx@parse@font@name
\noexpand\expandafter\noexpand\expandafter\noexpand\expandafter
\noexpand\inlist@\noexpand\expandafter\noexpand\tmp@@@item
\noexpand\expandafter{\noexpand\kyenc@list}%
\noexpand\ifin@
\global\expandafter\font
\csname \curr@fontshape/\f@size\endcsname
\noexpand\fontname\jfont
\relax
\noexpand\else
\global\expandafter\font
\csname \curr@fontshape/\f@size\endcsname
\noexpand\fontname\font
\relax
\noexpand\fi}%
\aftergroup\subst@correction
}
(とりあえず \f@encoding
が和文用か調べている状況ですが)https://github.com/h-kitagawa/platex/tree/kitagawa_substcorr でいじっているところです.
@aminophen さんの方針とは違い,\inlist@
で調べる時に \detokenize
を使って調べるエントリ・リストとも文字列化するようにしています.
てっきり \font@name から取り出すものかと。
昔書いたコードなので覚えていませんが,おそらく「和文エンコーディングと欧文エンコーディングは交じることはない」(=和文エンコーディングで定義されたフォントは置換元もそうである)という前提で書いたのだと思います.
\inlist@ で調べる時に \detokenize を使って調べるエントリ・リストとも文字列化
動いていそうです。でも \expandafter しすぎ🍣なので https://github.com/texjporg/platex/tree/kitagawa_substcorr で減らしてみました。
今気づいたのですが,plfonts.dtx を読むと,アスキー版の頃から \do@subst@correction
が和文対応できていないことは知られていたようです。説明文だけ読むとその対策をとったつもりのようなのですが…なのに何故この issue のような問題が起きるんだろう…?(まあいいや,今回の改修をすれば動くようになるので,昔のことは気にしないことにしよう。)
% \subsubsection{一時コマンド}
%
% \begin{macro}{\afont}
% \LaTeX{}内部の|\do@subst@correction|マクロでは、
% |\fontname\font|で返される外部フォント名を用いて、
% \LaTeX{}フォント名を定義しています。したがって、|\font|をそのまま使うと、
% 和文フォント名に欧文の外部フォントが登録されたり、
% 縦組フォント名に横組用の外部フォントが割り付けられたりしますので、
% |\jfont|か|\tfont|を用いるようにします。
% |\afont|は、|\font|コマンドの保存用です。
% \begin{macrocode}
\let\afont\font
% \end{macrocode}
% \end{macro}
「pLaTeXカーネルがやっている\do@subst@correction
対策」というのは、確か、
「\do@subst@correction
を実行する前に、あらかじめ必要に応じて\let\font\jfont
とか\let\font\tfont
とかを実行しておく」
というものだったはずです。
(で、\font
を“元に戻す”ために用意されているのが\afont
。)
@zr-tex8r はい,そうだと思います。
なのに,実際には「\do@subst@correction
の実行時点では \let\font\jfont とか \let\font\tfont とかが効いてなかった」ことが今回判明しました。ここで気になるのが,
\selectfont
から呼び出しの場合は \let が効いていて,数式用の \getanddefine@fonts
が未対処だった,ということらしい。\do@subst@correction
以外にも,まだ和文対応できていない“何か”が残ってないか? → \DeclareFontSubstitution が該当した。\DeclareErrorKanjiFont も該当するが,これはエラー後のリカバリなのでそれほど重要ではないので放置しよう。pLaTeX2e 2020-04-12 を出したので close します。
LaTeX で otf と bm を併用するときに otf を先に読み込むと見出しが死ぬ
これは jsclasses の問題なのか、otf の問題なのか、それとも bm の問題なのかわかりませんが、念のため載せておきます。