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