[latex3-commits] [git/LaTeX3-latex3-latex2e] shipout-hook-adjust: reordered the execution of shipout hooks so that code in shipout/firstpage really executes first (3db2fc51)

Frank Mittelbach frank.mittelbach at latex-project.org
Tue Jan 19 12:58:54 CET 2021


Repository : https://github.com/latex3/latex2e
On branch  : shipout-hook-adjust
Link       : https://github.com/latex3/latex2e/commit/3db2fc51aac8eab2f75f18a65c05b1e2372589d2

>---------------------------------------------------------------

commit 3db2fc51aac8eab2f75f18a65c05b1e2372589d2
Author: Frank Mittelbach <frank.mittelbach at latex-project.org>
Date:   Tue Jan 19 12:58:54 2021 +0100

    reordered the execution of shipout hooks so that code in shipout/firstpage really executes first


>---------------------------------------------------------------

3db2fc51aac8eab2f75f18a65c05b1e2372589d2
 base/changes.txt                         |   5 ++
 base/ltshipout.dtx                       | 135 ++++++++++++++++++++++++-------
 base/testfiles-lthooks2/shipout2-016.lvt |  32 ++++++++
 base/testfiles-lthooks2/shipout2-016.tlg |  71 ++++++++++++++++
 4 files changed, 213 insertions(+), 30 deletions(-)

diff --git a/base/changes.txt b/base/changes.txt
index 2f6834b4..32b162ef 100644
--- a/base/changes.txt
+++ b/base/changes.txt
@@ -6,6 +6,11 @@ completeness or accuracy and it contains some references to files that
 are not part of the distribution.
 ================================================================================
 
+2021-01-19  Frank Mittelbach  <Frank.Mittelbach at latex-project.org>
+
+	* ltshipout.dtx: Reordered execution of shipout hooks so that code
+	in one can influence code in later ones in a more natural manner.
+
 2021-01-12  Frank Mittelbach  <Frank.Mittelbach at latex-project.org>
 
 	* ltshipout.dtx: Make sure that the shipout/firstpage hook material
diff --git a/base/ltshipout.dtx b/base/ltshipout.dtx
index 5dd75bf5..a0d7de0e 100644
--- a/base/ltshipout.dtx
+++ b/base/ltshipout.dtx
@@ -32,8 +32,8 @@
 %%% From File: ltshipout.dtx
 %
 %    \begin{macrocode}
-\providecommand\ltshipoutversion{v1.0g}
-\providecommand\ltshipoutdate{2021/01/18}
+\providecommand\ltshipoutversion{v1.0h}
+\providecommand\ltshipoutdate{2021/01/19}
 %    \end{macrocode}
 %
 %<*driver>
@@ -899,6 +899,15 @@
 %    \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
@@ -906,12 +915,12 @@
 %    \begin{macrocode}
               #3
 %    \end{macrocode}
-%    We then run \cs{@@_add_firstpage_hook:} that adds
+%    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_hook:
+              \@@_add_firstpage_specials:
 %    \end{macrocode}
 %    Then we check if we have to add the \hook{shipout/lastpage} hook
 %    or the corresponding kernel hook
@@ -946,7 +955,7 @@
 %    \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_hook:
+              \@@_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
@@ -1052,36 +1061,47 @@
 %  \end{macro}
 %
 %
-%  \begin{macro}{\@@_add_firstpage_hook:,\@@_drop_firstpage_hook}
+%  \begin{macro}{\@@_run_firstpage_hook:}
+%
+%    There are three commands to handle the \hook{shipout/firstpage}
+%    hook:
+%    \cs{@@_run_firstpage_hook:}, \cs{@@_add_firstpage_specials:} and
+%    \cs{@@_drop_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.
+%    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 \@@_add_firstpage_hook: {
+\cs_new:Npn \@@_run_firstpage_hook: {
+  \hook_if_empty:nTF {shipout/firstpage}
 %    \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.
+%    If not then we define the other two commands to do nothing.
 %    \begin{macrocode}
-  \hook_if_empty:nF {shipout/firstpage}
        {
+         \cs_gset_eq:NN \@@_add_firstpage_specials:  \prg_do_nothing:
+         \cs_gset_eq:NN \@@_drop_firstpage_specials: \prg_do_nothing:
+       }
 %    \end{macrocode}
-%    First we make a copy of the \cs{l_shipout_box} that we can
-%    restore it later on.
+%    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}
-         \box_set_eq:NN \l_@@_raw_box \l_shipout_box
-         \@@_add_background_box:n { \UseHook{shipout/firstpage} }
-%    \end{macrocode}
-%    After the actual shipout \cs{@@_drop_firstpage_hook:} is
-%    run. Normally that does nothing but now it is used (once) to
-%    restore the earlier content of \cs{l_shipout_box} and then
-%    redefines itself again to do nothing.
-%    \begin{macrocode}
-         \cs_gset:Npn \@@_drop_firstpage_hook: {
-           \box_set_eq:NN \l_shipout_box \l_@@_raw_box
-           \cs_gset_eq:NN \@@_drop_firstpage_hook:  \prg_do_nothing:
-         }
+       {
+         \hbox_set:Nn \l_@@_firstpage_box { \UseHook{shipout/firstpage} }
        }
 %    \end{macrocode}
 %    Once we are here we change the definition to do nothing next time
@@ -1089,7 +1109,7 @@
 %    to become a warning and not add further material to a hook that
 %    is never used again.
 %    \begin{macrocode}
-  \cs_gset_eq:NN \@@_add_firstpage_hook: \prg_do_nothing:
+  \cs_gset_eq:NN \@@_run_firstpage_hook: \prg_do_nothing:
   \cs_gset:Npn \@@_add_firstpage_material:Nn ##1 ##2 {
     \@latex at warning{
         First~ page~ is~ already~ shipped~ out,~ ignoring\MessageBreak
@@ -1097,12 +1117,67 @@
   }
 }
 %    \end{macrocode}
+% \end{macro}
+%
+%
+%
+%  \begin{macro}{\@@_add_firstpage_specials:,\@@_drop_firstpage_hook}
+%    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: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
+%    accured 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_eq:NN \@@_drop_firstpage_hook: \prg_do_nothing:
+\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
diff --git a/base/testfiles-lthooks2/shipout2-016.lvt b/base/testfiles-lthooks2/shipout2-016.lvt
new file mode 100644
index 00000000..0f6971a0
--- /dev/null
+++ b/base/testfiles-lthooks2/shipout2-016.lvt
@@ -0,0 +1,32 @@
+\RequirePackage[enable-debug]{expl3}
+\ExplSyntaxOn
+\debug_on:n { check-declarations , deprecation }
+\ExplSyntaxOff
+
+\documentclass[a4paper]{article}
+
+\input{regression-test}
+
+\AddToHook{shipout/foreground}{\show\foreground}
+\AddToHook{shipout/background}{\show\background}
+\AddToHook{shipout/firstpage}{\show\firstpage}
+\makeatletter
+\g at addto@macro \@kernel at after@shipout at background
+ {\show\kernel}
+\AddToHook{shipout/lastpage}{\show\lastpage}
+
+\DebugShipoutsOn
+
+\showoutput
+
+
+\begin{document}
+
+\START
+
+blub
+
+\end{document}
+
+
+
diff --git a/base/testfiles-lthooks2/shipout2-016.tlg b/base/testfiles-lthooks2/shipout2-016.tlg
new file mode 100644
index 00000000..65836000
--- /dev/null
+++ b/base/testfiles-lthooks2/shipout2-016.tlg
@@ -0,0 +1,71 @@
+This is a generated file for the l3build validation system.
+Don't change this file in any respect.
+Absolute page = 1 (target: 1)
+> \firstpage=undefined.
+\__hook_toplevel shipout/firstpage ... \firstpage 
+l. ...\end{document}
+> \foreground=undefined.
+\__hook_toplevel shipout/foreground ...foreground 
+l. ...\end{document}
+> \background=undefined.
+\__hook_toplevel shipout/background ...background 
+l. ...\end{document}
+> \kernel=undefined.
+\@kernel at after@shipout at background ->\show \kernel 
+l. ...\end{document}
+Executing lastpage hook on page 1
+> \lastpage=undefined.
+\__hook_toplevel shipout/lastpage ...ow \lastpage 
+l. ...\end{document}
+Completed box being shipped out [1]
+\vbox(682.0+0.0)x398.0
+.\hbox(0.0+0.0)x0.0
+.\hbox(0.0+0.0)x0.0
+..\kern -72.27
+..\vbox(0.0+0.0)x0.0, glue set 72.27fil
+...\kern -72.27
+...\hbox(0.0+0.0)x0.0
+....\glue 0.0 plus 1.0fil minus 1.0fil
+...\glue 0.0 plus 1.0fil minus 1.0fil
+.\glue 17.0
+.\vbox(665.0+0.0)x345.0, shifted 53.0
+..\vbox(12.0+0.0)x345.0, glue set 12.0fil
+...\glue 0.0 plus 1.0fil
+...\hbox(0.0+0.0)x345.0
+..\glue 25.0
+..\glue(\lineskip) 0.0
+..\vbox(598.0+0.0)x345.0, glue set 587.9372fil
+...\write-{}
+...\glue(\topskip) 3.05556
+...\hbox(6.94444+0.0)x345.0, glue set 310.5555fil
+....\hbox(0.0+0.0)x15.0
+....\OT1/cmr/m/n/10 b
+....\OT1/cmr/m/n/10 l
+....\OT1/cmr/m/n/10 u
+....\OT1/cmr/m/n/10 b
+....\penalty 10000
+....\glue(\parfillskip) 0.0 plus 1.0fil
+....\glue(\rightskip) 0.0
+...\glue 0.0 plus 1.0fil
+...\glue 0.0
+...\glue 0.0 plus 0.0001fil
+..\glue(\baselineskip) 23.55556
+..\hbox(6.44444+0.0)x345.0, glue set 170.0fil
+...\glue 0.0 plus 1.0fil
+...\OT1/cmr/m/n/10 1
+...\glue 0.0 plus 1.0fil
+.\kern -682.0
+.\hbox(0.0+0.0)x0.0
+..\kern -72.27
+..\vbox(0.0+0.0)x0.0, glue set 72.27fil
+...\kern -72.27
+...\hbox(0.0+0.0)x0.0
+....\glue 0.0 plus 1.0fil minus 1.0fil
+...\glue 0.0 plus 1.0fil minus 1.0fil
+.\kern 682.0
+.\kern 0.0
+.\kern 0.0
+.\kern -682.0
+.\hbox(0.0+0.0)x0.0
+.\kern 682.0
+(shipout2-016.aux)





More information about the latex3-commits mailing list.