%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % Module: ZzTeX Vertical Mode Facilities % % Synopsis: % % Author: Paul C. Anagnostopoulos % Created: 21 September 1989 % % Copyright 1989--2020 by Paul C. Anagnostopoulos % under The MIT License (opensource.org/licenses/MIT) % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Interline Skip % --------- ---- \def \nointerlineskip {% \prevdepth = -1000pt} \def \offinterlineskip {% \baselineskip = -1000pt \lineskip = 0pt \lineskiplimit = \maxdimen} % Vertical Skiping Environment % -------- ------- ----------- % The following registers make up the vertical skiping environment. \definecount{\zvskenvtype}{0} % Previous vertical skip type. \definecount{\zvskenvpen}{0} % Previous columnbreak penalty. \defineskip{\zvskenvreq}{0pt} % Previous required base-to-base skip. \defineskip{\zvskenvskip}{0pt} % Previous actual skip amount. \chardef \zvskenvdiscard = 0 % Just initialized the environment. \chardef \zvskenvpar = 1 % Previous element was a paragraph. \chardef \zvskenvabove = 2 % Just finished an above skip. \chardef \zvskenvbelow = 3 % Just finished a below skip. \chardef \zvskenvmath = 4 % Previous element was a paragraph ending % with a math display. \definecount{\zvskenvnopen}{20000\relax} \let \noskip = \mindimen % The vertical skiping environment is maintained in the vertical context. \zdeclareeveryvcontext{\zvskenvvcontext} \def \zvskenvvcontext {% \zsavevcontext{\zvskenvtype=\the\zvskenvtype \zvskenvpen=\the\zvskenvpen \zvskenvreq=\the\zvskenvreq \zvskenvskip=\the\zvskenvskip}% \zvskpar \global\zvskenvtype = \zvskenvdiscard} % Base-to-Base Skiping % ------------ ------- \declareeverypar{\zvskpar} \def \zvskpar {% \global\zvskenvtype = \zvskenvpar \global\zvskenvpen = \zvskenvnopen \global\zvskenvreq = \parskip \global\advance \zvskenvreq by \baselineskip \global\zvskenvskip = 0pt} %~ This command produces vertical space so that the base-to-base %~ distance above the next element is equal to the *glue*. The %~ space is preceded by the specified *penalty*. If there is a font %~ change for the next element, it must be specified before this command. \def \bbskipabove #1#2{% {penalty}{glue} %^vspace \if \neqlp{\zvskenvtype}{\zvskenvdiscard}% {\zvskprevmath{\parskip}{\baselineskip}% \zparseglue #2\zmark \setflag \znosk = {\dimeqlp{\zskipa}{\noskip}}% \vpenalty{#1}% \ifcase \zvskenvtype \relax \or \if \znosk \zskipa = \zvskenvreq \fi \or \zskipa = \zvskenvreq \or \if \dimlssp{\zskipa}{\zvskenvreq}\zskipa = \zvskenvreq \fi \or \if \dimlssp{\zskipa}{\zvskenvreq}\zskipa = \zvskenvreq \fi \fi \if \notp{\dimzerop{\zvskenvskip}}\vskip -\zvskenvskip \fi \zskipb = \zskipa \advance \zskipb by -\parskip \advance \zskipb by -\baselineskip \vskip \zskipb \if \notp{\znosk}% \global\zvskenvtype = \zvskenvabove \global\zvskenvreq = \zskipa \fi \global\zvskenvskip = \zskipb}% \fi} %~ This command produces vertical space so that the base-to-base %~ distance below the current element is equal to the *glue*. The %~ space is preceded by the specified *penalty*. \def \bbskipbelow #1#2{% {penalty}{glue} %^vspace \zvskbelow{#1}{#2}{\parskip}{\baselineskip}} \def \bbskipbelowblock #1#2{% {penalty}{glue} \zvskbelow{#1}{#2}{\enclosingparskip}{\enclosingbaselineskip}} % This macro "returns" a value in \parnext: % \noindent if next token does not start a new paragraph. % empty if next token starts a new paragraph. \def \bbskipbelowblockpar #1#2#3{% {token}{penalty}{glue} {\setflag \znext = \false % Set \true if token starts new paragraph. \ifcat \noexpand#1\relax \setflag \znext = \true \fi \ifcat \noexpand#1\endgraf \setflag \znext = \true \fi \ifcat \noexpand#1\egroup \setflag \znext = \true \fi \ifcat \noexpand#1&\setflag \znext = \true \fi \ifx #1\noindent \setflag \znext = \false \fi \xdef \parnext {\if \znext \else \noindent \fi}% \zskipa = #3\relax \if \andp{\znext}{\dimneqlp{#3}{\noskip}}% \tdimena = \zskipa \advance \zskipa by -\tdimena \advance \zskipa by \enclosingparskip \advance \zskipa by \enclosingbaselineskip \if \dimlssp{\zskipa}{#3}\zskipa = #3\fi \fi \zvskbelow{#2}{\zskipa}{\enclosingparskip}{\enclosingbaselineskip}}} \def \zvskbelow #1#2#3#4{% {penalty}{glue}{parskip}{baselineskip} {\zvskprevmath{#3}{#4}% \zparseglue #2\zmark \setflag \znosk = {\dimeqlp{\zskipa}{\noskip}}% \vpenalty{#1}% \ifcase \zvskenvtype \zzerror{Skiping type is discard}% \or \if \znosk \zskipa = #3 \advance \zskipa by #4\fi \or \error{skipab}{A `skip below' follows a `skip above'}% \or \if \znosk \zskipa = \zvskenvreq \fi \or \if \dimlssp{\zskipa}{\zvskenvreq}\zskipa = \zvskenvreq \fi \fi \if \notp{\dimzerop{\zvskenvskip}}\vskip -\zvskenvskip \fi \zskipb = \zskipa \advance \zskipb by -#3% \advance \zskipb by -#4% \vskip \zskipb \if \notp{\znosk}% \if \neqlp{\zvskenvtype}{\zvskenvmath}% % Stay as math type so \global\zvskenvtype = \zvskenvbelow % subsequent below skip \fi % won't override. \global\zvskenvreq = \zskipa \fi \global\zvskenvskip = \zskipb}} \def \zvskprevmath #1#2{% {parskip}{baselineskip} \if \eqlp{\mathdisplayprevgraf}{\prevgraf}% \global\zvskenvtype = \zvskenvmath \global\zvskenvpen = \mathdisplayprevpenalty \global\zvskenvreq = \mathdisplayprevskip \global\advance \zvskenvreq by #1 \global\advance \zvskenvreq by #2 \global\zvskenvskip = \mathdisplayprevskip \global\mathdisplayprevgraf = -1\relax \fi} %~ This command forces the next base-to-base skip command %~ regardless of the relationship between the previous element %~ and the next one. \def \forcenextbbskip {% %^vspace \global\zvskenvtype = \zvskenvpar \global\mathdisplayprevgraf = -1\relax} \definecount{\zvpen}{0} \def \vpenalty #1{% {penalty} \zvpen = \if \emptyargp{#1}\breaknever \else #1\fi \if \orp{\eqlp{\zvskenvpen}{\zvskenvnopen}} {\eqlp{\zvpen}{\breaknever}}% \columnbreak{\zvpen}% \global\zvskenvpen = \zvpen\relax \else \if \andp{\posp{\zvskenvpen}}{\gtrp{\zvpen}{\zvskenvpen}}% \columnbreak{\zvpen}% \global\zvskenvpen = \zvpen\relax \fi\fi} \def \forcenextpenalty {% \global\zvskenvpen = \zvskenvnopen} \def \repeatpenalty {% \if \neqlp{\zvskenvpen}{\zvskenvnopen}% \columnbreak{\zvskenvpen}% \fi} %~ This command inserts the specified amount of extra vertical space %~ between the previous element and the next one. \def \vspace #1{% {glue} %^vspace \if \neqlp{\zvskenvtype}{\zvskenvdiscard}% \zparseglue #1\zmark \vskip \zskipa \fi} %~ This command inserts extra vertical space between the previous element %~ and the next one. The space is measured in lines; a fractional number %~ is allowed. \def \linespace #1{\vspace{#1\baselineskip}}% {lines} %^vspace \def \zparseglue #1#2\zmark{% {token}{tokens...} \def \znext {#1}% \def \zskip {\skip}% \if \tokeqlp{\znext}{\zskip}% \setskip \zskipa = #2\relax \else \zskipa = #1#2\relax \fi} % Top to Text Skipping % --- -- ---- -------- % These commands use \zskipb so as not to screw up \fakepar. \def \vsinkfromtypearea #1{% {sinkage} \endgraf \nobreak % So \fakepar can't break. \fakepar % So \bbskipabove won't discard. \vbox{}% % Force start of page if not already. \kern -\pagetotal \kern -\headerheight \bbskipabove{\breaknever}{#1}} \let \vsink = \vsinkfromtypearea \def \vsinkfromtrim #1{% {sinkage} \zskipb = #1\relax \advance \zskipb by -\headmargin \vsinkfromtypearea{\zskipb}} \def \vsinkfromtextarea #1{% {sinkage} \zskipb = #1\relax \advance \zskipb by \headerheight \if \topdeltaadjustment \advance \zskipb by \topdelta \fi \vsinkfromtypearea{\zskipb}} % Rules % ----- \def \parrule #1#2{% {shift}{dimensions} \endgraf {\if \notp{\baselinetoprules}\zadjrule{#2}\fi \hfuzz = 100pc \noindent \hspace{#1}\vbox{\hrule height 0pt depth 0pt #2}\endgraf}} \def \colorparrule #1#2#3{% {color}{shift}{dimensions} \endgraf {\if \notp{\baselinetoprules}\zadjrule{#3}\fi \hfuzz = 100pc \noindent \hspace{#2}% \color{#1}\vbox{\hrule height 0pt depth 0pt #3}\endcolor \endgraf}} \def \scotchrule #1#2#3{% {shift}{width}{height,gap,...} \endgraf {\hfuzz = 100pc \commalist{\zscotchlist}{#3}% \tcounta = 1\relax \maplist{\zscotchb{#1}{#2}{##1}}{\zscotchlist}}} \def \zscotchb #1#2#3{% {shift}{width}{dimension} \if \andp{\eqlp{\tcounta}{1}}{\notp{\baselinetoprules}}% \zadjrule{height #3 depth 0pt}% \fi \if \oddp{\tcounta} \noindent \hspace{#1}\vbox{\hrule height #3 depth 0pt width #2}\endgraf \parskip = 0pt \else \nobreak \vspace{#3}% \nointerlineskip \fi \increment \tcounta} \def \zadjrule #1{% {dimensions} \if \notp{\innermodep}% \fakepar \tdimena = \baselineskip \advance \tdimena by -\prevdepth \setbox \zboxa = \hbox{\vrule #1}% \advance \tdimena by -\ht\zboxa \vskip \tdimena \vskip \topskip \rule{height 0pt depth 0pt width 0pt}% \penalty \breaknever \vskip -\topskip \parskip = 0pt \baselineskip = \ht\zboxa \fi} % Vertical Alignment % -------- --------- \def \bottomout {% \hrule width 0pt height 0pt % Make sure \vskip isn't discarded. \vskip 0pt plus 1filll} % Counting Lines % -------- ----- \definecount{\zlinect}{0} \def \countlines #1#2#3#4{% {\count}{width}{font}{text} \setbox\zboxa = \vbox{% \hsize = #2% #3% #4\par}% \global\zlinect = 0 \setbox\zboxa = \vbox{\unvbox\zboxa \zscanvbox}% #1=\zlinect} \def \zscanvbox {% \loop \setflag \zscanagain = \false \setbox\zboxa = \lastbox \if \hboxp{\zboxa}% \global\increment \zlinect \setflag \zscanagain = \true \else\if \notp{\dimzerop{\lastskip}}% \unskip \setflag \zscanagain = \true \else\if \notp{\dimzerop{\lastkern}}% \unkern \setflag \zscanagain = \true \else\if \notp{\zerop{\lastpenalty}}% \unpenalty \setflag \zscanagain = \true \fi\fi\fi\fi \if \zscanagain \repeat} % Special Boxes % ------- ----- \definedimen{\zibprevdepth}{0pt} \long\def \interjectbox #1#2{% {right-shift}{content} {\zibprevdepth = \prevdepth \penalty \breaknever \nointerlineskip \moveright #1 \vbox to 0pt{% \zpushvcontext #1\relax \zpopvcontext}% \prevdepth = \zibprevdepth}} \long\def \smashbox #1{% \vbox to 0pt{% #1\relax \vss}}