マクロツイーター

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

dvipdfmxの色スタックがアレなのをなんとかする(ナントカもする)

アレForumのアレな話

dvipdfmxがアレらしい。

Each \color command executes

\special {color push \current@color }\aftergroup \reset@color

but the push is never followed by a pop (except at the end of the job).

The color stack apparently has a limitation of 127 or 128 positions (you get red, I get blue, so it can be off by one depending on the version of the software).

ただし、このTeX Forumの問題のように「トップレベルで\colorを大量に使うと失敗する」ことについては割と簡単に対処できそうである。

トップレベルではそもそも\aftergroupで挿入したトークンは実行されないので、\reset@colorは元々一度も実行されていないはずである。だから色スタックに関するトップレベルでの整合性は元々要求されていないことになる。となると、次の動作をすればよい。

  • まず最初に初期色をスタックに積んでおく。*1
  • トップレベルで\set@colorが実行された場合は本来の動作の代わりに「色スタックをpop → \current@colorをpush」をする(トップレベルなので\aftergroupはそもそも無意味)。これでスタックの深さは変わらなくなる。

イマドキのTeXエンジンであればe-TeX拡張の\currentgrouplevelが使えるので「いまトップレベルにいるか」が判定できる。

やってみた

というわけで、なんとかしてみた。

あとは適当な例で試すだけだが、折角なんとかしたのだからナントカすることにする。

% upLaTeX + dvipdfmx (essential)
\documentclass[dvipdfmx]{jsarticle}
\usepackage{xcolor}
\colorlet{R}{red}\colorlet{B}{blue}\colorlet{G}{green!50!black}
\usepackage{bxdpx-tchack}
\newcommand*\cS[1]{\color{#1}\color{black}}
\newcommand*\cNice[7]{%
  \cS{#1}\cS{#2}\cS{#3}\cS{#4}\cS{#5}っ \cS{#6}っっ♪\cS{#7}っっ♪}
\newcommand*\cNicePar{%
  \cNice{R}{B}{R}{G}{B}{R}{R} \cNice{B}{B}{G}{R}{G}{B}{B}\par
  \cNice{G}{R}{R}{R}{B}{G}{G} \cNice{R}{G}{R}{B}{G}{R}{R}\par}
\begin{document}
\cNicePar \cNicePar \cNicePar \cNicePar \cNicePar
\end{document}

出力(トッテモ素敵😊)

まとめ

色とりどりのナントカはトッテモ素敵😊😊😊

*1:これはcolorパッケージ自体が既に行っているようではあるが、ここでの内部動作は“\color{black}”を(トップレベルの)プリアンブルで実行したのと全く同じなので、これが想定外の状態を引き起こすことはないはずである。