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