Hatena::ブログ(Diary)

アセトアミノフェンの気ままな日常

2016-03-15

「ベースライン補正」の話の脱線について(続きの続き)

前回の続き。

3. オングストローム(Å)の記号(続)

以下のソースを pLaTeX で処理する:

\documentclass{jarticle}
\begin{document}{A\AA\aa}\ybaselineshift=2pt{A\AA\aa}\end{document}
\documentclass{tarticle}
\begin{document}{A\AA\aa}\tbaselineshift=0pt{A\AA\aa}\end{document}

f:id:acetaminophen:20160316234526p:image

一方、LuaLaTeX (LuaTeX-ja) では:

\documentclass{ltjarticle}
\begin{document}{A\AA\aa}\ltjsetparameter{yalbaselineshift=2pt}{A\AA\aa}\end{document}
\documentclass{ltjtarticle}
\begin{document}{A\AA\aa}\ltjsetparameter{talbaselineshift=0pt}{A\AA\aa}\end{document}

f:id:acetaminophen:20160316234525p:image

あれ、LuaTeX-ja は小文字も変だぞ? 二重シフトしている。
→ 対策:そもそもアクセント記号を「文字の合成」で実現していること自体に問題があるともいえる。そこで、デフォルトの「OT1 エンコーディングの Computer Modern フォント」ではなく「T1 エンコーディングの Latin Modern フォント」に切り替えてみよう(参考:LaTeX の「アレなデフォルト」傾向と対策)。

% プリアンブルに以下の2行を追加
\usepackage[T1]{fontenc}
\usepackage{lmodern}

f:id:acetaminophen:20160316235130p:image

これで期待どおりの出力になる。

2016-03-14

「ベースライン補正」の話の脱線について(続き)

前回の件で、ほかにも例があるかどうか調べてみた。というわけで

「\sbox\z@ T から \ht\z@ の値を参照して文字の高さを取得するようなコード」がベースラインシフトが 0pt でない場合に意図しない動作を引き起こしている(と思われる)特集

とする。これをどう考えるかは未検討である。

1. LaTeX のロゴ

前回の記事参照。
→ 対策:前田さんが例示してくださっているように LaTeX の定義を変更する:

\documentclass{jarticle}
\makeatletter
\DeclareRobustCommand{\LaTeX}{L\kern-.36em%
  {\def\@tempa{\check@mathfonts
        \fontsize\sf@size\z@
        \math@fontsfalse\selectfont
        A}%
    \begingroup
    \ybaselineshift0pt%
    \tbaselineshift0pt%
    \sbox\z@ T%
    \@tempdima\ht\z@
    \sbox\z@\@tempa
    \global\advance\@tempdima-\ht\z@
    \endgroup
    \iftdir
    \advance\@tempdima-\tbaselineshift % なぜ?
    \fi
    \raise\@tempdima\hbox{\@tempa}}%
  \kern-.15em%
  \TeX}
\makeatother
\begin{document}
\LaTeX ロゴ
\ybaselineshift20pt
\LaTeX ロゴ
\end{document}

ただし、この方法が「筋がよい」かどうかは不明。

2. ascmac パッケージの \mask

texjporg には既に報告済み。ascmac パッケージ (tascmac.sty) で定義されている「網掛けマクロ」である \mask が、ベースラインシフトを大きくすると Arithmetic overflow を起こす。

\documentclass{jarticle}
\usepackage{ascmac}
\begin{document}
\ybaselineshift8pt
\mask{網掛1}{A}
\end{document}
! Arithmetic overflow.
<recently read> \@bcal 

l.5 \mask{網掛1}{A}

? 

原因は、網掛け用に用意されている ascgrp フォント(欧文扱い)のグリフの高さを取得する際に、ベースラインシフトのせいで「高さがゼロ」となってしまうこと。「網掛けを敷き詰めるためにまずグリフの高さを取得し、敷き詰めるべき面積の高さをこの値で割る」という動作を含むため、ゼロによる除算でエラーとなっている。
→ 対策:マクロ側で対策可能なのでパッチしてみた

3. オングストローム(Å)の記号

フォーラムで報告済み。LaTeX で定義されている \AA は、アクセントをつけるときにやはり高さの取得を行っている。これが深刻なのは、縦組のデフォルトのベースラインシフト量ですら期待外れな出力になってしまうことである。

