%% %% pxpgftate.sty %% %% Support for PGF/TikZ in the vertical (tate) direction of %% pLaTeX and upLaTeX with the dvipdfmx and dvips drivers, %% for PGF versions without native support. %% %% Copyright (C) 2015-2026 Munehiro Yamamoto %% %% This file may be distributed and/or modified %% %% 1. under the LaTeX Project Public License, version 1.3c or later %% (https://www.latex-project.org/lppl.txt), and/or %% 2. under the GNU General Public License, version 2 or later, %% %% like PGF itself. %% \NeedsTeXFormat{pLaTeX2e} \ProvidesPackage{pxpgftate} [2026/11/04 v1.0 PGF/TikZ in the tate direction of (u)pLaTeX] %% ------------------------------------------------------------------ %% Engine check: \iftdir is a primitive of pTeX and upTeX. The test %% does not leave \iftdir defined as \relax on other engines. \begingroup\expandafter\expandafter\expandafter\endgroup \expandafter\ifx\csname iftdir\endcsname\relax \PackageWarningNoLine{pxpgftate}{% This package needs pTeX or upTeX.\MessageBreak Nothing is done}% \expandafter\endinput \fi \newif\ifpxpgftate@tate \newif\ifpxpgftate@applied \newif\ifpxpgftate@active \newbox\pxpgftate@box %% ------------------------------------------------------------------ %% Helpers % Rotation of a picture in the tate direction (dvipdfmx): the x-axis % points in the direction of the line (downwards), the y-axis to the % right. \def\pxpgftate@rotate{\special{pdf:code 0 -1 1 0 0 0 cm}} \def\pxpgftate@unrotate{\special{pdf:code 0 1 -1 0 0 0 cm}} % Undo the rotation around the current point (dvipdfmx). This uses % `pdf:bcontent' like PGF pictures themselves, since `pdf:btrans' of % dvipdfmx before TeX Live 2021 is misplaced inside `pdf:bcontent' and % in XObjects. \def\pxpgftate@bunrotate{% \special{pdf:bcontent}% \special{pdf:code 0 1 -1 0 0 0 cm}% } \def\pxpgftate@eunrotate{\special{pdf:econtent}} % Wrap the box #1 so that its contents are not rotated. \def\pxpgftate@unrotatebox#1{% \setbox#1\hbox{\pxpgftate@bunrotate\box#1\pxpgftate@eunrotate}% } % Determine the direction at the beginning of a picture. Inside a % tate picture the page (`current page') is rotated, too. \def\pxpgftate@beginpicture{% \iftdir \pxpgftate@tatetrue \expandafter\def\csname pgf@sh@nt@current page\endcsname {{0}{1}{-1}{0}{0pt}{0pt}}% \else \pxpgftate@tatefalse \expandafter\def\csname pgf@sh@nt@current page\endcsname {{1}{0}{0}{1}{0pt}{0pt}}% \fi } % Rotate a position \pgfqpoint{}{} on the page into the % coordinate system of a tate picture. Other values (undefined % positions, the page origin) are left alone. \def\pxpgftate@rotateposition#1{% \expandafter\pxpgftate@rotateposition@#1\@nil#1} \def\pxpgftate@rotateposition@#1#2\@nil#3{% \ifx\pgfqpoint#1% \pxpgftate@rotateposition@@#2#3% \fi } \def\pxpgftate@rotateposition@@#1#2#3{\def#3{\pgfqpoint{-#2}{#1}}} % Is #1 (a macro) the same string as #2? \def\pxpgftate@ifstr#1#2{% \edef\pxpgftate@tempa{\detokenize\expandafter{#1}}% \edef\pxpgftate@tempb{\detokenize{#2}}% \ifx\pxpgftate@tempa\pxpgftate@tempb \expandafter\@firstoftwo \else \expandafter\@secondoftwo \fi } %% ------------------------------------------------------------------ %% Patches for both drivers \def\pxpgftate@patch@common{% % Position tracking (remember picture, overlay). \ifx\pgfsys@getposition\@undefined\else \let\pxpgftate@orig@getposition\pgfsys@getposition \def\pgfsys@getposition##1##2{% \pxpgftate@orig@getposition{##1}##2% \ifpxpgftate@tate\pxpgftate@rotateposition##2\fi }% \fi % The material for the beginning of the page is always collected in % the yoko direction, since it is unboxed in the yoko direction at % shipout. \ifx\pgfutil@insertatbegincurrentpagefrombox\@undefined\else \let\pxpgftate@orig@insertfrombox\pgfutil@insertatbegincurrentpagefrombox \long\def\pgfutil@insertatbegincurrentpagefrombox##1{% \ifydir \pxpgftate@orig@insertfrombox{##1}% \else \setbox\pxpgftate@box\hbox{\yoko\pxpgftate@orig@insertfrombox{##1}}% \fi }% \fi % Fadings do not depend on the direction: set them yoko. \ifx\pgfdeclarefading\@undefined\else \let\pxpgftate@orig@declarefading\pgfdeclarefading \long\def\pgfdeclarefading##1##2{% \ifydir \pxpgftate@orig@declarefading{##1}{##2}% \else \setbox\pxpgftate@box\hbox{\yoko\pxpgftate@orig@declarefading{##1}{##2}}% \fi }% \fi \pxpgftate@patch@tikzfadings % LaTeX before 2020-10-01: the hooks of everyshi.sty (v3) are run in % the current direction. Run them in the yoko direction, as the % pxeveryshi package does. \@ifpackageloaded{pxeveryshi}{}{% \ifx\@EveryShipout@Output\@undefined\else \def\@EveryShipout@Output{% \setbox\pxpgftate@box\vbox{% \yoko \@EveryShipout@Hook \@EveryShipout@AtNextHook \global\setbox\@cclv=\box\@cclv }% \gdef\@EveryShipout@AtNextHook{}% \@EveryShipout@Org@Shipout\box\@cclv }% \fi }% } % The fadings library of TikZ builds the picture of a fading before % \pgfdeclarefading is called. \def\pxpgftate@patch@tikzfadings{% \ifx\tikzfadingfrompicture\@undefined\else \ifx\tikzfadingfrompicture\pxpgftate@tikzfadingfrompicture\else \let\tikzfadingfrompicture\pxpgftate@tikzfadingfrompicture \let\pxpgftate@orig@tikzfading\tikzfading \def\tikzfading[##1]{% \ifydir \pxpgftate@orig@tikzfading[##1]% \else \setbox\pxpgftate@box\hbox{\yoko\pxpgftate@orig@tikzfading[##1]}% \fi }% \fi \fi } \def\pxpgftate@tikzfadingfrompicture{% \begingroup \setbox\pgfpic=\hbox\bgroup \yoko \tikzpicture } %% ------------------------------------------------------------------ %% dvipdfmx: dvipdfmx places the characters rotated in the tate %% direction, but does not rotate the coordinate system of `pdf:code'. \def\pxpgftate@patch@dvipdfmx{% \let\pxpgftate@orig@beginpicture\pgfsys@beginpicture \def\pgfsys@beginpicture{% \pxpgftate@orig@beginpicture \pxpgftate@beginpicture \ifpxpgftate@tate\pxpgftate@rotate\fi }% \let\pxpgftate@orig@endpicture\pgfsys@endpicture \def\pgfsys@endpicture{% \ifpxpgftate@tate\pxpgftate@unrotate\fi \pxpgftate@orig@endpicture }% % Boxes in a picture: undo the rotation around the current point. \let\pxpgftate@orig@hbox\pgfsys@hbox \let\pxpgftate@orig@hboxsynced\pgfsys@hboxsynced \ifx\pgfsys@dvipdfmx@suspendcontent\@undefined % PGF 2.10 returns to the page coordinates with a trick that only % works if the picture is not rotated. Use the code of PGF 3.0 in % tate pictures instead. \let\pxpgftate@tate@hbox\pxpgftate@hbox@pgfiii \let\pxpgftate@tate@hboxsynced\pxpgftate@hboxsynced@pgfiii \else \let\pxpgftate@tate@hbox\pxpgftate@orig@hbox \let\pxpgftate@tate@hboxsynced\pxpgftate@orig@hboxsynced \fi \def\pgfsys@hbox##1{% \ifpxpgftate@tate \pxpgftate@unrotatebox##1% \pxpgftate@tate@hbox##1% \else \pxpgftate@orig@hbox##1% \fi }% \def\pgfsys@hboxsynced##1{% \ifpxpgftate@tate \pxpgftate@unrotatebox##1% \pxpgftate@tate@hboxsynced##1% \else \pxpgftate@orig@hboxsynced##1% \fi }% % Transparency groups: the only material placed in the picture is % the XObject. \ifx\pgfsys@transparencygroupfrombox\@undefined\else \let\pxpgftate@orig@transparencygroupfrombox\pgfsys@transparencygroupfrombox \def\pgfsys@transparencygroupfrombox##1{% \ifpxpgftate@tate\pxpgftate@bunrotate\fi \pxpgftate@orig@transparencygroupfrombox##1% \ifpxpgftate@tate\pxpgftate@eunrotate\fi }% \fi } % \pgfsys@hbox and \pgfsys@hboxsynced of pgfsys-dvipdfmx.def of PGF 3.0 % (copyright 2013 by Till Tantau and Jin-Hwan Cho), for tate pictures % with PGF 2.10. \def\pxpgftate@suspendcontent{% \special{pdf:code q -1 0 0 -1 0 0 cm q}% \special{pdf: econtent}% \special{pdf: bcontent}% \special{pdf:code -1 0 0 -1 0 0 cm}% \special{pdf:code q}% \special{pdf: econtent}% } \def\pxpgftate@unsuspendcontent{% \special{pdf: bcontent}% \special{pdf:code Q Q Q}% } \def\pxpgftate@start@force@reset@color{% \special{pdf:bcolor [1]}% \special{pdf:bcolor [0]}% } \def\pxpgftate@stop@force@reset@color{% \special{pdf:ecolor}% \special{pdf:ecolor}% } \def\pxpgftate@hbox@pgfiii#1{% \pgfsys@beginscope \setbox#1=\hbox{\box#1}% \wd#1=0pt \ht#1=0pt \dp#1=0pt \pxpgftate@suspendcontent \pgfsys@invoke{0 J [] 0 d}% \pxpgftate@start@force@reset@color \box#1% \pxpgftate@stop@force@reset@color \pxpgftate@unsuspendcontent \pgfsys@endscope } \def\pxpgftate@hboxsynced@pgfiii#1{% \pgfsys@beginscope \setbox#1=\hbox{\box#1}% \wd#1=0pt \ht#1=0pt \dp#1=0pt \pxpgftate@suspendcontent \pgfsys@invoke{0 J [] 0 d}% \pxpgftate@start@force@reset@color \pgf@sys@bp@correct\pgf@pt@x \pgf@sys@bp@correct\pgf@pt@y \special{pdf:btrans matrix \pgf@pt@aa\space \pgf@pt@ab\space \pgf@pt@ba\space \pgf@pt@bb\space \pgf@sys@tonumber{\pgf@pt@x} \pgf@sys@tonumber{\pgf@pt@y}}% \box#1% \special{pdf:etrans}% \pxpgftate@stop@force@reset@color \pxpgftate@unsuspendcontent \pgfsys@endscope } %% ------------------------------------------------------------------ %% dvips: dvips rotates the coordinate system of PostScript specials in %% the tate direction by itself. \def\pxpgftate@patch@dvips{% \let\pxpgftate@orig@beginpicture\pgfsys@beginpicture \def\pgfsys@beginpicture{% \pxpgftate@orig@beginpicture \pxpgftate@beginpicture }% } %% ------------------------------------------------------------------ %% Apply the patches once PGF has been loaded. \def\pxpgftate@apply{% \ifpxpgftate@applied\else \ifx\pgfsys@beginpicture\@undefined \PackageWarningNoLine{pxpgftate}{% PGF is not loaded.\MessageBreak Nothing is done}% \else \global\pxpgftate@appliedtrue \ifx\pgfsys@ptex@tate@supported\@undefined \pxpgftate@ifstr\pgfsysdriver{pgfsys-dvipdfmx.def}{% \global\pxpgftate@activetrue \pxpgftate@patch@dvipdfmx \pxpgftate@patch@common \PackageInfo{pxpgftate}{Patched the dvipdfmx driver}% }{% \pxpgftate@ifstr\pgfsysdriver{pgfsys-dvips.def}{% \global\pxpgftate@activetrue \pxpgftate@patch@dvips \pxpgftate@patch@common \PackageInfo{pxpgftate}{Patched the dvips driver}% }{% \PackageInfo{pxpgftate}{% The driver \pgfsysdriver\space is not supported.\MessageBreak Nothing is done}% }% }% \else \PackageInfo{pxpgftate}{% PGF supports the tate direction itself.\MessageBreak Nothing is done}% \fi \fi \fi } % The fadings library may be loaded after this package. \def\pxpgftate@atbegindocument{% \pxpgftate@apply \ifpxpgftate@active\pxpgftate@patch@tikzfadings\fi } \ifx\pgfsys@beginpicture\@undefined \AtBeginDocument{\pxpgftate@atbegindocument} \else \pxpgftate@apply \AtBeginDocument{\pxpgftate@atbegindocument} \fi \endinput %% %% End of file `pxpgftate.sty'.