-
-
Notifications
You must be signed in to change notification settings - Fork 245
/
ltshipout.dtx
1999 lines (1995 loc) · 69.9 KB
/
ltshipout.dtx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
% \iffalse meta-comment
%
% Copyright (C) 2020-2021 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.0f}
\providecommand\ltshipoutdate{2021/01/08}
% \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, \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
% forground 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 extra shipouts. It does have access to \cs{Shipoutbox}
% though if it is used in \hook{shipout/before} 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}).
% \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).
%
% \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.}
%
% 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).
%
%
% \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.
%
% Once the (page) box has been shipped out the
% \hook{shipout/after} hook is called (while you are still inide
% the output routine.
%
% 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.
%
% If \cs{RawShipout} is used instead of \cs{shipout} then only the
% hooks \hook{shipout/firstpage} and \hook{shipout/lastpage} are
% executed, all others are bypassed.
%
%
% \subsection{Legacy \LaTeX{} commands}
%
%
% \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{.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.
% \end{function}
%
% As these two wrappers have been available for a long time we
% continue offering them. However, for new code we 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. For this reason we do not
% provide any other wrapper commands for the above hooks in the
% kernel.
%
%
% \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)!
% 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 restricition, 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, forground 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}
%
%
% \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 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 it 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}{\@@_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 deadcyles, 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
{ \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 #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
{ \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 #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
{ \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 #1
% \end{macrocode}
% Run the hooks for background and foreground (or nothing if this
% is called by \cs{RawShipout}.
% \begin{macrocode}
#3
% \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}
% 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}
% 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 #1
% \end{macrocode}
% The \hook{shipout/after} hook (if exected in \verb=#4=) needs to
% run with \cs{protect}ed commands again being executedas 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}
%
% \begin{macrocode}
\cs_new:Npn \@@_execute_nohooks_cont: {
\@@_execute_main_cont:Nnnn \l_@@_raw_box {}{}{}
}
% \end{macrocode}
% \end{macro}
% \begin{macro}{\RawShipout}
% The interface name for raw shipout.
% \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}