\documentclass{tarticle}
\begin{document}{A\AA\aa}\tbaselineshift=0pt{A\AA\aa}\end{document}

f:id:acetaminophen:20160316020825p:image

しかもこれ、より詳しくみると pLaTeX と LuaTeX-ja で結果が異なることがわかっている。このあたりはまた次回

2016-03-13

「ベースライン補正」の話の脱線について

前回、件のトピックの本題である「数式中のボックスとベースライン補正」の話は完結している。しかし、同じトピックから脱線して広がったもうひとつの話題が、けっこう厄介な気がしている。

pLaTeX で「LaTeX のロゴ」が乱れる話

新仕様でも旧仕様でもよいので、pLaTeX で次のソースを処理してみる。

\documentclass{jarticle}
\begin{document}
\ybaselineshift2pt
\LaTeX のロゴ。
\ybaselineshift7pt
\LaTeX のロゴ。
\end{document}

すると、あれれ?

f:id:acetaminophen:20160316014526p:image

ベースラインシフト量を大きくすると、ロゴの「A」が上がらなくなっていく。

今度は縦組にしてみよう。

\documentclass{tarticle}
\begin{document}
%\tbaselineshift3.41666pt
\LaTeX のロゴ。
\tbaselineshift20pt
\LaTeX のロゴ。
\end{document}

これも変だ。

f:id:acetaminophen:20160316014814p:image

LuaTeX-ja で試してみる

同じソースを LuaTeX-ja 用に書き変えてみる。横組:

\documentclass{ltjarticle}
\begin{document}
\ltjsetparameter{yalbaselineshift=2pt}
\LaTeX のロゴ。
\ltjsetparameter{yalbaselineshift=7pt}
\LaTeX のロゴ。
\end{document}

次に縦組:

\documentclass{ltjtarticle}
\begin{document}
%\ltjsetparameter{talbaselineshift=3.41666pt}
\LaTeX のロゴ。
\ltjsetparameter{talbaselineshift=20pt}
\LaTeX のロゴ。
\end{document}

これはやっぱり pLaTeX と同じ。

f:id:acetaminophen:20160316015311p:image

原因は?

これはどうやら pTeX の仕様らしい。北川さんの発言:

pTeX は「欧文をずらす」という実装になっているので,
「和文ベースラインを基準にした時のボックスの寸法」と考えれば
そんなに不自然ではないように思えます.

ただ、この実装だと前田さんの発言:

\LaTeX の例は,今の仕様だと \sbox\z@ T から \ht\z@ の値を参照
して文字の高さを取得するようなコードに対して,\ybaselineshift
が 0pt でない場合に意図しない動作を引き起こす場合があることを
示唆しているのではないか

という現状である。「和文ベースラインを基準にしたときのボックスの寸法」を返すという仕様は、pTeX としては確かに合理的だと思う。しかし、LaTeXTeX のマクロの中には「文字の高さを取得する」というコードがたくさん含まれているはずで、この場合に欧文文字の高さがゼロになってしまう場合が多発するのは否めない。

続く

2016-03-12

「数式中のボックスとベースライン補正」の話

某フォーラムの件

前提知識:pTeX のベースラインシフト

pTeX には \ybaselineshift\tbaselineshift というプリミティブがあり、それぞれ横組、縦組ボックス内での「和欧文フォント間のベースラインを調整するためのグルーを格納するレジスタ」である。アスキーのページの簡潔なプリミティブ一覧以外であまり説明されていないが、pTeX のこれらのプリミティブは「和文ベースラインを基準に欧文ベースラインをシフトする」という仕様になっている。通常、pTeX 横組みではベースラインシフトはゼロであるが、縦組では和文ベースライン(中央)と欧文ベースライン(“足”のないアルファベットの下端)をずらして*1自然な組版を実現している。ユーザが調節している場面はなかなか見かけないが、和文フォントと欧文フォントのデザイン上のミスマッチがよほど気になる場合に補正するために使えるということだろう。

f:id:acetaminophen:20160316013010p:image

LuaTeX-ja のベースラインシフト

LuaTeX-ja の説明書 (luatexja-ja.pdf) によると、LuaTeX-ja では「日本語が主ではない文書に対しては,欧文フォントではなく和文フォントのベースラインを移動した方がよい」との考えから、欧文フォントのベースラインシフト量と和文フォントのベースラインシフト量を独立に設定できるように設計されている。これらはプリミティブではなく、パラメータとして実装されている(横組:yalbaselineshift parameter と yjabaselineshift parameter、縦組:talbaselineshift parameter と tjabaselineshift parameter)。

