spac-ver.mkiv /size: 79 Kb    last modification: 2021-10-28 13:50
1%D \module
2%D   [       file=spac-ver,
3%D        version=2009.10.16, % 1997.03.31, was core-spa.tex
4%D          title=\CONTEXT\ Spacing Macros,
5%D       subtitle=Vertical,
6%D         author=Hans Hagen,
7%D           date=\currentdate,
8%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
9%C
10%C This module is part of the \CONTEXT\ macro||package and is
11%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
12%C details.
13
14\writestatus{loading}{ConTeXt Spacing Macros / Vertical}
15
16\unprotect
17
18\registerctxluafile{spac-ver}{optimize}
19
20% todo: use usernodes ?
21
22% todo: itemize : intro ... only when there is one or two lines preceding and then
23% keep these together i.e. \blank[intro]
24
25% Isn't it about time to get rid of topskip i.e. make it equivalent to
26% \openstrutheight so that we can remove delta code.
27%
28% There might be more namespace protection.
29
30%D There are two ways to influence the interline spacing. The most general and often
31%D most consistent way is using
32%D
33%D \showsetup{setupinterlinespace}
34%D
35%D For instance
36%D
37%D \starttyping
38%D \setupinterlinespace[line=2.8ex]
39%D \stoptyping
40%D
41%D This setting adapts itself to the bodyfontsize, while for instance saying
42%D
43%D \starttyping
44%D \setupinterlinespace[line=12pt]
45%D \stoptyping
46%D
47%D sets things fixed for all sizes, which is definitely not what we want. Therefore
48%D one can also say:
49%D
50%D \starttyping
51%D \definebodyfontenvironment[9pt][interlinespace=11pt]
52%D \stoptyping
53%D
54%D One can still use \type {\setupinterlinespace} (without arguments) to set the
55%D interline space according to the current font, e.g. a \type {\bfa}.
56
57% will be cleaned up but it will stay messy because we accept so
58% many variants
59
60\newif\iflocalinterlinespace
61
62\newskip \s_spac_vspacing_temp \s_spac_vspacing_temp\bigskipamount
63
64\def\skipfactor    {.75}
65\def\skipgluefactor{.25}
66
67\def\normalskipamount
68  {\openlineheight
69     \ifgridsnapping \else \ifconditional\c_spac_whitespace_flexible
70       \s!plus \skipgluefactor\openlineheight
71       \s!minus\skipgluefactor\openlineheight
72     \fi \fi
73   \relax}
74
75\ifdefined\bodyfontinterlinespace \else
76  \let\bodyfontinterlinespace\empty
77\fi
78
79\unexpanded\def\presetnormallineheight % each bodyfont
80  {\edef\normallineheight{\interlinespaceparameter\c!line}%
81   \iflocalinterlinespace \else
82     \edef\m_spac_normallineheight{\bodyfontinterlinespace}%
83     \ifx\m_spac_normallineheight\empty \else
84       \let\normallineheight\m_spac_normallineheight
85     \fi
86   \fi}
87
88\unexpanded\def\setupspecifiedinterlinespace[#1]%
89  {\setupcurrentinterlinespace[#1]%
90   \spac_linespacing_setup_specified_interline_space}
91
92\def\spac_linespacing_setup_specified_interline_space
93  {\edef\strutheightfactor    {\interlinespaceparameter\c!height   }%
94   \edef\strutdepthfactor     {\interlinespaceparameter\c!depth    }%
95   \edef\minimumstrutheight   {\interlinespaceparameter\c!minheight}%
96   \edef\minimumstrutdepth    {\interlinespaceparameter\c!mindepth }%
97   \edef\minimumlinedistance  {\interlinespaceparameter\c!distance }%
98   \edef\normallineheight     {\interlinespaceparameter\c!line     }%
99   \edef\topskipfactor        {\interlinespaceparameter\c!top      }%
100   \edef\maxdepthfactor       {\interlinespaceparameter\c!bottom   }%
101   \edef\m_spac_vertical_baseline_stretch_factor{\interlinespaceparameter\c!stretch  }%
102   \edef\m_spac_vertical_baseline_shrink_factor {\interlinespaceparameter\c!shrink   }%
103   % often topskip does more bad than good, so:
104   \ifx\topskipfactor\v!height
105     \let\topskipfactor\strutheightfactor
106   \fi
107   \setfontparameters % redundant, can be \setstrut, test first
108   \updateraggedskips} % yes indeed
109
110\installcorenamespace{interlinespacerelative}
111
112\let\setrelativeinterlinespace    \relax % used elsewhere
113\let\currentrelativeinterlinespace\empty
114
115\setvalue{\??interlinespacerelative\v!on   }{\oninterlineskip}
116\setvalue{\??interlinespacerelative\v!off  }{\offinterlineskip}
117\setvalue{\??interlinespacerelative\v!reset}{\let\currentrelativeinterlinespace\empty
118                                             \let\setrelativeinterlinespace\relax
119                                             \setfontparameters}
120\setvalue{\??interlinespacerelative\v!auto }{\let\setrelativeinterlinespace\spac_linespacing_set_relative_interlinespace}
121
122\def\spac_linespacing_set_specified_relative_interlinespace#1% fragile?
123  {\doifelsedimenstring{#1}
124     {\setupspecifiedinterlinespace[\c!line=#1]}
125     {\assignvalue{#1}\currentrelativeinterlinespace{1.00}{1.25}{1.50}%
126      \spacing\currentrelativeinterlinespace}}
127
128\unexpanded\def\setuprelativeinterlinespace[#1]%
129  {\processcommalist[#1]\spac_linespacing_setup_relative_interlinespace}
130
131\def\spac_linespacing_setup_relative_interlinespace#1%
132  {\ifcsname\??interlinespacerelative#1\endcsname
133     \lastnamedcs
134   \else
135     \spac_linespacing_set_specified_relative_interlinespace{#1}%
136   \fi}
137
138\def\spac_linespacing_set_relative_interlinespace
139  {\ifx\currentrelativeinterlinespace\empty\else
140     \spacing\currentrelativeinterlinespace
141   \fi}
142
143\unexpanded\def\spac_linespacing_setup_use
144  {\ifcsname\namedinterlinespacehash\m_spac_interlinespace\s!parent\endcsname
145      \let\currentinterlinespace\m_spac_interlinespace
146      \spac_linespacing_setup_specified_interline_space
147 % \else
148     % we only support named interlinespaces
149   \fi}
150
151\unexpanded\def\useinterlinespaceparameter#1% see footnotes
152  {\edef\m_spac_interlinespace{#1\c!interlinespace}%
153   \ifx\m_spac_interlinespace\empty \else
154     \spac_linespacing_setup_use
155   \fi}
156
157\newtoks\everysetupglobalinterlinespace
158\newtoks\everysetuplocalinterlinespace
159
160\newconditional\interlinespaceisset
161
162\installcorenamespace{interlinespace}
163
164\installcommandhandler \??interlinespace {interlinespace} \??interlinespace
165
166\installmacrostack\currentinterlinespace
167
168\unexpanded\def\setupinterlinespace
169  {\dosingleempty\spac_linespacing_setup}
170
171\def\spac_linespacing_setup[#1]%
172  {\settrue\interlinespaceisset % reset has to be done when needed
173   \iffirstargument
174     \ifcsname\namedinterlinespacehash{#1}\s!parent\endcsname
175        \edef\currentinterlinespace{#1}%
176        \spac_linespacing_setup_specified_interline_space
177       %\dosetupspecifiedinterlinespaceindeed
178     \else
179       \spac_linespacing_setup_specified_or_relative[#1]%
180     \fi
181   \else
182     \let\currentinterlinespace\empty
183     \spac_linespacing_synchronize_local
184   \fi}
185
186\def\spac_linespacing_setup_specified_or_relative[#1]%
187  {\doifelseassignment{#1}\setupspecifiedinterlinespace\setuprelativeinterlinespace[#1]%
188   \the\iflocalinterlinespace\everysetuplocalinterlinespace\else\everysetupglobalinterlinespace\fi}
189
190\def\spac_linespacing_synchronize_local % adapts to the font
191  {\localinterlinespacetrue
192   \setfontparameters
193   \updateraggedskips % funny one here
194   \the\everysetuplocalinterlinespace
195   \localinterlinespacefalse}
196
197\unexpanded\def\dosetupcheckedinterlinespace#1% often a chain
198  {\edef\p_spac_checked_interlinespace{#1}%
199   \ifx\p_spac_checked_interlinespace\empty
200     \spac_linespacing_synchronize_local
201   \else\ifcsname\namedinterlinespacehash\p_spac_checked_interlinespace\s!parent\endcsname % we could have a \s!check
202     \push_macro_currentinterlinespace
203     \let\currentinterlinespace\p_spac_checked_interlinespace
204     \spac_linespacing_setup_specified_interline_space % \dosetupspecifiedinterlinespaceindeed
205     \iflocalinterlinespace
206       \the\everysetuplocalinterlinespace
207     \else
208       \localinterlinespacetrue
209       \the\everysetuplocalinterlinespace
210       \localinterlinespacefalse
211     \fi
212     \pop_macro_currentinterlinespace
213   \else
214     \normalexpanded{\noexpand\doifelseassignment{\p_spac_checked_interlinespace}%
215       \setupspecifiedinterlinespace\setuprelativeinterlinespace[\p_spac_checked_interlinespace]}%
216     \iflocalinterlinespace
217       \the\everysetuplocalinterlinespace
218     \else
219       \localinterlinespacetrue
220       \the\everysetuplocalinterlinespace
221       \localinterlinespacefalse
222     \fi
223   \fi\fi}
224
225\unexpanded\def\setuplocalinterlinespace[#1]%
226  {\localinterlinespacetrue
227   \push_macro_currentinterlinespace
228   \setupinterlinespace[#1]%
229   \pop_macro_currentinterlinespace
230   \localinterlinespacefalse}
231
232\let\switchtointerlinespace\setuplocalinterlinespace
233
234%D Helpers
235
236\newskip \s_spac_lastskip
237\newdimen\d_spac_prevdepth
238\newcount\c_spac_spacefactor
239\newdimen\d_spac_prevcontent % set by lua
240
241\unexpanded\def\removelastskip
242  {\ifvmode\ifzeropt\lastskip\else\vskip-\lastskip\fi\fi}
243
244\def\doifoutervmode
245  {\ifvmode
246     \ifinner
247       \doubleexpandafter\gobbleoneargument
248     \else
249       \doubleexpandafter\firstofoneargument
250     \fi
251   \else
252     \expandafter\gobbleoneargument
253   \fi}
254
255\unexpanded\def\dosomebreak#1%
256  {\doifoutervmode
257     {\s_spac_lastskip\lastskip
258      \removelastskip
259      #1\relax
260      \ifzeropt\s_spac_lastskip
261        % avoid interference with footnotes
262      \else
263        \vskip\s_spac_lastskip
264      \fi}}
265
266\unexpanded\def\packed
267  {\nointerlineskip}
268
269\unexpanded\def\godown[#1]%
270  {\relax
271   \ifhmode\endgraf\fi
272   \ifvmode\nointerlineskip\vskip#1\relax\fi}
273
274\unexpanded\def\smallskip{\vskip\smallskipamount}
275\unexpanded\def\medskip  {\vskip\medskipamount}
276\unexpanded\def\bigskip  {\vskip\bigskipamount}
277
278\unexpanded\def\smallbreak
279  {\par
280   \ifvmode\ifdim\lastskip<\smallskipamount
281     \removelastskip
282     \penalty-\plusfifty
283     \smallskip
284   \fi\fi}
285
286\unexpanded\def\medbreak
287  {\par
288   \ifvmode\ifdim\lastskip<\medskipamount
289     \removelastskip
290     \penalty-\plusonehundred
291     \medskip
292   \fi\fi}
293
294\unexpanded\def\bigbreak
295  {\par
296   \ifvmode\ifdim\lastskip<\bigskipamount
297     \removelastskip
298     \penalty-\plustwohundred
299     \bigskip
300   \fi\fi}
301
302\unexpanded\def\break     {\penalty-\plustenthousand} % can be hmode or vmode
303\unexpanded\def\nobreak   {\penalty \plustenthousand} % can be hmode or vmode
304\unexpanded\def\allowbreak{\penalty \zerocount}       % can be hmode or vmode
305
306\unexpanded\def\goodbreak {\par\ifvmode\penalty-\plusfivehundred\relax\fi}       % forces vmode
307\unexpanded\def\filbreak  {\par\ifvmode\vfil\penalty-\plustwohundred\vfilneg\fi} % forces vmode
308
309%D Made slightly more readable:
310
311\unexpanded\def\vglue  {\afterassignment\spac_helpers_vglue_indeed\s_spac_lastskip=}
312\unexpanded\def\hglue  {\afterassignment\spac_helpers_hglue_indeed\s_spac_lastskip=}
313\unexpanded\def\topglue{\par\ifvmode\nointerlineskip\vglue-\topskip\vglue\fi}
314
315\def\spac_helpers_vglue_indeed
316  {\par
317   \ifvmode
318     \d_spac_prevdepth\prevdepth
319     \hrule\s!height\zeropoint
320     \nobreak
321     \vskip\s_spac_lastskip
322     \prevdepth\d_spac_prevdepth
323   \fi}
324
325\def\spac_helpers_hglue_indeed
326  {\dontleavehmode
327   \c_spac_spacefactor\spacefactor
328   \vrule\s!width\zeropoint
329   \nobreak
330   \hskip\s_spac_lastskip
331   \spacefactor\c_spac_spacefactor}
332
333%D We adapt plain's \type {\removelastskip} a bit:
334
335\unexpanded\def\removelastskip % also in supp-box
336  {\ifvmode\ifzeropt\lastskip\else\vskip-\lastskip\fi\fi}
337
338% The whitespace handler. We could cache settings but normally there are not
339% that many in a set.
340
341\installcorenamespace{whitespacemethod}
342
343\newskip       \s_spac_whitespace_parskip   \s_spac_whitespace_parskip\zeropoint
344\newconditional\c_spac_whitespace_flexible  \settrue\c_spac_whitespace_flexible
345\newconstant   \c_spac_whitespace_grid_mode % option in layout / 1=permit_half_lines
346
347%def\v_spac_whitespace_current{\zeropoint}
348\let\v_spac_whitespace_current\v!none
349
350\unexpanded\def\setupwhitespace
351  {\doifelsenextoptionalcs\spac_whitespace_setup_yes\spac_whitespace_setup_nop}
352
353\def\spac_whitespace_setup_nop
354  {\ifx\v_spac_whitespace_current\v!none\else
355     \spac_whitespace_setup
356   \fi}
357
358\let\synchronizewhitespace\spac_whitespace_setup_nop
359
360\def\spac_whitespace_setup_yes[#1]%
361  {\edef\m_spac_whitespace_asked{#1}%
362   \ifx\m_spac_whitespace_asked\empty
363     \spac_whitespace_setup_nop
364   \else
365     \let\v_spac_whitespace_current\m_spac_whitespace_asked
366     \spac_whitespace_setup
367   \fi}
368
369\def\spac_whitespace_setup % quick test for no list
370  {\ifcsname\??whitespacemethod\v_spac_whitespace_current\endcsname
371     \lastnamedcs
372   \else
373     \expandafter\processcommalist\expandafter[\v_spac_whitespace_current]\spac_whitespace_setup_method % can be raw
374   \fi\relax
375   \ifgridsnapping
376     \spac_whitespace_setup_grid
377   \else
378     \spac_whitespace_setup_normal
379   \fi
380   \parskip\s_spac_whitespace_parskip}
381
382\def\spac_whitespace_setup_normal
383  {\ifconditional\c_spac_whitespace_flexible \else
384     \s_spac_whitespace_parskip\plusone\s_spac_whitespace_parskip
385   \fi}
386
387\def\spac_whitespace_setup_grid
388  {\setfalse\c_spac_whitespace_flexible
389   \ifdim\s_spac_whitespace_parskip>\zeropoint
390     \s_spac_whitespace_parskip
391       \ifcase\c_spac_whitespace_grid_mode
392         \baselineskip
393       \or
394         \ifdim\scratchdimen=\baselineskip % maybe range
395           \baselineskip
396         \else
397           \numexpr\s_spac_whitespace_parskip/\dimexpr.5\lineheight\relax\relax\dimexpr.5\lineheight\relax
398         \fi
399       \else
400         \baselineskip
401       \fi
402   \fi}
403
404\unexpanded\def\installwhitespacemethod#1#2%
405  {\setvalue{\??whitespacemethod#1}{#2}}
406
407\installwhitespacemethod \v!fix         {}
408\installwhitespacemethod \v!fixed       {\setfalse\c_spac_whitespace_flexible}
409\installwhitespacemethod \v!flexible    {\settrue \c_spac_whitespace_flexible}
410
411\installwhitespacemethod \v!line        {\s_spac_whitespace_parskip   \baselineskip}
412\installwhitespacemethod \v!halfline    {\s_spac_whitespace_parskip .5\baselineskip}
413\installwhitespacemethod \v!quarterline {\s_spac_whitespace_parskip.25\baselineskip}
414\installwhitespacemethod \v!none        {\s_spac_whitespace_parskip   \zeropoint}
415\installwhitespacemethod \v!big         {\s_spac_whitespace_parskip   \bigskipamount}
416\installwhitespacemethod \v!medium      {\s_spac_whitespace_parskip   \medskipamount}
417\installwhitespacemethod \v!small       {\s_spac_whitespace_parskip   \smallskipamount}
418
419\installwhitespacemethod \s!default     {\spac_whitespace_setup_nop} % also covers none
420
421\def\spac_whitespace_setup_method#1%
422  {\ifcsname\??whitespacemethod#1\endcsname
423     \lastnamedcs
424   \else
425     \s_spac_whitespace_parskip#1\fi
426   \relax}
427
428\unexpanded\def\forgetparskip
429  {\s_spac_whitespace_parskip\zeropoint
430   \parskip\zeropoint
431   \let\v_spac_whitespace_current\v!none}
432
433\appendtoks
434    \forgetparskip
435\to \everyforgetall
436
437% \installwhitespacemethod \s!unknown  {\s_spac_whitespace_parskip\commalistelement\relax}
438%
439% \def\spac_whitespace_setup_method#1%
440%   {\csname\??whitespacemethod\ifcsname\??whitespacemethod#1\endcsname#1\else\s!unknown\endcsname\relax}
441
442\unexpanded\def\nowhitespace{\directcheckedvspacing\v!nowhite} % {\vspacing[\v!nowhite]}
443\unexpanded\def\whitespace  {\directcheckedvspacing\v!white}   % {\vspacing[\v!white]}
444
445\setupwhitespace
446  [\v!none]
447
448% Packed:
449
450% todo: when packed blocks blank, we need to enable forced
451
452\newconditional\c_spac_packed_blank \settrue\c_spac_packed_blank
453\newcount      \c_spac_packed_level
454
455\unexpanded\def\startpacked
456  {\dosingleempty\spac_packed_start}
457
458\def\spac_packed_start[#1]% nesting afvangen
459  {\global\advance\c_spac_packed_level\plusone
460   \par
461   \ifnum\c_spac_packed_level=\plusone \ifvmode
462     \begingroup
463     \whitespace % not combined
464     \directcheckedvspacing\v!disable % \blank[\v!disable]% or \inhibitblank
465     \doifelse{#1}\v!blank\settrue\setfalse\c_spac_packed_blank
466     \setupwhitespace[\v!none]% or \forgetparskip
467   \fi \fi}
468
469\unexpanded\def\stoppacked
470  {\par
471   \ifnum\c_spac_packed_level=\plusone \ifvmode
472     \endgroup
473   \fi \fi
474   \global\advance\c_spac_packed_level\minusone}
475
476\unexpanded\def\startunpacked
477  {\directdefaultvspacing % \blank
478   \begingroup}
479
480\unexpanded\def\stopunpacked
481  {\endgroup
482   \directdefaultvspacing}% \blank}
483
484% \prevdepth crosses pageboundaries!
485%
486% todo: a version that works ok inside a box
487
488% global : outer hsize + keep skips
489% local  : inner hsize + reset skips
490
491\installcorenamespace{linesaround}
492
493\let\spac_lines_vbox\vbox
494
495\installtextracker
496  {linecorrection.boxes}
497  {\let\spac_lines_vbox\ruledvbox}
498  {\let\spac_lines_vbox\vbox}
499
500\let\v_spac_lines_around_action_set\relax
501\let\m_spac_lines_around           \empty
502
503\newconstant\c_spac_lines_correction_mode
504
505\setvalue{\??linesaround\v!blank  }{\blank}
506\letvalue{\??linesaround\empty    }\relax
507\setvalue{\??linesaround\s!unknown}{\directcheckedvspacing\m_spac_lines_around} % \blank[\m_spac_lines_around]}
508
509\def\spac_lines_action_around % we used to let this one but it's cleaner this way
510  {\csname\??linesaround      % i.e. do it twice
511     \ifcsname\??linesaround\m_spac_lines_around\endcsname\m_spac_lines_around\else\s!unknown\fi
512   \endcsname}
513
514\unexpanded\def\startlinecorrection
515  {\endgraf
516   \begingroup
517   \setconstant\c_spac_lines_correction_mode\plusone
518   \dosingleempty\spac_lines_start_correction}
519
520\unexpanded\def\startlocallinecorrection
521  {\endgraf
522   \begingroup
523   \setconstant\c_spac_lines_correction_mode\plustwo
524   \dosingleempty\spac_lines_start_correction}
525
526\unexpanded\def\spac_lines_start_correction[#1]%
527  {\edef\m_spac_lines_around{#1}%
528   \spac_lines_action_around
529   \d_spac_prevdepth\prevdepth
530   \spac_lines_initialize_corrections
531   \offbaselinecorrection % ???
532   \setbox\scratchbox\spac_lines_vbox\bgroup
533     \ifcase\c_spac_lines_correction_mode
534       % nothing
535     \or
536       % global
537     \or
538       % local
539       \setlocalhsize
540       \hsize\localhsize
541       \forgetbothskips
542     \fi
543     \ignorespaces}
544
545\unexpanded\def\spac_lines_stop_correction
546  {\removeunwantedspaces
547   \egroup
548   \ifgridsnapping
549     \spac_lines_stop_correction_ongrid
550   \else
551     \spac_lines_stop_correction_normal
552   \fi
553   \endgroup}
554
555\unexpanded\def\spac_lines_stop_correction_ongrid
556  {\directcheckedvspacing\v!white % \blank[\v!white]%
557   \spac_lines_action_around
558   \snaptogrid\hpack{\box\scratchbox}%
559   \directcheckedvspacing\v!white
560   \spac_lines_action_around}
561
562\unexpanded\def\spac_lines_stop_correction_normal
563  {\directcheckedvspacing\v!nowhite % \blank[\v!nowhite]%
564   \ifdim\parskip>\zeropoint
565      % too fuzzy otherwise
566   \else
567      % doesn't like whitespace
568     \ifdim\d_spac_prevdepth<\maxdimen
569       \unless\ifdim\d_spac_prevdepth<\zeropoint
570         \ifdim\d_spac_prevdepth<\strutdp \relax
571           \pushlastnode
572           \ifdim\d_spac_prevdepth>\zeropoint
573              \kern-\d_spac_prevdepth
574           \fi
575           \kern\strutdp
576           \prevdepth\strutdp
577           \poplastnode
578         \fi
579       \fi
580     \fi
581   \fi
582   \ifdim\pagegoal<\maxdimen
583   % \blank[\v!white,\the\d_spac_lines_correction_before]% \blank[\v!white]\dotopbaselinecorrection
584     \directcheckedvspacing{\v!white,\the\d_spac_lines_correction_before}% \blank[\v!white]\dotopbaselinecorrection
585   \fi
586   \nointerlineskip % new
587   \noindent % not \dontleavehmode !
588   \ifcase\c_spac_lines_correction_mode
589     % nothing
590   \or
591     % global
592     \hskip-\leftskip % more tricky would be hangindent so we ignore that one
593   \or
594     % local
595   \fi
596   \box\scratchbox
597   \endgraf
598   %
599   % eventually i'll get it right ... (i also need to check all whitespace code elsewhere)
600   %
601 % \blank[\the\d_spac_lines_correction_after]% \dobotbaselinecorrection
602 % \directcheckedvspacing{\the\d_spac_lines_correction_after}% \dobotbaselinecorrection
603   \directcheckedvspacing{\v!white,\the\d_spac_lines_correction_after}% \dobotbaselinecorrection
604 % \allowbreak % new, otherwise problems when many in a row
605   \prevdepth\strutdp
606   \spac_lines_action_around}
607
608\let\stoplinecorrection     \spac_lines_stop_correction
609\let\stoplocallinecorrection\spac_lines_stop_correction
610
611% todo:
612
613\unexpanded\def\correctwhitespace
614  {\dowithnextboxcs\correctwhitespacefinish\vbox}
615
616\unexpanded\def\correctwhitespacefinish
617  {\startbaselinecorrection
618   \flushnextbox
619   \stopbaselinecorrection}
620
621\unexpanded\def\verticalstrut  {\vpack{\hsize\zeropoint\forgetall\strut}}
622\unexpanded\def\horizontalstrut{\hpack                          {\strut}}
623
624%D Here follow some presets related to interline spacing and therefore also struts.
625%D The values 2.8, 0.07, 0.72 and 0.28 originate in \INRSTEX, a package that we used
626%D a while after we decided that \LATEX\ was not flexible enough. After that
627%D \CONTEXT\ evolved, from some wrapper code around (old) \LATEX\ (on a floppy
628%D disk), to using modules from \INRSTEX\ (which also fit on a floppy) and finally
629%D all written from scratch. I simply didn't understand all that \TEX\ code at that
630%D time, and it was easier to figure it out myself. But \unknown\ some settings
631%D stayed, as the height|/|depth ratios, and they never proved to be bad ones! The
632%D same is true for the font size relations.
633
634%D \starttabulate
635%D \NC  \type {\lineheight}        \NC the height of a line \NC \NR
636%D \NC  \type {\spacing{number}}   \NC adapting the interline space \NC \NR
637%D \NC  \type {\normalbaselines}   \NC initialize the interline spacing \NC \NR
638%D \NC  \type {\setstrut}          \NC initialize \type {\strut} \NC \NR
639%D \NC  \type {\setnostrut}        \NC disable the \type {\strut}, \type {\endstrut}, \type {\begstrut} \NC \NR
640%D \NC  \type {\setteststrut}      \NC initialize the visual \type {\strut} \NC \NR
641%D \NC  \type {\resetteststrut}    \NC disable the visual \type {\strut} \NC \NR
642%D \NC  \type {\setfontparameters} \NC synchronize parameters with foints \NC \NR
643%D \stoptabulate
644%D
645%D \unknown\ and many more (this is a decades old list).
646%D
647%D The lineheight is the sum of the height and depth of \type {strut}, which is
648%D an invisible blob that can be used to enforce the proper dimensions.
649%D
650%D Such a blob, when placed at the beginning of a paragraph can have side effects
651%D that can be prevented with \type {\dontleavehmode}. Never use \type
652%D {\leavevmode}!
653
654\newdimen\strutdimen
655\newdimen\lineheight
656\newdimen\openlineheight
657\newdimen\openstrutheight
658\newdimen\openstrutdepth
659\newdimen\topskipgap
660\newdimen\struttotal
661
662\def\strutheightfactor      {.72}
663\def\strutdepthfactor       {.28}
664
665\def\baselinefactor         {2.8}
666
667\let\m_spac_vertical_baseline_stretch_factor \zerocount
668\let\m_spac_vertical_baseline_shrink_factor  \zerocount
669
670\def\minimumstrutheight     {\zeropoint}
671\def\minimumstrutdepth      {\zeropoint}
672
673\def\normallineheight       {\baselinefactor\exheight}
674\def\minimumlinedistance    {\lineskip}
675
676\def\strutheight            {\zeropoint}
677\def\strutdepth             {\zeropoint}
678\def\strutwidth             {\zeropoint}
679
680\let\spacingfactor          \plusone
681
682\def\topskipfactor          {1.0}
683\def\maxdepthfactor         {0.5}
684
685\def\systemtopskipfactor    {\topskipfactor}
686\def\systemmaxdepthfactor   {\maxdepthfactor}
687
688\ifdefined\globalbodyfontsize \else
689    \newdimen\globalbodyfontsize
690    \globalbodyfontsize=12pt
691\fi
692
693\ifdefined\normalizedbodyfontsize \else
694    \def\normalizedbodyfontsize{12pt}
695\fi
696
697\unexpanded\def\topskipcorrection
698  {\simpletopskipcorrection
699   \vskip-\struttotal
700   \verticalstrut}
701
702\unexpanded\def\simpletopskipcorrection
703  {\ifdim\topskip>\openstrutheight
704     % == \vskip\topskipgap
705     \vskip\topskip
706     \vskip-\openstrutheight
707   \fi}
708
709\unexpanded\def\settopskip % the extra test is needed for the lbr family
710  {\topskip
711     \ifgridsnapping
712       \zeropoint
713     \else
714       \systemtopskipfactor\globalbodyfontsize
715       \ifcase\bottomraggednessmode % ragged bottom
716         \s!plus5\globalbodyfontsize
717       \fi
718   \fi
719   %\relax
720   \topskipgap\topskip
721   \advance\topskipgap -\openstrutheight\relax
722   \ifdim\minimumstrutheight>\zeropoint
723     \ifdim\topskip<\minimumstrutheight
724       \topskip\minimumstrutheight\relax
725     \fi
726   \else
727     \ifdim\topskip<\strutheightfactor\openlineheight
728       \topskip\strutheightfactor\openlineheight\relax
729     \fi
730   \fi}
731
732\unexpanded\def\setmaxdepth
733  {\maxdepth\systemmaxdepthfactor\globalbodyfontsize}
734
735\newskip \usedbaselineskip
736\newskip \usedlineskip
737\newdimen\usedlineskiplimit
738
739\unexpanded\def\normalbaselines
740  {\baselineskip \usedbaselineskip
741   \lineskip     \usedlineskip
742   \lineskiplimit\usedlineskiplimit}
743
744\unexpanded\def\flexiblebaselines
745  {\baselineskip \usedbaselineskip
746   \lineskip     1\usedlineskip \s!plus 1\s!fill
747   \lineskiplimit\usedlineskiplimit}
748
749\unexpanded\def\setnormalbaselines
750  {\ifdim\normallineheight>\zeropoint
751     \lineheight\normallineheight
752   \fi
753   \openlineheight\spacingfactor\lineheight
754   \openstrutheight \ifdim\minimumstrutheight>\zeropoint
755     \minimumstrutheight % new
756   \else
757     \strutheightfactor\openlineheight
758   \fi
759   \openstrutdepth \ifdim\minimumstrutdepth>\zeropoint
760     \minimumstrutdepth % new
761   \else
762     \strutdepthfactor \openlineheight
763   \fi
764   \ifdim\dimexpr\minimumstrutdepth+\minimumstrutheight\relax>\zeropoint
765     \openlineheight\dimexpr\openstrutheight+\openstrutdepth\relax % new
766   \fi
767   \usedbaselineskip\openlineheight
768     \ifgridsnapping\else
769       \s!plus \m_spac_vertical_baseline_stretch_factor\openlineheight
770       \s!minus\m_spac_vertical_baseline_shrink_factor \openlineheight
771     \fi
772   \usedlineskip\minimumlinedistance\relax % \onepoint\relax
773   \usedlineskiplimit\zeropoint\relax
774   \normalbaselines}
775
776\unexpanded\def\spacing#1% vertical
777  {\ifgridsnapping
778     \let\spacingfactor\plusone
779   \else
780     \edef\spacingfactor{#1}%
781   \fi
782   \edef\systemtopskipfactor {\withoutpt\the\dimexpr#1\dimexpr\topskipfactor \points}%
783   \edef\systemmaxdepthfactor{\withoutpt\the\dimexpr#1\dimexpr\maxdepthfactor\points}%
784   \setnormalbaselines
785   \setstrut}
786
787% \unexpanded\def\forgetverticalstretch % \forgetspacing
788%   {\spacing\plusone}
789
790\unexpanded\def\forgetverticalstretch
791  {\let\spacingfactor       \plusone
792   \let\systemtopskipfactor \topskipfactor
793   \let\systemmaxdepthfactor\maxdepthfactor
794   \setnormalbaselines
795   \setstrut}
796
797\appendtoks
798    \forgetverticalstretch
799\to \everyforgetall % needed in otr
800
801%D Sometimes one needs to freeze the interlinespacing
802%D
803%D \starttyping
804%D \rm \saveinterlinespace .... {\ss \restoreinterlinespace .... \endgraf}
805%D \stoptyping
806
807\let\restoreinterlinespace\relax
808
809\unexpanded\def\saveinterlinespace
810  {\unexpanded\edef\restoreinterlinespace
811     {\lineheight         \the\lineheight
812      \openstrutheight    \the\openstrutheight
813      \openstrutdepth     \the\openstrutdepth
814      \openlineheight     \the\openlineheight
815      \usedbaselineskip   \the\usedbaselineskip
816      \usedlineskip       \the\usedlineskip
817      \usedlineskiplimit  \the\usedlineskiplimit
818      \noexpand\def\noexpand\normallineheight{\the\dimexpr\normallineheight}%
819      \noexpand\normalbaselines}}
820
821%D This is the plain definition:
822%D
823%D \starttyping
824%D \def\strut{\relax\ifmmode\copy\strutbox\else\unhcopy\strutbox\fi}
825%D \stoptyping
826%D
827%D which could be:
828%D
829%D \starttyping
830%D \def\strut{\relax\ifmmode\copy\else\unhcopy\fi\strutbox}
831%D \stoptyping
832%D
833%D But we do things differently.
834
835\newbox\strutbox
836
837\setbox\strutbox\hpack{\vrule\s!height8.5pt\s!depth3.5pt\s!width\zeropoint} % just a start
838
839\def\strut{\relax\ifmmode\copy\else\unhcopy\fi\strutbox}
840
841% \unexpanded\def\strut
842%   {\relax
843%    \ifmmode\copy\else\dontleavehmode\unhcopy\fi\strutbox}
844
845\let\normalstrut\strut
846
847%D The double \type {\hbox} construction enables us to backtrack boxes.
848
849\let\strutht\undefined \newdimen\strutht
850\let\strutdp\undefined \newdimen\strutdp
851
852\unexpanded\def\setstrut
853  {\ifgridsnapping
854     \setstrutgridyes
855   \else
856     \setstrutgridnop
857   \fi}
858
859\unexpanded\def\setstrutgridyes
860  {\strutht\spacingfactor\dimexpr
861     \ifdim\minimumstrutheight>\zeropoint
862       \minimumstrutheight
863     \else
864       \strutheightfactor\dimexpr\normallineheight
865     \fi
866   \strutdp\dimexpr
867     \ifdim\minimumstrutdepth>\zeropoint
868       \minimumstrutdepth
869     \else
870       \normallineheight-\strutht
871     \fi
872   \dosetstrut}
873
874\unexpanded\def\setstrutgridnop
875  {\strutht\spacingfactor\dimexpr
876     \ifdim\minimumstrutheight>\zeropoint
877       \minimumstrutheight
878     \else
879       \strutheightfactor\dimexpr\normallineheight
880     \fi
881   \strutdp\spacingfactor\dimexpr
882     \ifdim\minimumstrutdepth>\zeropoint
883       \minimumstrutdepth
884     \else
885       \strutdepthfactor\dimexpr\normallineheight
886     \fi
887   \dosetstrut}
888
889\unexpanded\def\setcharstrut#1%
890  {\setbox\strutbox\hbox{#1}% no \hpack, in case we have smallcaps
891   \strutht\ht\strutbox
892   \strutdp\dp\strutbox
893   \dosetstrut}
894
895\unexpanded\def\settightstrut
896  {\setcharstrut{(}}
897
898\unexpanded\def\setfontstrut
899  {\setcharstrut{(gplQT}}
900
901\unexpanded\def\setcapstrut% could be M, but Q has descender
902  {\setcharstrut{Q}}
903
904%D Handy for math (used in mathml):
905
906\unexpanded\def\charhtstrut
907  {\begingroup
908   \setcharstrut{GJY}%
909   \vrule\s!width\zeropoint\s!depth\zeropoint\s!height\strutht
910   \endgroup}
911
912\unexpanded\def\chardpstrut
913  {\begingroup
914   \setcharstrut{gjy}%
915   \vrule\s!width\zeropoint\s!depth\strutdp\s!height\zeropoint
916   \endgroup}
917
918%D Because of all the callbacks in mkiv, we avoid unnecessary boxes ... maybe use an
919%D attribute so that we can tag boxes that don't need a treatment; tests with using
920%D an attribute so far have shown that it's slower because testing the attribute
921%D takes time too.
922
923\unexpanded\def\dosetstrut
924  {\let\strut\normalstrut
925   \ifabsnum\dimexpr\strutht+\strutdp-\lineheight\relax<\plustwo
926     % compensate rounding error /- 1sp to avoid too many
927     % 1sp baselineskips in for instance verbatim
928     % \strutht\dimexpr\lineheight-\strutdp\relax
929     % better:
930     \strutdp\dimexpr\lineheight-\strutht\relax
931     \struttotal\lineheight
932   \else
933     \struttotal\dimexpr\strutht+\strutdp\relax
934   \fi
935   \edef\strutheight{\the\strutht}%
936   \edef\strutdepth {\the\strutdp}%
937   \ifdim\strutwidth=\zeropoint
938      \spac_struts_set_hide
939   \else
940      \spac_struts_set_vide
941   \fi}
942
943\def\spac_struts_set_hide
944  {\setbox\strutbox\hpack
945     {\vrule
946        \s!width \zeropoint
947        \s!height\strutht
948        \s!depth \strutdp}}
949
950\newconstant\c_strut_visual_mode
951
952\def\spac_struts_set_vide
953  {\setbox\strutbox\hpack  % at some time this extra wrapping was needed
954     {\spac_struts_vide_hbox to \zeropoint
955        {\ifcase\c_strut_visual_mode
956           \spac_struts_black
957         \or
958           \spac_struts_color
959         \else
960           \spac_struts_black
961         \fi}}}
962
963\def\spac_struts_black
964  {\vrule
965     \s!width \strutwidth
966     \s!height\strutht
967     \s!depth \strutdp
968   \hss}
969
970\def\spac_struts_color
971  {\hss % new, will be option
972   \scratchwidth.1\struthtdp
973   \begingroup
974   \directcolor[f:b:t]%
975   \vrule
976     \s!width \scratchwidth
977     \s!height\strutht
978     \s!depth \strutdp
979   \kern-\scratchwidth
980   \vrule
981     \s!width \scratchwidth
982     \s!height\zeropoint
983     \s!depth \strutdp
984   \endgroup
985   \kern-.625\scratchwidth
986   \vrule
987     \s!width .25\scratchwidth
988     \s!height\strutht
989     \s!depth \strutdp
990   \hss}
991
992\let\spac_struts_vide_hbox\hbox % overloaded in trac-vis.mkiv
993
994%D The dimen \type {\struttotal} holds the exact size of the strut; occasionally a
995%D one scaled point difference can show up with the lineheight. This is more
996%D efficient (less callbacks):
997
998\newbox\b_spac_struts_empty \setbox\b_spac_struts_empty\emptyhbox
999
1000\def\spac_struts_set_hide
1001  {\setbox\strutbox\copy\b_spac_struts_empty
1002   \ht\strutbox\strutht
1003   \dp\strutbox\strutdp}
1004
1005\unexpanded\def\strut % still callbacks for \hbox{\strut}
1006  {\relax
1007   \dontleavehmode
1008   \copy\strutbox}
1009
1010% \unexpanded\def\strut % slightly faster
1011%   {\relax
1012%    \ifmmode\copy\else\dontleavehmode\unhcopy\fi\strutbox}
1013
1014\let\normalstrut\strut
1015
1016\unexpanded\def\halfstrut
1017  {\relax
1018   \dontleavehmode
1019   \begingroup
1020   \setbox\scratchbox\copy\strutbox
1021   \ht\scratchbox\dimexpr\strutht/\plustwo\relax
1022   \dp\scratchbox\dimexpr\strutdp/\plustwo\relax
1023   \box\scratchbox
1024   \endgroup}
1025
1026\unexpanded\def\quarterstrut
1027  {\relax
1028   \dontleavehmode
1029   \begingroup
1030   \setbox\scratchbox\copy\strutbox
1031   \ht\scratchbox\dimexpr\strutht/\plusfour\relax
1032   \dp\scratchbox\dimexpr\strutdp/\plusfour\relax
1033   \box\scratchbox
1034   \endgroup}
1035
1036\unexpanded\def\depthstrut
1037  {\relax
1038   \dontleavehmode
1039   \begingroup
1040   \setbox\scratchbox\copy\strutbox
1041   \ht\scratchbox\dimexpr\strutht-\struthtdp/\plustwo\relax % assumes that ht > lineheight/2
1042   \box\scratchbox
1043   \endgroup}
1044
1045\unexpanded\def\halflinestrut
1046  {\relax
1047   \dontleavehmode
1048   \begingroup
1049   \setbox\scratchbox\copy\strutbox
1050   \ht\scratchbox\dimexpr\strutht-.5\strutht-.5\strutdp\relax
1051   \box\scratchbox
1052   \endgroup}
1053
1054\unexpanded\def\noheightstrut
1055  {\relax
1056   \dontleavehmode
1057   \begingroup
1058   \setbox\scratchbox\copy\strutbox
1059   \ht\scratchbox\zeropoint
1060   \box\scratchbox
1061   \endgroup}
1062
1063%D Sometimes a capstrut comes in handy
1064%D
1065%D \starttabulate[|Tl|l|l|]
1066%D \NC yes          \NC normal strut               \NC {\showstruts\setupstrut[yes]\strut}  \NC \NR
1067%D \NC no           \NC no strut                   \NC {\showstruts\setupstrut[no]\strut}  \NC \NR
1068%D \NC kap          \NC a capital strut (i.e. Q)   \NC {\showstruts\setupstrut[cap]\strut} \NC \NR
1069%D \NC A B \unknown \NC a character strut (e.g. A) \NC {\showstruts\setupstrut[A]\strut}   \NC \NR
1070%D \NC              \NC a normal strut             \NC {\showstruts\setupstrut\strut}      \NC \NR
1071%D \stoptabulate
1072%D
1073%D Beware: using an unknown value results in char struts.
1074
1075\installcorenamespace{struts}
1076
1077\unexpanded\def\setupstrut
1078  {\dosingleempty\spac_struts_setup}
1079
1080\def\spac_struts_setup[#1]%
1081  {\edef\m_strut{#1}%
1082   \ifcsname\??struts\m_strut\endcsname
1083     \lastnamedcs
1084   \else
1085     \setcharstrut\m_strut
1086   \fi}
1087
1088\unexpanded\def\synchronizestrut#1% no [] parsing, faster for internal
1089  {\edef\m_strut{#1}%
1090   \ifcsname\??struts\m_strut\endcsname
1091     \lastnamedcs
1092   \else
1093     \setcharstrut\m_strut
1094   \fi}
1095
1096\unexpanded\def\dosynchronizestrut#1% no [] parsing, faster for internal
1097  {\ifcsname\??struts#1\endcsname
1098     \lastnamedcs
1099   \else
1100     \setcharstrut{#1}%
1101   \fi}
1102
1103\unexpanded\def\showstruts % adapts .. is wrong
1104  {\c_strut_visual_mode\zerocount
1105   \setteststrut
1106   \settestcrlf}
1107
1108\unexpanded\def\showcolorstruts % adapts .. is wrong
1109  {\c_strut_visual_mode\plusone
1110   \setteststrut
1111   \settestcrlf}
1112
1113\unexpanded\def\setteststrut
1114  {\def\strutwidth{.8pt}%
1115   \setstrut}
1116
1117\unexpanded\def\dontshowstruts
1118  {\unsetteststrut
1119   \settestcrlf}
1120
1121\unexpanded\def\unsetteststrut
1122  {\let\strutwidth\zeropoint
1123   \setstrut}
1124
1125\def\autostrutfactor{1.1}
1126
1127\unexpanded\def\setautostrut
1128  {\begingroup
1129   \setbox\scratchbox\copy\strutbox
1130   \setstrut
1131   \ifdim\strutht>\autostrutfactor\ht\scratchbox
1132     \endgroup \setstrut
1133   \else\ifdim\strutdp>\autostrutfactor\dp\scratchbox
1134     \endgroup \setstrut
1135   \else
1136     \endgroup
1137   \fi\fi}
1138
1139\newbox\nostrutbox \setbox\nostrutbox\emptyhbox
1140
1141\newtoks\everysetnostrut
1142
1143\unexpanded\def\setnostrut
1144  {\the\everysetnostrut}
1145
1146\appendtoks
1147    \setbox\strutbox\copy\nostrutbox
1148    \let\strut\empty
1149    \let\endstrut\empty
1150    \let\begstrut\empty
1151\to \everysetnostrut
1152
1153%D When enabled, sigstruts will remove themselves if nothing goes inbetween. For
1154%D practical reasons we define some boundary characters here.
1155
1156\unexpanded\def\leftboundary   {\protrusionboundary\plusone}
1157\unexpanded\def\rightboundary  {\protrusionboundary\plustwo}
1158\unexpanded\def\signalcharacter{\boundary\plusone\char\zerocount\boundary\plustwo} % not the same as strut signals
1159
1160\newsignal\strutsignal \setfalse\sigstruts
1161
1162\unexpanded\def\begstrut
1163  {\relax\ifcase\strutht
1164     % \ignorespaces % maybe
1165   \else
1166     \spac_struts_beg
1167   \fi}
1168
1169\def\spac_struts_beg
1170  {\ifconditional\sigstruts
1171     \spac_struts_beg_signal
1172   \else
1173     \spac_struts_beg_normal
1174   \fi
1175   \ignorespaces}
1176
1177\def\spac_struts_beg_signal
1178  {\noindent\horizontalstrut
1179   \penalty\plustenthousand
1180   \hskip-\strutsignal
1181   \hskip\strutsignal}
1182
1183\def\spac_struts_beg_normal
1184  {\boundary\plusone
1185   \strut
1186  %\boundary\plusone
1187   \penalty\plustenthousand
1188  %\boundary\plusone
1189   \hskip\zeropoint}
1190
1191\unexpanded\def\endstrut
1192  {\relax\ifhmode
1193     \ifcase\strutht
1194       % \removeunwantedspaces % maybe
1195     \else
1196       \spac_struts_end
1197     \fi
1198   \fi}
1199
1200\def\spac_struts_end
1201  {\ifconditional\sigstruts
1202     \spac_struts_end_signal
1203   \else
1204     \spac_struts_end_normal
1205   \fi}
1206
1207\def\spac_struts_end_signal
1208  {\ifdim\lastskip=\strutsignal
1209     \unskip
1210     \unskip
1211     \unpenalty
1212     \setbox\scratchbox\lastbox
1213   \else
1214     \penalty\plustenthousand
1215     \hskip\zeropoint
1216     \strut
1217   \fi}
1218
1219\def\spac_struts_end_normal
1220  {\removeunwantedspaces
1221   \penalty\plustenthousand
1222  %\boundary\plustwo
1223   \hskip\zeropoint
1224  %\boundary\plustwo
1225   \strut
1226   \boundary\plustwo}
1227
1228% unsave:
1229%
1230% \def\pseudostrut
1231%   {\bgroup
1232%    \setnostrut
1233%    \normalstrut
1234%    \egroup}
1235%
1236% try:
1237%
1238% \startchemie
1239%   \chemie[ONE,Z0,SB15,MOV1,SB15,Z0][C,C]
1240% \stopchemie
1241%
1242% so:
1243
1244\unexpanded\def\pseudostrut
1245  {\noindent} % better: \dontleavehmode
1246
1247\let\pseudobegstrut\pseudostrut
1248\let\pseudoendstrut\removeunwantedspaces
1249
1250\unexpanded\def\resetteststrut
1251  {\def\strutwidth{\zeropoint}% no let
1252   \setstrut}
1253
1254\ifdefined\setfontparameters \else
1255    \def\setfontparameters{\the\everybodyfont}
1256\fi
1257
1258%D Keyword based strutting:
1259
1260\letvalue{\??struts\v!yes    }\setstrut
1261\letvalue{\??struts\v!auto   }\setautostrut
1262\letvalue{\??struts\v!no     }\setnostrut
1263\letvalue{\??struts\v!cap    }\setcapstrut
1264\letvalue{\??struts\v!fit    }\setfontstrut
1265\letvalue{\??struts\v!line   }\setstrut
1266\letvalue{\??struts\s!default}\setstrut
1267\letvalue{\??struts\empty    }\setstrut
1268
1269%D Handy:
1270
1271\def\baselinedistance{\the\lineheight}
1272
1273%D We need \type {\normaloffinterlineskip} because the new definition contains an
1274%D assignment, and |<|don't ask me why|>| this assignment gives troubles in for
1275%D instance the visual debugger.
1276
1277\unexpanded\def\offinterlineskip
1278  {\baselineskip-\thousandpoint
1279   \lineskip     \zeropoint
1280   \lineskiplimit\maxdimen
1281   % We also need this here now; thanks to taco for figuring that out!
1282   \def\minimumlinedistance{\zeropoint}}
1283
1284\unexpanded\def\nointerlineskip
1285  {\prevdepth-\thousandpoint}
1286
1287\let\normaloffinterlineskip\offinterlineskip % knuth's original
1288
1289%D This is tricky. The prevdepth value is still set to the last one even if there is
1290%D nothing on the page. The same is true for prevgraf, which doesn't resemble the
1291%D value on the current page.
1292%D
1293%D So, here we kick in a checker but it has to happen after the output group and it
1294%D only has to be done once (output can trigger itself!).
1295%D
1296%D However, prevgraf is somehow bound to hangindent so we can get very nasty side
1297%D effects. So, in tne end we use our own variable!
1298
1299\ifdefined\getnofpreviouslines
1300    % defined public at the lua end
1301\else
1302    \let\getnofpreviouslines\!!zerocount
1303\fi
1304
1305\unexpanded\def\page_otr_synchronize_page_yes
1306  {\aftergroup\page_otr_synchronize_page_indeed
1307   \glet\page_otr_synchronize_page\relax}
1308
1309% \unexpanded\def\page_otr_synchronize_page_indeed
1310%   {\clf_synchronizepage
1311%    \glet\page_otr_synchronize_page\page_otr_synchronize_page_yes}
1312%
1313% This has to become an otr method: \s!page_otr_command_synchonize_page
1314
1315\unexpanded\def\page_otr_synchronize_page_indeed
1316  {\ifx\currentoutputroutine\s!multicolumn\else\clf_synchronizepage\fi
1317   \glet\page_otr_synchronize_page\page_otr_synchronize_page_yes}
1318
1319\let\page_otr_synchronize_page\page_otr_synchronize_page_yes
1320
1321\appendtoks
1322    \page_otr_synchronize_page
1323\to \everyaftershipout
1324
1325%D My own one:
1326
1327\unexpanded\def\spac_helpers_push_interlineskip_yes
1328  {\edef\oninterlineskip
1329     {\baselineskip \the\baselineskip
1330      \lineskip     \the\lineskip
1331      \lineskiplimit\the\lineskiplimit
1332      \noexpand\edef\noexpand\minimumlinedistance{\the\dimexpr\minimumlinedistance}%
1333      \let\noexpand\offinterlineskip\noexpand\normaloffinterlineskip}} % \noexpand not needed
1334
1335\unexpanded\def\spac_helpers_push_interlineskip_nop
1336  {\let\oninterlineskip\setnormalbaselines}
1337
1338\unexpanded\def\offinterlineskip
1339  {\ifdim\baselineskip>\zeropoint
1340     \spac_helpers_push_interlineskip_yes
1341   \else
1342     \spac_helpers_push_interlineskip_nop
1343   \fi
1344   \normaloffinterlineskip}
1345
1346\let\oninterlineskip\relax
1347
1348\unexpanded\def\resetpenalties#1%
1349  {\ifdefined#1%
1350     #1\minusone
1351   \fi}
1352
1353\unexpanded\def\setpenalties#1#2#3%
1354  {\ifdefined#1% space before #3 prevents lookahead problems, needed when #3=text
1355     #1\numexpr#2+\plusone\relax\space\doexpandedrecurse{\the\numexpr#2\relax}{ #3}\zerocount\relax
1356   \fi}
1357
1358%D \macros
1359%D   {keeplinestogether}
1360%D
1361%D Dirty hack, needed in margin content that can run of a page.
1362
1363% just before margintexts ... will eventually be done differently in mkiv using
1364% attributes
1365
1366\newcount\c_spac_keep_lines_together
1367\let\restoreinterlinepenalty\relax
1368
1369\unexpanded\def\spac_penalties_restore
1370  {\glet\restoreinterlinepenalty\relax
1371   \global\resetpenalties\interlinepenalties
1372   \global\c_spac_keep_lines_together\zerocount}
1373
1374\unexpanded\def\keeplinestogether#1%
1375  {\ifnum#1>\c_spac_keep_lines_together
1376     \global\c_spac_keep_lines_together#1%
1377     \global\setpenalties\interlinepenalties\c_spac_keep_lines_together\plustenthousand
1378     \glet\restoreinterlinepenalty\spac_penalties_restore
1379   \fi}
1380
1381\def\defaultdisplaywidowpenalty        {50}
1382\def\defaultwidowpenalty             {2000} % was: 1000
1383\def\defaultclubpenalty              {2000} % was:  800
1384\def\defaultbrokenpenalty             {100}
1385\def\defaultdoublehyphendemerits    {10000}
1386\def\defaultfinalhyphendemerits      {5000}
1387\def\defaultadjdemerits             {10000}
1388
1389\def\defaultgriddisplaywidowpenalty     {0}
1390\def\defaultgridwidowpenalty            {0}
1391\def\defaultgridclubpenalty             {0}
1392\def\defaultgridbrokenpenalty           {0}
1393\def\defaultgriddoublehyphendemerits{10000} % always was so
1394\def\defaultgridfinalhyphendemerits  {5000} % always was so
1395\def\defaultgridadjdemerits         {10000} % always was so
1396
1397\unexpanded\def\nopenalties
1398  {\widowpenalty        \zerocount
1399   \clubpenalty         \zerocount
1400   \brokenpenalty       \zerocount
1401   \doublehyphendemerits\zerocount
1402   \finalhyphendemerits \zerocount
1403   \adjdemerits         \zerocount}
1404
1405\unexpanded\def\setdefaultpenalties
1406  {\directsetup{\systemsetupsprefix\s!default}}
1407
1408\startsetups [\systemsetupsprefix\s!reset]
1409    \resetpenalties\widowpenalties
1410    \resetpenalties\clubpenalties
1411    \resetpenalties\interlinepenalties
1412\stopsetups
1413
1414%D We use \directsetup because it's faster and we know there is no csl:
1415
1416\startsetups [\systemsetupsprefix\s!default]
1417
1418    \directsetup{\systemsetupsprefix\s!reset}
1419
1420    \widowpenalty        \defaultwidowpenalty
1421    \clubpenalty         \defaultclubpenalty
1422    \displaywidowpenalty \defaultdisplaywidowpenalty
1423    \brokenpenalty       \defaultbrokenpenalty
1424    \doublehyphendemerits\defaultdoublehyphendemerits
1425    \finalhyphendemerits \defaultfinalhyphendemerits
1426    \adjdemerits         \defaultadjdemerits
1427
1428\stopsetups
1429
1430\startsetups [\v!grid] [\systemsetupsprefix\s!default]
1431
1432    \directsetup{\systemsetupsprefix\s!reset}
1433
1434    \widowpenalty        \defaultgridwidowpenalty
1435    \clubpenalty         \defaultgridclubpenalty
1436    \displaywidowpenalty \defaultgriddisplaywidowpenalty
1437    \brokenpenalty       \defaultgridbrokenpenalty
1438    \doublehyphendemerits\defaultgriddoublehyphendemerits
1439    \finalhyphendemerits \defaultgridfinalhyphendemerits
1440    \adjdemerits         \defaultgridadjdemerits
1441
1442\stopsetups
1443
1444%D As an illustration:
1445
1446\startsetups [\systemsetupsprefix\v!strict]
1447
1448    \directsetup{\systemsetupsprefix\s!reset}
1449
1450    \setpenalties \widowpenalties      \plustwo \maxdimen
1451    \setpenalties \clubpenalties       \plustwo \maxdimen
1452                  \brokenpenalty                \maxdimen
1453                  \doublehyphendemerits         \defaultdoublehyphendemerits
1454                  \finalhyphendemerits          \defaultfinalhyphendemerits
1455                  \adjdemerits                  \defaultadjdemerits
1456
1457\stopsetups
1458
1459\setdefaultpenalties % will happen later in \setuplayout
1460
1461%D To be checked:
1462
1463\newbox\b_spac_struts_saved
1464
1465\unexpanded\def\savestrut {\setbox\b_spac_struts_saved\copy\strutbox}
1466\unexpanded\def\savedstrut{\copy  \b_spac_struts_saved}
1467
1468%D Good old blank redone:
1469
1470%definesystemattribute[kernchars]    [public]
1471\definesystemattribute[skipcategory] [public]
1472\definesystemattribute[skippenalty]  [public]
1473\definesystemattribute[skiporder]    [public]
1474\definesystemattribute[snapmethod]   [public]
1475\definesystemattribute[snapvbox]     [public]
1476%definesystemattribute[snapcategory] [public]
1477
1478% TODO: NAMED SNAPPERS
1479
1480\installcorenamespace{gridsnappers}
1481\installcorenamespace{gridsnapperattributes}
1482\installcorenamespace{gridsnappersets}
1483
1484\newskip  \bodyfontlineheight
1485\newdimen \bodyfontstrutheight
1486\newdimen \bodyfontstrutdepth
1487
1488\newskip  \globalbodyfontlineheight % why a skip
1489\newdimen \globalbodyfontstrutheight
1490\newdimen \globalbodyfontstrutdepth
1491
1492\def\snappedvboxattribute{\ifgridsnapping    attr\snapvboxattribute\c_attr_snapmethod\fi}
1493\def\setlocalgridsnapping{\ifgridsnapping \c_attr_snapvbox         \c_attr_snapmethod\fi}
1494
1495\def\spac_grids_set_local_snapping#1%
1496  {\ifgridsnapping
1497     \doifsomething{#1}%
1498       {\spac_grids_snap_value_set{#1}%
1499        \c_attr_snapvbox\c_attr_snapmethod}%
1500   \fi}
1501
1502% \unexpanded\def\installsnapvalues#1#2% todo: a proper define
1503%   {\edef\currentsnapper{#1:#2}%
1504%    \ifcsname\??gridsnapperattributes\currentsnapper\endcsname \else
1505%      \setevalue{\??gridsnapperattributes\currentsnapper}{\clf_definesnapmethod{#1}{#2}}%
1506%    \fi
1507%    \setevalue{\??gridsnappers#1}{\c_attr_snapmethod\csname\??gridsnapperattributes\currentsnapper\endcsname\space}}
1508
1509\def\spac_grids_expand_snapper#1%
1510  {\edef\m_spac_snapper
1511     {\ifx\m_spac_snapper\empty\else\m_spac_snapper,\fi
1512      \ifcsname\??gridsnappersets#1\endcsname
1513        \lastnamedcs\else#1%
1514      \fi}}
1515
1516\unexpanded\def\installsnapvalues#1#2%
1517  {\let\m_spac_snapper\empty
1518   \rawprocesscommacommand[#2]\spac_grids_expand_snapper
1519   \edef\currentsnapper{#1:\m_spac_snapper}%
1520   \ifcsname\??gridsnapperattributes\currentsnapper\endcsname
1521     \scratchcounter\lastnamedcs % already defined
1522   \else
1523     \scratchcounter\clf_definesnapmethod{#1}{\m_spac_snapper}%
1524     \setevalue{\??gridsnapperattributes\currentsnapper}{\the\scratchcounter}%
1525   \fi
1526   \setevalue{\??gridsnappers#1}{\c_attr_snapmethod\the\scratchcounter\relax}%
1527   \letvalue{\??gridsnappersets#1}\m_spac_snapper}
1528
1529\def\theexpandedsnapperset#1{\begincsname\??gridsnappersets#1\endcsname} % only for manuals
1530
1531\unexpanded\def\usegridparameter#1% no checking here
1532  {\edef\m_spac_grid_asked{#1\c!grid}%
1533   \ifx\m_spac_grid_asked\empty
1534     \c_attr_snapvbox\attributeunsetvalue
1535   \else
1536     \spac_grids_snap_value_set\m_spac_grid_asked
1537     \c_attr_snapvbox\c_attr_snapmethod
1538   \fi}
1539
1540\unexpanded\def\definegridsnapping
1541  {\dodoubleargument\spac_grids_define}
1542
1543\def\spac_grids_define[#1][#2]%
1544  {\installsnapvalues{#1}{#2}}
1545
1546\edef\spac_grids_snap_value_reset
1547  {%\gridsnappingfalse
1548   \c_attr_snapmethod\attributeunsetvalue}
1549
1550\def\spac_grids_snap_value_set#1%
1551  {%\gridsnappingtrue
1552   \begincsname\??gridsnappers#1\endcsname}
1553
1554% maybe:
1555%
1556% \def\spac_grids_snap_value_set#1%
1557%   {%\gridsnappingtrue
1558%    \ifcsname\??gridsnappers#1\endcsname
1559%      \lastnamedcs
1560%    \else
1561%      \definegridsnapping[#1][#1]%
1562%      \begincsname\??gridsnappers#1\endcsname
1563%    \fi}
1564
1565\def\spac_grids_snap_value_auto#1%
1566  {\ifcsname\??gridsnappers#1\endcsname
1567     \lastnamedcs
1568   \else
1569     \installsnapvalues\s!dummy{#1}%
1570     \csname\??gridsnappers\s!dummy\endcsname
1571   \fi}
1572
1573% \installsnapvalues{loose} {\v!maxdepth:0.8,\v!maxheight:0.8,\v!strut}
1574% \installsnapvalues{normal}{\v!maxdepth:1.0,\v!maxheight:1.0,\v!strut}
1575% \installsnapvalues{tight} {\v!maxdepth:1.2,\v!maxheight:1.2,\v!strut}
1576
1577% none             don't enlarge
1578% halfline         enlarge by halfline/halfline
1579% line             enlarge by line/line
1580% strut            enlarge by ht/dp (default)
1581% first            align to top line
1582% last             align to bottom line
1583% mindepth         round depth down
1584% maxdepth         round depth up
1585% minheight        round height down
1586% maxheight        round height up
1587% local            use local interline space
1588% offset:-3tp      vertical shift within box
1589% bottom:lines
1590% top:lines
1591% box              centers a box rounded upwards (box:.5 -> tolerance)
1592% min              centers a box rounded downwards
1593% max              centers a box rounded upwards
1594
1595%D We're not downward compatible with \MKII ! Not yet in interface file:
1596
1597\definegridsnapping[\v!normal]           [\v!maxheight,\v!maxdepth,\v!strut]
1598\definegridsnapping[\v!standard]         [\v!maxheight,\v!maxdepth,\v!strut]
1599\definegridsnapping[\v!yes]              [\v!maxheight,\v!maxdepth,\v!strut]
1600
1601\definegridsnapping[\v!strict]           [\v!maxdepth:0.8,\v!maxheight:0.8,\v!strut]
1602\definegridsnapping[\v!tolerant]         [\v!maxdepth:1.2,\v!maxheight:1.2,\v!strut]
1603\definegridsnapping[\v!verytolerant]     [\v!maxdepth:1.4,\v!maxheight:1.4,\v!strut]
1604
1605\definegridsnapping[\v!tolerant:10]      [\v!maxdepth:1.1,\v!maxheight:1.1,\v!strut] % 10 pct tolerance
1606\definegridsnapping[\v!tolerant:20]      [\v!maxdepth:1.2,\v!maxheight:1.2,\v!strut] % 20 pct tolerance
1607\definegridsnapping[\v!tolerant:30]      [\v!maxdepth:1.3,\v!maxheight:1.3,\v!strut] % 30 pct tolerance
1608\definegridsnapping[\v!tolerant:40]      [\v!maxdepth:1.4,\v!maxheight:1.4,\v!strut] % 40 pct tolerance
1609
1610\definegridsnapping[\v!top]              [\v!minheight,\v!maxdepth,\v!strut]
1611\definegridsnapping[\v!bottom]           [\v!maxheight,\v!mindepth,\v!strut]
1612\definegridsnapping[\v!both]             [\v!minheight,\v!mindepth,\v!strut]
1613
1614\definegridsnapping[\v!broad]            [\v!maxheight,\v!maxdepth,\v!strut,0.8] % maybe 0.85
1615\definegridsnapping[\v!fit]              [\v!maxheight,\v!maxdepth,\v!strut,1.2] % tight 0.15
1616
1617\definegridsnapping[\v!first]            [\v!first]
1618\definegridsnapping[\v!last]             [\v!last]
1619\definegridsnapping[\v!high]             [\v!minheight,\v!maxdepth,\v!none]
1620\definegridsnapping[\v!one]              [\v!minheight,\v!mindepth]
1621\definegridsnapping[\v!low]              [\v!maxheight,\v!mindepth,\v!none]
1622\definegridsnapping[\v!none]             [\v!none]
1623\definegridsnapping[\v!line]             [\v!line]
1624\definegridsnapping[\v!strut]            [\v!strut]
1625\definegridsnapping[\v!box]              [\v!box]
1626\definegridsnapping[\v!min]              [\v!min]
1627\definegridsnapping[\v!max]              [\v!max]
1628
1629\definegridsnapping[\v!middle]           [\v!maxheight,\v!maxdepth] % used in placement
1630
1631\definegridsnapping[\v!math]             [\v!maxdepth:1.05,\v!maxheight:1.05,\v!strut] % experimental, maybe 1.1
1632\definegridsnapping[\v!math:\v!line]     [\v!math,\v!line,\v!split]
1633\definegridsnapping[\v!math:\v!halfline] [\v!math,\v!halfline,\v!split]
1634\definegridsnapping[\v!math:-\v!line]    [\v!math,-\v!line,\v!split]
1635\definegridsnapping[\v!math:-\v!halfline][\v!math,-\v!halfline,\v!split]
1636
1637\unexpanded\def\synchronizelocallinespecs
1638  {\bodyfontlineheight \normallineheight
1639   \bodyfontstrutheight\strutht
1640   \bodyfontstrutdepth \strutdp}
1641
1642\unexpanded\def\synchronizegloballinespecs
1643  {\global\globalbodyfontlineheight \normallineheight
1644   \global\globalbodyfontstrutheight\strutht
1645   \global\globalbodyfontstrutdepth \strutdp}
1646
1647\appendtoks
1648    \synchronizegloballinespecs
1649    \synchronizelocallinespecs
1650\to \everysetupglobalinterlinespace
1651
1652\appendtoks
1653    \synchronizelocallinespecs
1654\to \everysetuplocalinterlinespace
1655
1656%D We still have to synchronize these:
1657
1658\unexpanded\def\synchronizeskipamounts
1659  {\bigskipamount
1660                 \skipfactor\baselineskip
1661      \s!plus\skipgluefactor\baselineskip
1662     \s!minus\skipgluefactor\baselineskip
1663   \relax
1664   \medskipamount  \bigskipamount \divide\medskipamount  \plustwo
1665   \smallskipamount\bigskipamount \divide\smallskipamount\plusfour}
1666
1667%D Snapping.
1668
1669\newif\ifgridsnapping
1670
1671%unexpanded\def\moveongrid {\dosingleempty\spac_grids_move_on}
1672\unexpanded\def\snaptogrid {\dosingleempty\spac_grids_snap_to}
1673\unexpanded\def\placeongrid{\dosingleempty\spac_grids_place_on}
1674
1675\unexpanded\def\startgridsnapping
1676  {\dosingleempty\spac_grids_start_snapping}
1677
1678\unexpanded\def\spac_grids_start_snapping[#1]%
1679  {\snaptogrid[#1]\vbox\bgroup}
1680
1681\unexpanded\def\stopgridsnapping
1682  {\egroup}
1683
1684% \def\spac_grids_move_on[#1]%
1685%   {[obsolete]} % gone, unless we set an attribute
1686
1687\def\spac_grids_place_on[#1]%
1688  {\snaptogrid[#1]\vbox} % mark as done
1689
1690\def\spac_grids_snap_to[#1]% list or predefined
1691  {\ifgridsnapping
1692     \expandafter\spac_grids_snap_to_indeed
1693   \else
1694     \expandafter\gobbleoneargument
1695   \fi{#1}}
1696
1697\def\spac_grids_snap_to_indeed#1%
1698  {\bgroup
1699   \spac_grids_snap_value_reset
1700   \dowithnextbox{\spac_grids_snap_to_finish{#1}}}
1701
1702% eventually there will always be a line snap
1703
1704\def\spac_grids_snap_to_finish#1%
1705  {\ifvbox\nextbox % this will go away
1706     \clf_vspacingcollapse\nextbox\relax % isn't that already done?
1707   \fi
1708   \doifelsenothing{#1}{\spac_grids_snap_value_set\v!normal}{\spac_grids_snap_value_set{#1}}%
1709   \clf_vspacingsnap\nextbox\c_attr_snapmethod\relax
1710   \ifvbox\nextbox\vbox\else\hbox\fi attr \snapmethodattribute \zerocount {\box\nextbox}% no pack (?), we snap
1711   \egroup}
1712
1713\def\spac_grids_check_nop
1714  {\gridsnappingfalse
1715   \resetsystemmode\v!grid
1716   \spac_grids_snap_value_reset}
1717
1718\def\spac_grids_check_yes
1719  {\gridsnappingtrue
1720   \setsystemmode\v!grid
1721   \spac_grids_snap_value_set\askedgridmode}
1722
1723\unexpanded\def\synchronizegridsnapping
1724  {\edef\askedgridmode{\layoutparameter\c!grid}%
1725   \ifx\askedgridmode\v!no       % official
1726     \spac_grids_check_nop
1727   \else\ifx\askedgridmode\v!off % for taco and luigi
1728     \spac_grids_check_nop
1729   \else\ifx\askedgridmode\empty % to be sure
1730     \spac_grids_check_nop
1731   \else
1732     \spac_grids_check_yes
1733   \fi\fi\fi}
1734
1735\unexpanded\def\setupgridsnapping[#1]% less overhead than setuplayout (needs testing)
1736  {\setlayoutparameter\c!grid{#1}\synchronizegridsnapping}
1737
1738\unexpanded\def\checkgridmethod#1%
1739  {\edef\p_grid{#1}%
1740   \ifx\p_grid\empty
1741     \let\checkedgridmethod\empty
1742     \let\checkedgridscope \v!local
1743   \else
1744     \splitatcolon\p_grid\checkedgridscope\checkedgridmethod
1745     \ifx\checkedgridmethod\empty
1746       \ifx\checkedgridscope\v!local\else\ifx\checkedgridscope\v!global\else
1747         \let\checkedgridmethod\checkedgridscope
1748         \let\checkedgridscope \v!local
1749       \fi\fi
1750     \fi
1751   \fi}
1752
1753\unexpanded\def\applygridmethod#1#2#3% content localsettings (used in head rendering)
1754   {\checkgridmethod{#1}%
1755    \ifx\checkedgridscope\v!global
1756      \ifx\checkedgridmethod\empty \else
1757        % we assume that the call is grouped because grouping here has the side
1758        % effect that the eventually constructed line will get the value outside
1759        % the group
1760        %
1761        % overkill: \setupgridsnapping[\checkedgridmethod]%
1762        % maybe   : \spac_grids_snap_value_auto\checkedgridmethod
1763        \spac_grids_snap_value_set\checkedgridmethod
1764      \fi
1765      \hbox{#3}%
1766    \else
1767      % the extra hbox will trigger the global snapper on top of the local and
1768      % we really need that in this case (compatibility etc etc) so here we don't
1769      % het an already done hit (otherwise we would not snap)
1770      \hbox\bgroup
1771        \ifx\checkedgridmethod\empty\else
1772          \ifconditional\headisdisplay
1773            #2%
1774          \fi
1775        \fi
1776        \snaptogrid[\checkedgridmethod]\hbox{#3}%
1777      \egroup
1778    \fi}
1779
1780\unexpanded\gdef\page_layouts_calculate_overshoot
1781  {\ifgridsnapping\ifcase\layoutlines
1782     \getnoflines\textheight
1783     \textovershoot\dimexpr\noflines\globalbodyfontlineheight-\textheight\relax
1784   \fi\fi}
1785
1786\unexpanded\def\page_layouts_report_overshoot
1787  {\page_layouts_calculate_overshoot
1788   \ifdim\textovershoot>\zeropoint
1789     \writestatus\m!layouts{gridmode,\space
1790       noflines: \the\noflines,\space
1791       textheight: \the\textheight,\space
1792       textovershoot: \the\textovershoot\space
1793       (maybe set number of lines instead)%
1794    }%
1795  \fi
1796  \glet\page_layouts_report_overshoot\page_layouts_calculate_overshoot}
1797
1798\appendtoks
1799    \page_layouts_report_overshoot
1800\to \everybeforepagebody
1801
1802%D Visualization:
1803
1804\definepalet
1805  [grid]
1806  [  one=red,
1807     two=green,
1808   three=blue,
1809    four=gray]
1810
1811\unexpanded\def\setgridtracebox#1[#2]% % maybe reverse the order
1812  {\setbox\nextbox#1%
1813     {\hbox
1814        {\hbox to \zeropoint
1815           {\setlayoutcomponentattribute{\v!grid:\v!test}%
1816            \color[grid:#2]{\ruledhbox \layoutcomponentboxattribute {\fakebox\nextbox}}%
1817            \hss}%
1818         \flushnextbox}}}
1819
1820\setnewconstant\gridboxlinenomode\plusone % 0:nothing 1:all 2:lines 3:frame 4:l/r
1821\setnewconstant\gridboxlinemode  \plusone
1822
1823\unexpanded\def\gridboxvbox
1824  {\ifcase\gridboxlinemode
1825     \vpack
1826   \or
1827     \ruledvpack
1828   \or
1829     \vpack
1830   \or
1831     \ruledvpack
1832   \else
1833     \ruledvpack
1834   \fi}
1835
1836\def\gridboxwidth{\ifcase\gridboxlinemode0\or.5\or.5\or0\else.5\fi\linewidth}
1837
1838\unexpanded\def\setgridbox#1#2#3% maybe ifgridsnapping at outer level
1839  {\setbox#1\gridboxvbox to #3 % given size
1840     {\forgetall
1841      \resetvisualizers
1842      \resetteststrut
1843      \offinterlineskip
1844      \hsize#2%
1845      \ifcase\gridboxlinenomode\or\or\or
1846        \gridboxlinenomode\doifoddpageelse\plusone\plustwo % 3: outer
1847      \or
1848        \gridboxlinenomode\doifoddpageelse\plustwo\plusone % 4: inner
1849      \fi
1850      \topskipcorrection
1851      \gridboxvbox % calculated size
1852        {\getrawnoflines{#3}% \getnoflines{#3}%
1853         \scratchdimen\dimexpr#2+\lineheight\relax
1854         \dorecurse\noflines
1855           {\strut
1856            \hskip-.5\lineheight\relax
1857            \ifcase\gridboxlinenomode\or
1858              \rlap
1859                {\hskip\dimexpr.2\bodyfontsize+\scratchdimen\relax
1860                 \infofont\hbox to \emwidth{\hss\recurselevel}}%
1861            \or
1862              \llap
1863                {\infofont\hbox to \emwidth{\hss\recurselevel}%
1864                 \hskip.2\bodyfontsize}%
1865            \fi
1866            \vrule
1867              \s!height \gridboxwidth
1868              \s!depth  \gridboxwidth
1869              \s!width  \scratchdimen
1870            \par}}
1871      \vfill}}
1872
1873%D This has become obsolete:
1874
1875% \def\moveboxontogrid#1#2#3% will become obsolete, but it needs checking
1876%   {}
1877
1878%D Helper:
1879
1880\unexpanded\def\spac_helpers_assign_skip#1#2% ook nog \v!halfline+fuzzysnap
1881  {\doifelse{#2}\v!line
1882     {#1\ifgridsnapping
1883        \bodyfontlineheight
1884      \else
1885        \openlineheight
1886      \fi}
1887     {\ifgridsnapping
1888        \assigndimension{#2}{#1}{.25\bodyfontlineheight}{.5\bodyfontlineheight}\bodyfontlineheight
1889      \else
1890        \assigndimension{#2}{#1}\smallskipamount\medskipamount\bigskipamount
1891      \fi}%
1892   \relax}
1893
1894% \start \dosetstretch{.25em} \setuptolerance[tolerant,stretch] \input tufte \endgraf \stop
1895% \start \dosetstretch{.5em} effe flink doorfietsen \stop
1896
1897% experimental code, not yet interfaced:
1898
1899% category:
1900%
1901%  0 == discard                             discard
1902%  1 == only if larger                      largest
1903%  2 == force even if smaller               force
1904%  3 == only take penalty component         penalty
1905%  4 == add to existing skip                add
1906%  5 == disable (ignore following)          disable
1907%  6 == kill whitespace                     nowhite
1908%  7 == discard previous                    back
1909% 10 == no topskip
1910%
1911% penalty: larger wins
1912% order: larger wins
1913% category:2,order:5,penalty:10000,skip:value|kw
1914%
1915% \defineblankmethod  [\v!joinedup] {\ifvmode\nointerlineskip\fi}
1916
1917% todo, in grid mode: builders.vspacing.fixed = false
1918%
1919% \ifgridsnapping will go
1920
1921\installcorenamespace{vspacingamount}
1922
1923\unexpanded\def\definevspacingamount
1924  {\dotripleempty\spac_vspacing_define_amount}
1925
1926\def\spac_vspacing_define_amount[#1][#2][#3]% can be combined
1927  {\ifthirdargument
1928     \setvalue{\??vspacingamount#1}{\ifgridsnapping#3\else#2\fi}%
1929   \else\ifsecondargument
1930     \setvalue{\??vspacingamount#1}{\ifgridsnapping\lineheight\else#2\fi}%
1931   \else
1932     \setvalue{\??vspacingamount#1}{\lineheight}%
1933   \fi\fi
1934   \clf_vspacingsetamount{#1}}
1935
1936\def\spac_vspacing_no_topskip % use grouped
1937  {\c_attr_skipcategory\pluseleven}
1938
1939% \installcorenamespace{vspacingamountnormal}
1940% \installcorenamespace{vspacingamountgrid}
1941
1942% \def\spac_vspacing_define_amount[#1][#2][#3]% can be combined
1943%   {\ifcsname n>#1\endcsname\else
1944%      \expandafter\newtoks\csname n>#1\endcsname
1945%      \expandafter\newtoks\csname g>#1\endcsname
1946%    \fi
1947%    \csname n>#1\endcsname{#2}%
1948%    \csname g>#1\endcsname{#3}%
1949%    \clf_vspacingsetamount{#1}}
1950
1951\unexpanded\def\definevspacing
1952  {\dodoubleempty\spac_vspacing_define}
1953
1954\def\spac_vspacing_define[#1][#2]%
1955  {\clf_vspacingdefine{#1}{#2}}
1956
1957%D The injector code (generated at the \LUA\ end):
1958
1959\newtoks\everybeforeblankhandling
1960\newtoks\everyafterblankhandling
1961
1962\newconditional\c_space_vspacing_done
1963\newconditional\c_space_vspacing_fixed
1964\newconditional\c_space_ignore_parskip
1965
1966\appendtoks
1967    \s_spac_vspacing_temp\zeropoint
1968    \c_attr_skipcategory\plusone
1969    \c_attr_skippenalty \attributeunsetvalue
1970    \c_attr_skiporder   \attributeunsetvalue
1971    \ifgridsnapping
1972        \settrue\c_space_vspacing_fixed
1973    \else
1974        \setfalse\c_space_vspacing_fixed
1975    \fi
1976\to \everybeforeblankhandling
1977
1978\appendtoks
1979    \s_spac_vspacing_temp\plusone\s_spac_vspacing_temp
1980      \ifconditional\c_space_vspacing_fixed \else
1981        \s!plus \skipgluefactor\s_spac_vspacing_temp
1982        \s!minus\skipgluefactor\s_spac_vspacing_temp
1983      \fi
1984    \relax
1985\to \everyafterblankhandling
1986
1987\unexpanded\def\setblankpacked
1988  {\settrue\c_space_ignore_parskip}
1989
1990\unexpanded\def\setblankcategory#1%
1991  {\settrue\c_space_vspacing_done
1992   \c_attr_skipcategory#1\relax}
1993
1994\unexpanded\def\setblankorder#1%
1995  {\c_attr_skiporder#1\relax}
1996
1997\unexpanded\def\fixedblankskip
1998  {\settrue\c_space_vspacing_fixed}
1999
2000\unexpanded\def\flexibleblankskip
2001  {\setfalse\c_space_vspacing_fixed}
2002
2003% \unexpanded\def\addblankskip#1#2#3%
2004%   {\settrue\c_space_vspacing_done
2005%    \advance\s_spac_vspacing_temp#1\dimexpr\ifgridsnapping#3\else#2\fi\relax\relax}
2006
2007\unexpanded\def\setblankpenalty#1%
2008  {\flushblankhandling
2009   \settrue\c_space_vspacing_done
2010   \c_attr_skipcategory\plusthree
2011   \c_attr_skippenalty #1\relax
2012   \flushblankhandling}
2013
2014\unexpanded\def\startblankhandling % move this to \vspacing
2015  {\par
2016   \ifvmode
2017     \expandafter\dostartblankhandling
2018   \else
2019     \expandafter\nostartblankhandling
2020   \fi}
2021
2022\unexpanded\def\nostartblankhandling#1\stopblankhandling
2023  {}
2024
2025\def\dostartblankhandling
2026  {\begingroup
2027   \setfalse\c_space_vspacing_done
2028   \setfalse\c_space_ignore_parskip
2029   \the\everybeforeblankhandling}
2030
2031\unexpanded\def\stopblankhandling
2032  {\the\everyafterblankhandling
2033   \ifconditional\c_space_vspacing_done
2034     \vskip\s_spac_vspacing_temp
2035   \fi
2036   \ifconditional\c_space_ignore_parskip
2037     \endgroup\ignoreparskip
2038   \else
2039     \endgroup
2040   \fi}
2041
2042\unexpanded\def\flushblankhandling
2043  {\the\everyafterblankhandling
2044   \ifconditional\c_space_vspacing_done
2045     \vskip\s_spac_vspacing_temp
2046   \fi
2047   \setfalse\c_space_vspacing_done
2048   \the\everybeforeblankhandling}
2049
2050\unexpanded\def\addpredefinedblankskip#1#2%
2051  {\settrue\c_space_vspacing_done
2052   \advance\s_spac_vspacing_temp#1\dimexpr\csname\??vspacingamount#2\endcsname\relax}
2053
2054% \unexpanded\def\addpredefinedblankskip#1#2%
2055%   {\settrue\c_space_vspacing_done
2056%    \advance\s_spac_vspacing_temp#1\dimexpr\the\csname\ifgridsnapping g\else n\fi>#2\endcsname\relax}
2057
2058\unexpanded\def\addaskedblankskip#1#2%
2059  {\settrue\c_space_vspacing_done
2060   \advance\s_spac_vspacing_temp#1\dimexpr#2\relax}
2061
2062% The main spacer:
2063
2064\unexpanded\def\vspacing
2065  {\doifelsenextoptionalcs\spac_vspacing_yes\spac_vspacing_nop}
2066
2067\def\spac_vspacing_yes
2068  {\ifinpagebody % somewhat weird
2069     \singleexpandafter\spac_vspacing_yes_indeed
2070   \else\ifconditional\c_spac_packed_blank
2071     \doubleexpandafter\spac_vspacing_yes_indeed
2072   \else
2073     \doubleexpandafter\spac_vspacing_yes_ignore
2074   \fi\fi}
2075
2076\def\spac_vspacing_nop
2077  {\ifinpagebody % somewhat weird
2078     \singleexpandafter\spac_vspacing_nop_indeed
2079   \else\ifconditional\c_spac_packed_blank
2080     \doubleexpandafter\spac_vspacing_nop_indeed
2081   \else
2082     \doubleexpandafter\spac_vspacing_nop_ignore
2083   \fi\fi}
2084
2085\def\spac_vspacing_yes_indeed[#1]%
2086  {\ifmmode\else\par\clf_vspacing{#1}\fi}
2087
2088\def\spac_vspacing_yes_ignore[#1]%
2089  {\ifmmode\else\par\fi}
2090
2091\def\spac_vspacing_nop_indeed
2092  {\ifmmode\else\par\clf_vspacing{\currentvspacing}\fi}
2093
2094\def\spac_vspacing_nop_ignore
2095  {\ifmmode\else\par\fi}
2096
2097% \unexpanded\def\directvspacing#1%
2098%   {\par\clf_vspacing{#1}}
2099%
2100%
2101% \def\directdefaultvspacing
2102%   {\ifinpagebody % somewhat weird
2103%      \clf_vspacing{\currentvspacing}%
2104%    \else\ifconditional\c_spac_packed_blank
2105%      \clf_vspacing{\currentvspacing}%
2106%    \fi\fi}
2107%
2108% \unexpanded\def\useblankparameter#1% faster local variant
2109%   {\edef\m_spac_blank_asked{#1\c!blank}%
2110%    \ifx\m_spac_blank_asked\empty\else
2111%      \clf_vspacing{\m_spac_blank_asked}
2112%    \fi}
2113
2114\installcorenamespace{vspacing}
2115
2116\unexpanded\def\directvspacing#1%
2117  {\par
2118   \ifcsname\??vspacing#1\endcsname
2119     \lastnamedcs
2120   \else
2121     \spac_vspacing_yes_preset{#1}%
2122   \fi}
2123
2124\def\spac_vspacing_yes_preset#1%
2125  {\setxvalue{\??vspacing#1}{\clf_vspacing{#1}}%
2126  %\writestatus{}{}%
2127  %\writestatus{#1}{\expandafter\meaning\csname\??vspacing#1\endcsname}%
2128  %\writestatus{}{}%
2129   \csname\??vspacing#1\endcsname}
2130
2131\def\spac_vspacing_yes_indeed[#1]%
2132  {\ifmmode\else
2133     \directvspacing{#1}%
2134   \fi}
2135
2136\def\spac_vspacing_nop_indeed
2137  {\ifmmode\else
2138     \directvspacing\currentvspacing
2139   \fi}
2140
2141\def\directdefaultvspacing
2142  {\ifinpagebody % somewhat weird
2143     \directvspacing\currentvspacing
2144   \else\ifconditional\c_spac_packed_blank
2145     \directvspacing\currentvspacing
2146   \fi\fi}
2147
2148\def\directcheckedvspacing
2149  {\ifinpagebody % somewhat weird
2150     \expandafter\directvspacing
2151   \else\ifconditional\c_spac_packed_blank
2152     \doubleexpandafter\directvspacing
2153   \else
2154     \doubleexpandafter\gobbleoneargument
2155   \fi\fi}
2156
2157\unexpanded\def\usespecificblankparameter#1#2% faster local variant
2158  {\edef\m_spac_blank_asked{#1#2}%
2159   \ifx\m_spac_blank_asked\empty\else
2160     \directvspacing\m_spac_blank_asked
2161   \fi}
2162
2163\unexpanded\def\useblankparameter#1% faster local variant
2164  {\usespecificblankparameter#1\c!blank}
2165
2166%D Handy (and faster):
2167
2168\unexpanded\def\directvpenalty#1%
2169  {\begingroup
2170   \c_attr_skipcategory\plusthree
2171   \c_attr_skippenalty #1\relax
2172   \c_attr_skiporder   \attributeunsetvalue
2173   \vskip\zeropoint
2174   \endgroup}
2175
2176\unexpanded\def\directvskip#1%
2177  {\begingroup
2178   \c_attr_skipcategory\plusone
2179   \c_attr_skippenalty \attributeunsetvalue
2180   \c_attr_skiporder   \attributeunsetvalue
2181   \vskip#1\relax
2182   \endgroup}
2183
2184%D These depend on bigskipamount cum suis so we'd better sync them:
2185
2186\unexpanded\def\setupvspacing
2187  {\doifelsenextoptionalcs\setupvspacing_yes\setupvspacing_nop}
2188
2189\let\currentvspacing\s!default % hm, default, standard ...
2190
2191\def\setupvspacing_yes[#1]%
2192  {\edef\currentvspacing{#1}%
2193   \spac_whitespace_setup_nop % yes or no, was forgotten
2194  }
2195
2196\def\setupvspacing_nop
2197  {\ifx\empty\currentvspacing % mistakenly had an \else
2198     \let\currentvspacing\s!default
2199   \fi
2200   \spac_whitespace_setup_nop}
2201
2202\unexpanded\def\restorestandardblank % or default ?
2203  {\let\currentvspacing\v!standard}
2204
2205\let\synchronizevspacing\setupvspacing_nop
2206
2207%D The \type {category:4} is default.
2208
2209\definevspacingamount[\v!none]        [\zeropoint]         [\zeropoint]
2210\definevspacingamount[\v!big]         [\bigskipamount]     [\bodyfontlineheight]
2211\definevspacingamount[\v!medium]      [\medskipamount]     [.5\bodyfontlineheight]
2212\definevspacingamount[\v!small]       [\smallskipamount]   [.25\bodyfontlineheight]
2213\definevspacingamount[\v!line]        [\openlineheight]    [\bodyfontlineheight]
2214\definevspacingamount[\v!halfline]    [.5\openlineheight]  [.5\bodyfontlineheight]
2215\definevspacingamount[\v!quarterline] [.25\openlineheight] [.25\bodyfontlineheight]
2216\definevspacingamount[\v!formula]     [\medskipamount]     [.5\bodyfontlineheight]
2217\definevspacingamount[\v!white]       [\parskip]           [\bodyfontwhitespace]
2218\definevspacingamount[\v!height]      [\strutht]           [\bodyfontstrutheight]
2219\definevspacingamount[\v!depth]       [\strutdp]           [\bodyfontstrutdepth]
2220
2221\definevspacingamount[\v!standard]    [.75\openlineheight] [.75\openlineheight] % mkii compatible
2222
2223\def\bodyfontwhitespace
2224  {\dimexpr
2225     \ifzeropt\parskip
2226       \zeropoint
2227     \else\ifgridsnapping
2228       \bodyfontlineheight
2229     \else
2230       \parskip
2231     \fi\fi
2232   \relax}
2233
2234%D used in itemize \unknown\ always test this:
2235
2236\newdimen\d_spac_overlay
2237
2238\def\spac_overlay_lines
2239  {\directcheckedvspacing{\v!back,\v!overlay}% \blank[\v!back,\v!overlay]%
2240   \nointerlineskip}
2241
2242% \startitemize[n]
2243%     \item \input zapf
2244%     \item \startitemize[a]
2245%         \item \input knuth
2246%     \stopitemize
2247% \stopitemize
2248%
2249% \strut \hfill first line \blank[overlay] second line \hfill \strut
2250%
2251% \ruledvbox {
2252%     \strut \hfill line 1 \blank[overlay]
2253%     line 2 \hfill \strut \blank[overlay]
2254%     \strut \hfill line 3 \hfill \strut
2255% }
2256%
2257% \dorecurse{50}
2258%   {\startitemize[n] \startitem \startitemize[a] \item #1 \stopitemize \stopitem \stopitemize}
2259
2260\definevspacing[\v!preference][penalty:-500]  % goodbreak
2261\definevspacing[\v!samepage]  [penalty:10000] % nobreak
2262
2263\definevspacing[\v!always]    [category:0] % hm, internally it's discard
2264\definevspacing[\v!max]       [category:1]
2265\definevspacing[\v!force]     [category:2]
2266\definevspacing[\v!disable]   [category:5]
2267\definevspacing[\v!nowhite]   [category:6]
2268\definevspacing[\v!back]      [category:7]
2269\definevspacing[\v!packed]    [category:8]  % noparskip (kind of special)
2270\definevspacing[\v!overlay]   [category:9]
2271\definevspacing[\v!enable]    [category:10]
2272
2273%definevspacing[\v!noparskip] [category:8]
2274%definevspacing[\v!notopskip] [category:11]
2275
2276\definevspacing[\v!weak]      [order:0]
2277\definevspacing[\v!strong]    [order:100]
2278
2279\definevspacing[\s!default]   [\v!white] % was big for a while
2280
2281\newcount\c_spac_vspacing_special_base \c_spac_vspacing_special_base = 32250 % 4000
2282\newcount\c_spac_vspacing_special_step \c_spac_vspacing_special_step =    10 %  250
2283\newcount\c_spac_vspacing_special_done
2284
2285% 2019-05-31 : upgraded a bit to more distinctive samepage-[level]-[0|1|2] names
2286
2287\unexpanded\def\spac_vspacing_define_same_step#1#2% alternatively we could have samepage-n-m
2288  {\begingroup
2289   \scratchcounterone\numexpr\plusthree*#1+#2\relax
2290   \scratchcountertwo\numexpr\c_spac_vspacing_special_base+\c_spac_vspacing_special_step*\scratchcounterone\relax
2291  %\writestatus{defined}{\v!samepage-\number#1-\number#2\space=>\space penalty:\the\scratchcountertwo}%
2292   \normalexpanded{\definevspacing[\v!samepage-\number#1-\number#2][penalty:\the\scratchcountertwo]}%
2293   \endgroup}
2294
2295\unexpanded\def\spac_vspacing_define_same_page#1%
2296  {\dostepwiserecurse\c_spac_vspacing_special_done{#1}\plusone
2297     {\spac_vspacing_define_same_step\recurselevel\zerocount % before
2298      \spac_vspacing_define_same_step\recurselevel\plusone   % after
2299      \spac_vspacing_define_same_step\recurselevel\plustwo}% % whatever
2300   \global\c_spac_vspacing_special_done#1\relax}
2301
2302\spac_vspacing_define_same_page{12} % 12 levels should be more than enough as a start
2303
2304\def\spac_vspacing_same_page#1#2% level offset (starts at 0)
2305  {\ifnum#1>\c_spac_vspacing_special_done
2306     \spac_vspacing_define_same_page{#1}%
2307   \fi
2308  %\writestatus{used}{\v!samepage-\number#1-\number#2}%
2309   \vspacing[\v!samepage-\number#1-\number#2]}
2310
2311\definevspacing[\v!default]  [\v!big]      % todo: needs to adapt to \setupblank
2312\definevspacing[\v!before]   [\v!default]  % but we need to avoid circular references
2313\definevspacing[\v!inbetween][\v!default]  % then
2314\definevspacing[\v!after]    [\v!before]
2315
2316\setupvspacing
2317  [\v!big] % alternatively [\v!standard]
2318
2319%D Maybe at some point we will differ between \type {\vspacing} and \type {\blank}
2320%D (we needed the first one while playing with the new code).
2321
2322% We keep this one as reference
2323%
2324% \unexpanded\def\inhibitblank
2325%   {\vspacing[\v!disable]}
2326%
2327% but use the following more efficient variant instead:
2328
2329\unexpanded\def\inhibitblank
2330  {\ifvmode
2331     \begingroup
2332     \c_attr_skipcategory\plusfive
2333     \vskip\zeropoint
2334     \endgroup
2335   \fi}
2336
2337\let\doinhibitblank\inhibitblank % keep this command, used in styles
2338
2339\let\defineblank      \definevspacing
2340\let\setupblank       \setupvspacing
2341\let\blank            \vspacing
2342\let\synchronizeblank \synchronizevspacing
2343\let\defineblankmethod\definevspacingamount
2344
2345%D The following command is for Wolfgang. It has to be used with care as it does
2346%D {\em not} work in tandem with the other spacing commands.
2347
2348\installcorenamespace{vspace}
2349
2350\unexpanded\def\definevspace
2351  {\dotripleempty\spac_vspace_define}
2352
2353\def\spac_vspace_define[#1][#2][#3]%
2354  {\ifthirdargument
2355     \setvalue{\??vspace#1:#2}{#3}%
2356   \else
2357     \setvalue{\??vspace:#1}{#2}%
2358   \fi}
2359
2360\letvalue{\??vspace:\s!unknown}\zeropoint
2361
2362\unexpanded\def\vspace
2363  {\dodoubleempty\spac_vspace_inject}
2364
2365% \def\spac_vspace_inject[#1][#2]% use \lastnamedcs
2366%   {\par
2367%    \ifvmode
2368%      \removelastskip
2369%      \vskip
2370%        \csname\??vspace
2371%          \ifsecondargument
2372%            \ifcsname\??vspace#1:#2\endcsname
2373%              #1:#2%
2374%            \else\ifcsname\??vspace:#2\endcsname
2375%              :#2%
2376%            \else
2377%              :\s!unknown
2378%            \fi\fi
2379%          \else\iffirstargument
2380%            \ifcsname\??vspace:#1\endcsname
2381%              :#1%
2382%            \else
2383%              :\s!unknown
2384%            \fi
2385%          \else
2386%            \ifcsname\??vspace:\s!default\endcsname
2387%              :\s!default
2388%            \else
2389%              :\s!unknown
2390%            \fi
2391%          \fi\fi
2392%        \endcsname
2393%      \relax
2394%    \fi}
2395
2396\def\spac_vspace_unknown
2397  {\csname\??vspace:\s!unknown\endcsname}
2398
2399\def\spac_vspace_inject[#1][#2]% use \lastnamedcs
2400  {\par
2401   \ifvmode
2402     \removelastskip
2403     \vskip
2404       \ifsecondargument
2405         \ifcsname\??vspace#1:#2\endcsname
2406           \lastnamedcs
2407         \else\ifcsname\??vspace:#2\endcsname
2408           \lastnamedcs
2409         \else
2410           \spac_vspace_unknown
2411         \fi\fi
2412       \else\iffirstargument
2413         \ifcsname\??vspace:#1\endcsname
2414           \lastnamedcs
2415         \else
2416           \spac_vspace_unknown
2417         \fi
2418       \else
2419         \ifcsname\??vspace:\s!default\endcsname
2420           \lastnamedcs
2421         \else
2422           \spac_vspace_unknown
2423         \fi
2424       \fi\fi
2425     \relax
2426   \fi}
2427
2428%D Some preliminary code: a simple and fast hanger, for usage in macros.
2429
2430\installcorenamespace {hanging}
2431
2432\installdirectcommandhandler \??hanging {hanging}
2433
2434\setuphanging
2435  [\c!distance=.5\emwidth,
2436   \c!location=\v!left,
2437   \c!n=\zerocount]
2438
2439\unexpanded\def\starthanging
2440  {\dontleavehmode\bgroup
2441   \dosingleempty\spac_hanging_start}
2442
2443\unexpanded\def\stophanging
2444  {\endgraf
2445   \egroup}
2446
2447\let\m_spac_hanging_location\empty
2448
2449\def\spac_hanging_start[#1]%
2450  {\doifelseassignment{#1}
2451     {\let\m_spac_hanging_location\empty
2452      \setupcurrenthanging[#1]}%
2453     {\edef\m_spac_hanging_location{#1}}%
2454   \ifx\m_spac_hanging_location\empty
2455     \edef\m_spac_hanging_location{\directhangingparameter\c!location}%
2456   \fi
2457   \dowithnextboxcs\spac_hanging_finish\hbox}
2458
2459\def\spac_hanging_finish
2460  {\scratchdistance\directhangingparameter\c!distance\relax
2461   \ifdim\ht\nextbox>\strutht
2462     \setbox\nextbox\tbox{\box\nextbox}%
2463   \fi
2464   \scratchcounter\directhangingparameter\c!n\relax
2465   \ifnum\scratchcounter>\zerocount
2466     \hangafter-\scratchcounter
2467   \else
2468     \getboxheight\scratchdimen\of\box\nextbox
2469     \getnoflines\scratchdimen
2470     \hangafter-\noflines
2471   \fi
2472   \ht\nextbox\strutht
2473   \dp\nextbox\strutdp
2474   \scratchwidth\dimexpr\wd\nextbox+\scratchdistance\relax
2475   \ifx\m_spac_hanging_location\v!right
2476     \hangindent\ifconditional\displaylefttoright-\fi\scratchwidth
2477     \rlap{\hskip\dimexpr\hsize-\leftskip-\wd\nextbox\relax\box\nextbox}% \leftskip is new
2478   \else
2479     \hangindent\ifconditional\displaylefttoright\else-\fi\scratchwidth
2480     \llap{\box\nextbox\hskip\scratchdistance}%
2481   \fi
2482   \ignorespaces}
2483
2484
2485%D \macros
2486%D   {startfixed}
2487%D
2488%D \starttyping
2489%D \startitemize
2490%D     \startitem \externalfigure[cow][height=1cm] \stopitem
2491%D     \startitem \externalfigure[cow][height=1cm] \stopitem
2492%D
2493%D     \startitem \startfixed      \externalfigure[cow][height=1cm]\stopfixed \stopitem
2494%D     \startitem \startfixed[high]\externalfigure[cow][height=1cm]\stopfixed \stopitem
2495%D     \startitem \startfixed[low] \externalfigure[cow][height=1cm]\stopfixed \stopitem
2496%D     \startitem \startfixed[lohi]\externalfigure[cow][height=1cm]\stopfixed \stopitem
2497%D
2498%D     \startitem test \par \startfixed      \externalfigure[koe][height=1cm]\stopfixed \stopitem
2499%D     \startitem test \par \startfixed[high]\externalfigure[koe][height=1cm]\stopfixed \stopitem
2500%D     \startitem test \par \startfixed[low] \externalfigure[koe][height=1cm]\stopfixed \stopitem
2501%D     \startitem test \par \startfixed[lohi]\externalfigure[koe][height=1cm]\stopfixed \stopitem
2502%D \stopitemize
2503%D \stopbuffer
2504%D
2505%D \typebuffer \getbuffer
2506
2507\installcorenamespace{fixedalternatives}
2508
2509\unexpanded\def\startfixed
2510  {\bgroup
2511   \dosingleempty\typo_fixed_start}
2512
2513\def\typo_fixed_start
2514  {\ifhmode
2515     \expandafter\typo_fixed_start_h
2516   \else
2517     \expandafter\typo_fixed_start_v
2518   \fi}
2519
2520\def\typo_fixed_start_h[#1]%
2521  {\let\stopfixed\typo_fixed_stop_h
2522   \dowithnextbox{\typo_fixed_finish{#1}}%
2523   \vbox\bgroup
2524   %ignorespaces
2525   \setlocalhsize}
2526
2527\unexpanded\def\typo_fixed_stop_h
2528  {%removeunwantedspaces
2529   \egroup
2530   \egroup}
2531
2532\def\typo_fixed_start_v[#1]%
2533  {\let\stopfixed\typo_fixed_stop_v
2534   \startbaselinecorrection}
2535
2536\unexpanded\def\typo_fixed_stop_v
2537  {\stopbaselinecorrection
2538   \egroup}
2539
2540\letvalue{\??fixedalternatives   \v!high}\bbox
2541\letvalue{\??fixedalternatives    \v!low}\tbox
2542\letvalue{\??fixedalternatives \v!middle}\vcenter
2543\letvalue{\??fixedalternatives   \v!lohi}\vcenter
2544\letvalue{\??fixedalternatives\s!unknown}\tbox
2545\letvalue{\??fixedalternatives\s!default}\tbox
2546
2547\unexpanded\def\typo_fixed_finish#1%
2548  {\expandnamespacevalue\??fixedalternatives{#1}\s!default{\box\nextbox}}
2549
2550% %D Forgotten already:
2551%
2552% \def\shapefill{\vskip\zeropoint\s!plus\lineheight\s!minus\lineheight\relax}
2553
2554%D Nasty:
2555
2556% \writestatus{1}{\the\prevdepth} \blank[force,5*big] { \writestatus{1}{\the\prevdepth} \baselineskip1cm xxxxxxxxx \par } \page
2557% \writestatus{2}{\the\prevdepth} \blank[force,5*big] { \writestatus{2}{\the\prevdepth} \baselineskip1cm xxxxxxxxx \par } \page
2558% \writestatus{3}{\the\prevdepth} \blank[force,5*big] { \writestatus{3}{\the\prevdepth} \baselineskip5cm xxxxxxxxx \par } \page
2559% \writestatus{4}{\the\prevdepth} \input tufte                                                                            \page
2560% \writestatus{5}{\the\prevdepth} \input tufte                                                                            \page
2561% \writestatus{6}{\the\prevdepth} \blank[force,5*big] { \writestatus{6}{\the\prevdepth} \baselineskip1cm xxxxxxxxx \par } \page
2562
2563% \writestatus{1}{\the\prevdepth} \null\vskip4cm      { \writestatus{1}{\the\prevdepth} \baselineskip1cm xxxxxxxxx \par } \page
2564% \writestatus{2}{\the\prevdepth} \null\vskip4cm      { \writestatus{2}{\the\prevdepth} \baselineskip1cm xxxxxxxxx \par } \page
2565% \writestatus{3}{\the\prevdepth} \null\vskip4cm      { \writestatus{3}{\the\prevdepth} \baselineskip5cm xxxxxxxxx \par } \page
2566% \writestatus{4}{\the\prevdepth} \input tufte                                                                            \page
2567% \writestatus{5}{\the\prevdepth} \input tufte                                                                            \page
2568% \writestatus{6}{\the\prevdepth} \null\vskip4cm      { \writestatus{6}{\the\prevdepth} \baselineskip1cm xxxxxxxxx \par } \page
2569
2570\appendtoks
2571    \ifvmode\prevdepth\zeropoint\fi % consistent, else first page -1000pt .. needed for fixed,3*big first/successive pages consistency
2572\to \everystarttext
2573
2574\prevdepth\zeropoint
2575
2576%D Helper:
2577
2578\unexpanded\def\checkedblank[#1]%
2579  {\edef\p_blank{#1}%
2580   \ifx\p_blank\empty
2581     % ignore
2582   \else\ifx\p_blank\v!none
2583     % ignore
2584   \else
2585     \blank[\p_blank]%
2586   \fi\fi}
2587
2588% \unexpanded\def\applycheckedblankwith#1#2#3%
2589%   {\edef\p_blank{#2}%
2590%    \ifx\p_blank\empty
2591%      % ignore
2592%    \else\ifx\p_blank\v!none
2593%      % ignore
2594%    \else
2595%      \edef\p_before{#1}%
2596%      \edef\p_after {#3}%
2597%      \blank[\ifx\p_before\empty\else\p_before,\fi\p_blank\ifx\p_after\empty\else,\p_after\fi]%
2598%    \fi\fi}
2599
2600% \setupwhitespace[line]
2601% \prerollblank[2*line]  \the\prerolledblank
2602% \prerollblank[-2*line] \the\prerolledblank
2603
2604\newskip\prerolledblank
2605
2606\unexpanded\def\prerollblank[#1]%
2607  {\begingroup
2608   \edef\p_blank{#1}%
2609   \ifx\p_blank\empty
2610     \global\prerolledblank\zeropoint
2611   \else\ifx\p_blank\v!none
2612     \global\prerolledblank\zeropoint
2613   \else
2614     % don't mess with \arskip here!
2615     \scratchskip\plusten\lineheight
2616     \setbox\scratchbox\vbox
2617       {\vskip\scratchskip
2618        \kern\zeropoint
2619        \blank[\p_blank]}%
2620     % \dimexpr doesn't work well with skips
2621     \advance\scratchskip-\ht\scratchbox
2622     \global\prerolledblank-\scratchskip
2623   \fi\fi
2624   \endgroup}
2625
2626\newcount\c_spac_vspacing_ignore_parskip
2627
2628% \setupwhitespace[line]
2629% \setuphead[subject][after={\blank[packed]},style=\bfb]
2630% \subject{foo}
2631% test \par
2632% test \par
2633% \blank[packed] % \ignoreparskip
2634% test \par
2635% test \par
2636% \ignoreparskip
2637% test \par
2638% test \par
2639% \setuphead[subject][after={\blank[nowhite]},style=\bfb]
2640% \subject{foo}
2641% test \par
2642% test \par
2643
2644% only main vertical list
2645
2646\unexpanded\def\ignoreparskip{\c_spac_vspacing_ignore_parskip\plusone}
2647
2648\protect \endinput
2649