diff options
author | Karl Berry <karl@freefriends.org> | 2020-10-02 21:49:18 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2020-10-02 21:49:18 +0000 |
commit | 5255c37137345163348d22ab46af2304cf9f55a6 (patch) | |
tree | 88246497477ddcc26834e5708566ad4c1c862a19 /Master/texmf-dist/source/latex/base/ltshipout.dtx | |
parent | 1922ba4684a59cde742dcef9ed152381d2d7b110 (diff) |
latex2e (2oct20)
git-svn-id: svn://tug.org/texlive/trunk@56514 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/base/ltshipout.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/base/ltshipout.dtx | 1739 |
1 files changed, 1739 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/base/ltshipout.dtx b/Master/texmf-dist/source/latex/base/ltshipout.dtx new file mode 100644 index 00000000000..8f0422c887b --- /dev/null +++ b/Master/texmf-dist/source/latex/base/ltshipout.dtx @@ -0,0 +1,1739 @@ +% \iffalse meta-comment +%% +%% File: ltshipout.dtx (C) Copyright 2020 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.0c} +\providecommand\ltshipoutdate{2020/09/27} +% \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 + +\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} +% +% \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. +% \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}). +% \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/foreground,shipout/background, +% shipout/firstpage, +% shipout/lastpage} +% The code 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). +% +% \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 +% +% ^^A \fmi{not sure it has to be that restrictive.} +% +% +% \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 --- +% or rather on the page that \LaTeX{} believes is the last one. +% +% 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. +% +% \end{description} +% \end{variable}\footnotetext{In +% \LaTeXe{} that was already existing, but implemented using a box +% register with the name \cs{@begindvibox}.} +% +% 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. The other hooks 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. +% +% In a document that doesn't produce pages, e.g., only makes +% \cs{typeout}s, none of the hooks are executed (as there is no +% \cs{shipout}) not even the \hook{shipout/lastpage} hook. +% +% \begin{function}{\AtBeginDvi,\AtEndDvi} +% \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{.dvx}. +% +% \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. +% +% \fmi{better names? Any suggestions?} +% +% \end{function} +% +% \subsection{Special commands for use inside the hooks} +% +% \begin{function}{\DiscardShipoutBox,\shipout_discard_box:} +% \begin{syntax} +% \cs{AddToHookNext} \texttt{\{shipout/before\} \{...\cs{DiscardShipoutBox}...\}} +% \end{syntax} +% The \cs{DiscardShipoutBox} declaration (L3 name +% \cs{shipout_discard_box:}) +% 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! +% +% \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{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)! +% +% 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 but if you do, 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}\Arg{\cs{ReadonlyShipoutCounter}} 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). +% +% 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 usedin the +% preamble it expands to +% \texttt{0}. Note that this is a command to 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 in other packages they are emulated when they are loaded +% via \cs{usepackage} or \cs{RequirePackage}. +% +% +% \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}{\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}} +% +% +% \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} +% +% +% +% \subsection{Emulating \pkg{atenddvi}} +% +% The \pkg{atenddvi} package implemented only a single command: +% \cs{AtEndDvi} and that is now available out of the box. +% +% +% +% \subsection{Emulating \pkg{everypage}} +% +% This page takes over the original \cs{@begindvi} hook and replaces +% it. It should be all covered by the hooks offered here (details +% need checking) and thus could simply use the provided hooks +% rather than defining its own. +% +% +% +% \StopEventually{\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 mangement (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}{\@@_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:} +% 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 (perhaps).. +% +% 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 deadcyles, that would be up to the OR +% processing logic to do.} +% \begin{macrocode} +\cs_new:Npn \@@_execute_cont: { + \box_if_empty:NTF \l_shipout_box + { \PackageWarning{ltshipout}{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 + \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 \l_shipout_box +% \end{macrocode} +% Then we execute the \hook{shipout/before} hook. +% \begin{macrocode} + \hook_use:n {shipout/before} +% \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{} 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 + { \PackageInfo{ltshipout}{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 \l_shipout_box \l_shipout_box +% \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 \l_shipout_box + { \PackageWarning{ltshipout}{ + Shipout~ box~ was~ voided~ by~ hook,\MessageBreak + ignoring~ shipout~ box } + } +% \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 \l_shipout_box + \hook_if_empty:nF {shipout/foreground} + { \@@_add_foreground_picture:n + { \hook_use:n {shipout/foreground} } } + \hook_if_empty:nF {shipout/background} + { \@@_add_background_picture:n + { \@kernel@before@shipout@background + \hook_use:n {shipout/background} } } +% \end{macrocode} +% We then run \cs{@@_execute_firstpage_hook:} 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} + \@@_execute_firstpage_hook: +% \end{macrocode} +% The we check if we have to add the \hook{shipout/lastpage} hook +% because we have reached the last page. This test will be false for +% all but one (and hopefully the correct) page. +% \begin{macrocode} + \int_compare:nNnT \@abspage@last = \g_shipout_readonly_int + { \hook_if_empty:nF {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} +% 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} +% 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}{\@@_saved_protect:} +% Remeber the current \cs{protect} state. +% \begin{macrocode} +\cs_new_eq:NN \@@_saved_protect: \protect +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{shipout/before, +% 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/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} +% And here are the internal kernel hooks going before or after the +% public ones where needed. +% \begin{macrocode} +\let\@kernel@after@shipout@lastpage\@empty +\let\@kernel@before@shipout@background\@empty +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\@@_execute_firstpage_hook: } +% This command adds any specials into a box and adds that to the +% very beginning of the first box shipped out. After that we +% redefine it to do nothing on later pages. +% \begin{macrocode} +\cs_new:Npn \@@_execute_firstpage_hook: { +% \end{macrocode} +% Adding something to the beginning means adding it to the +% background as that layer is done first in the output. Of course +% that is only needed if the hook actually contains anything. +% \begin{macrocode} + \hook_if_empty:nF {shipout/firstpage} + { \@@_add_background_box:n { \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 \@@_execute_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}{\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 te 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 initializes (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 +% tis 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\% 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 change 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 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. +% \begin{macrocode} + \bool_if:NF \g_@@_lastpage_handled_bool + { +% \end{macrocode} +% 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 \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} +% +% \begin{macrocode} +\cs_new_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. +% +% \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} +% \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}{The hook management (shipout)}% +%<latexrelease>\expandafter\let\expandafter\shipout\csname tex_shipout:D\endcsname +%<latexrelease> +%<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> +%<latexrelease>\let \AtBeginShipoutDiscard \@undefined +%<latexrelease> +%<latexrelease>\let \AtBeginShipoutAddToBox \@undefined +%<latexrelease>\let \AtBeginShipoutAddToBoxForeground \@undefined +%<latexrelease>\let \AtBeginShipoutUpperLeft \@undefined +%<latexrelease>\let \AtBeginShipoutUpperLeftForeground \@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 should not interfer with existing +% commands) and properly removing it would mean we need to make the +% \cs{unclare@...} and its support macros available in all earlier +% kernel releases which is pointless (and actually worse). +% \begin{macrocode} +%\undeclare@file@substitution{everyshi.sty} +% \end{macrocode} +% +% \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 interfer 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 to simulating it is easy +% and actually sensible to provide as part of the kernel. +% \begin{macrocode} +%</2ekernel> +%<*2ekernel|latexrelease> +%<latexrelease>\IncludeInRelease{2020/10/01}% +%<latexrelease> {\AtEndDvi}{atenddvi emulation}% +\ExplSyntaxOn +\cs_new_protected:Npn \AtEndDvi {\AddToHook{shipout/lastpage}} +\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} + [2020/08/17 v1.0a + Emulation of the original atbegshi package^^Jwith 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 +% \begin{macrocode} +\protected \def \AtBeginShipout {\AddToHook{shipout/before}} +\protected \def \AtBeginShipoutNext {\AddToHookNext{shipout/before}} +% \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}{\ShipoutBoxHeight,\ShipoutBoxWidth,\ShipoutoBoxDepth} +% 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} +\ExplSyntaxOn +\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} +% +% \begin{macrocode} +%<*everyshi-ltx> +% \end{macrocode} +% +% \begin{macrocode} +\ProvidesPackage{everyshi-ltx} + [2020/08/17 v1.0a + Emulation of the original everyshi package^^Jwith kernel methods] +% \end{macrocode} +% +% \begin{macro}{\EveryShipout,\AtNextShipout} +% This package has only two public commands so simulating it is easy: +% \begin{macrocode} +\protected \def \EveryShipout {\AddToHook{shipout/before}} +\protected \def \AtNextShipout {\AddToHookNext{shipout/before}} +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +% This is one difference between \pkg{everyshi} and the kernel +% implementation, the latter does not directly use box 255. +% +% For usage by ordinary users this makes no difference but of a +% package use complicated code together with \pkg{everyshi} and +% directly manipulates box 255 then this package needs updating. +% In most cases the updates are simple because the kernel offers +% hooks that makes such complicated code unnecessary. +% +% We therefore add a little file into the adjusted package +% \begin{macrocode} +%% +%% In normal circumstances the above emulation is sufficient and in +%% all known packages (we know of) that use everyshi it either works or +%% the packages have been adjusted. +%% +%% Code that directly manipulates box 255, however, might fail. +%% If that is the case look at the shipout hooks offered now as +%% they are normally sufficienct to avoid such minpulations (or +%% replace box 255 with \ShipoutBox in the code. +%% +%</everyshi-ltx> +% \end{macrocode} +% +% +% If the package is requested we substitute the one above: +% \begin{macrocode} +%<*2ekernel> +\declare@file@substitution{everyshi.sty}{everyshi-ltx.sty} +%</2ekernel> +% \end{macrocode} +% +% +% Rather important :-) +% \begin{macrocode} +%<@@=> +% \end{macrocode} +% +% \Finale +% +% +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\endinput +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |