https://github.com/latex3/latex2e
Tip revision: 677a0faec3ada45402c67ba34d9a34e3dd9d5479 authored by Joseph Wright on 30 November 2022, 21:06:22 UTC
Step release tag
Step release tag
Tip revision: 677a0fa
ltshipout.dtx
% \iffalse meta-comment
%%
%% Copyright (C) 2020-2022
%% Frank Mittelbach, LaTeX Team
%%
%
% This file is part of the LaTeX base system.
% -------------------------------------------
%
% It may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3c
% of this license or (at your option) any later version.
% The latest version of this license is in
% https://www.latex-project.org/lppl.txt
% and version 1.3c or later is part of all distributions of LaTeX
% version 2008 or later.
%
% This file has the LPPL maintenance status "maintained".
%
% The list of all files belonging to the LaTeX base distribution is
% given in the file `manifest.txt'. See also `legal.txt' for additional
% information.
%
% The list of derived (unpacked) files belonging to the distribution
% and covered by LPPL is defined by the unpacking scripts (with
% extension .ins) which are part of the distribution.
%
% \fi
%
% \iffalse
%
%%% From File: ltshipout.dtx
%
% \begin{macrocode}
\providecommand\ltshipoutversion{v1.0m}
\providecommand\ltshipoutdate{2022/08/26}
% \end{macrocode}
%
%<*driver>
\documentclass{l3doc}
% bug fix fo l3doc.cls
\ExplSyntaxOn
\cs_set_protected:Npn \__codedoc_macro_typeset_one:nN #1#2
{
\vbox_set:Nn \l__codedoc_macro_box
{
\vbox_unpack_drop:N \l__codedoc_macro_box
\hbox { \llap { \__codedoc_print_macroname:nN {#1} #2
\MacroFont % <----- without it the \ is in lmr10 if a link is made
\
} }
}
\int_incr:N \l__codedoc_macro_int
}
\ExplSyntaxOff
\providecommand\InternalDetectionOff{}
\providecommand\InternalDetectionOn{}
\EnableCrossrefs
\CodelineIndex
\begin{document}
\DocInput{ltshipout.dtx}
\end{document}
%</driver>
%
% \fi
%
%
% \long\def\fmi#1{\begin{quote}\itshape Todo: #1\end{quote}}
%
% \providecommand\hook[1]{\texttt{#1}}
% \providecommand\pkg[1]{\texttt{#1}}
%
%
% \title{The \texttt{ltshipout} package\thanks{This package has version
% \ltshipoutversion\ dated \ltshipoutdate, \copyright\ \LaTeX\
% Project.}}
%
% \author{Frank Mittelbach, \LaTeX{} Project Team}
%
% \maketitle
%
%
% \tableofcontents
%
% \section{Introduction}
%
% The code provides an interface to the \cs{shipout} primitive of
% \TeX{} which is called when a finished pages is finally
% \enquote{shipped out} to the target output file, e.g., the
% \texttt{.dvi} or \texttt{.pdf} file.
% A good portion of the code is based on ideas by Heiko Oberdiek
% implemented in his packages \pkg{atbegshi} and \pkg{atenddvi}
% even though the interfaces are somewhat
% different.\footnote{Heiko's interfaces are emulated by the kernel
% code, if a document requests his packages, so older documents
% will continue to work.}
%
% \subsection{Overloading the \cs{shipout} primitive}
%
%
% \begin{function}{\shipout}
% With this implementation \TeX's shipout primitive is no longer
% available for direct use. Instead \cs{shipout} is running some
% (complicated) code that picks up the box to be shipped out
% regardless of how that is done, i.e., as a constructed \cs{vbox}
% or \cs{hbox} or as a box register.
%
% It then stores it in a named box register. This box can then be
% manipulated through a set of hooks after which it is shipped out
% for real.
%
% Each shipout that actually happens (i.e., where the material is
% not discarded for one or the other reason) is recorded and the
% total number is available in a readonly variable and in a
% \LaTeX{} counter.
% \end{function}
%
%
% \begin{function}{\RawShipout}
% This command implements a simplified shipout that bypasses the
% foreground and background
% hooks, e.g., only \hook{shipout/firstpage} and
% \hook{shipout/lastpage} are executed and the total shipout
% counters are incremented.
%
% The command doesn't use \cs{ShipoutBox} but its own private box
% register so that it can be used inside of shipout hooks to do
% some additional shipouts while already in the output routine with
% the current page being stored in \cs{ShipoutBox}. It does have
% access to \cs{ShipoutBox} if it is used in \hook{shipout/before}
% (or \hook{shipout/after}) and can use its content.
%
% It is safe to use it in \hook{shipout/before} or
% \hook{shipout/after} but not necessarily in the other
% \hook{shipout/...} hooks as they are intended for special
% processing.
% \end{function}
%
% \begin{variable}{\ShipoutBox,\l_shipout_box}
% This box register is called \cs{ShipoutBox} (alternatively
% available via the L3 name \cs{l_shipout_box}).
%
% This box is a ``local'' box and assignments to it should be done
% only locally. Global assignments (as done by some packages with
% older code where this is box is known as 255) may work but they are
% conceptually wrong and may result in errors under certain
% circumstances.
%
% During the execution of \hook{shipout/before} this box contains
% the accumulated material for the page, but not yet any material
% added by other shipout hooks.
% During execution of \hook{shipout/after}, i.e., after the shipout
% has happened, the box also contains any background or foreground
% material.
%
% Material from the hooks \hook{shipout/firstpage} or
% \hook{shipout/lastpage} is not included (but only used during the
% actual shipout) to facilitate reuse of the box data (e.g.,
% \hook{shipout/firstpage} material should never be added to a
% later page of the output).
% \end{variable}
%
%
% \begin{variable}{\l_shipout_box_ht_dim,
% \l_shipout_box_dp_dim,\l_shipout_box_wd_dim,
% \l_shipout_box_ht_plus_dp_dim}
% The shipout box dimensions are available in the L3 registers
% \cs{l_shipout_box_ht_dim}, etc.\ (there are no \LaTeXe{}
% names).\footnotemark{} These variables can be used
% inside the hook code for \hook{shipout/before},
% \hook{shipout/foreground} and \hook{shipout/background} if needed.
% \end{variable}
% \footnotetext{Might need changing, but HO's version as strings
% is not really helpful I think).}
%
%
%
%
% \subsection{Provided hooks}
%
% \begin{variable}{shipout/before,shipout/after,
% shipout/foreground,shipout/background,
% shipout/firstpage,
% shipout/lastpage}
% The code for \cs{shipout} offers a number of hooks into which packages (or the
% user) can add code to support different use cases.
% These are:
% \begin{description}
% \item[\hook{shipout/before}]
%
% This hook is executed after the finished page has been stored in
% \cs{ShipoutBox} / \cs{l_shipout_box}).
% It can be used to alter that box content or to discard it
% completely (see \cs{DiscardShipoutBox} below).
%
% You can use \cs{RawShipout} inside this hook for special use
% cases. It can make use of \cs{ShipoutBox} (which doesn't yet
% include the background and foreground material).
%
% \textbf{Note:} It is not possible (or say advisable) to try
% and use this hook to typeset material with the intention to
% return it to main vertical list, it will go wrong and give
% unexpected results in many cases---for starters it will appear
% after the current page not before or it will vanish or the
% vertical spacing will be wrong!
% \end{description}
% \end{variable}
%
% \begin{description}
% \item[\hook{shipout/background}]
%
% This hook adds a picture environment into the background of
% the page with the \texttt{(0,0)} coordinate in the top-left
% corner using a \cs{unitlength} of \texttt{1pt}.
%
% It should therefore only receive \cs{put} commands or other
% commands suitable in a \texttt{picture} environment and the
% vertical coordinate values would normally be
% negative.
%
% Technically this is implemented by adding a zero-sized
% \cs{hbox} as the very first item into the \cs{ShipoutBox}
% containing that \texttt{picture} environment. Thus the rest of
% the box content will overprint what ever is typeset by that hook.
%
%
% \item[\hook{shipout/foreground}]
%
% This hook adds a picture environment into the foreground of
% the page with the \texttt{(0,0)} coordinate in the top-left
% corner using a \cs{unitlength} of \texttt{1pt}.
%
% Technically this is implemented by adding a zero-sized
% \cs{hbox} as the very last item into the \cs{ShipoutBox} and
% raising it up so that it still has its \texttt{(0,0)} point in
% the top-left corner.
% But being placed after the main box content it will be typeset
% later and thus overprints it (i.e., is in the foreground).
%
%
% \item[\hook{shipout/firstpage}]
%
% The material from this hook is executed only once at the very
% beginning of the first output page that is shipped out (i.e.,
% not discarded at the last minute). It should only contain
% \cs{special} or similar commands needed to direct post processors
% handling the \texttt{.dvi} or \texttt{.pdf} output.\footnotemark
% \footnotetext{In
% \LaTeXe{} that was already existing, but implemented using a box
% register with the name \cs{@begindvibox}.}
%
% ^^A \fmi{not sure it has to be that restrictive.}
%
% This hook is added to the very first page regardless of how it
% is shipped out (i.e., with \cs{shipout} or \cs{RawShipout}).
%
% \item[\hook{shipout/lastpage}]
%
% The corresponding hook to add \cs{special}s at the very end of
% the output file. It is only executed on the very last page of
% the output file ---
% or rather on the page that \LaTeX{} believes is the last one.
% Again it is executed regardless of the shipout method.
%
% It may not be possible for \LaTeX{} to correctly determine
% which page is the last one without several reruns. If this
% happens and the hook is non-empty then \LaTeX{} will add an
% extra page to place the material and also request a rerun to
% get the correct placement sorted out.
%
% \item[\hook{shipout/after}]
%
% This hook is executed after a shipout has happened. If the
% shipout box is discarded this hook is not looked at.
%
% You can use \cs{RawShipout} inside this hook for special use
% cases and the main \cs{ShipoutBox} is still available at this
% point (but in contrast to \hook{shipout/before} it now
% includes the background and foreground material).
%
% \textbf{Note:} Just like \hook{shipout/before} this hook is
% not meant to be used for adding typeset material back
% to the main vertical list---it might vanish or the
% vertical spacing will be wrong!
%
%
% \end{description}
%
% As mentioned above the hook \hook{shipout/before} is executed
% first and can manipulate the prepared shipout box stored in
% \cs{ShipoutBox} or set things up for use in \cs{write} during the
% actual shipout. It is even run if there was a
% \cs{DiscardShipoutBox} request in the document.
%
% The other hooks (except \hook{shipout/after}) are added inside
% hboxes to the box being shipped out in the following order:
% \begin{center}
% \begin{tabular}{ll}
% \hook{shipout/firstpage} & only on the first page \\
% \hook{shipout/background} & \\
% \meta{boxed content of \cs{ShipoutBox}} & \\
% \hook{shipout/foreground} & \\
% \hook{shipout/lastpage} & only on the last page \\
% \end{tabular}
% \end{center}
% If any of the hooks has no code then that particular no box is
% added at that point.
%
% Once the (page) box has been shipped out the \hook{shipout/after}
% hook is called (while you are still inside the output routine). It
% is not called if the shipout box was discarded.
%
% In a document that doesn't produce pages, e.g., only makes
% \cs{typeout}s, none of the hooks are ever executed (as there is no
% \cs{shipout}) not even the \hook{shipout/lastpage} hook.
%
% If \cs{RawShipout} is used instead of \cs{shipout} then only the
% hooks \hook{shipout/firstpage} and \hook{shipout/lastpage} are
% executed (on the first or last page), all others are bypassed.
%
%
%
% \subsection{Legacy \LaTeX{} commands}
%
% \begin{function}{\AtBeginDvi,\AtEndDvi}
% \begin{syntax}
% \cs{AtBeginDvi} \Arg{code}
% \end{syntax}
% \cs{AtBeginDvi} is the existing \LaTeXe{} interface to fill the
% \hook{shipout/firstpage} hook. This is not really a good name
% as it is not just supporting \texttt{.dvi} but also \texttt{.pdf}
% output or \texttt{.xdv}.
%
% \cs{AtEndDvi} is the counterpart that was not available in the
% kernel but only through the package \pkg{atenddvi}. It fills the
% \hook{shipout/lastpage} hook.
%
% Neither interface can set a code label but uses the current default label.
%
% \end{function}
%
% As these two wrappers have been available for a long time we
% continue offering them (but not enhancing them, e.g., by providing
% support for code labels).
%
% For new code we strongly suggest using the high-level hook
% management commands directly instead of ``randomly-named''
% wrappers. This will lead to code that is easier to understand
% and to maintain and it also allows you to set code labels if
% needed.
%
% For this reason we do not provide any other ``new'' wrapper
% commands for the above hooks in the kernel, but only keep
% the existing ones for backward compatibility.
%
%
% \subsection{Special commands for use inside the hooks}
%
% \begin{function}{\DiscardShipoutBox,\shipout_discard:}
% \begin{syntax}
% \cs{AddToHookNext} \texttt{\{shipout/before\} \{...\cs{DiscardShipoutBox}...\}}
% \end{syntax}
% The \cs{DiscardShipoutBox} declaration (L3 name
% \cs{shipout_discard:})
% requests that on the next
% shipout the page box is thrown away instead of being shipped to
% the \texttt{.dvi} or \texttt{.pdf} file.
%
% Typical applications wouldn't do this unconditionally, but have
% some processing logic that decides to use or not to use the page.
%
% Note that if this declaration is used directly in the document it
% may depend on the placement to which page it applies, given that
% \LaTeX{} output routine is called in an asynchronous manner!
% Thus normally one would use this only as part of the
% \hook{shipout/before} code.
%
% \fmi{Once we have a new mark mechanism available we can improve
% on that and make sure that the declaration applies to the page
% that contains it.}
% \end{function}
%
% In the \pkg{atbegshi} package there are a number of additional
% commands for use inside the \hook{shipout/before} hook. They
% should normally not be needed any more as one can instead simply
% add code to the hooks \hook{shipout/before},
% \hook{shipout/background} or
% \hook{shipout/foreground}.\footnote{If that assumption turns out to
% be wrong it would be trivial to change them to public functions
% (right now they are private).} If \pkg{atbegshi} gets loaded then
% those commands become available as public functions with their original
% names as given below.
%
%
%
% \subsection{Provided Lua\TeX\ callbacks}
%
% \begin{variable}{pre_shipout_filter}
% Under Lua\TeX{} the \texttt{pre\_shipout\_filter} Lua callback is
% provided which gets called immediately before the shipout primitive gets invoked.
% The signature is
% \begin{verbatim}
% function(<node> head)
% return true
% end
% \end{verbatim}
% The \texttt{head} is the list node corresponding to the box to be shipped out.
% The return value should always be \texttt{true}.
% \end{variable}
%
% \subsection{Information counters}
%
%
% \begin{variable}{\ReadonlyShipoutCounter,\g_shipout_readonly_int}
% \begin{syntax}
% \cs{ifnum}\cs{ReadonlyShipoutCounter}\texttt{=...}
% \cs{int_use:N} \cs{g_shipout_readonly_int} \texttt{\% expl3 usage}
% \end{syntax}
% This integer holds the number of pages shipped out up to now
% (including the one to be shipped out when inside the output
% routine). More precisely, it is incremented only after it is
% clear that a page will be shipped out, i.e., after the
% \hook{shipout/before} hook (because that might discard the page)!
% In contrast \hook{shipout/after} sees the incremented value.
%
% Just like with the \texttt{page} counter its value is
% only accurate within the output routine. In the body of the
% document it may be off by one as the output routine is called
% asynchronously!
%
% Also important: it \emph{must not} be set, only read. There are
% no provisions to prevent that restriction, but if you manipulate
% it, chaos will be the result. To emphasize this fact it is not
% provided as a \LaTeX{} counter but as a \TeX{} counter (i.e., a
% command), so \cs{Alph}\verb={=\cs{ReadonlyShipoutCounter}\verb=}=
% etc, would not work.
% \end{variable}
%
% \begin{variable}{totalpages,\g_shipout_totalpages_int}
% \begin{syntax}
% \cs{arabic}\texttt{\{totalpages\}}
% \cs{int_use:N} \cs{g_shipout_totalpage_int} \texttt{\% expl3 usage}
% \end{syntax}
% In contrast to \cs{ReadonlyShipoutCounter}, the
% \texttt{totalpages} counter is a \LaTeX{} counter and incremented
% for each shipout attempt including those pages that are discarded
% for one or the other reason. Again \hook{shipout/before} sees
% the counter before it is incremented. In contrast
% \hook{shipout/after} sees the incremented value.
%
% Furthermore, while it is incremented for each page, its value is
% never used by \LaTeX. It can therefore be freely reset or changed by user
% code, for example, to additionally count a number of pages that
% are not build by \LaTeX\ but are added in a later part of the
% process, e.g., cover pages or picture pages made externally.
%
% Important: as this is a page-related counter its value is only
% reliable inside the output routine!
% \end{variable}
%
% \begin{variable}{\PreviousTotalPages}
% \begin{syntax}
% \cs{thetotalpages}/\cs{PreviousTotalPages}
% \end{syntax}
% Command that expands to the number of total pages from the
% previous run. If there was no previous run or if used in the
% preamble it expands to
% \texttt{0}. Note that this is a command and not a counter, so in order
% to display the number in, say, Roman numerals you have to assign
% its value to a counter and then use \cs{Roman} on that counter.
% \end{variable}
%
%
% \subsection{Debugging shipout code}
%
% \begin{function}{\DebugShipoutsOn,\DebugShipoutsOff,
% \shipout_debug_on:,\shipout_debug_off:}
% \begin{syntax}
% \cs{DebugShipoutsOn}
% \end{syntax}
% Turn the debugging of shipout code on or off. This displays
% changes made to the shipout data structures. \fmi{This needs
% some rationalizing and may not stay this way.}
% \end{function}
%
%
%
%
% \section{Emulating commands from other packages}
%
% The packages in this section are no longer necessary, but as they
% are used by other packages, they are emulated when they are
% explicitly loaded with \cs{usepackage} or \cs{RequirePackage}.
%
% Please note that the emulation only happens if the package is
% explicitly requested, i.e., the commands documented below are not
% automatically available in the \LaTeX{} kernel! If you write a
% new package we suggest to use the appropriate kernel hooks
% directly instead of loading the emulation.
%
%
% \subsection{Emulating \pkg{atbegshi}}
%
%
% \begin{function}{\AtBeginShipoutUpperLeft,\AtBeginShipoutUpperLeftForeground}
% \begin{syntax}
% \cs{AddToHook} \texttt{\{shipout/before\} \{...\cs{AtBeginShipoutUpperLeft}}\Arg{code}\texttt{...\}}
% \end{syntax}
% This adds a \texttt{picture} environment into the background of the shipout
% box expecting \meta{code} to contain \texttt{picture}
% commands. The same effect can be obtained by simply using kernel
% features as follows:
% \begin{quote}
% \cs{AddToHook}\texttt{\{shipout/background\}}\Arg{code}
% \end{quote}
% There is one technical difference: if
% \cs{AtBeginShipoutUpperLeft} is used several times each
% invocation is put into its own box inside the shipout box whereas
% all \meta{code} going into \hook{shipout/background} ends up
% all in the same box in the order it is added or sorted based on
% the rules for the hook chunks.
%
% \cs{AtBeginShipoutUpperLeftForeground} is similar with the
% difference that the \texttt{picture} environment is placed in the
% foreground. To model it with the kernel functions use the hook
% \hook{shipout/foreground} instead.
% \end{function}
%
%
% \begin{function}{\AtBeginShipoutAddToBox,\AtBeginShipoutAddToBoxForeground}
% \begin{syntax}
% \cs{AddToHook} \texttt{\{shipout/before\} \{...\cs{AtBeginShipoutAddToBox}}\Arg{code}\texttt{...\}}
% \end{syntax}
% These work like \cs{AtBeginShipoutUpperLeft} and
% \cs{AtBeginShipoutUpperLeftForeground} with the difference that
% \meta{code} is directly placed into an \cs{hbox} inside the
% shipout box and not surrounded by a \texttt{picture} environment.
%
% To emulate them using \hook{shipout/background} or
% \hook{shipout/foreground} you may have to wrap \meta{code} into
% a \cs{put} statement but if the code is not doing any typesetting
% just adding it to the hook should be sufficient.
% \end{function}
%
%
%
% \begin{function}{\AtBeginShipoutBox}
% This is the name of the shipout box as \pkg{atbegshi} knows it.
% \end{function}
%
%
% \begin{function}{\AtBeginShipoutOriginalShipout}
% This is the name of the \cs{shipout} primitive as \pkg{atbegshi}
% knows it. This bypasses all the mechanisms set up by the \LaTeX{}
% kernel and there are various scenarios in which it can therefore
% fail. It should only be used to run existing legacy
% \pkg{atbegshi} code but not in newly developed applications.
%
% The kernel alternative is \cs{RawShipout} which is integrated
% with the \LaTeX{} mechanisms and updates, for example, the
% \cs{ReadonlyShipoutCounter} counter. Please use \cs{RawShipout}
% for new code if you want to bypass the before, foreground and
% background hooks.
% \end{function}
%
% \begin{function}{\AtBeginShipoutInit}
% By default \pkg{atbegshi} delayed its action until
% \verb=\begin{document}=. This command was forcing it in an earlier
% place. With the new concept it does nothing.
% \end{function}
%
% \begin{function}{\AtBeginShipout,\AtBeginShipoutNext}
% \begin{syntax}
% \cs{AtBeginShipout}\Arg{code} $\equiv$ \cs{AddToHook}\texttt{\{shipout/before\}}\Arg{code}
% \cs{AtBeginShipoutNext}\Arg{code} $\equiv$ \cs{AddToHookNext}\texttt{\{shipout/before\}}\Arg{code}
% \end{syntax}
% This is equivalent to filling the \hook{shipout/before} hook
% by either using \cs{AddToHook} or \cs{AddToHookNext}, respectively.
% \end{function}
%
% \begin{function}{\AtBeginShipoutFirst,\AtBeginShipoutDiscard}
% The \pkg{atbegshi} names for \cs{AtBeginDvi} and \cs{DiscardShipoutBox}.
% \end{function}
%
%
%
%
% \subsection{Emulating \pkg{everyshi}}
%
% The \pkg{everyshi} package is providing commands to run arbitrary
% code just before the shipout starts.
% One point of difference: in the new shipout hooks the page is
% available as \cs{ShipoutBox} for inspection of change, one should
% not manipulate box 255 directly inside \hook{shipout/before}, so
% old code doing this would change to use \cs{ShipoutBox} instead
% of \texttt{255} or \cs{@cclv}.
%
% \begin{function}{\EveryShipout}
% \begin{syntax}
% \cs{EveryShipout}\Arg{code} $\equiv$ \cs{AddToHook}\texttt{\{shipout/before\}}\Arg{code}
% \end{syntax}
% \end{function}
%
% \begin{function}{\AtNextShipout}
% \begin{syntax}
% \cs{AtNextShipout}\Arg{code} $\equiv$ \cs{AddToHookNext}\texttt{\{shipout/before\}}\Arg{code}
% \end{syntax}
% \end{function}
%
% However, most use cases for \pkg{everyshi} are attempts to put
% some picture or text into the background or foreground of the page
% and that can be done today simply by using the
% \hook{shipout/background} and
% \hook{shipout/foreground} hooks without any need to coding.
%
%
% \subsection{Emulating \pkg{atenddvi}}
%
% The \pkg{atenddvi} package implemented only a single command:
% \cs{AtEndDvi} and that is now available out of the box so the
% emulation makes the package a no-op.
%
%
%
% \subsection{Emulating \pkg{everypage}}
%
% This package patched the original \cs{@begindvi} hook and replaced
% it with its own version.
% Its functionality is now covered by the hooks offered by the
% kernel so that there is no need for such patching any longer.
%
% \begin{function}{\AddEverypageHook}
% \begin{syntax}
% \cs{AddEverypageHook}\Arg{code} $\equiv$
% \qquad\cs{AddToHook}\texttt{\{shipout/background\}\{\cs{put}(1in,-1in)\Arg{code}\}}
% \end{syntax}
% \cs{AddEverypageHook} is adding something into the
% background of every page at a position of 1in to the right and
% 1in down from the top left corner of the page.
% By using the kernel hook directly you can put your material
% directly to the right place, i.e., use other coordinates in the
% \cs{put} statement above.
% \end{function}
%
% \begin{function}{\AddThispageHook}
% \begin{syntax}
% \cs{AddThispageHook}\Arg{code} $\equiv$
% \qquad\cs{AddToHookNext}\texttt{\{shipout/background\}\{\cs{put}(1in,-1in)\Arg{code}\}}
% \end{syntax}
% The \cs{AddThispageHook} wrapper is similar but uses
% \cs{AddToHookNext}.
% \end{function}
%
%
% \MaybeStop{\setlength\IndexMin{200pt} \PrintIndex }
%
%
% \section{The Implementation}
% \begin{macrocode}
%<@@=shipout>
% \end{macrocode}
%
% At the moment the whole module rolls back in one go, but if we
% make any modifications in later releases this will then need
% splitting.
% \begin{macrocode}
%<*2ekernel|latexrelease>
%<latexrelease>\IncludeInRelease{2020/10/01}%
%<latexrelease> {\shipout}{Hook management (shipout)}%
% \end{macrocode}
%
%
% \begin{macrocode}
\ExplSyntaxOn
% \end{macrocode}
%
%
% \subsection{Debugging}
%
% \begin{macro}{\g_@@_debug_bool}
% Holds the current debugging state.
% \begin{macrocode}
\bool_new:N \g_@@_debug_bool
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\shipout_debug_on:,\shipout_debug_off:}
% \begin{macro}{\@@_debug:n}
% \begin{macro}{\@@_debug_gset:}
% Turns debugging on and off by redefining \cs{@@_debug:n}.
% \begin{macrocode}
\cs_new_eq:NN \@@_debug:n \use_none:n
\cs_new_protected:Npn \shipout_debug_on:
{
\bool_gset_true:N \g_@@_debug_bool
\@@_debug_gset:
}
\cs_new_protected:Npn \shipout_debug_off:
{
\bool_gset_false:N \g_@@_debug_bool
\@@_debug_gset:
}
\cs_new_protected:Npn \@@_debug_gset:
{
\cs_gset_protected:Npx \@@_debug:n ##1
{ \bool_if:NT \g_@@_debug_bool {##1} }
}
% \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
%
%
%
%
% \begin{macro}{\ShipoutBox,\l_shipout_box}
% The box filled with the page to be shipped out (both L3 and
% \LaTeXe{} name).
% \begin{macrocode}
\box_new:N \l_shipout_box
% \end{macrocode}
%
% \begin{macrocode}
\cs_set_eq:NN \ShipoutBox \l_shipout_box
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\l_@@_raw_box}
% The \cs{RawShipout} gets its own box but it is internal as there
% is no hook manipulation for it.
% \begin{macrocode}
\box_new:N \l_@@_raw_box
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_finalize_box:}
% For Lua\TeX{} invoke the \texttt{pre\_shipout\_filter} callback.
% \changes{v1.0i}{2021/01/22}{Add \texttt{pre\_shipout\_filter} Lua callback}
% \begin{macrocode}
\sys_if_engine_luatex:TF
{
\newprotectedluacmd \@@_finalize_box:
\exp_args:Nx \everyjob {
\exp_not:V \everyjob
\exp_not:N \lua_now:n {
luatexbase.create_callback('pre_shipout_filter', 'list')
local~call, getbox, setbox = luatexbase.call_callback, tex.getbox, tex.setbox~
lua.get_functions_table()[\the \allocationnumber] = function()
local~head = getbox(\the \l_shipout_box)
local~result = call('pre_shipout_filter', head)
if~not (result == head) then~
setbox(\the \l_shipout_box, result~or~nil)
end~
end
}
}
} {
\cs_set_eq:NN \@@_finalize_box: \scan_stop:
}
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_execute:}
% This is going to the be the code run by \cs{shipout}. The code
% follows closely the ideas from \pkg{atbegshi}, so not
% documenting that here for now.
% \begin{macrocode}
\cs_set_protected:Npn \@@_execute: {
\tl_set:Nx \l_@@_group_level_tl
{ \int_value:w \tex_currentgrouplevel:D }
\tex_afterassignment:D \@@_execute_test_level:
\tex_setbox:D \l_shipout_box
}
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\shipout}
% Overloading the \cs{shipout} primitive:
% \begin{macrocode}
\cs_gset_eq:NN \shipout \@@_execute:
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\l_@@_group_level_tl}
% Helper token list to record the group level at which
% \cs{@@_execute:} is encountered.
% \begin{macrocode}
\tl_new:N \l_@@_group_level_tl
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_execute_test_level:}
% If the group level has changed then we are still constructing
% \cs{l_shipout_box} and to continue we need to wait until the
% current group has finished, hence the \cs{tex_aftergroup:D}.
% \begin{macrocode}
\cs_new:Npn \@@_execute_test_level: {
\int_compare:nNnT
\l_@@_group_level_tl < \tex_currentgrouplevel:D
\tex_aftergroup:D \@@_execute_cont:
}
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_execute_cont:}
% This does the actual shipout running several hooks as part of it.
% The code for them is passed as argument \verb=#2= to \verb=#4=
% to \cs{@@_execute_main_cont:Nnnn}; the first argument is the box
% to be shipped out.
% \begin{macrocode}
\cs_new:Npn \@@_execute_cont: {
\@@_execute_main_cont:Nnnn
\l_shipout_box
{ \hook_use:n {shipout/before} }
{ \hook_if_empty:nF {shipout/foreground}
{ \@@_add_foreground_picture:n
{ \hook_use:n {shipout/foreground} } }
% \end{macrocode}
% If the user hook for the background (\hook{shipout/background}) has
% no code, there might still code in the kernel hook so we need to
% test for this too.
% We only test for the \cs{@kernel@before@shipout@background}
% though. If the \cs{@kernel@after@shipout@background} needs
% executing even if the user hook is empty then we can add another
% test (or the kernel could put something into the before hook).
%
% \changes{v1.0d}{2020/11/23}{Check for both kernel and user hook (gh/431)}
% \changes{v1.0f}{2021/01/08}{Added another kernel hook for more
% flexibility (cf \texttt{https://github.com/pgf-tikz/pgf/issues/960}}
% \begin{macrocode}
\bool_lazy_and:nnF
{ \hook_if_empty_p:n {shipout/background} }
{ \tl_if_empty_p:N \@kernel@before@shipout@background }
{ \@@_add_background_picture:n
{ \@kernel@before@shipout@background
\hook_use:n {shipout/background}
\@kernel@after@shipout@background }
}
}
{ \hook_use:n {shipout/after} }
}
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_execute_main_cont:Nnnn}
% When we have reached this point the shipout box has been
% processed and is available in \cs{l_shipout_box} and ready for
% real ship out (unless it gets discarded during the process).
%
% The three arguments hold hook code that is executed just before the
% actual shipout (\verb=#1=), within the shipout adding
% background and foreground material (\verb=#2=) and after the
% shipout has happened (\verb=#3=).
% These are passed as arguments because the same code without those
% hooks is also used when doing a ``raw'' shipout implemented by
% \cs{RawShipout}.
% The only hook that is always executed is that for the very last
% page, i.e., \hook{shipout/lastpage}.
%
% First we quickly check if it is void (can't happen in the
% standard \LaTeX{} output routine but \cs{shipout} might be called
% from a package that has some special processing logic). If it is
% void we aren't shipping anything out and processing ends.\footnote{In that
% case we don't reset the deadcycles, that would be up to the OR
% processing logic to do.}
% \begin{macrocode}
\cs_new:Npn \@@_execute_main_cont:Nnnn #1#2#3#4 {
\box_if_empty:NTF #1
{ \@latex@warning@no@line{ Ignoring~ void~ shipout~ box } }
{
% \end{macrocode}
% Otherwise we assume that we will ship something and prepare for
% final adjustments (in particular setting the state of
% \cs{protect} while we are running the hook code).
% We also save the current \cs{protect} state to restore it later.
% \begin{macrocode}
% \bool_gset_false:N \g_@@_discard_bool % setting this would disable
% \DiscardShipoutBox on doc-level
\cs_set_eq:NN \@@_saved_protect: \protect
\set@typeset@protect
% \end{macrocode}
% We also store the current shipout box dimension in registers, so that
% they can be used in the hook code.\footnote{This is not really
% necessary as the code could access them via \cs{box_ht:N}, etc.,
% but it is perhaps convenient.}
% \begin{macrocode}
\@@_get_box_size:N #1
% \end{macrocode}
% Then we execute the \hook{shipout/before} hook (or nothing in
% case of \cs{RawShipout}).
% \begin{macrocode}
#2
% \end{macrocode}
% In \cs{g_shipout_totalpages_int} we count all shipout attempts so
% we increment that counter already here (the other one is
% incremented later when we know for sure that we do a
% \cs{shipout}.
%
% We increment it after running the above hook so that the values
% for \cs{g_shipout_totalpages_int} and \cs{g_shipout_readonly_int}
% are in sync while the
% hook is executed (in the case that totalpages isn't manually
% altered or through discarding pages that is).
% \begin{macrocode}
\int_gincr:N \g_shipout_totalpages_int
% \end{macrocode}
% The above hook might contain code that requests the page to be discarded so
% we now test for it.
% \begin{macrocode}
\bool_if:NTF \g_@@_discard_bool
{ \@latex@info@no@line{Completed~ page~ discarded}
\bool_gset_false:N \g_@@_discard_bool
% \end{macrocode}
% As we are discarding the page box and not shipping anything out,
% we need to do some house cleaning and reset \TeX's deadcycles so
% that it doesn't complain about too many calls to the OR without
% any shipout.
% \begin{macrocode}
\tex_deadcycles:D \c_zero_int
% \end{macrocode}
% \fmi{In \pkg{atbegshi} the box was dropped but is that actually
% needed? Or the resetting of \cs{protect} to its kernel value?}
% \begin{macrocode}
% \group_begin:
% \box_set_eq_drop:NN #1 #1
% \group_end:
% \cs_set_eq:NN \protect \exp_not:N
}
% \end{macrocode}
% Even if there was no explicit request to discard the box it is
% possible that the code for the hook \hook{shipout/before} has
% voided the box (by mistake or deliberately). We therefore test
% once more but this time make it a warning, because the best
% practice way is to use the request mechanism.
% \begin{macrocode}
{ \box_if_empty:NTF #1
{ \@latex@warning@no@line { Ignoring~ void~ shipout~ box.
\MessageBreak The~ shipout~ box~ was~ voided~ by~ hook~ code }
}
% \end{macrocode}
% Finally, if the box is still non-empty we are nearly ready to
% ship it out.
% First we increment the total page counter so that we can later
% test if we have reached the final page according to our available
% information.\footnote{Doing that earlier would be wrong because we
% might end up with the last page counted but discard and then we
% have no place to add the final objects into the output file.}
% \begin{macrocode}
{
\int_gincr:N \g_shipout_readonly_int
\@@_debug:n {
\typeout{Absolute~ page~ =~ \int_use:N \g_shipout_readonly_int
\space (target:~ \@abspage@last)}
}
% \end{macrocode}
% Then we store the box sizes again (as they may have
% changed) and then look at the hooks \hook{shipout/foreground}
% and \hook{shipout/background}. If either or both are non-empty
% we add a \texttt{picture} environment to the box (in the
% foreground and/or in the background) and execute the hook code
% inside that environment.
%
% \begin{macrocode}
\@@_get_box_size:N #1
% \end{macrocode}
% The first hook we run is the \hook{shipout/firstpage} hook. This
% is only done once, then the \cs{@@_run_firstpage_hook:}
% command redefines itself to do nothing. If the hook contains
% \cs{special}s for integration at the top of the page they will be
% temporarily stored in a safe place and added later with
% \cs{@@_add_firstpage_specials:}.
% \begin{macrocode}
\@@_run_firstpage_hook:
% \end{macrocode}
% Run the hooks for background and foreground or, if this
% is called by \cs{RawShipout}, copy the box \cs{l_@@_raw_box} to
% \cs{l_shipout_box} so that firstpage and lastpage material gets
% added if necessary (that is always done to \cs{l_shipout_box}.
% \begin{macrocode}
#3
% \end{macrocode}
% We then run \cs{@@_add_firstpage_specials:} that adds
% the content of the hook \hook{shipout/firstpage} to the
% start of the first page (if non-empty). It is then redefined to
% do nothing on later pages.
% \begin{macrocode}
\@@_add_firstpage_specials:
% \end{macrocode}
% Then we check if we have to add the \hook{shipout/lastpage} hook
% or the corresponding kernel hook
% because we have reached the last page. This test will be false for
% all but one (and hopefully the correct) page.
% \changes{v1.0d}{2020/11/23}{Check for both kernel and user hook (gh/431)}
% \begin{macrocode}
\int_compare:nNnT \@abspage@last = \g_shipout_readonly_int
{ \bool_lazy_and:nnF
{ \hook_if_empty_p:n {shipout/lastpage} }
{ \tl_if_empty_p:N \@kernel@after@shipout@lastpage }
{ \@@_debug:n { \typeout{Executing~ lastpage~ hook~
on~ page~ \int_use:N \g_shipout_readonly_int } }
\_@@_add_foreground_box:n
{ \UseHook{shipout/lastpage}
\@kernel@after@shipout@lastpage }
\bool_gset_true:N \g_@@_lastpage_handled_bool
% \end{macrocode}
% We record that we have handled the \hook{shipout/lastpage} hook
% but only if we really did.
% \changes{v1.0m}{2022/05/08}{Handle case where shipout/lastpage is
% run too early (gh/813)}
% \begin{macrocode}
}
}
\@@_finalize_box:
% \end{macrocode}
% Finally we run the actual \TeX{} primitive for shipout. As that will
% expand delayed \cs{write} statements inside the page in which
% protected commands should not expand we first change \cs{protect}
% to the appropriate definition for that case.
% \begin{macrocode}
\cs_set_eq:NN \protect \exp_not:N
\tex_shipout:D \box_use:N \l_shipout_box
% \end{macrocode}
% The \cs{l_shipout_box} may contain the firstpage material if this
% was the very first shipout. That makes it unsuitable for reuse in
% another shipout, so as a safety measure the next command resets
% \cs{l_shipout_box} to its earlier state if that is necessary. On
% later pages this is then a no-op.
% \begin{macrocode}
\@@_drop_firstpage_specials:
% \end{macrocode}
% The \hook{shipout/after} hook (if in \verb=#4=) needs to run with
% \cs{protect}ed commands again being executed, because that hook
% will ``typeset'' material added at the top of the next page.
% \begin{macrocode}
\set@typeset@protect
#4
}
}
% \end{macrocode}
% Restore the value of \cs{protect} in case \cs{shipout} is called
% outside of the output routine (where it is automatically restored
% because of the implicit group).
% \begin{macrocode}
\cs_set_eq:NN \protect \@@_saved_protect:
}
}
% \end{macrocode}
% \end{macro}
%
%
%
%
% \begin{macro}{\@@_execute_raw:,
% \@@_execute_test_level_raw:}
%
% This implements the ``raw'' shipout which bypasses the before,
% foreground, background and after hooks. It follows the same pattern than
% \cs{_@@_execute_raw:} except that it finally calls
% \cs{_@@_execute_main_cont:Nnnn} with three empty arguments.
% instead of the hook code.
% \begin{macrocode}
\cs_set_protected:Npn \@@_execute_raw: {
\tl_set:Nx \l_@@_group_level_tl
{ \int_value:w \tex_currentgrouplevel:D }
\tex_afterassignment:D \@@_execute_test_level_raw:
\tex_setbox:D \l_@@_raw_box
}
% \end{macrocode}
%
% \begin{macrocode}
\cs_new:Npn \@@_execute_test_level_raw: {
\int_compare:nNnT
\l_@@_group_level_tl < \tex_currentgrouplevel:D
\tex_aftergroup:D \@@_execute_nohooks_cont:
}
% \end{macrocode}
% Well, not totally empty arguments, we add some debugging if we
% are actually doing a shipout.
% \begin{macrocode}
\cs_new:Npn \@@_execute_nohooks_cont: {
\@@_execute_main_cont:Nnnn \l_@@_raw_box
{} { \@@_debug:n{ \typeout{Doing~ raw~ shipout~ ...} }
\box_set_eq:NN \l_shipout_box \l_@@_raw_box } {}
}
% \end{macrocode}
% \end{macro}
% \begin{macro}{\RawShipout}
% The interface name for raw shipout.
% \changes{v1.0g}{2021/01/10}{Macro added}
% \begin{macrocode}
\cs_gset_eq:NN \RawShipout \@@_execute_raw:
% \end{macrocode}
% \end{macro}
%
%
%
%
% \begin{macro}{\@@_saved_protect:}
% Remember the current \cs{protect} state.
% \begin{macrocode}
\cs_new_eq:NN \@@_saved_protect: \protect
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{shipout/before,shipout/after,
% shipout/foreground,shipout/background,
% shipout/firstpage,
% shipout/lastpage}
% Declaring all hooks for the shipout code.
% \begin{macrocode}
\hook_new:n{shipout/before}
\hook_new:n{shipout/after}
\hook_new:n{shipout/foreground}
\hook_new:n{shipout/background}
\hook_new:n{shipout/firstpage}
\hook_new:n{shipout/lastpage}
% \end{macrocode}
% \end{macro}
%
%
%
% \begin{macro}{\@kernel@after@shipout@lastpage,
% \@kernel@before@shipout@background,
% \@kernel@after@shipout@background}
% And here are the internal kernel hooks going before or after the
% public ones where needed.
% \changes{v1.0g}{2021/01/10}{Internal hook
% \cs{@kernel@after@shipout@background} added}
% \begin{macrocode}
\let\@kernel@after@shipout@lastpage\@empty
\let\@kernel@before@shipout@background\@empty
\let\@kernel@after@shipout@background\@empty
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_run_firstpage_hook:}
%
% \changes{v1.0h}{2021/01/19}{Handling of firstpage hook altered}
%
% There are three commands to handle the \hook{shipout/firstpage}
% hook:
% \cs{@@_run_firstpage_hook:}, \cs{@@_add_firstpage_specials:} and
% \cs{@@_drop_firstpage_specials:}.
%
% That hook is supposed to contain \cs{special}s and similar
% material to be placed at the very beginning of the output page
% and so it needs careful placing to avoid that anything else gets
% in front of it. And this means we have to wait with this until
% other hooks such as \hook{shipout/background} have added their
% bits. It is also important that such \cs{special}s show up only
% on the very first page, so if this page gets saved before
% \cs{shipout} for later reuse, we have to make sure that they
% aren't in the saved version.
%
% In addition the hook may also contain code to be executed ``first'', e.g.,
% visible from code in \hook{shipout/background} and this conflicts
% with adding the \cs{special}s late.
%
% Therefore the processing is split into different parts:
% \cs{@@_run_firstpage_hook:} is done early and checks if there is
% any material in the hook.
% \begin{macrocode}
\cs_new:Npn \@@_run_firstpage_hook: {
\hook_if_empty:nTF {shipout/firstpage}
% \end{macrocode}
% If not then we define the other two commands to do nothing.
% \begin{macrocode}
{
\cs_gset_eq:NN \@@_add_firstpage_specials: \prg_do_nothing:
\cs_gset_eq:NN \@@_drop_firstpage_specials: \prg_do_nothing:
}
% \end{macrocode}
% If there is material we execute inside a box, which means any
% \cs{special} will end up in that box and any other code is
% executed and can have side effects (as long as they are global).
% \begin{macrocode}
{
\hbox_set:Nn \l_@@_firstpage_box { \UseHook{shipout/firstpage} }
}
% \end{macrocode}
% Once we are here we change the definition to do nothing next time
% and we also change the command used to implement \cs{AtBeginDvi}
% to become a warning and not add further material to a hook that
% is never used again.
% \begin{macrocode}
\cs_gset_eq:NN \@@_run_firstpage_hook: \prg_do_nothing:
\cs_gset:Npn \@@_add_firstpage_material:Nn ##1 ##2 {
\@latex@warning{ First~ page~ is~ already~ shipped~ out,~ ignoring
\MessageBreak \string##1 }
}
}
% \end{macrocode}
% \end{macro}
%
%
%
% \begin{macro}{\@@_add_firstpage_specials:,\@@_drop_firstpage_specials:}
% The \cs{@@_add_firstpage_specials:} then adds the \cs{special}s
% stored in \cs{l_@@_firstpage_box} to the page to be shipped out
% when the time is ready. Note that if there was no material in the
% \hook{shipout/firstpage} hook then this command gets redefined to
% do nothing. But for most documents there is something, e.g., some
% PostScript header, or some meta data declaration, etc.\ so by
% default we assume there is something to do.
% \begin{macrocode}
\cs_new:Npn \@@_add_firstpage_specials: {
% \end{macrocode}
% First we make a copy of the \cs{l_shipout_box} that we can
% restore it later on.
% \begin{macrocode}
\box_set_eq:NN \l_@@_raw_box \l_shipout_box
% \end{macrocode}
% Adding something to the beginning means adding it to the
% background as that layer is done first in the output.
% \begin{macrocode}
\@@_add_background_box:n { \hbox_unpack_drop:N \l_@@_firstpage_box }
% \end{macrocode}
% After the actual shipout \cs{@@_drop_firstpage_specials:} is
% run to
% restore the earlier content of \cs{l_shipout_box} and then
% redefines itself again to do nothing.
%
% As a final act we change the definition to do nothing next time.
% \begin{macrocode}
\cs_gset_eq:NN \@@_add_firstpage_specials: \prg_do_nothing:
}
% \end{macrocode}
%
% The \cs{@@_drop_firstpage_specials:} is run after the shipout has
% occurred but before the \hook{shipout/afterpage} hook is executed.
% That is the point where we have to restore the \cs{ShipoutBox} to
% its state without the \hook{shipout/firstpage} material.
% \begin{macrocode}
\cs_new:Npn \@@_drop_firstpage_specials: {
\box_set_eq:NN \l_shipout_box \l_@@_raw_box
% \end{macrocode}
% If there was no such material then \cs{@@_run_firstpage_hook:}
% will have changed the definition to a no-op already. Otherwise
% this is what we do here.
% \begin{macrocode}
\cs_gset_eq:NN \@@_drop_firstpage_specials: \prg_do_nothing:
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\l_@@_firstpage_box}
% The box to hold any firstpage \cs{special}s.
% \begin{macrocode}
\box_new:N \l_@@_firstpage_box
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\g_@@_lastpage_handled_bool}
% A boolean to signal if we have already handled the
% \hook{shipout/lastpage} hook.
% \begin{macrocode}
\bool_new:N \g_@@_lastpage_handled_bool
% \end{macrocode}
% \end{macro}
%
%
%
% \begin{macro}{\@@_add_firstpage_material:Nn}
% This command adds material to the
% \hook{shipout/firstpage} hook. It is used in
% \cs{AtBeginDvi}, etc. The first argument is the
% command through which is it called. Initially this is ignored but
% once we are passed the first page it can be used to generate a
% warning message mentioning the right user command.
% \begin{macrocode}
\cs_new:Npn \@@_add_firstpage_material:Nn #1#2 {
\AddToHook{shipout/firstpage}{#2}
}
% \end{macrocode}
% \end{macro}
%
%
%
%
%
%
%
% \begin{macro}{\@@_get_box_size:N}
% Store the box dimensions in dimen registers.
% \fmi{This could/should perhaps be generalized to set height depth and
% width given an arbitrary box.}
% \begin{macrocode}
\cs_new:Npn \@@_get_box_size:N #1 {
\dim_set:Nn \l_shipout_box_ht_dim { \box_ht:N #1 }
\dim_set:Nn \l_shipout_box_dp_dim { \box_dp:N #1 }
\dim_set:Nn \l_shipout_box_wd_dim { \box_wd:N #1 }
\dim_set:Nn \l_shipout_box_ht_plus_dp_dim
{ \l_shipout_box_ht_dim + \l_shipout_box_dp_dim }
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\l_shipout_box_ht_dim,
% \l_shipout_box_dp_dim,\l_shipout_box_wd_dim,
% \l_shipout_box_ht_plus_dp_dim}
% And here are the variables set by \cs{@@_get_box_size:N}.
% \begin{macrocode}
\dim_new:N \l_shipout_box_ht_dim
\dim_new:N \l_shipout_box_dp_dim
\dim_new:N \l_shipout_box_wd_dim
\dim_new:N \l_shipout_box_ht_plus_dp_dim
% \end{macrocode}
% \end{macro}
%
%
%
%
%
% \begin{macro}{\g_@@_discard_bool}
% Indicate whether or not the current page box should be discarded
% \begin{macrocode}
\bool_new:N \g_@@_discard_bool
% \end{macrocode}
% \end{macro}
%
%
%
% \begin{macro}{\l_@@_tmp_box,\l_@@_saved_badness_tl}
% We need a box for the background and foreground material and a
% token register to remember badness settings as we disable them
% during the buildup below.
% \begin{macrocode}
\box_new:N \l_@@_tmp_box
\tl_new:N \l_@@_saved_badness_tl
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_add_background_box:n}
% In standard \LaTeX{} the shipout box is always a \cs{vbox} but
% here we are allow for other usage as well, in case some package
% has its own output routine.
% \begin{macrocode}
\cs_new:Npn \@@_add_background_box:n #1
{ \@@_get_box_size:N \l_shipout_box
% \end{macrocode}
% But we start testing for a vertical box as that should be the
% normal case.
% \begin{macrocode}
\box_if_vertical:NTF \l_shipout_box
{
% \end{macrocode}
% Save current values of \cs{vfuzz} and \cs{vbadness} then change
% them to allow box manipulations without warnings.
% \begin{macrocode}
\tl_set:Nx \l_@@_saved_badness_tl
{ \vfuzz=\the\vfuzz\relax
\vbadness=\the\vbadness\relax }
\vfuzz=\c_max_dim
\vbadness=\c_max_int
% \end{macrocode}
% Then we reconstruct \cs{l_shipout_box} \ldots
% \begin{macrocode}
\vbox_set_to_ht:Nnn \l_shipout_box \l_shipout_box_ht_plus_dp_dim
{
% \end{macrocode}
% \ldots{} the material in \verb=#1= is placed into a horizontal
% box with zero dimensions.
% \begin{macrocode}
\hbox_set:Nn \l_@@_tmp_box
{ \l_@@_saved_badness_tl #1 }
\box_set_wd:Nn \l_@@_tmp_box \c_zero_dim
\box_set_ht:Nn \l_@@_tmp_box \c_zero_dim
\box_set_dp:Nn \l_@@_tmp_box \c_zero_dim
% \end{macrocode}
% The we typeset that box followed by whatever was in
% \cs{l_shipout_box} before (unpacked).
% \begin{macrocode}
\skip_zero:N \baselineskip
\skip_zero:N \lineskip
\skip_zero:N \lineskiplimit
\box_use:N \l_@@_tmp_box
\vbox_unpack:N \l_shipout_box
% \end{macrocode}
% The \cs{kern} ensures that the box has no depth which is
% afterwards explicitly corrected.
% \begin{macrocode}
\kern \c_zero_dim
}
\box_set_ht:Nn \l_shipout_box \l_shipout_box_ht_dim
\box_set_dp:Nn \l_shipout_box \l_shipout_box_dp_dim
% \end{macrocode}
% \fmi{The whole boxing maneuver looks a bit like overkill to me, but for
% the moment I leave.}
% \begin{macrocode}
\l_@@_saved_badness_tl
}
{
% \end{macrocode}
% A horizontal box is handled in a similar way. The last case would
% be a void box in which case we do nothing hence the missing
% \texttt{F} branch.
% \begin{macrocode}
\box_if_horizontal:NT \l_shipout_box
{
\tl_set:Nx \l_@@_saved_badness_tl
{ \hfuzz=\the\hfuzz\relax
\hbadness=\the\hbadness\relax }
\hfuzz=\c_max_dim
\hbadness=\c_max_int
\hbox_set_to_wd:Nnn \l_shipout_box \l_shipout_box_wd_dim
{
\hbox_set:Nn \l_@@_tmp_box
{ \l_@@_saved_badness_tl #1 }
\box_set_wd:Nn \l_@@_tmp_box \c_zero_dim
\box_set_ht:Nn \l_@@_tmp_box \c_zero_dim
\box_set_dp:Nn \l_@@_tmp_box \c_zero_dim
\box_move_up:nn
\l_shipout_box_ht_dim
{ \box_use:N \l_@@_tmp_box }
\hbox_unpack:N \l_shipout_box
}
\l_@@_saved_badness_tl
}
}
}
% \end{macrocode}
% \end{macro}
%
%
%
%
% \begin{macro}{\@@_add_foreground_box:n}
% Foreground boxes are done in the same way, only the order and
% placement of boxes has to be done differently.
% \begin{macrocode}
\cs_new:Npn \@@_add_foreground_box:n #1
{
\box_if_vertical:NTF \l_shipout_box
{
\tl_set:Nx \l_@@_saved_badness_tl
{ \vfuzz=\the\vfuzz\relax
\vbadness=\the\vbadness\relax }
\vfuzz=\c_max_dim
\vbadness=\c_max_int
\vbox_set_to_ht:Nnn \l_shipout_box \l_shipout_box_ht_plus_dp_dim
{
\hbox_set:Nn \l_@@_tmp_box
{ \l_@@_saved_badness_tl #1 }
\box_set_wd:Nn \l_@@_tmp_box \c_zero_dim
\box_set_ht:Nn \l_@@_tmp_box \c_zero_dim
\box_set_dp:Nn \l_@@_tmp_box \c_zero_dim
\skip_zero:N \baselineskip
\skip_zero:N \lineskip
\skip_zero:N \lineskiplimit
\vbox_unpack:N \l_shipout_box
\kern -\l_shipout_box_ht_plus_dp_dim
\box_use:N \l_@@_tmp_box
\kern \l_shipout_box_ht_plus_dp_dim
}
\l_@@_saved_badness_tl
\box_set_ht:Nn \l_shipout_box \l_shipout_box_ht_dim
\box_set_dp:Nn \l_shipout_box \l_shipout_box_dp_dim
}
{
\box_if_horizontal:NT \l_shipout_box
{
\tl_set:Nx \l_@@_saved_badness_tl
{ \hfuzz=\the\hfuzz\relax
\hbadness=\the\hbadness\relax }
\hfuzz=\c_max_dim
\hbadness=\c_max_int
\hbox_set_to_wd:Nnn \l_shipout_box \l_shipout_box_wd_dim
{
\hbox_unpack:N \l_shipout_box
\kern -\box_wd:N \l_shipout_box
\hbox_set:Nn \l_@@_tmp_box
{ \l_@@_saved_badness_tl #1 }
\box_set_wd:Nn \l_@@_tmp_box \c_zero_dim
\box_set_ht:Nn \l_@@_tmp_box \c_zero_dim
\box_set_dp:Nn \l_@@_tmp_box \c_zero_dim
\box_move_up:nn { \box_ht:N \l_shipout_box }
{ \box_use:N \l_@@_tmp_box }
\kern \box_wd:N \l_shipout_box
}%
\l_@@_saved_badness_tl
}
}
}
% \end{macrocode}
% \end{macro}
%
%
%
%
% \begin{macro}{\@@_init_page_origins:,\c_@@_horigin_tl,\c_@@_vorigin_tl}
% Two constants holding the offset of the top-left with respect to
% the media box.
%
% Setting the constants this way is courtesy of Bruno.
%
% We delay setting the constants to the last possible place as
% there might be updates in the preamble or even in the
% \hook{begindocument} hook that affects their setup.
% \begin{macrocode}
\cs_new:Npn \@@_init_page_origins: {
\tl_const:Nx \c_@@_horigin_tl
{
\cs_if_exist_use:NTF \pdfvariable { horigin }
{ \cs_if_exist_use:NF \pdfhorigin { 1in } }
}
\tl_const:Nx \c_@@_vorigin_tl
{
\cs_if_exist_use:NTF \pdfvariable { vorigin }
{ \cs_if_exist_use:NF \pdfvorigin { 1in } }
}
% \end{macrocode}
% After the constants have been set there is no need to execute
% this command again, in fact it would raise an error, so we
% redefine it to do nothing.
% \begin{macrocode}
\cs_gset_eq:NN \@@_init_page_origins: \prg_do_nothing:
}
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_picture_overlay:n}
% Put the argument into a \texttt{picture} environment that doesn't take up
% any size and uses \texttt{1pt} for \cs{unitlength}.
% \fmi{Could perhaps be generalized as it might be useful elsewhere. For
% now it is not.}
% \begin{macrocode}
\cs_new:Npn \@@_picture_overlay:n #1 {
% \end{macrocode}
% The very first time this is executed we have to initialize (and
% freeze) the origins.
% \begin{macrocode}
\@@_init_page_origins:
% \end{macrocode}
%
% \begin{macrocode}
\kern -\c_@@_horigin_tl \scan_stop:
\vbox_to_zero:n {
\kern -\c_@@_vorigin_tl \scan_stop:
\unitlength 1pt \scan_stop:
% \end{macrocode}
% This mimics a simple zero-sized picture environment. The \cs{hss}
% is need in case there is horizontal material (without using
% \cs{put} with a positive width.
% \changes{v1.0b}{2020/09/09}
% {Prevent overfull box warnings (gh/387)}
% \begin{macrocode}
\hbox_set_to_wd:Nnn \l_@@_tmp_box \c_zero_dim
{ \ignorespaces #1 \hss }
\box_set_ht:Nn \l_@@_tmp_box \c_zero_dim
\box_set_dp:Nn \l_@@_tmp_box \c_zero_dim
\box_use:N \l_@@_tmp_box
\tex_vss:D
}
}
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_add_background_picture:n}
% Put a \texttt{picture} env in the background of the shipout box
% with its reference point in the top-left corner.
%
% \begin{macrocode}
\cs_new:Npn \@@_add_background_picture:n #1 {
\@@_add_background_box:n { \@@_picture_overlay:n {#1} }
}
% \end{macrocode}
% \end{macro}
%
%
%
% \begin{macro}{\@@_add_foreground_picture:n}
%
% Put a \texttt{picture} env in the foreground of the shipout box
% with its reference point in the top-left corner.
% \begin{macrocode}
\cs_new:Npn \@@_add_foreground_picture:n #1 {
\@@_add_foreground_box:n { \@@_picture_overlay:n {#1} }
}
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\shipout_discard:}
% Request that the next shipout box should be discarded. At the
% moment this is just setting a boolean, but we may want to augment
% this behavior that the position of the call is taken into account
% (in case \LaTeX{} looks ahead and is not using the position for
% on the next page).
% \begin{macrocode}
\cs_new_protected:Npn \shipout_discard: {
\bool_gset_true:N \g_@@_discard_bool
}
% \end{macrocode}
% \end{macro}
%
%
%
%
% \subsection{Handling the end of job hook}
%
% At the moment this is partly solved by using the existing hooks.
% But rather than putting the code into these hooks it should be
% moved to the right place directly as we shouldn't prefill hooks
% with material unless it needs to interact with other code.
%
%
%
% \begin{macro}{\g_shipout_readonly_int,\ReadonlyShipoutCounter}
% We count every shipout activity that makes a page (but not those
% that are discarded) in order to know how many pages got produced.
% \begin{macrocode}
\int_new:N \g_shipout_readonly_int
% \end{macrocode}
% For \LaTeXe{} it is available as a command (i.e., a \TeX{}
% counter only.
% \begin{macrocode}
\cs_new_eq:NN \ReadonlyShipoutCounter \g_shipout_readonly_int
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\g_shipout_totalpages_int,\c@totalpages}
% We count every shipout attempt (even those that are discarded) in
% this counter. It is not used in the code but may get used in user
% code.
% \begin{macrocode}
\int_new:N \g_shipout_totalpages_int
% \end{macrocode}
% For \LaTeXe{} this is offered as a \LaTeX{} counter so can be
% easily typeset inside the output routine to display things like
% \enquote{\cs{thepage}\texttt{/}\cs{thetotalpages}}, etc.
% \begin{macrocode}
\cs_new_eq:NN \c@totalpages \g_shipout_totalpages_int
\cs_new:Npn \thetotalpages { \arabic{totalpages} }
% \end{macrocode}
% \end{macro}
%
%
%
%
% \begin{macro}{\@abspage@last}
% In \cs{@abspage@last} record the number of pages from the last
% run. This is written to the \texttt{.aux} and this way made
% available to the next run. In case there is no \texttt{.aux} file
% or the statement is missing from it we initialize it with the
% largest possible number in \TeX{}. We use this as the default
% because then we are inserting the \hook{shipout/lastpage} on
% the last page (or after the last page) but not on page 1 for a
% multipage document.
% \begin{macrocode}
\xdef\@abspage@last{\number\maxdimen}
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\enddocument}
%
% Instead of using the hooks \hook{enddocument} and
% \hook{enddocument/afterlastpage} we add this code to private
% kernel hooks to be 100\% sure when it is executed and to avoid
% cluttering the hooks with data that is always there.
%
% Inside \cs{enddocument} there is a \cs{clearpage}. Just before
% that we execute this code here. There is a good chance that we
% are on the last page. Therefore, if we don't know the value from
% the last run, we assume that the current page is the right
% one. So we set \cs{@abspage@last} and as a result the next
% shipout will run the \hook{shipout/lastpage} code. Of course,
% if there are floats that still need a placement this guess will
% be wrong but then rerunning the document will give us the correct
% value next time around.
%
% \begin{macro}{\@kernel@after@enddocument}
% \begin{macrocode}
\g@addto@macro \@kernel@after@enddocument {
\int_compare:nNnT \@abspage@last = \maxdimen
{
% \end{macrocode}
% We use \LaTeXe{} coding as \cs{@abspage@last} is not an L3 name.
% \begin{macrocode}
\xdef\@abspage@last{ \int_eval:n {\g_shipout_readonly_int + 1} }
}
}
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@kernel@after@enddocument@afterlastpage}
% Once the \cs{clearpage} has done its work inside \cs{enddocument}
% we know for sure how many pages this document has, so we record
% that in the \texttt{.aux} file for the next run.
%
% \begin{macrocode}
\g@addto@macro \@kernel@after@enddocument@afterlastpage {
% \end{macrocode}
% There is one special case: If no output is produced then there is
% no point in a) recording the number as 0 will never match the
% page number of a real page and b) adding an extra page to ran the
% \hook{shipout/lastpage} is pointless as well (as it would
% remain forever). So we test for this and run the code only if
% there have been pages.
% \begin{macrocode}
\int_compare:nNnF \g_shipout_readonly_int = 0
{
% \end{macrocode}
% This ends up in the \texttt{.aux} so we use \LaTeXe{} names here.
% \fmi{This needs an interface for \cs{nofiles} in expl3, doesn't at the moment!}
% \begin{macrocode}
\if@filesw
\iow_now:Nx \@auxout {
\gdef\string\@abspage@last {\int_use:N \g_shipout_readonly_int}}
\fi
% \end{macrocode}
% But we may have guessed wrongly earlier and have run it too early
% or we still have to run the
% \hook{shipout/lastpage} even though there is no page to place
% it into. If that is the case we make a trivial extra page and put
% it there. This temporary page will then vanish again on the next
% run but helps to keep pdf viewers happy.
% In either case we should put out an appropriate ``rerun'' warning.
% \changes{v1.0m}{2022/05/08}{Handle case where shipout/lastpage is
% run too early (gh/813)}
% \begin{macrocode}
\bool_if:NTF \g_@@_lastpage_handled_bool
{
% \end{macrocode}
% If the hook was already executed, we have to test if that total
% shipouts match the shipouts from last run (because that
% corresponds to the page it was executed). If not we output a warning.
% \begin{macrocode}
\int_compare:nNnF \@abspage@last = \g_shipout_readonly_int
{
\@latex@warning@no@line{Hook~ 'shipout/lastpage'~ executed~
on~ wrong~ page~ (\@abspage@last\space not~
\int_use:N\g_shipout_readonly_int).\MessageBreak
Rerun~ to~ correct~ this}%
}
}
{
% \end{macrocode}
% If the hook was not run, we need to add an extra page and place
% it there.
% However, making this extra page in case the hook is actually
% empty would be forcing a rerun without any reason, so we check
% that condition and also check if
% \cs{@kernel@after@shipout@lastpage} contains any code. If both
% are empty we omit the page generation.
% \begin{macrocode}
\bool_lazy_and:nnF
{ \hook_if_empty_p:n {shipout/lastpage} }
{ \tl_if_empty_p:N \@kernel@after@shipout@lastpage }
{
\tex_shipout:D\vbox to\textheight
{
\hbox:n { \UseHook{shipout/lastpage}
\@kernel@after@shipout@lastpage }
% \end{macrocode}
% This extra page could be totally empty except for the hook
% content, but to help the user understanding why it is there we
% put some text into it.
% \begin{macrocode}
\@@_excuse_extra_page:
\null
}
% \end{macrocode}
% At this point we also signal to \LaTeX{}'s endgame that a rerun is
% necessary so that an appropriate message can be shown on the
% terminal. We do this by simply defining a command used as a flag and
% tested in \cs{enddocument}.
% \begin{macrocode}
\cs_gset_eq:NN \@extra@page@added \relax
}
}
}
}
% \end{macrocode}
% \end{macro}
% \end{macro}
%
%
%
% \begin{macro}{\@@_excuse_extra_page:}
% Say mea culpa \ldots
% \begin{macrocode}
\cs_new:Npn \@@_excuse_extra_page: {
\vfil
\begin{center}
\bfseries Temporary~ page!
\end{center}
\LaTeX{}~ was~ unable~ to~ guess~ the~ total~ number~ of~ pages~
correctly.~ ~ As~ there~ was~ some~ unprocessed~ data~ that~
should~ have~ been~ added~ to~ the~ final~ page~ this~ extra~
page~ has~ been~ added~ to~ receive~ it.
\par
If~ you~ rerun~ the~ document~ (without~ altering~ it)~ this~
surplus~ page~ will~ go~ away,~ because~ \LaTeX{}~ now~ knows~
how~ many~ pages~ to~ expect~ for~ this~ document.
\vfil
}
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\PreviousTotalPages,\@kernel@before@begindocument}
% In the preamble before the \texttt{aux} file was read
% \cs{PreviousTotalPages} is always zero.
% \begin{macrocode}
\def\PreviousTotalPages{0}
% \end{macrocode}
% In the \texttt{aux} file there should be an update for
% \cs{@abspage@last} recording the number of pages from the
% previous run. If not that macro holds the value of
% \cs{maxdimen}. So we test for it and update
% \cs{PreviousTotalPages} if there was a real value. This should
% happen just before the \hook{begindocument} hook is executed so
% that the value can be used inside that hook.
% \begin{macrocode}
\g@addto@macro\@kernel@before@begindocument
{\ifnum\@abspage@last<\maxdimen
\xdef\PreviousTotalPages{\@abspage@last}\fi}
% \end{macrocode}
% \end{macro}
%
%
% \section{Legacy \LaTeXe{} interfaces}
%
%
%
% \begin{macro}{\DiscardShipoutBox}
% Request that the next shipout box is to be discarded.
% \begin{macrocode}
\cs_new_eq:NN \DiscardShipoutBox \shipout_discard:
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\AtBeginDvi}
% If we roll forward from an earlier kernel \cs{AtBeginDvi} is
% defined so we better not use \cs{cs_new_protected:Npn} here.
% \changes{v1.0d}{2020/11/24}{Support for roll forward (gh/434)}
% \begin{macrocode}
\cs_set_protected:Npn \AtBeginDvi
{\@@_add_firstpage_material:Nn \AtBeginDvi}
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\DebugShipoutsOn,\DebugShipoutsOff}
%
% \begin{macrocode}
\cs_new_eq:NN \DebugShipoutsOn \shipout_debug_on:
\cs_new_eq:NN \DebugShipoutsOff \shipout_debug_off:
% \end{macrocode}
% \end{macro}
%
%
% \section{Internal commands needed elsewhere}
%
% These internal commands use double and triple \texttt{@} signs so
% we need to stop getting them translated to the module name.
% \begin{macrocode}
%<@@=>
% \end{macrocode}
%
% \begin{macro}{\@expl@@@shipout@add@firstpage@material@@Nn,
% \@expl@@@shipout@add@background@box@@n,
% \@expl@@@shipout@add@foreground@box@@n,
% \@expl@@@shipout@add@background@picture@@n,
% \@expl@@@shipout@add@foreground@picture@@n}
% Some internals needed elsewhere.
%
% \InternalDetectionOff
% \begin{macrocode}
\cs_set_eq:NN \@expl@@@shipout@add@firstpage@material@@Nn
\__shipout_add_firstpage_material:Nn
% \end{macrocode}
%
% \begin{macrocode}
\cs_set_eq:NN \@expl@@@shipout@add@background@box@@n
\__shipout_add_background_box:n
% \end{macrocode}
%
% \begin{macrocode}
\cs_set_eq:NN \@expl@@@shipout@add@foreground@box@@n
\__shipout_add_foreground_box:n
% \end{macrocode}
%
% \begin{macrocode}
\cs_set_eq:NN \@expl@@@shipout@add@background@picture@@n
\__shipout_add_background_picture:n
% \end{macrocode}
%
% \begin{macrocode}
\cs_set_eq:NN \@expl@@@shipout@add@foreground@picture@@n
\__shipout_add_foreground_picture:n
% \end{macrocode}
% \InternalDetectionOn
% \end{macro}
%
% \begin{macrocode}
\ExplSyntaxOff
%</2ekernel|latexrelease>
%<latexrelease>\EndIncludeInRelease
% \end{macrocode}
%
%
% Rolling back here doesn't undefine the interface commands as they
% may be used in packages without rollback functionality. So we
% just make them do nothing which may or may not work depending on
% the code usage.
%
% \begin{macrocode}
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease> {\shipout}{Hook management (shipout)}%
%<latexrelease>
% \end{macrocode}
% If we roll forward then \cs{tex\_shipout:D} may not be defined in
% which case \cs{shipout} does have it original definition and so
% we must not \cs{let} it to something else which is \cs{relax}!
% \changes{v1.0d}{2020/11/24}{Support for roll forward (gh/434)}
% \begin{macrocode}
%<latexrelease>\ifcsname tex_shipout:D\endcsname
%<latexrelease>\expandafter\let\expandafter\shipout
%<latexrelease> \csname tex_shipout:D\endcsname
%<latexrelease>\fi
%<latexrelease>
%<latexrelease>\let \RawShipout\@undefined
%<latexrelease>\let \ShipoutBox\@undefined
%<latexrelease>\let \ReadonlyShipoutCounter \@undefined
%<latexrelease>\let \c@totalpages \@undefined
%<latexrelease>\let \thetotalpages \@undefined
%<latexrelease>
%<latexrelease>\let \DiscardShipoutBox \@undefined
%<latexrelease>\let \DebugShipoutsOn \@undefined
%<latexrelease>\let \DebugShipoutsOff \@undefined
%<latexrelease>
%<latexrelease>\DeclareRobustCommand \AtBeginDvi [1]{%
%<latexrelease> \global \setbox \@begindvibox
%<latexrelease> \vbox{\unvbox \@begindvibox #1}%
%<latexrelease>}
%<latexrelease>
%<latexrelease>\let \AtBeginShipout \@undefined
%<latexrelease>\let \AtBeginShipoutNext \@undefined
%<latexrelease>
%<latexrelease>\let \AtBeginShipoutFirst \@undefined
%<latexrelease>
%<latexrelease>\let \ShipoutBoxHeight \@undefined
%<latexrelease>\let \ShipoutBoxDepth \@undefined
%<latexrelease>\let \ShipoutBoxWidth \@undefined
%<latexrelease>
% \end{macrocode}
% We do not undo a substitution when rolling back. As the file
% support gets undone the underlying data is no longer used (and
% sufficiently obscure that it should not interfere with existing
% commands) and properly removing it would mean we need to make the
% \cs{undeclare@...} and its support macros available in all earlier
% kernel releases which is pointless (and actually worse).
%
% \begin{macrocode}
%<latexrelease>
%<latexrelease>\let \AtEndDvi \@undefined
% \end{macrocode}
% We do not reenable a disabled package load when rolling back. As the file
% support gets undone the underlying data is no longer checked (and
% sufficiently obscure that it should not interfere with existing
% commands) and properly removing it would mean we need to make the
% \cs{reenable@package@load} command available in all earlier
% kernel releases which is pointless (and actually worse).
% \begin{macrocode}
%\reenable@package@load{atenddvi}
% \end{macrocode}
%
% \begin{macrocode}
%<latexrelease>
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
% \end{macrocode}
%
%
%
%
% \section{Package emulation for compatibility}
%
%
% \subsection{Package \pkg{atenddvi} emulation}
%
%
% \begin{macro}{\AtEndDvi}
% This package has only one public command, so simulating it is easy
% and actually sensible to provide as part of the kernel.
% \changes{v1.0l}{2022/01/06}{Correctly simulate \cs{AtEndDvi} without
% extending the syntax}
% \begin{macrocode}
%</2ekernel>
%<*2ekernel|latexrelease>
%<latexrelease>\IncludeInRelease{2020/10/01}%
%<latexrelease> {\AtEndDvi}{atenddvi emulation}%
\ExplSyntaxOn
\cs_new_protected:Npn \AtEndDvi #1 {\AddToHook{shipout/lastpage}{#1}}
\ExplSyntaxOff
% \end{macrocode}
% As the package is integrate we prevent loading (no need to roll that back):
% \begin{macrocode}
\disable@package@load{atenddvi}
{\PackageWarning{atenddvi}
{Functionality of this package is already\MessageBreak
provided by LaTeX.\MessageBreak\MessageBreak
It is there no longer necessary to load it\MessageBreak
and you can safely remove it.\MessageBreak
Found on}}
% \end{macrocode}
%
% \begin{macrocode}
%</2ekernel|latexrelease>
% \end{macrocode}
%
% \begin{macrocode}
%<latexrelease>\EndIncludeInRelease
%<latexrelease>\IncludeInRelease{0000/00/00}%
%<latexrelease> {\AtEndDvi}{atenddvi emulation}%
%<latexrelease>\let \AtEndDvi \@undefined
%<latexrelease>\EndIncludeInRelease
%<*2ekernel>
% \end{macrocode}
% \end{macro}
%
%
%
% \begin{macrocode}
%</2ekernel>
% \end{macrocode}
%
%
% \subsection{Package \pkg{atbegshi} emulation}
%
%
%
%
%
% \begin{macrocode}
%<*atbegshi-ltx>
\ProvidesPackage{atbegshi-ltx}
[2021/01/10 v1.0c
Emulation of the original atbegshi^^Jpackage with kernel methods]
% \end{macrocode}
%
%
% \begin{macro}{\AtBeginShipoutBox}
% \begin{macrocode}
\let \AtBeginShipoutBox \ShipoutBox
% \end{macrocode}
% \end{macro}
%
%
%
% \begin{macro}{\AtBeginShipoutInit}
% Compatibility only, we aren't delaying \ldots
% \begin{macrocode}
\let \AtBeginShipoutInit \@empty
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\AtBeginShipout,\AtBeginShipoutNext}
% Filling hooks
% \changes{v1.0l}{2022/01/06}{Correctly simulate \cs{AtBeginShipout}
% and \cs{AtBeginShipoutNext} without extending the syntax}
% \begin{macrocode}
\protected\long\def\AtBeginShipout #1{\AddToHook{shipout/before}{#1}}
\protected\long\def\AtBeginShipoutNext #1{\AddToHookNext{shipout/before}{#1}}
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\AtBeginShipoutFirst}
% Slightly more complex as we need to know the name of the command under which the
% \hook{shipout/firstpage} hook is filled.
% \begin{macrocode}
\protected \def \AtBeginShipoutFirst
{\@expl@@@shipout@add@firstpage@material@@Nn \AtBeginShipoutFirst}
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\AtBeginShipoutDiscard}
% Just a different name.
% \begin{macrocode}
\let \AtBeginShipoutDiscard \DiscardShipoutBox
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\AtBeginShipoutAddToBox,\AtBeginShipoutAddToBoxForeground,
% \AtBeginShipoutUpperLeft,\AtBeginShipoutUpperLeftForeground}
% We don't expose them.
% \begin{macrocode}
\let \AtBeginShipoutAddToBox
\@expl@@@shipout@add@background@box@@n
\let \AtBeginShipoutAddToBoxForeground
\@expl@@@shipout@add@foreground@box@@n
% \end{macrocode}
%
% \begin{macrocode}
\let \AtBeginShipoutUpperLeft
\@expl@@@shipout@add@background@picture@@n
\let \AtBeginShipoutUpperLeftForeground
\@expl@@@shipout@add@foreground@picture@@n
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\AtBeginShipoutOriginalShipout}
% This offers the raw \cs{shipout} primitive of the engine. A page
% shipped out with this is not counted by
% \cs{ReadonlyShipoutCounter} counter and thus the mechanism to
% place \cs{special}s at the very end of the output might fail,
% etc. It should therefore not be used in new applications but is
% only provided to allow running legacy code. For new code use the
% commands provided by the kernel instead.
% \begin{macrocode}
\ExplSyntaxOn
\cs_new_eq:NN \AtBeginShipoutOriginalShipout \tex_shipout:D
% \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\ShipoutBoxHeight,\ShipoutBoxWidth,\ShipoutBoxDepth}
% This is somewhat different from the original in \pkg{atbegshi}
% where \cs{ShipoutBoxHeight} etc.\ only holds the
% \verb=\the\ht<box>= value. This may has some implications in some
% use cases and if that is a problem then it might need changing.
% \begin{macrocode}
\cs_new:Npn \ShipoutBoxHeight { \dim_use:N \l_shipout_box_ht_dim }
\cs_new:Npn \ShipoutBoxDepth { \dim_use:N \l_shipout_box_dp_dim }
\cs_new:Npn \ShipoutBoxWidth { \dim_use:N \l_shipout_box_wd_dim }
\ExplSyntaxOff
% \end{macrocode}
% \end{macro}
%
%
% \begin{macrocode}
%</atbegshi-ltx>
% \end{macrocode}
%
% If the package is requested we substitute the one above:
% \begin{macrocode}
%<*2ekernel>
\declare@file@substitution{atbegshi.sty}{atbegshi-ltx.sty}
%</2ekernel>
% \end{macrocode}
%
%
%
%
%
%
% \subsection{Package \pkg{everyshi} emulation}
%
% This is now directly handled in that package so emulation is not
% necessary any more.
%
%
% Rather important :-)
% \begin{macrocode}
%<@@=>
% \end{macrocode}
%
% \Finale
%
%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\endinput
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%