pTeX と LuaTeX-ja の「意図的な実装の違い」

LuaTeX-ja の説明書に「数式における挙動:pTeX との違い」と題した記述がある:

ALchar のベースラインを補正する yalbaselineshift パラメータはほぼ pTeX における \ybaselineshift に対応しているものであるが,数式中の挙動は異なっているので注意が必要である.例えば,表4のように,数式中に明示的に現れた \hbox は,
pTeX では,ボックス全体が \ybaselineshift だとシフトされるので,表4中の “い” のように,ボックス中の和文文字は \ybaselineshift だけシフトされ,一方, “for all” のように,ボックス内の欧文文字は2重にシフトされることになる.
◎ 一方,LuaTeX-ja ではそのようなことはおこらず,数式中に明示的に現れた \hbox はシフトしない.そのため,表4 中の “い” も “for all” も,それぞれ本文中に書かれたときと同じ上下位置に組まれる.

この挙動の違いが、冒頭で掲げたフォーラムの議題である。この違いは、北川さんのパッチが TeX Live r39938 に取り込まれたことで解消した。TeX Live 2016 には新しい挙動の pTeX が入ることになる。

テストソース:pLaTeX 用

\documentclass{jarticle}
\begin{document}
\ybaselineshift=10pt
あa$b\hbox{いc}$
\end{document}

LuaLaTeX (LuaTeX-ja) 用

\documentclass{ltjarticle}
\begin{document}
\ltjsetparameter{yalbaselineshift=10pt}
あa$b\hbox{いc}$
\end{document}

f:id:acetaminophen:20160316013032p:image

新しいプリミティブ

今回の変更で

  • \textbaselineshiftfactor(標準値は 1000: 1倍)
  • \scriptbaselineshiftfactor(標準値は 700: 0.7倍)
  • \scriptscriptbaselineshiftfactor(標準値は 500: 0.5倍)

という「ベースラインシフトの戻し量」を指定するプリミティブが追加された。数式中の \displaystyle\textstyle なものは「1回分」、\scriptstyle なものは「0.7回分」、\scriptscriptstyle なものは「0.5回分」ベースラインシフトが戻される*2。備忘録として、W32TeX の 2016/03/05 の ChangeLog も引用しておく:

(04) ptex-w32.tar.xz
Update ptex.dll, and eptex.dll: H. Kitagawa added new primitives
\textbaselineshiftfactor (=1000), \scriptbaselineshiftfactor (=700),
\scriptscriptbaselineshiftfactor (=500) to improve typesetting with
non-vanishing \ybaselineshift. If all three are zero, the old features are
recovered.

全部ゼロに戻せば従来と同じ挙動を示すので、仮にマズイ場合はフォーマットか何かで修正できることになり、たぶん問題ないと思う。

今回の変更の効果

qa:54286 で報告された問題も、qa:54294 で解説されているとおり「数式中の明示的な \hbox が二重にシフトされる」ことに起因するものである。

\documentclass{jarticle}
\begin{document}
\begin{equation}
  y = f(x)= x^2+2x+1 + \int_{0}^{\pi} \frac{1+tx^2}{1-t^2}\,dt
\end{equation}
\end{document}

新しい pTeX なら、数式軸からずれることなく数式番号が表示される(薄青)。

f:id:acetaminophen:20160316014038p:image

続く

*1:jarticle クラスの既定のフォントサイズの場合は 3.41666pt である。

*2:ディスプレイ・テキスト・スクリプト・スクリプトスクリプトについては、doraTeX さんの「¥mathchoice の闇」の記事で登場したことで記憶に新しい。

2016-03-10

amsmath を読み込むと結果が変わる、とっても古いバグの話

11年前の texqa より。ascmac パッケージの \keytop[c]{あ} を amsmath パッケージと一緒に使うとなんか変、という話(例示ソースをもう少し小さくしてみた)。

\documentclass{jarticle}
\usepackage{amsmath} % ←これの有無
\usepackage{ascmac}
\def\hoge{\keytop[c]{}}
\begin{document}
\hoge \hoge
\end{document}

左が「amsmath パッケージを読んだ場合」、右が「amsmath パッケージを読み込まなかった場合」。あらら…

