%%
%% 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{<x>}{<y>} 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'.
