マクロツイーター

はてダから移行した記事の表示が崩れてますが、そのうちに直せればいいのに(えっ)

ヤバくない \text 命令を作る話(補足)

前回の続き)
ヤバくない \text 命令の作り方

bxamstext パッケージの「2 パス処理」を実現するのに zref パッケージをどのように使ったか、について概説することにする。(例の記事を読んでいることを前提とする。)

プロパティとラベルの使用に関する方針。

  • 「2 パスで数式スタイルの情報を得る」処理を行う場合、\mathchoice の引数の中で遅延書込を行う必要がある。
  • zref ではラベルを置くとプロパティ値記録のための遅延書込が行われる。
  • 従って、(数式中の)\text があるたびにラベルを新しく作る必要がある。このため整数レジスタによる自動採番を行い bxtt:42 のようなラベルを作る。
  • プロパティは bxtt@ms(判定結果の数式スタイルの値)だけを用意する。D、T、S、SS を 1〜4 の整数で表し、(参照が)未定義の場合は 0 とする。
  • プロパティが 1 つしかないが、一応リスト bxtt を用意する。((ラベルを置くときに記録対象とするプロパティのセットは、普通は \zref@labelbylist{bxtt:42}{bxtt} のようにリスト単位で指定するが、\zref@labelbyprops{bxtt:42}{bxtt@ms} のようにプロパティ単位で指定することも可能である。))

初期設定。

\zref@newlist{bxtt}          % リスト bxtt を作る
\zref@newprop{bxtt@ms}[0]{0} % プロパティ bxtt@ms を作る
\zref@addprop{bxtt}{bxtt@ms}

数式中で \text が使われた場合(この場合処理が内部マクロ \text@ に回る)、以下の手順を実行する。

  • ユニークなラベル値(例えば“bxtt:42”)を生成する。
  • 以下の命令が「前回コンパイル時の数式スタイル」(1〜4 の整数、未定義なら0)に展開されるので、その値を利用して(\mathchoice の代わりに条件分岐を行って)テキストの組版を行う。
    \zref@extract{bxtt:42}{bxtt@ms}
  • \mathchoice を用いて(今回コンパイルの)数式スタイルにより分岐して、そこでは(何も組版せず)プロパティ値を設定してラベルを置く。
    \mathchoice
      {\zref@setcurrent{bxtt@ms}{1}\zref@labelbylist{bxtt:42}{bxtt}}% D
      {\zref@setcurrent{bxtt@ms}{2}\zref@labelbylist{bxtt:42}{bxtt}}% T
      {\zref@setcurrent{bxtt@ms}{3}\zref@labelbylist{bxtt:42}{bxtt}}% S
      {\zref@setcurrent{bxtt@ms}{4}\zref@labelbylist{bxtt:42}{bxtt}}% SS
    なお、補助(.aux)ファイルに書き出す処理は、\zref@labelbylist の中で行われる。zref の既定ではこの際に遅延書込が行われるため、\mathchoice の中で用いた場合、正しい選択肢に対応する書込だけが実際に行われる。
“初回コンパイル”の扱い

ところで、前回の記事で出した、1 回目と 2 回目のコンパイル結果をもう一度見てほしい。

  • 1 回目:
  • 2 回目:

1 回目のコンパイルは「数式スタイルの情報」が得られないので、当然、正しくない文字サイズで出力されるわけであるが、横幅はほとんど同じになっている(だから文字がわずかに重なっている)。初回のコンパイルで正しい結果が得られないのは仕方が無いとして、横幅が正しい値から大きくずれるのはできれば避けたいので、そのための工夫を入れている。

TeX の長さ単位には mu(<math unit)という数式専用のものがある。1mu は「現在の数式用フォント*1の 1/18 em に等しい長さ」と定義されている。ここで「現在の」と言っているのは数式スタイルも込めた意味なので、「現在の数式スタイル」が T(\textstyle)のときと S(\scriptstyle)のときでは 1mu の長さは異なる。これを利用して、(T 相当のフォントサイズで組んだ)テキストの幅を mu 単位に変換して、強制的にテキストの幅をその値に変えてしまうことで、テキストの幅だけは“正しい値”、すなわち現在の数式スタイルに相当するフォントサイズで組んだ幅に大体合うようにしているのである。

例えば次の例を考える

\documentclass[a4paper]{article} % 基底フォントサイズ 10pt
\usepackage{bxamstext}% フォントは Computer Roman のまま
\begin{document}
$\pi^{\text{hoge}}$ % 上添字で \text を使った
\end{document}
  • テキストのフォントサイズが 10pt なので、T の数式のフォントサイズも 10pt であり、この時 S の数式のフォントサイズは 7pt である。(ちなみに SS は 5pt。)
  • T の数式フォント(cmsy10)の 1em は 10.00002pt、従って、T の 1mu は 0.55554pt。
  • S の数式フォント(cmsy7)の 1em は 8.19447pt、従って、S の 1mu は 0.45525pt。
  • 数式スタイルが不明なので暫定的に T のフォントサイズ(10pt)を用いる。
  • 10pt でテキスト「hoge」を組むと幅は 20.00005pt になる。
  • これを“T の mu 単位”に換算すると 36.00109 mu。
  • 従って、以下のものに相当する((実際には \hbox の幅に mu 単位は使えない。)) hbox を出力する。
    \hbox to 36.00109mu{hoge\hss}
  • さて、実際には数式スタイルは S であった。
  • 従って、36.00109mu は 16.38949pt に相当し、よってこの幅が確保されて出力される。(当然文字はこの幅をはみ出す。)
  • 本来の正しい出力では、S のフォントサイズ(7pt)でテキストが組まれるべきである。
  • 7pt でテキスト「hoge」を組むと 15.94452pt。
  • 従って、先の暫定的に決めた幅(16.38949pt)は大体あっていることが判る。

1mu の大きさに関する“Tの値”対“Sの値”の比は 1:0.819、「hoge」の幅に関する同様の比は 1:0.797 でどちらも公称サイズの比 10:7(=1:0.700)からはかなり離れているのが、この 2 つの比同士は割と近いことに注意してほしい。

実際の実装は次のようになる。TeX には実数のデータ型がない(長さしかない)ので少しトリッキーになっているが、上記の手順が解っていれば理解は容易であろう。

% #2 が元々の \text の引数のテキスト
\setbox0=\hbox{#2}% (Tのフォントサイズで)テキストを組む
\@tempdimb\fontdimen6\textfont2\relax % Tのフォントの1emの値
% テキストの横幅(\wd0)を mu 単位に換算したい.
% この場合の計算式は \wd0×18mu÷1em となるが直接は計算できない.
% そこでまず, calc で \wd0×18pt÷1em を計算する.
\setlength\@tempdima{\wd0*\ratio{18pt}{\@tempdimb}}%
% その値(寸法)の単位 pt を除去する.
\edef\bxtt@tmpa{\strip@pt\@tempdima}%
% すなわち "\bxtt@tmpa mu" が所望の"mu単位の長さ"となる.
% "\hbox to ...mu" は不可なので, まずゼロ幅で配置した後に,
% \mskip でmu単位の移動を行う.
\hbox to 0pt{\box\z@\hss}\mskip\bxtt@tmpa mu\relax

*1:正確にいうと、メインの記号用フォントに使われる「数式ファミリ 2」に割り当てられているフォント。