f:id:acetaminophen:20160310234813p:image

明らかに amsmath パッケージを読み込むと衝突している。ascmac パッケージ側での対処法が挙げられているが、どうやら \box0 が衝突しているらしい。

これは衝突しやすい0番のレジスタを使っているという点で ascmac も一部悪いが、根本的な問題は amsmath 側である。現に、ここで例示されているとおり

\documentclass{article}
\usepackage{amsmath}
\begin{document}
%%$A$
\setbox0=\hbox{A}
$\box0$$\box0$
\end{document}

でも再現する:これを pdfLaTeX などで処理すると、amsmath ありでは「(A」と出力され、なしでは「A」と出力される。しかも、コメントアウトしてある $A$ の部分を有効化すれば、この違いはなくなる。「最初の数式」がおかしくなるようだ*1

amsmath [2016/02/20] では…?

なんと、amsmath [2016/02/20] をインストールすると、LuaLaTeX/XeLaTeX の場合だけ問題が解消していた。そこでコードを見てみる。

\ifx\Umathcharnumdef\@undefined
\def\resetMathstrut@{%
 (中略:オリジナルのコードの定義)
}
\else
\def\resetMathstrut@{%
 (中略:LuaTeX/XeLaTeX 用の新しいコードの定義)
}
\fi

というわけで、「UnicodeTeX の場合に新たなコードを使う」という変更が施されていた*2。これがどういうわけかうまいこと問題を解消していたようである。

とはいえ、pdfLaTeX や pLaTeX では相変わらずこの問題が起こる。これは嬉しくないので、やはり11年前に提案されていたコードを入れてみる:

\ifx\Umathcharnumdef\@undefined
\def\resetMathstrut@{%
  \begingroup
  \setbox\z@\hbox{%
    \mathchardef\@tempa\mathcode`\(\relax
    \def\@tempb##1"##2##3{\the\textfont"##3\char"}%
    \expandafter\@tempb\meaning\@tempa \relax}%
  \edef\@tempa{%
     \ht\Mathstrutbox@\the\ht\z@\relax
     \dp\Mathstrutbox@\the\dp\z@\relax}%
  \expandafter\endgroup\@tempa
}
\else
 (中略)
\fi

すると…

f:id:acetaminophen:20160311000102p:image

直るじゃん…「グループ内で処理して外に吐きだす」だそうだ。なんであのとき報告しなかったのか? というわけで、いまのメンテナンスを担当している LaTeX Team に報告してすぐに修正された (2016/03/10) 。

教訓

改善点をみつけたら早く報告しましょう。

*1:なお、\keytop[c] は自明ではないが、コードを見れば \vcenter で「キートップを数式軸に合わせて配置する」ためにいったん数式モードに入っている。このため、見た目は違えど根は同じ。

*2:なお、この新しいコードに 2016/02/20 版では「余分なスペース」が入っていたことが判明し、2016/03/03 版で修正されている。

2016-03-09

nidanfloat で「右側の文章が段抜きフロートと重なる」

積み残しのひとつ:アスキーの pLaTeX に付属している nidanfloat パッケージについて、qa:44116qa:51706 で指摘されている問題点がある。

右側の文章が bottom フロートに重なる

table 環境を [b] 指定すると、フロートの高さ分だけ文章が重なる。

\documentclass[twocolumn]{article}
\usepackage{nidanfloat}
\usepackage{lipsum}
\begin{document}
\lipsum[1-5]
\begin{table*}[b]
\begin{tabular}{cccccccc}
\hline
AAAAAA & BBBBBB & CCCCCC & DDDDDD & EEEEEE & FFFFFF & GGGGGG & HHHHHH \\
\hline
a & 1.00 & 1.00 & 1.00 & 1.00 & 1.00 & 1.00 & 1.00 \\ 
a & 2.00 & 2.00 & 2.00 & 2.00 & 2.00 & 2.00 & 2.00 \\ 
a & 3.00 & 3.00 & 3.00 & 3.00 & 3.00 & 3.00 & 3.00 \\ 
a & 4.00 & 4.00 & 4.00 & 4.00 & 4.00 & 4.00 & 4.00 \\ 
\hline
\end{tabular}
\end{table*}
\lipsum[1-3]
\end{document}

f:id:acetaminophen:20160311140406p:image

右側の文章の高さがはみ出す

table 環境を [b] ではなく[t] にしても、今度はフロートの高さ分だけ文章がはみ出す。

\documentclass[twocolumn]{article}
\usepackage{nidanfloat}
\usepackage{lipsum}
\begin{document}
\lipsum[1-5]
\begin{table*}[t]
\begin{tabular}{cccccccc}
\hline
AAAAAA & BBBBBB & CCCCCC & DDDDDD & EEEEEE & FFFFFF & GGGGGG & HHHHHH \\
\hline
a & 1.00 & 1.00 & 1.00 & 1.00 & 1.00 & 1.00 & 1.00 \\ 
a & 2.00 & 2.00 & 2.00 & 2.00 & 2.00 & 2.00 & 2.00 \\ 
a & 3.00 & 3.00 & 3.00 & 3.00 & 3.00 & 3.00 & 3.00 \\ 
a & 4.00 & 4.00 & 4.00 & 4.00 & 4.00 & 4.00 & 4.00 \\ 
\hline
\end{tabular}
\end{table*}
\lipsum[1-3]
\end{document}

f:id:acetaminophen:20160311140405p:image

いずれにせよ、「フロートが左側でなく右側のカラムに登場するとき、文章の高さを正しく設定できていない」という状態である。対症療法としてフロートが左側に現れるように文章の長さを調節することが挙げられているが、根本的な解決策は不明。

2016-03-08

ascmac パッケージのテスト(続き)

積み残しの残り:先日に続き ascmac パッケージ。

ascmac パッケージのベースライン補正

以下の \keytop を使ったソース。

\documentclass{tarticle}
\usepackage{ascmac}
\begin{document}
あいうえおabc\par
キートップ\keytop{A}キートップ\par
あいうえおabc
\end{document}

\keytop のあとは、すべて \tbaselineshift が 0 にリセットされてしまう。

f:id:acetaminophen:20160311135048p:image

\keytop は最初に\tbaselineshift をゼロにしているが、これを終了後に復帰する処置が欠けている。というわけで、\@savetbaselineshift にいったん元の値を退避して、それを復帰させればよいと思う。

itembox 環境のタイトル部分もベースラインシフトが効かない仕様だったので、ついでにここも効くようにしてみた。

2016-03-03

ascmac パッケージのテスト

いつか調べようと思っていた積み残しの一つ:ascmac パッケージの shadebox 環境を使ってみるテスト。

\documentclass{jarticle}
\pagestyle{empty}
\usepackage{ascmac}
\def\showdimens{%
  fboxsep: \the\fboxsep      \par
  fboxrule: \the\fboxrule    \par
  shaderule: \the\shaderule}
\def\test{%
  shadebox環境です。
  \begin{shadebox}
    shadebox環境です。shadebox環境です。shadebox環境です。shadebox環境です。shadebox環境です。
  \end{shadebox}
  shadebox環境です。}
\def\testwithpar{%
  shadebox環境です。\par
  \begin{shadebox}
    shadebox環境です。shadebox環境です。shadebox環境です。shadebox環境です。shadebox環境です。
  \end{shadebox}
  shadebox環境です。}
\begin{document}\verb+\textwidth+幅の線↓

\hrule height 1pt width \textwidth
\medskip

\showdimens

\test \par \testwithpar

%\fboxsep0pt
\fboxrule6pt
\shaderule10pt

\showdimens

\test \par \testwithpar

\medskip

\hrule height 1pt width \textwidth
\medskip\verb+\textwidth+幅の線↑

\end{document}

2016/03/03 現在、CTAN にあるバージョン (2006/07/14) で処理するとこうなる。

f:id:acetaminophen:20160304011339p:image

要するに:

  • shadebox 環境の前で改段落されない(要するに箱がもれなく版面をはみ出す)
  • shadebox 環境の“箱+影”の幅がなぜか \textwidth(一段組では \linewidth に等しい)に満たない

という点が不自然である*1

これを、ちょっと改変すると以下のようにできる。

f:id:acetaminophen:20160304011336p:image

後者のほうが自然だと思うのだが、どうだろう?

もうひとつ不自然な点があるが、それは後日

*1:前者は tascmac.sty で定義されているほかの環境と比べても不自然である。後者は「日本語 LaTeX2e ブック」の解説に「shadebox 環境の横の長さはその時点での \linewidth の値になります」とあることに反する。