[Tex/LaTex] How to change the text color in such a way that the effect transcends groups

colorgroupingpdftex

I'd like to have a command \globalred that makes all subsequent text red, even if the command is issued inside a group. For example, the output of the TeX file

\documentclass{article}
\begin{document}
a {\globalred b} c
\end{document}

should be  desired output, with a red c. I do have some very hacky solution, but it only works by redefining the \set@color and \reset@color commands from pdftex.def to what they where up to version 0.03t (or by using an old TeX installation before 2007):

\documentclass{article}
\usepackage[pdftex]{xcolor}
\makeatletter
\def\set@color  {\pdfliteral{\current@color}%
                 \aftergroup\reset@color}
\def\reset@color{\pdfliteral{\current@color}}
\def\globalred  {\xdef\current@color{\xcolor@ {}{1 0 0 rg 1 0 0 RG}{rgb}{1,0,0}}%
                 \set@color}
\makeatother
\begin{document}
a {\globalred b} c
\end{document}

This leads me to the following questions:

  • Is there an "official" way to achieve what I want?
  • Why doesn't \set@color from more recent pdftex.def versions act globally anymore, although I globally redefine \current@color with \xdef? (Is this a design choice or just an unforeseen side effect of the new implementation of \set@color?)

Let me shortly explain how I came up with this: in my hacky code above, I'm roughly emulating what beamer does to produce transparent text. beamer aims to do this in a way that transcedes groups (see the user guide, pages 24 and 79), but it appears that it doesn't work anymore; at least for me, the example on page 79 gives strange output:

strange output of itemize with pauses

The same problem (and hacky solution) came up in this question my mine.

Best Answer

There is no official way to do it in LaTeX. Color changes are bound to groups. That the "global trick" works with older versions of pdftex.def is due to the shortcomings of the color implmentation there. Older versions of pdfTeX do not provide a color stack and have therefore serious trouble with page breaks.

Dvips provides a color stack where the current color is put on the stack in the driver, the color is changed and after the group the color of the stack is restored, \current@color is not used during restoring the color value. The same now happens with pdftex.def and pdfTeX, if they are not too old. Also pdfTeX improves the color stack of dvips by supporting multiple color stacks. For example, an additional color stack can be used for footnotes (package pdfcol) to support color changes in footnotes that are broken across pages. See packages pdfcolparrallel or pdfcolparcolumns for other examples. Furthermore other parameters than color can be managed this way, see example package pdftransparent for transparency or pdfrender.

\documentclass{article}
\usepackage[pdftex]{xcolor}
\makeatletter
\def\set@color{%
  \pdfliteral{\current@color}%
  \aftergroup\reset@color
}
\def\reset@color{%
  \pdfliteral{\current@color}%
}
% colorfix stuff for old implementation of color for pdfTeX
\RequirePackage{ltxcmds}
\AtBeginDocument{%
  \ltx@ifundefined{@ldc@l@r}{%
    \let\@ldc@l@r\color
    \def\color{%
      \ltx@IfUndefined{if@inlabel}{}{%
        \csname if@inlabel\expandafter\endcsname
        \expandafter\leavevmode\csname fi\endcsname
      }%
      \@ldc@l@r
    }%
  }{}%
  \ltx@ifundefined{@lduseb@x}{%
    \ltx@IfUndefined{usebox}{}{%
      \let\@lduseb@x\usebox
      \def\usebox#1{\@lduseb@x{#1}\reset@color}%
    }%
  }{}%
}

\newcommand*{\globalcolor}{%
  \let\saved@set@color\set@color
  \def\set@color{%
    \saved@set@color
    \global\let\current@color\current@color
    \let\set@color\saved@set@color
  }%
  \color
}
\makeatother

\begin{document}
a \textcolor{blue}{b \globalcolor{red}c }d
\end{document}

Example

\pdfcolorstack could be disabled, then pdftex.def would automatically switch to the old behaviour. However this would also break other stuff not related to color (e.g. pdfrender, pdftransparent, …).

And this \globalcolor will not work for other drivers like dvips. Therefore I do not recommend this method.