math-stc.mklx /size: 58 Kb    last modification: 2025-02-21 11:03
1%D \module
2%D   [       file=math-stc,
3%D        version=2012.12.29,
4%D          title=\CONTEXT\ Math Macros,
5%D       subtitle=Stackers,
6%D        comment=This replaces math-arr and friends,
7%D         author=Hans Hagen,
8%D           date=\currentdate,
9%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
10%C
11%C This module is part of the \CONTEXT\ macro||package and is
12%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
13%C details.
14
15\writestatus{loading}{ConTeXt Math Macros / Stackers}
16
17% todo mathmeaning like fractions
18
19\unprotect
20
21% is subtype for tagged needed: dosettagproperty only used here .. maybe for tagged pdf?
22
23%D WARNING: If the code here changes, the export needs to be checked! Stackers are
24%D rather special because the order in mathml matters, so we flush in [base under
25%D over] order. We also do some analysis at the \TEX\ end (passing the right
26%D variant). It's easy in the export to deal with it but in the pdf stream less
27%D trivial as we don't actually analyze there.
28%D
29%D At some point the \MKII\ arrow mechanism has been converted to \MKIV, but we kept
30%D most of the logic. We now have a more generic variant dealing with extensibles.
31%D There are a few demands than we need to meet:
32%D
33%D \startitemize
34%D \startitem
35%D    The width of the extensible need to adapt itself automatically.
36%D \stopitem
37%D \startitem
38%D   We need to be able to control horizontal and vertical offsets.
39%D \stopitem
40%D \startitem
41%D   We best have a math as well as a text variant (which is handy for chemistry).
42%D \stopitem
43%D \startitem
44%D    For historic reasons we need to deal with optional arguments in a special
45%D    (reverse) way.
46%D \stopitem
47%D \startitem
48%D    We need alternatives for extensibles on top, in the middle and at the bottom.
49%D \stopitem
50%D \stopitemize
51%D
52%D After I had experimented a bit with virtual characters for two headed arrows I
53%D discussed the issue with the Gyre folks and we came to the conclusion that it
54%D made sense to have real extensibles instead of constructing them out of snippets.
55%D After all, \OPENTYPE\ math provides for it. So, in December 2013 beta versions of
56%D Latin Modern and Gyre fonts came available that had these! Because we still want
57%D to support the traditional Latin Modern Virtual math font those were extended
58%D with a couple of virtual extensibles as well.
59%D
60%D {\em For the moment we still have some mess here: we can deal with known
61%D dimensions, but fillers (like \type {\rightarrowfil} don't work with \OPENTYPE\
62%D extensibles yet because there is no way to let them stretch like leaders. At some
63%D point \LUATEX\ might provide a auto||fit||to||encapsulated||box and if not I will
64%D cook up a \LUA\ based variant.}
65%D
66%D We could mess with something like \type {$mid\limits^{top}_{bottom}$} but we like
67%D a bit more control. At some point we need to add some hacks to get exports
68%D working well.
69%D
70%D In the end we have a more flexible mechanism which also handles text variants.
71
72%D When wrapping up some math developments I decided to add mp support here as well.
73%D A nice evening job with Joe Bonamassa performing live on the big screen (real
74%D nice bluray's). See meta-imp-mat.mkiv for examples.
75
76% possible improvements:
77%
78% - we could skip the left/right offsets when offset=normal, this saves some access time
79%   at the lua end and some checking: use \mathhorizontalcode or \mathextensiblecode
80%   but in practice arrows etc are not used that often
81
82% At some point we can consider to use the more natural \LUAMETATEX\ features but the
83% problem is that we lack proper support in fonts and we also have less control.
84
85%installcorenamespace {mathextensiblefallbacks}
86
87% In math mode we no longer fallback, simply because only a few fonts implement
88% extensible using minus and equal signs. So either we provide a tweaked one or we
89% simply ignore the lack. Better choose a font that matches expectations that some
90% fragile imperfect hackery.
91
92%D The extensible gets sort of inlined so we loose tagging applied to the box
93%D which actually is an nested mlist_to_list call then. Kind of messy in the
94%D tagging code.
95
96\def\math_stackers_fallback
97  {\mathstylehbox to \scratchwidth{% no \bgroup ... \egroup
98     \usemathstackerscolorparameter\c!color
99     \hss
100     \hskip{\mathstackersparameter\c!topoffset}% for manual italic correction
101   % \ifcsname\??mathextensiblefallbacks\the\scratchunicode\endcsname
102   %   \lastnamedcs
103   % \else
104       \Umathchar\zerocount\zerocount\scratchunicode
105   % \fi
106     \hss}}
107
108\def\math_stackers_regular
109  {\mathstylehbox{%
110     \hskip\d_math_stackers_offset_l
111     \ifcstok{\mathstackersparameter\c!plugin}\v!mp
112       \edef\p_mp{\mathstackersparameter\c!mp}%
113       \ifempty\p_mp\else
114         \clf_set_extensible_data
115             mp      {\p_mp}
116             unicode \scratchunicode
117          \relax
118       \fi
119     \else
120       \lettonothing\p_mp
121     \fi
122     \Uhextensible
123       \usedsymbolcolorparameterattributes{\mathstackersparameter\c!symbolcolor}%
124       \ifempty\p_mp\else
125         \s!usecallback\relaxedspace
126       \fi
127       middle
128       \ifcstok{\mathstackersparameter\c!stretch}\v!yes
129         stretch
130       \fi
131       \ifcstok{\mathstackersparameter\c!shrink}\v!yes
132         shrink
133       \fi
134       width {\scratchwidth-\d_math_stackers_offset_l-\d_math_stackers_offset_r}%
135       \zerocount\scratchunicode
136     \relax
137     \hskip\d_math_stackers_offset_r
138   }}
139
140% these delimiters are a unuseable as they don't center for small arguments:
141%
142% $\Umathaccent   0 0 "2190{x}$ \par $\Umathaccent   0 0 "27F8{x}$\par
143% $\Udelimiterunder 0 "2190{x}$ \par $\Udelimiterunder 0 "27F8{x}$\par
144
145% \defcsname\??mathextensiblefallbacks\endcsname
146%   {\hpack{\vrule\s!width\scratchwidth\s!height.1\mathexheight\s!depth\zeropoint}}
147
148%D We don't really need this because we can assume that fonts have the right
149%D extensibles. If needed I will make a general virtual extender for \OPENTYPE\
150%D fonts.
151%D
152%D Because we have quite some control over positioning, we have somewhat extensive
153%D tracing built in.
154
155\let\math_stackers_top   \relax
156\let\math_stackers_middle\relax
157\let\math_stackers_bottom\relax
158\let\math_stackers_skip  \hskip
159
160\installtextracker
161  {math.stackers.texts}
162  {\let\math_stackers_top   \filledhboxb
163   \let\math_stackers_middle\filledhboxr
164   \let\math_stackers_bottom\filledhboxg
165   \let\math_stackers_skip  \math_stackers_skip_indeed}
166  {\let\math_stackers_top   \relax
167   \let\math_stackers_middle\relax
168   \let\math_stackers_bottom\relax
169   \let\math_stackers_skip  \hskip}
170
171\def\math_stackers_skip_indeed#amount%
172  {\filledhboxk{\strut\hskip#amount}}
173
174\let         \math_stackers_start_tagged_mid\gobbleoneargument
175\let         \math_stackers_start_tagged_top\gobbleoneargument
176\let         \math_stackers_start_tagged_bot\gobbleoneargument
177\lettonothing\math_stackers_stop_tagged
178
179\def\math_stackers_unicode{\ifcase\scratchunicode\else\the\scratchunicode\fi}
180
181\def\math_stackers_reset_variables
182  {\scratchunicode\zerocount
183   \edef\p_offset     {\mathstackersparameter\c!offset}%
184   \edef\p_location   {\mathstackersparameter\c!location}%
185   \edef\p_strut      {\mathstackersparameter\c!strut}%
186   \edef\p_alternative{\mathstackersparameter\c!alternative}%
187   \scratchleftoffset \zeropoint
188   \scratchrightoffset\zeropoint}
189
190\appendtoks
191    \def\math_stackers_start_tagged_mid#1{\dostarttagged\t!mstackermid{#1}\hbox\bgroup}%
192    \def\math_stackers_start_tagged_top#1{\dostarttagged\t!mstackertop{#1}\hbox\bgroup}%
193    \def\math_stackers_start_tagged_bot#1{\dostarttagged\t!mstackerbot{#1}\hbox\bgroup}%
194    \def\math_stackers_stop_tagged       {\egroup\dostoptagged}%
195\to \everysetuptagging
196
197%D We define a full featured command handler.
198
199\installcorenamespace {mathstackers}
200
201\installcommandhandler \??mathstackers {mathstackers} \??mathstackers
202
203\setupmathstackers
204  [%c!alternative=\v!text,    % text | mathematics
205   \c!left=,
206   \c!right=,
207   \c!mathclass=\s!relation,
208   \c!alternative=\v!normal,
209   \c!voffset=.25\mathexheight, % maybe less
210   \c!hoffset=\zeropoint,
211   \c!topoffset=\zeropoint, % for manual italic correction
212   \c!distance=\mathstackersparameter\c!voffset, % distance between symbol and base (can be different from voffset)
213   \c!minheight=\mathexheight,
214   \c!mindepth=\zeropoint,
215 % \c!minwidth=.5\mathemwidth,
216   \c!minwidth=.25\mathemwidth, % \iota
217   \c!order=\v!normal,
218   \c!strut=,
219   \c!color=,
220   \c!symbolcolor=\mathstackersparameter\c!color,
221   \c!topcommand=,
222   \c!middlecommand=,
223   \c!bottomcommand=,
224   \c!offset=\v!normal,       % normal | min | max
225   \c!location=\v!top]        % none | normal | small | medium | big
226
227%D We assume that the middle characters (that can be an extensible) to sit on
228%D top of the baseline by default.
229
230\installcorenamespace {mathstackerslocation}
231\installcorenamespace {mathstackersalternative}
232
233\letcsname\??mathstackerslocation\v!top    \endcsname\plusone   % on top of baseline
234\letcsname\??mathstackerslocation\v!high   \endcsname\plustwo   % 25 % down
235\letcsname\??mathstackerslocation\v!middle \endcsname\plusthree % centered
236\letcsname\??mathstackerslocation\v!low    \endcsname\plusfour  % 75 % down
237\letcsname\??mathstackerslocation\v!bottom \endcsname\plusfive  % below baseline
238\letcsname\??mathstackerslocation          \endcsname\zerocount
239
240%D First we implement the helper that deals with an extensible in the middle and
241%D top and|/|or bottom texts:
242
243\lettonothing\m_math_stackers_text_top
244\lettonothing\m_math_stackers_text_bottom
245\lettonothing\m_math_stackers_text_middle
246
247\def\math_stackers_flushtext#command#style#color#text%
248  {\ifdim\scratchleftoffset>\zeropoint
249     \math_stackers_skip\scratchleftoffset
250   \fi
251   \ifx\p_strut\v!no \else
252     \strut
253   \fi
254   \usemathstackersstyleandcolor#style#color%
255   \mathstackersparameter#command#text%
256   \ifdim\scratchrightoffset>\zeropoint
257     \math_stackers_skip\scratchrightoffset
258   \fi}
259
260\def\math_stackers_toptext   {\math_stackers_flushtext\c!topcommand   \c!topstyle   \c!topcolor   \m_math_stackers_text_top   }
261\def\math_stackers_bottomtext{\math_stackers_flushtext\c!bottomcommand\c!bottomstyle\c!bottomcolor\m_math_stackers_text_bottom}
262\def\math_stackers_middletext{\math_stackers_flushtext\c!middlecommand\c!middlestyle\c!middlecolor\m_math_stackers_text_middle}
263
264\def\math_stackers_content
265  {\ifcase\scratchcounter
266     \math_stackers_fallback
267   \or % left
268     \math_stackers_regular
269   \or % right
270     \math_stackers_regular
271   \or % horizontal
272     \math_stackers_regular
273   \else
274     \math_stackers_fallback
275   \fi}
276
277% no checking, we assume sane use
278
279\letcsname\??mathstackersalternative\v!normal \endcsname\math_stackers_content
280\letcsname\??mathstackersalternative\v!default\endcsname\math_stackers_content
281
282\setupmathstackers
283  [\c!mp=math:stacker:\the\scratchunicode,
284   \c!mpheight=\mathcharht\scratchunicode,
285   \c!mpdepth=\mathchardp\scratchunicode,
286   \c!mpoffset=.25\mathexheight]
287
288% for now we do this:
289
290\setupmathstackers
291  [\c!mp=\ifcstok{\mathstackersparameter\c!plugin}\v!mp simplefun::math:default\else math:stacker:\the\scratchunicode\fi]
292
293% so far
294
295\defcsname\??mathstackersalternative\v!mp\endcsname
296  {\normalexpanded{\math_stackers_mp_box
297     {\todimension{\mathstackersparameter\c!mpheight}}%
298     {\todimension{\mathstackersparameter\c!mpdepth}}%
299     {\todimension{\mathstackersparameter\c!mpoffset}}%
300     {\todimension{\triggeredmathstyleparameter\Umathfractionrule}}%
301     {\todimension{\triggeredmathstyleparameter\Umathaxis}}%
302     {\todimension\mathexheight}%
303     {\todimension\mathemwidth}%
304   }}
305
306\protected\def\math_stackers_mp_box#1#2#3#4#5#6#7%
307  {\hpack\bgroup %  todo: add code key + tag
308   % we can speed up \mathexheight expansion a bit
309   \d_overlay_width    \scratchwidth
310   \d_overlay_height   {#1}%
311   \d_overlay_depth    {#2}%
312   \d_overlay_offset   {#3}%
313   \d_overlay_linewidth{#4}%
314   \edef\overlaylinecolor{\mathstackersparameter\c!color}%
315   \edef\p_mp{\mathstackersparameter\c!mp}%
316   \uniqueMPgraphic{\p_mp}{axis=#5,ex=#6,em=#7}%
317   \egroup}
318
319\def\math_stackers_check_unicode#codepoint%
320  {\scratchunicode#codepoint\relax
321   \scratchhoffset{\mathstackersparameter\c!hoffset}%
322   \scratchvoffset{\mathstackersparameter\c!voffset}%
323   \scratchcounter\mathhorizontalcode\fam\scratchunicode\relax % also sets \leftscratchoffset and \rightscratchoffset
324   \ifx\p_offset\v!max
325     % heads/tails + hoffset
326   \orelse\ifx\p_offset\v!min
327     % heads/tails - hoffset
328     \advanceby\scratchleftoffset -\scratchhoffset
329     \advanceby\scratchrightoffset-\scratchhoffset
330   \else % \v!normal
331     % hoffset
332     \scratchleftoffset\zeropoint
333     \scratchrightoffset\zeropoint
334   \fi
335   \ifdim\scratchleftoffset<\zeropoint
336     \scratchleftoffset\zeropoint
337   \fi
338   \ifdim\scratchrightoffset<\zeropoint
339     \scratchrightoffset\zeropoint
340   \fi}
341
342\def\math_stackers_normalize_three
343  {\scratchheight\ht\scratchboxthree
344   \scratchdepth \dp\scratchboxthree
345   \scratchtopoffset   \scratchheight
346   \scratchbottomoffset\scratchdepth
347   \scratchdimen{\mathstackersparameter\c!minheight}%
348   \ifdim\scratchheight<\scratchdimen
349     \scratchheight\scratchdimen
350     \ht\scratchboxthree\scratchheight
351   \fi
352   \scratchdimen{\mathstackersparameter\c!mindepth}%
353   \ifdim\scratchdepth<\scratchdimen
354     \scratchdepth\scratchdimen
355     \dp\scratchboxthree\scratchdepth
356   \fi
357   \advanceby\scratchtopoffset   -\scratchheight
358   \advanceby\scratchbottomoffset-\scratchdepth
359   \ifdim\scratchtopoffset<\zeropoint
360     \scratchtopoffset\zeropoint
361   \fi
362   \ifdim\scratchbottomoffset<\zeropoint
363     \scratchbottomoffset\zeropoint
364   \fi}
365
366\def\math_stackers_get_max_width
367  {\ifdim\wd\scratchboxone>\scratchwidth
368     \scratchwidth\wd\scratchboxone
369   \fi
370   \ifdim\wd\scratchboxtwo>\scratchwidth
371     \scratchwidth\wd\scratchboxtwo
372   \fi
373   \ifdim\wd\scratchboxthree>\scratchwidth
374     \scratchwidth\wd\scratchboxthree
375   \fi}
376
377\def\math_stackers_set_max_width
378  {\ifdim\wd\scratchboxone<\scratchwidth
379     \setbox\scratchboxone\hpack to \scratchwidth{\hss\unhbox\scratchboxone\hss}% unhboxing makes leaders work
380   \fi
381   \ifdim\wd\scratchboxtwo<\scratchwidth
382     \setbox\scratchboxtwo\hpack to \scratchwidth{\hss\unhbox\scratchboxtwo\hss}%
383   \fi
384   \ifdim\wd\scratchboxthree<\scratchwidth
385     \setbox\scratchboxthree\hpack to \scratchwidth{\hss\unhbox\scratchboxthree\hss}%
386   \fi}
387
388\protected\def\math_stackers_triplet#method#category#codepoint#toptext#bottomtext%
389 %{\math_stackers_start_group{#category}%
390  {\begingroup
391   \cdef\currentmathstackers{#category}%
392   \mathstackersparameter\c!left\relax
393   \dostarttagged\t!mstacker\currentmathstackers
394   \ifmmode\math_atom_by_parameter\mathstackersparameter\else\dontleavehmode\fi
395     {\math_stackers_reset_variables
396      \edef\m_math_stackers_text_top   {#toptext}%
397      \edef\m_math_stackers_text_bottom{#bottomtext}%
398      \ifparameter#bottomtext\or
399        \ifcstok{\mathstackersparameter\c!order}\v!reverse
400          \swapmacros\m_math_stackers_text_top\m_math_stackers_text_bottom
401        \fi
402      \fi
403      \ifcase#method\relax
404        \math_stackers_check_unicode{#codepoint}%
405      \else
406       %\scratchunicode\zerocount
407        \edef\m_math_stackers_text_middle{#codepoint}%
408      \fi
409      \ifempty\m_math_stackers_text_top
410        \setbox\scratchboxone\emptyhbox
411      \else
412        \setmathsmalltextbox\scratchboxone\hbox{\math_stackers_toptext}%
413      \fi
414      \ifempty\m_math_stackers_text_bottom
415        \setbox\scratchboxtwo\emptyhbox
416      \else
417        \setmathsmalltextbox\scratchboxtwo\hbox{\math_stackers_bottomtext}%
418      \fi
419      %
420      \ifcase#method\relax
421        % e.g. extensible
422       %\scratchwidth\wd
423       %  \ifdim\wd\scratchboxone>\wd\scratchboxtwo
424       %    \scratchboxone
425       %  \else
426       %    \scratchboxtwo
427       %  \fi
428       %\relax
429        \scratchwidth\mathcharwd\scratchunicode
430        \ifdim\wd\scratchboxone>\scratchwidth
431          \scratchwidth\wd\scratchboxone
432        \fi % no \elseif here
433        \ifdim\wd\scratchboxtwo>\scratchwidth
434          \scratchwidth\wd\scratchboxtwo
435        \fi
436      \else
437        \ifempty\m_math_stackers_text_middle
438          \setbox\scratchboxthree\emptyhbox
439        \else
440          \dostarttaggednodetail\t!mstackermid
441            \setmathtextbox\scratchboxthree\hbox{\math_stackers_middletext}%
442          \dostoptagged
443        \fi
444        \math_stackers_get_max_width
445      \fi
446      %
447      \scratchdimen{\mathstackersparameter\c!minwidth}%
448      \ifdim\scratchwidth<\scratchdimen
449         \scratchwidth\scratchdimen
450      \fi
451      \advanceby\scratchwidth2\scratchhoffset
452      %
453      \ifcase#method\relax
454        \dostarttaggednodetail\t!mstackermid
455        \setbox\scratchboxthree\csname\??mathstackersalternative\p_alternative\endcsname
456        \dostoptagged
457      \fi
458%       \ifdim\wd\scratchboxthree>\scratchwidth
459%         \scratchwidth\wd\scratchboxthree
460%       \fi
461      %
462      \math_stackers_set_max_width
463      %
464      \ifcsname\??mathstackerslocation\p_location\endcsname
465        \ifcase\csname\??mathstackerslocation\p_location\endcsname\relax
466          \scratchdistance\zeropoint
467        \or % top
468          \scratchdistance\zeropoint
469        \or % high
470          \scratchdistance.25\htdp\scratchboxthree
471        \or % centered
472          \scratchdistance.5\htdp\scratchboxthree
473        \or % low
474          \scratchdistance.75\htdp\scratchboxthree
475        \or % bottom
476          \scratchdistance\htdp\scratchboxthree
477        \else
478          \scratchdistance\zeropoint
479        \fi
480      \else
481        \scratchdistance\p_location\htdp\scratchboxthree
482      \fi
483      %
484      \ifzeropt\scratchdistance\else
485        \setbox\scratchboxthree\hpack{\lower\scratchdistance\box\scratchboxthree}%
486      \fi
487      \math_stackers_normalize_three
488      % analysis: is this still ok here?
489      \ifdim\htdp\scratchboxtwo>\zeropoint
490        \ifdim\htdp\scratchboxone>\zeropoint
491          \dosettagproperty\s!subtype\t!munderover
492        \else
493          \dosettagproperty\s!subtype\t!munder
494        \fi
495      \else
496        \ifdim\htdp\scratchboxone>\zeropoint
497          \dosettagproperty\s!subtype\t!mover
498        \else
499          % brrr
500        \fi
501      \fi
502      % base
503      \math_stackers_start_tagged_mid\math_stackers_unicode
504        \math_stackers_middle\bgroup
505          \box\scratchboxthree
506        \egroup
507      \math_stackers_stop_tagged
508      % under
509      \ifdim\htdp\scratchboxtwo>\zeropoint
510        \math_stackers_start_tagged_bot\empty
511          \scratchoffset\scratchvoffset
512          \kern-\scratchwidth
513          \math_stackers_bottom\bgroup
514            \lower{%
515              \ht\scratchboxtwo+\scratchdepth+\scratchoffset+\scratchbottomoffset
516            }\box\scratchboxtwo
517          \egroup
518        \math_stackers_stop_tagged
519      \fi
520      % over
521      \ifdim\htdp\scratchboxone>\zeropoint
522        \math_stackers_start_tagged_top\empty
523          \scratchoffset\scratchvoffset
524          \kern-\scratchwidth
525          \math_stackers_top\bgroup
526            \raise{%
527              \dp\scratchboxone+\scratchheight+\scratchoffset+\scratchtopoffset
528            }\box\scratchboxone
529          \egroup
530        \math_stackers_stop_tagged
531      \fi
532      %
533      }%
534  \dostoptagged
535  \mathstackersparameter\c!right\relax
536  \endgroup}
537 %\math_stackers_stop_group}
538
539\permanent\tolerant\protected\def\definemathextensible[#1]#*[#2]#*[#3]% category name unicode
540  {\ifarguments\or\or
541     \frozen\protected\edefcsname#1\endcsname{\math_stackers_auto_normal\noexpand\currentmathstackers{\number#2}}%
542   \or
543     \frozen\protected\edefcsname#2\endcsname{\math_stackers_auto_normal{#1}{\number#3}}%
544   \fi}
545
546% \tolerant\protected\def\math_stackers_auto_normal#1#2#*[#3]#:#*#=#*#=%
547%   {\begingroup
548%    \scratchcounter#2\relax
549%    \cdef\currentmathstackers{\ifparameter#3\or#3\else#1\fi}%
550%    \math_stackers_triplet\zerocount\currentmathstackers\scratchcounter{#4}{#5}%
551%    \endgroup}
552
553\tolerant\protected\def\math_stackers_auto_normal#1#2#*[#3]#:#*#=#*#=%
554  {\begingroup
555   \scratchcounter#2\relax
556   \cdef\currentmathstackers{#1}%
557   \ifhastok={#3}%
558     \setupcurrentmathstackers[#3]%
559   \orelse\ifparameter#3\or
560     \cdef\currentmathstackers{#3}%
561   \fi
562   \math_stackers_triplet\zerocount\currentmathstackers\scratchcounter{#4}{#5}%
563   \endgroup}
564
565%D A few direct accessors (in the meantime we redefined \mathextensible so we renamed the
566%D following):
567
568\permanent\tolerant\protected\def\directmathextensible[#category]%
569  {\begingroup
570   \math_stackers_handle_extensible{\ifparameter#category\or#category\else\v!mathematics\fi}} % will be defined later on
571
572\permanent\tolerant\protected\def\directtextextensible[#category]%
573  {\begingroup
574   \math_stackers_handle_extensible{\ifparameter#category\or#category\else\v!text\fi}} % will be defined later on
575
576\aliased\let\mathstacker\directmathextensible
577\aliased\let\textstacker\directtextextensible
578
579\def\math_stackers_handle_extensible#category#codepoint#toptext#bottomtext%
580  {\math_stackers_triplet\zerocount{#category}{#codepoint}{#toptext}{#bottomtext}%
581   \endgroup}
582
583% 1 0 name n 0 | 0 1 name n 0 | 1 1 name n n
584
585\let\math_stackers_stop_group\endgroup
586
587\protected\def\math_stackers_start_group#category%
588  {\begingroup
589   \cdef\currentmathstackers{#category}%
590   \ifcstok{\mathstackersparameter\c!mathlimits}\v!yes
591     \def\math_stackers_stop_group{\egroup\endgroup\ordlimits}%
592   % \mathop\bgroup
593     \mathaccent\bgroup
594   \else
595     \let\math_stackers_stop_group\endgroup
596   \fi}
597
598\newconstant \c_math_stackers_top
599\newconstant \c_math_stackers_bottom
600\newconstant \c_math_stackers_codepoint
601\newconstant \c_math_stackers_extracode
602\newdimension\d_math_stackers_offset_l
603\newdimension\d_math_stackers_offset_r
604
605\setupmathstackers[lt=\zeropoint,rt=\zeropoint,lb=\zeropoint,rb=\zeropoint]
606
607\newbox\b_math_stackers_top_text
608\newbox\b_math_stackers_bottom_text
609
610\def\math_stackers_double_reset_texts
611  {\global\setbox\b_math_stackers_top_text   \emptybox
612   \global\setbox\b_math_stackers_bottom_text\emptybox}
613
614\def\math_stackers_double_set_toptext
615  {\edef\math_stackers_toptext{\mathstackersparameter\c!top}%
616   \ifempty\math_stackers_toptext\else
617     \global\setbox\b_math_stackers_top_text\hbox to \scratchwidth\bgroup
618       \usemathstackersstyleandcolor\c!topstyle\c!topcolor
619       \spac_align_simple{\mathstackersparameter\c!topalign}\math_stackers_toptext
620      \hskip\d_math_stackers_offset_l\relax
621     \egroup
622   \fi}
623
624\def\math_stackers_double_set_bottomtext
625  {\edef\math_stackers_bottomtext{\mathstackersparameter\c!bottom}%
626   \ifempty\math_stackers_bottomtext\else
627     \global\setbox\b_math_stackers_bottom_text\hbox to \scratchwidth\bgroup
628       \usemathstackersstyleandcolor\c!bottomstyle\c!bottomcolor
629       \hskip\d_math_stackers_offset_l\relax
630       \spac_align_simple{\mathstackersparameter\c!bottomalign}\math_stackers_bottomtext
631     \egroup
632   \fi}
633
634\def\math_stackers_double_flush_texts
635  {\ifvoid\b_math_stackers_top_text\else
636     \superscript{\box\b_math_stackers_top_text}%
637   \fi
638   \ifvoid\b_math_stackers_bottom_text\else
639     \subscript{\box\b_math_stackers_bottom_text}%
640   \fi}
641
642\tolerant\protected\def\math_stackers_make_double#top#bottom#category#codepoint#codeextra#spacer[#S#settings]#:#*#text%
643  {\math_stackers_start_group{#category}%
644   \c_math_stackers_top      #top\relax
645   \c_math_stackers_bottom   #bottom\relax
646   \c_math_stackers_codepoint#codepoint\relax
647   \c_math_stackers_extracode#codeextra\relax
648   \ifparameter#settings\or
649     \setupcurrentmathstackers[#settings]%
650   \fi
651   \mathstackersparameter\c!left\relax
652   \dostarttagged\t!mstacker\currentmathstackers
653   \ifmmode\math_atom_by_parameter\mathstackersparameter\else\dontleavehmode\fi
654     {\math_stackers_reset_variables
655      \edef\m_math_stackers_text_middle{#text}%
656      \math_stackers_check_unicode\c_math_stackers_codepoint
657      \let\math_stackers_unicode_two\math_stackers_unicode
658      \let\math_stackers_unicode_one\empty
659      \ifempty\math_stackers_middle
660        \setbox\scratchboxthree\emptyhbox
661      \else
662        \dostarttagged\t!mstackermid\empty
663        \setmathtextbox\scratchboxthree\hbox{\math_stackers_middletext}%
664        \dostoptagged
665      \fi
666      \scratchwidth\wd\scratchboxthree
667      %
668      \scratchdimen{\mathstackersparameter\c!minwidth}%
669      \ifdim\scratchwidth<\scratchdimen
670         \scratchwidth\scratchdimen
671      \fi
672      \advanceby\scratchwidth2\scratchhoffset
673      %
674     %\scratchunicode\c_math_stackers_codepoint
675      \ifcase\c_math_stackers_bottom
676        \d_math_stackers_offset_l\mathstackersparameter{lt}%
677        \d_math_stackers_offset_r\mathstackersparameter{rt}%
678      \orelse\ifcase\c_math_stackers_top
679        \d_math_stackers_offset_l\mathstackersparameter{lb}%
680        \d_math_stackers_offset_r\mathstackersparameter{rb}%
681      \else
682        \d_math_stackers_offset_l\mathstackersparameter{lt}%
683        \d_math_stackers_offset_r\mathstackersparameter{rt}% or rb ?
684      \fi
685      %
686      \setbox\scratchboxtwo\csname\??mathstackersalternative\p_alternative\endcsname
687      \setbox\scratchboxthree\hpack to \scratchwidth{\hss\box\scratchboxthree\hss}%
688      %
689      \scratchunicode\c_math_stackers_extracode
690      \ifcase\scratchunicode\else % uses \scratchunicode
691        \d_math_stackers_offset_l\mathstackersparameter{lb}%
692        \d_math_stackers_offset_r\mathstackersparameter{rb}%
693        \setbox\scratchboxone\csname\??mathstackersalternative\p_alternative\endcsname
694        \math_stackers_check_unicode\c_math_stackers_extracode
695        \let\math_stackers_unicode_one\math_stackers_unicode
696      \fi
697      %
698      \math_stackers_normalize_three
699      \math_stackers_get_max_width
700      \math_stackers_set_max_width
701      % analysis: is this still ok here?
702      \ifcase\c_math_stackers_bottom
703        \ifcase\c_math_stackers_top
704            \dosettagproperty\s!subtype\t!munderover
705        \else
706            \dosettagproperty\s!subtype\t!mover
707        \fi
708      \else
709        \ifcase\c_math_stackers_top
710            \dosettagproperty\s!subtype\t!munder
711        \else
712            % brrr
713        \fi
714      \fi
715      % base
716    % \math_stackers_start_tagged_mid\math_stackers_unicode
717        \math_stackers_middle\bgroup
718          \box\scratchboxthree
719        \egroup
720    % \math_stackers_stop_tagged
721      %
722\math_stackers_double_reset_texts
723      %
724      \ifdim\htdp\scratchboxtwo>\zeropoint
725        \ifcase\c_math_stackers_bottom\else
726          \kern-\scratchwidth
727          % under
728          \math_stackers_start_tagged_bot{\ifcase\c_math_stackers_top\math_stackers_unicode_two\else\math_stackers_unicode_one\fi}%
729            \math_stackers_bottom\bgroup
730              \lower{%
731                 \scratchdepth
732                +\ht\ifcase\c_math_stackers_top\scratchboxtwo\else\scratchboxone\fi
733                +(\mathstackersparameter\c!distance)% was \c!voffset
734              }\box\ifcase\c_math_stackers_top\scratchboxtwo\else\scratchboxone\fi
735            \egroup
736          \math_stackers_stop_tagged
737\math_stackers_double_set_toptext
738        \fi
739        \ifcase\c_math_stackers_top\else
740          \kern-\scratchwidth
741          % over
742          \math_stackers_start_tagged_top\math_stackers_unicode_two
743            \math_stackers_top\bgroup
744              \raise{%
745                 \scratchheight
746                +\dp\scratchboxtwo % new
747                +(\mathstackersparameter\c!distance)% was \c!voffset
748              }\box\scratchboxtwo
749            \egroup
750          \math_stackers_stop_tagged
751\math_stackers_double_set_bottomtext
752        \fi
753      \fi}%
754  \dostoptagged
755  \mathstackersparameter\c!right\relax
756  \math_stackers_stop_group
757\math_stackers_double_flush_texts
758   }
759
760\permanent\tolerant\protected\def\definemathoverextensible[#1]#*[#2]#*[#3]%
761  {\ifparameter#3\or
762     \frozen\protected\edefcsname#2\endcsname{\math_stackers_make_double\plusone  \zerocount{#1}{\number#3}{0}}%
763   \else
764     \frozen\protected\edefcsname#1\endcsname{\math_stackers_make_double\plusone  \zerocount\noexpand\currentmathstackers{\number#2}{0}}%
765   \fi}
766
767\permanent\tolerant\protected\def\definemathunderextensible[#1]#*[#2]#*[#3]%
768  {\ifparameter#3\or
769     \frozen\protected\edefcsname#2\endcsname{\math_stackers_make_double\zerocount\plusone{#1}{\number#3}{0}}%
770   \else
771     \frozen\protected\edefcsname#1\endcsname{\math_stackers_make_double\zerocount\plusone\noexpand\currentmathstackers{\number#2}{0}}%
772   \fi}
773
774\permanent\tolerant\protected\def\definemathdoubleextensible[#1]#*[#2]#*[#3]#*[#4]%
775  {\ifparameter#4\or
776     \frozen\protected\edefcsname#2\endcsname{\math_stackers_make_double\plusone  \plusone{#1}{\number#3}{\number#4}}%
777   \else
778     \frozen\protected\edefcsname#1\endcsname{\math_stackers_make_double\plusone  \plusone\noexpand\currentmathstackers{\number#2}{\number#3}}%
779   \fi}
780
781\permanent\tolerant\protected\def\definemathover[#category]#spacer[#command]#spacer[#topcode]%
782  {\frozen\protected\defcsname#command\endcsname{\math_stackers_handle_direct\plusone\zerocount{#category}{#topcode}{0}}}
783
784\permanent\tolerant\protected\def\definemathunder[#category]#spacer[#command]#spacer[#bottomcode]%
785  {\frozen\protected\defcsname#command\endcsname{\math_stackers_handle_direct\zerocount\plusone{#category}{#bottomcode}{0}}}
786
787\permanent\tolerant\protected\def\definemathdouble[#category]#spacer[#command]#spacer[#topcode]#spacer[#bottomcode]%
788  {\frozen\protected\defcsname#command\endcsname{\math_stackers_handle_direct\plusone\plusone{#category}{#topcode}{#bottomcode}}}
789
790\permanent\tolerant\protected\def\mathover[#category]#spacer[#S#settings]#:#*#topcode#*#text%
791  {\begingroup
792   \cdef\currentmathstackers{\ifparameter#category\or#category\else\v!top\fi}%
793   \ifparameter#settings\or
794      \setupcurrentmathstackers[#settings]%
795   \fi
796   \math_stackers_make_double\plusone\zerocount
797     {\currentmathstackers}%
798     {#topcode}%
799     {0}%
800     {#text}%
801   \endgroup}
802
803\permanent\tolerant\protected\def\mathunder[#category]#spacer[#S#settings]#:#*#bottomcode#*#text%
804  {\begingroup
805   \cdef\currentmathstackers{\ifparameter#category\or#category\else\v!bottom\fi}%
806   \ifparameter#settings\or
807      \setupcurrentmathstackers[#settings]%
808   \fi
809   \math_stackers_make_double\zerocount\plusone
810     {\currentmathstackers}%
811     {#bottomcode}%
812     {0}%
813     {#text}%
814   \endgroup}
815
816\permanent\tolerant\protected\def\mathdouble[#category]#spacer[#settings]#:#*#topcode#*#bottomcode#*#text%
817  {\begingroup
818   \cdef\currentmathstackers{\ifparameter#category\or#category\else\v!both\fi}%
819   \ifparameter#settings\or
820      \setupcurrentmathstackers[#settings]%
821   \fi
822   \math_stackers_make_double\plusone\plusone
823     {\currentmathstackers}%
824     {#topcode}%
825     {#bottomcode}%
826     {#text}%
827   \endgroup}
828
829\def\math_stackers_handle_direct#top#bottom#category#topcode#bottomcode#text%
830  {\begingroup
831   \math_stackers_make_double#top#bottom{#category}{#topcode}{#bottomcode}{#text}%
832   \endgroup}
833
834%D A relative new one is a combination of accents and text (as needed in mathml):
835
836\protected\def\math_stackers_make_double_text#where#category#codepoint#text#extra%
837  {\math_stackers_start_group{#category}%
838   \mathstackersparameter\c!left\relax
839   \dostarttagged\t!mstacker\currentmathstackers
840   \ifmmode\math_atom_by_parameter\mathstackersparameter\else\dontleavehmode\fi
841     {\math_stackers_reset_variables
842      \edef\m_math_stackers_text_middle{#text}%
843      \math_stackers_check_unicode{#codepoint}%
844      \scratchunicode#codepoint\relax
845      %
846      \ifempty\math_stackers_middle
847        \setbox\scratchboxthree\emptyhbox
848      \else
849        \dostarttagged\t!mstackermid{\math_stackers_unicode}%
850        \setmathtextbox\scratchboxthree\hbox{\math_stackers_middletext}%
851        \dostoptagged
852      \fi
853      %
854      \ifcase#where\relax
855        \edef\m_math_stackers_text_top{#extra}%
856        \ifempty\math_stackers_top
857          \setbox\scratchboxone\emptyhbox
858        \else
859          \setmathsmalltextbox\scratchboxone\hbox{\math_stackers_toptext}%
860        \fi
861      \else
862        \edef\m_math_stackers_text_bottom{#extra}%
863        \ifempty\math_stackers_bottom
864          \setbox\scratchboxone\emptyhbox
865        \else
866          \setmathsmalltextbox\scratchboxone\hbox{\math_stackers_bottomtext}%
867        \fi
868      \fi
869      %
870      \scratchwidth\wd
871        \ifdim\wd\scratchboxone>\wd\scratchboxthree
872          \scratchboxone
873        \else
874          \scratchboxthree
875        \fi
876      \relax
877      \scratchdimen\mathstackersparameter\c!minwidth\relax
878      \ifdim\scratchwidth<\scratchdimen
879         \scratchwidth\scratchdimen
880      \fi
881      \advanceby\scratchwidth2\scratchhoffset
882      %
883      \ifdim\wd\scratchboxone<\scratchwidth
884        \setbox\scratchboxone\hpack to \scratchwidth{\hss\unhbox\scratchboxone\hss}%
885      \fi
886      \ifdim\wd\scratchboxthree<\scratchwidth
887        \setbox\scratchboxthree\hpack to \scratchwidth{\hss\unhbox\scratchboxthree\hss}%
888      \fi
889      %
890      \math_stackers_normalize_three
891      % analysis: is this still ok here?
892      \dosettagproperty\s!subtype\t!munderover
893      % base
894      \math_stackers_middle\bgroup
895        \box\scratchboxthree
896      \egroup
897      %
898      \setbox\scratchboxtwo\csname\??mathstackersalternative\p_alternative\endcsname
899      \kern-\scratchwidth
900      \ifcase#where\relax
901        % under
902        \math_stackers_start_tagged_bot\empty
903          \math_stackers_bottom\bgroup
904            \lower{%
905              \scratchdepth
906             +\ht\scratchboxtwo
907             +(\mathstackersparameter\c!distance)%
908            }\box\scratchboxtwo % accent
909          \egroup
910        \math_stackers_stop_tagged
911        \kern-\scratchwidth
912        % over
913        \math_stackers_start_tagged_top\empty
914          \math_stackers_top\bgroup
915            \raise{%
916               \scratchheight
917              +\dp\scratchboxone
918              +(\mathstackersparameter\c!voffset)%
919            }\box\scratchboxone % toptext
920          \egroup
921        \math_stackers_stop_tagged
922      \else
923        % under
924        \math_stackers_start_tagged_bot\empty
925          \math_stackers_bottom\bgroup
926            \lower{%
927               \scratchdepth
928              +\ht\scratchboxone
929              +(\mathstackersparameter\c!voffset)%
930            }\box\scratchboxone % bottext
931          \egroup
932        \math_stackers_stop_tagged
933        \kern-\scratchwidth
934        % over
935        \math_stackers_start_tagged_top\empty
936          \math_stackers_top\bgroup
937            \raise{%
938               \scratchheight
939              +\dp\scratchboxtwo % new
940              +(\mathstackersparameter\c!distance)%
941            }\box\scratchboxtwo % accent
942          \egroup
943        \math_stackers_stop_tagged
944      \fi
945      }%
946   \dostoptagged
947   \mathstackersparameter\c!right\relax
948   \math_stackers_stop_group}
949
950\permanent\tolerant\protected\def\definemathovertextextensible[#1]#*[#2]#*[#3]%
951  {\ifparameter#3\or
952     \frozen\protected\edefcsname#2\endcsname{\math_stackers_make_double_text\plusone{#1}{\number#3}}%
953   \else
954     \frozen\protected\edefcsname#1\endcsname{\math_stackers_make_double_text\plusone\noexpand\currentmathstackers{\number#2}}%
955   \fi}
956
957\permanent\tolerant\protected\def\definemathundertextextensible[#1]#*[#2]#*[#3]%
958  {\ifparameter#3\or
959     \frozen\protected\edefcsname#2\endcsname{\math_stackers_make_double_text\zerocount{#1}{\number#3}}%
960   \else
961     \frozen\protected\edefcsname#1\endcsname{\math_stackers_make_double_text\zerocount\noexpand\currentmathstackers{\number#2}}%
962   \fi}
963
964\permanent\tolerant\protected\def\mathovertext[#category]%
965  {\begingroup
966   \math_stackers_direct_double_text\plusone  {\ifarguments#category\or#category\else\v!top\fi}}
967
968\permanent\tolerant\protected\def\mathundertext[#category]%
969  {\begingroup
970   \math_stackers_direct_double_text\zerocount{\ifarguments#category\or#category\else\v!bottom\fi}}
971
972\def\math_stackers_direct_double_text#where#category#codepoint#text#extra%%
973  {\math_stackers_make_double_text#where{#category}{#codepoint}{#text}{#extra}%
974   \endgroup}
975
976%D Here is a bonus macro that takes three texts. It can be used to get consistent
977%D mixed usage.
978
979\permanent\tolerant\protected\def\mathtriplet[#1]#:#*#=#*#=#*#=%
980  {\begingroup
981   \ifparameter#1\or\cdef\currentmathstackers{#1}\fi
982   \math_stackers_triplet\plusone\currentmathstackers{#2}{#3}{#4}%
983   \endgroup}
984
985\permanent\tolerant\protected\def\definemathtriplet[#1]#*[#2]#*[#3]% category name default
986  {\ifarguments\or
987     \frozen\protected\edefcsname#1\endcsname{\math_stackers_auto_triplet_nop[\noexpand\currentmathstackers]}%
988   \or
989     \frozen\protected\edefcsname#2\endcsname{\math_stackers_auto_triplet_nop[#1]}%
990   \or
991     \frozen\protected\edefcsname#2\endcsname{\math_stackers_auto_triplet_yes[#1][#3]}%
992   \fi}
993
994\tolerant\protected\def\math_stackers_auto_triplet_yes[#1][#2]#*[#3]#:#*#=#*#=% [#2]% #2 gobble spaces
995  {\begingroup
996   \cdef\currentmathstackers{#1}%
997   \def \m_math_stackers_text_middle{#2}%
998   \ifparameter#3\or\cdef\currentmathstackers{#3}\fi
999   \math_stackers_triplet\plusone\currentmathstackers\m_math_stackers_text_middle{#4}{#5}%
1000   \endgroup}
1001
1002\tolerant\protected\def\math_stackers_auto_triplet_nop[#1]#*[#2]#:#*#=#*#=#*#=% [#2]% #2 gobble spaces%
1003  {\begingroup
1004   \cdef\currentmathstackers{#1}%
1005   \ifparameter#2\or\cdef\currentmathstackers{#2}\fi
1006   \math_stackers_triplet\plusone\currentmathstackers{#3}{#4}{#5}%
1007   \endgroup}
1008
1009%D Definitions:
1010
1011\definemathstackers
1012  [\v!mathematics]
1013  [\c!topcommand=\mathematics,
1014   \c!middlecommand=\mathematics,
1015   \c!bottomcommand=\mathematics]
1016
1017\definemathstackers
1018  [\s!math]
1019  [\v!mathematics]
1020
1021\definemathstackers
1022  [\v!text]
1023  [\v!mathematics]
1024  [\c!topcommand=,
1025   \c!middlecommand=\mathematics,
1026   \c!bottomcommand=]
1027
1028\definemathstackers
1029  [\v!reverse]
1030  [\v!mathematics]
1031  [\c!order=\v!reverse]
1032
1033\definemathstackers
1034  [\v!both]
1035  [\v!mathematics]
1036  [\c!location=\v!top, % ?
1037   \c!mathclass=\s!accent,  % check chemistry
1038   \c!strut=\v!no,
1039   \c!middlecommand=\mathematics,
1040   \c!hoffset=\zeropoint]
1041
1042\definemathstackers
1043  [\v!top]
1044  [\v!both]
1045
1046\definemathstackers
1047  [\v!bottom]
1048  [\v!both]
1049
1050\definemathstackers
1051  [\v!vfenced]
1052  [\v!both]
1053  [\c!mathclass=\s!ordinary,
1054   \c!mathlimits=\v!yes,
1055   % only these arrows make sense
1056   \c!stretch=\v!yes,
1057   \c!shrink=\v!yes]
1058
1059% these are needed for mathml:
1060
1061% \setupmathstackers
1062%   [\v!both]
1063%   [\c!hoffset=1pt,
1064%    \c!voffset=1pt]
1065
1066\definemathstackers
1067  [\v!bothtext]
1068  [\v!both]
1069  [\c!strut=\v!yes]
1070
1071% These are compatibity definitions, math only.
1072
1073% todo: top= bottom= middle= is nicer (compare math-fen)
1074
1075%D We save a few definitions that we automatically got from the \type {char-def.lua}
1076%D database.
1077
1078% Be careful in choosing what accents you take (the code below uses a combining
1079% one):
1080%
1081% \startbuffer
1082% % $\Umathaccent top        0 0 "20D7 {example}$
1083% % $\Umathaccent top  fixed 0 0 "20D7 {example}$
1084% $\Umathaccent              0 0 "20D7 {example}$
1085% $\Umathaccent        fixed 0 0 "20D7 {example}$
1086% $\Umathaccent bottom       0 0 "20D7 {example}$
1087% $\Umathaccent bottom fixed 0 0 "20D7 {example}$
1088% $\Umathaccent both         0 0 "20D7
1089%                            0 0 "20D7 {example}$
1090% $\Umathaccent both fixed   0 0 "20D7
1091%                    fixed   0 0 "20D7 {example}$
1092% $\Umathaccent both         0 0 "20D7
1093%                    fixed   0 0 "20D7 {example}$
1094% $\Umathaccent both fixed   0 0 "20D7
1095%                            0 0 "20D7 {example}$
1096% \stopbuffer
1097%
1098% \setupbodyfont[modern]  \getbuffer
1099% \setupbodyfont[xits]    \getbuffer
1100% \setupbodyfont[cambria] \getbuffer
1101
1102\immutable\protected\def\normaldoublebrace {\Umathaccent \s!both \zerocount \zerocount "23DE \zerocount \zerocount "23DF }
1103\immutable\protected\def\normaldoubleparent{\Umathaccent \s!both \zerocount \zerocount "23DC \zerocount \zerocount "23DD }
1104
1105% let's keep this .. some are not defined so there's nothing normal
1106
1107\aliased\let\normaloverbrace      \overbrace
1108\aliased\let\normalunderbrace     \underbrace
1109\aliased\let\normaloverparent     \overparent
1110\aliased\let\normalunderparent    \underparent
1111\aliased\let\normaloverbracket    \overbracket
1112\aliased\let\normalunderbracket   \underbracket
1113
1114%aliased\let\normalunderleftarrow \underleftarrow
1115%aliased\let\normaloverleftarrow  \overleftarrow
1116%aliased\let\normalunderrightarrow\underrightarrow
1117%aliased\let\normaloverrightarrow \overrightarrow
1118
1119%D Here come the new ones:
1120
1121\definemathstackers [\v!none]   [\v!mathematics] [\c!hoffset=\zeropoint]
1122\definemathstackers [\v!normal] [\v!mathematics] [\c!hoffset=0.5\mathemwidth] % the default
1123\definemathstackers [\v!small]  [\v!mathematics] [\c!hoffset=1\mathemwidth]
1124\definemathstackers [\v!medium] [\v!mathematics] [\c!hoffset=1.5\mathemwidth]
1125\definemathstackers [\v!big]    [\v!mathematics] [\c!hoffset=2\mathemwidth]
1126
1127\definemathextensible [\v!reverse] [xrel]                ["2212] % ["002D]
1128\definemathextensible [\v!reverse] [xequal]              ["003D]
1129\definemathextensible [\v!reverse] [xleftarrow]          ["2190] % ["27F5]
1130\definemathextensible [\v!reverse] [xrightarrow]         ["2192] % ["27F6]
1131\definemathextensible [\v!reverse] [xleftrightarrow]     ["2194] % ["27F7]
1132\definemathextensible [\v!reverse] [xlongleftarrow]      ["27F5]
1133\definemathextensible [\v!reverse] [xlongrightarrow]     ["27F6]
1134\definemathextensible [\v!reverse] [xlongleftrightarrow] ["27F7]
1135\definemathextensible [\v!reverse] [xLeftarrow]          ["27F8] % why not ["27D2]
1136\definemathextensible [\v!reverse] [xRightarrow]         ["27F9] % why not ["27D0]
1137\definemathextensible [\v!reverse] [xLeftrightarrow]     ["27FA] % why not ["27D4]
1138\definemathextensible [\v!reverse] [xtwoheadleftarrow]   ["219E]
1139\definemathextensible [\v!reverse] [xtwoheadrightarrow]  ["21A0]
1140\definemathextensible [\v!reverse] [xmapsto]             ["21A6]
1141\definemathextensible [\v!reverse] [xhookleftarrow]      ["21A9]
1142\definemathextensible [\v!reverse] [xhookrightarrow]     ["21AA]
1143\definemathextensible [\v!reverse] [xleftharpoondown]    ["21BD]
1144\definemathextensible [\v!reverse] [xleftharpoonup]      ["21BC]
1145\definemathextensible [\v!reverse] [xrightharpoondown]   ["21C1]
1146\definemathextensible [\v!reverse] [xrightharpoonup]     ["21C0]
1147\definemathextensible [\v!reverse] [xrightoverleftarrow] ["21C4]
1148\definemathextensible [\v!reverse] [xleftoverrightarrow] ["21C6]
1149\definemathextensible [\v!reverse] [xleftrightharpoons]  ["21CB]
1150\definemathextensible [\v!reverse] [xrightleftharpoons]  ["21CC]
1151\definemathextensible [\v!reverse] [xtriplerel]          ["2261]
1152
1153\definemathextensible [\v!mathematics] [mrel]                ["2212] % ["002D]
1154\definemathextensible [\v!mathematics] [mequal]              ["003D]
1155\definemathextensible [\v!mathematics] [mleftarrow]          ["2190] % ["27F5]
1156\definemathextensible [\v!mathematics] [mrightarrow]         ["2192] % ["27F6]
1157\definemathextensible [\v!mathematics] [mleftrightarrow]     ["2194] % ["27F7]
1158\definemathextensible [\v!mathematics] [mLeftarrow]          ["21D0]
1159\definemathextensible [\v!mathematics] [mRightarrow]         ["21D2]
1160\definemathextensible [\v!mathematics] [mLeftrightarrow]     ["21D4]
1161\definemathextensible [\v!mathematics] [mtwoheadleftarrow]   ["219E]
1162\definemathextensible [\v!mathematics] [mtwoheadrightarrow]  ["21A0]
1163\definemathextensible [\v!mathematics] [mmapsto]             ["21A6]
1164\definemathextensible [\v!mathematics] [mhookleftarrow]      ["21A9]
1165\definemathextensible [\v!mathematics] [mhookrightarrow]     ["21AA]
1166\definemathextensible [\v!mathematics] [mleftharpoondown]    ["21BD]
1167\definemathextensible [\v!mathematics] [mleftharpoonup]      ["21BC]
1168\definemathextensible [\v!mathematics] [mrightharpoondown]   ["21C1]
1169\definemathextensible [\v!mathematics] [mrightharpoonup]     ["21C0]
1170\definemathextensible [\v!mathematics] [mrightoverleftarrow] ["21C4]
1171\definemathextensible [\v!mathematics] [mleftoverrightarrow] ["21C6]
1172\definemathextensible [\v!mathematics] [mleftrightharpoons]  ["21CB]
1173\definemathextensible [\v!mathematics] [mrightleftharpoons]  ["21CC]
1174\definemathextensible [\v!mathematics] [mtriplerel]          ["2261]
1175
1176\definemathextensible [\v!text] [trel]                ["2212] % ["002D]
1177\definemathextensible [\v!text] [tequal]              ["003D]
1178\definemathextensible [\v!text] [tmapsto]             ["21A6]
1179\definemathextensible [\v!text] [tleftarrow]          ["2190] % ["27F5]
1180\definemathextensible [\v!text] [trightarrow]         ["2192] % ["27F6]
1181\definemathextensible [\v!text] [tleftrightarrow]     ["2194] % ["27F7]
1182\definemathextensible [\v!text] [tLeftarrow]          ["21D0]
1183\definemathextensible [\v!text] [tRightarrow]         ["21D2]
1184\definemathextensible [\v!text] [tLeftrightarrow]     ["21D4]
1185\definemathextensible [\v!text] [ttwoheadleftarrow]   ["219E]
1186\definemathextensible [\v!text] [ttwoheadrightarrow]  ["21A0]
1187\definemathextensible [\v!text] [tmapsto]             ["21A6]
1188\definemathextensible [\v!text] [thookleftarrow]      ["21A9]
1189\definemathextensible [\v!text] [thookrightarrow]     ["21AA]
1190\definemathextensible [\v!text] [tleftharpoondown]    ["21BD]
1191\definemathextensible [\v!text] [tleftharpoonup]      ["21BC]
1192\definemathextensible [\v!text] [trightharpoondown]   ["21C1]
1193\definemathextensible [\v!text] [trightharpoonup]     ["21C0]
1194\definemathextensible [\v!text] [trightoverleftarrow] ["21C4]
1195\definemathextensible [\v!text] [tleftoverrightarrow] ["21C6]
1196\definemathextensible [\v!text] [tleftrightharpoons]  ["21CB]
1197\definemathextensible [\v!text] [trightleftharpoons]  ["21CC]
1198\definemathextensible [\v!text] [ttriplerel]          ["2261]
1199
1200\definemathoverextensible [\v!top] [overleftarrow]          ["2190] % ["27F5]
1201\definemathoverextensible [\v!top] [overrightarrow]         ["2192] % ["27F6]
1202\definemathoverextensible [\v!top] [overleftrightarrow]     ["2194] % ["27F7]
1203\definemathoverextensible [\v!top] [overtwoheadleftarrow]   ["219E] % ["27F8]
1204\definemathoverextensible [\v!top] [overtwoheadrightarrow]  ["21A0] % ["27F9]
1205\definemathoverextensible [\v!top] [overlefttailarrow]      ["21A2]
1206\definemathoverextensible [\v!top] [overrighttailarrow]     ["21A3]
1207\definemathoverextensible [\v!top] [overleftbararrow]       ["21A4]
1208\definemathoverextensible [\v!top] [overrightbararrow]      ["21A6]
1209\definemathoverextensible [\v!top] [overlefthookarrow]      ["21A9]
1210\definemathoverextensible [\v!top] [overrighthookarrow]     ["21AA]
1211\definemathoverextensible [\v!top] [overleftharpoondown]    ["21BD]
1212\definemathoverextensible [\v!top] [overleftharpoonup]      ["21BC]
1213\definemathoverextensible [\v!top] [overrightharpoondown]   ["21C1]
1214\definemathoverextensible [\v!top] [overrightharpoonup]     ["21C0]
1215\definemathoverextensible [\v!top] [overRightarrow]         ["21D2] % ["27F9]
1216\definemathoverextensible [\v!top] [overLeftarrow]          ["21D0] % ["27F8]
1217\definemathoverextensible [\v!top] [overLeftrightarrow]     ["21D4] % ["27F8]
1218\definemathoverextensible [\v!top] [overLeftbararrow]       ["2906]
1219\definemathoverextensible [\v!top] [overRightbararrow]      ["2907]
1220
1221\definemathunderextensible [\v!bottom] [underleftarrow]         ["2190] % ["27F5]
1222\definemathunderextensible [\v!bottom] [underrightarrow]        ["2192] % ["27F6]
1223\definemathunderextensible [\v!bottom] [underleftrightarrow]    ["2194] % ["27F7]
1224\definemathunderextensible [\v!bottom] [undertwoheadleftarrow]  ["219E] % ["27F8]
1225\definemathunderextensible [\v!bottom] [undertwoheadrightarrow] ["21A0] % ["27F9]
1226\definemathunderextensible [\v!bottom] [underlefttailarrow]     ["21A2]
1227\definemathunderextensible [\v!bottom] [underrighttailarrow]    ["21A3]
1228\definemathunderextensible [\v!bottom] [underleftbararrow]      ["21A4]
1229\definemathunderextensible [\v!bottom] [underrightbararrow]     ["21A6]
1230\definemathunderextensible [\v!bottom] [underlefthookarrow]     ["21A9]
1231\definemathunderextensible [\v!bottom] [underrighthookarrow]    ["21AA]
1232\definemathunderextensible [\v!bottom] [underleftharpoondown]   ["21BD]
1233\definemathunderextensible [\v!bottom] [underleftharpoonup]     ["21BC]
1234\definemathunderextensible [\v!bottom] [underrightharpoondown]  ["21C1]
1235\definemathunderextensible [\v!bottom] [underrightharpoonup]    ["21C0]
1236\definemathunderextensible [\v!bottom] [underRightarrow]        ["21D2] % ["27F9]
1237\definemathunderextensible [\v!bottom] [underLeftarrow]         ["21D0] % ["27F8]
1238\definemathunderextensible [\v!bottom] [underLeftrightarrow]    ["21D4] % ["27F8]
1239\definemathunderextensible [\v!bottom] [underLeftbararrow]      ["2906]
1240\definemathunderextensible [\v!bottom] [underRightbararrow]     ["2907]
1241
1242%D We don't use overline and underline. This is one of the overlooked aspects of
1243%D unicode cq. opentype math: why treat rules different than e.g. arrows and
1244%D accents. It is a bit unfortunate that the opportunity to move math to new
1245%D technologies happened outside the tex domain (and/or some aspects were kept while
1246%D in fact they were side effects of limitations of traditional fonts). From the
1247%D unicode aware tex engines' implementation point of view things could have been
1248%D done a bit nicer but then: the community didn't seem to care too much and just
1249%D has to follow now.
1250%D
1251%D Anyhow, we use a character based approach so that at least we get unicode stuff
1252%D in the backend (okay, we still need to deal with some cut and paste issues but at
1253%D least we now know what we deal with.
1254
1255\definemathoverextensible   [\v!vfenced] [overbar]       ["203E]         % todo: private
1256\definemathunderextensible  [\v!vfenced] [underbar]              ["203E] % todo: private
1257\definemathdoubleextensible [\v!vfenced] [doublebar]     ["203E] ["203E] % todo: private
1258
1259\definemathoverextensible   [\v!vfenced] [overbrace]     ["23DE]
1260\definemathunderextensible  [\v!vfenced] [underbrace]            ["23DF]
1261\definemathdoubleextensible [\v!vfenced] [doublebrace]   ["23DE] ["23DF]
1262
1263\definemathoverextensible   [\v!vfenced] [overparent]    ["23DC]
1264\definemathunderextensible  [\v!vfenced] [underparent]           ["23DD]
1265\definemathdoubleextensible [\v!vfenced] [doubleparent]  ["23DC] ["23DD]
1266
1267\definemathoverextensible   [\v!vfenced] [overbracket]   ["23B4]
1268\definemathunderextensible  [\v!vfenced] [underbracket]          ["23B5]
1269\definemathdoubleextensible [\v!vfenced] [doublebracket] ["23B4] ["23B5]
1270
1271%D For mathml:
1272
1273\definemathdoubleextensible    [\v!both]     [overbarunderbar]         ["203E] ["203E] % todo: private
1274\definemathdoubleextensible    [\v!both]     [overbraceunderbrace]     ["23DE] ["23DF]
1275\definemathdoubleextensible    [\v!both]     [overparentunderparent]   ["23DC] ["23DD]
1276\definemathdoubleextensible    [\v!both]     [overbracketunderbracket] ["23B4] ["23B5]
1277
1278\definemathovertextextensible  [\v!bothtext] [overbartext]             ["203E]         % todo: private
1279\definemathundertextextensible [\v!bothtext] [underbartext]                    ["203E] % todo: private
1280\definemathovertextextensible  [\v!bothtext] [overbracetext]           ["23DE]
1281\definemathundertextextensible [\v!bothtext] [underbracetext]                  ["23DF]
1282\definemathovertextextensible  [\v!bothtext] [overparenttext]          ["23DC]
1283\definemathundertextextensible [\v!bothtext] [underparenttext]                 ["23DD]
1284\definemathovertextextensible  [\v!bothtext] [overbrackettext]         ["23B4]
1285\definemathundertextextensible [\v!bothtext] [underbrackettext]                ["23B5]
1286
1287% \def\math_stackers_hacked_fill#1#2#3%
1288%   {\mathematics
1289%      {\begingroup
1290%       \mathsurround\zeropoint
1291%       \thickmuskip \zeromuskip
1292%       \medmuskip   \zeromuskip
1293%       \thinmuskip  \zeromuskip
1294%       \tinymuskip  \zeromuskip
1295%       \pettymuskip \zeromuskip
1296%       \ifrelax#1%
1297%         \cleaders\mathstylehbox{#2}\hfill
1298%       \else
1299%         #1%
1300%         \mkern-7\onemuskip
1301%         \cleaders\mathstylehbox{\mkern-2\onemuskip#2\mkern-2\onemuskip}\hfill
1302%         \mkern-7\onemuskip
1303%         #3%
1304%       \fi
1305%       \endgroup}}
1306%
1307% \immutable\protected\def\rightarrowfill        {\math_stackers_hacked_fill \relbar               \relbar              \rightarrow}
1308% \immutable\protected\def\leftarrowfill         {\math_stackers_hacked_fill \leftarrow            \relbar              \relbar}
1309% \immutable\protected\def\rightoverleftarrowfill{\math_stackers_hacked_fill \relax                \crightoverleftarrow \relax}
1310% \immutable\protected\def\leftoverrightarrowfill{\math_stackers_hacked_fill \relax                \cleftoverrightarrow \relax}
1311% \immutable\protected\def\equalfill             {\math_stackers_hacked_fill \Relbar               \Relbar              \Relbar}
1312% \immutable\protected\def\Rightarrowfill        {\math_stackers_hacked_fill \Relbar               \Relbar              \Rightarrow}
1313% \immutable\protected\def\Leftarrowfill         {\math_stackers_hacked_fill \Leftarrow            \Relbar              \Relbar}
1314% \immutable\protected\def\Leftrightarrowfill    {\math_stackers_hacked_fill \Leftarrow            \Relbar              \Rightarrow}
1315% \immutable\protected\def\leftrightarrowfill    {\math_stackers_hacked_fill \leftarrow            \relbar              \rightarrow}
1316% \immutable\protected\def\mapstofill            {\math_stackers_hacked_fill{\mapstochar\relbar}   \relbar              \rightarrow}
1317% \immutable\protected\def\twoheadrightarrowfill {\math_stackers_hacked_fill \relbar               \relbar              \twoheadrightarrow}
1318% \immutable\protected\def\twoheadleftarrowfill  {\math_stackers_hacked_fill \twoheadleftarrow     \relbar              \relbar}
1319% \immutable\protected\def\rightharpoondownfill  {\math_stackers_hacked_fill \relbar               \relbar              \rightharpoondown}
1320% \immutable\protected\def\rightharpoonupfill    {\math_stackers_hacked_fill \relbar               \relbar              \rightharpoonup}
1321% \immutable\protected\def\leftharpoondownfill   {\math_stackers_hacked_fill \leftharpoondown      \relbar              \relbar}
1322% \immutable\protected\def\leftharpoonupfill     {\math_stackers_hacked_fill \leftharpoonup        \relbar              \relbar}
1323% \immutable\protected\def\hookleftfill          {\math_stackers_hacked_fill \leftarrow            \relbar             {\relbar\joinrel\rhook}}
1324% \immutable\protected\def\hookrightfill         {\math_stackers_hacked_fill{\lhook\joinrel\relbar}\relbar              \rightarrow}
1325% \immutable\protected\def\relfill               {\math_stackers_hacked_fill \relbar               \relbar              \relbar}
1326% \immutable\protected\def\triplerelfill         {\math_stackers_hacked_fill \equiv                \equiv               \equiv}
1327%
1328% \permanent\tolerant\protected\def\defineextensiblefiller[#1]#*[#2]%
1329%   {\immutable\letcsname\??mathextensiblefallbacks\number#2\expandafter\endcsname\csname#1\endcsname}
1330
1331\installcorenamespace {mathadaptiveextensible}
1332
1333\defineadaptive
1334  [mathfiller]
1335  [\c!setups=adaptive:mathfiller,
1336   \c!stretch=1fill]
1337
1338\startsetups adaptive:mathfiller
1339    \setbox\usedadaptivebox\hbox to \usedadaptivewidth \bgroup
1340        \startimath
1341            \Uhextensible
1342                \s!width  \usedadaptivewidth
1343                \s!middle \zerocount \usedadaptivealternative
1344            \relax
1345        \stopimath
1346    \egroup
1347\stopsetups
1348
1349% \def\mathfiller#1%
1350%   {\begingroup
1351%    \scratchunicode#1\relax
1352%    \adaptivebox[mathfiller][\c!alternative=#1]{\hss\strut\hss}%
1353%    \endgroup}
1354
1355\permanent\protected\def\mathfiller#1%
1356  {\adaptivebox[mathfiller][\c!alternative=#1]{\hss\strut\hss}}
1357
1358\permanent\tolerant\protected\def\defineextensiblefiller[#1]#*[#2]%
1359  {\frozen\instance\edefcsname#1\endcsname{\mathfiller{\number#2}}}
1360
1361%defineextensiblefiller [barfill]                ["203E] % % todo: private
1362\defineextensiblefiller [relfill]                ["2212] % ["002D]
1363\defineextensiblefiller [equalfill]              ["003D]
1364\defineextensiblefiller [leftarrowfill]          ["2190]
1365\defineextensiblefiller [rightarrowfill]         ["2192]
1366\defineextensiblefiller [twoheadleftarrowfill]   ["219E]
1367\defineextensiblefiller [twoheadrightarrowfill]  ["21A0]
1368\defineextensiblefiller [mapstofill]             ["21A6]
1369%defineextensiblefiller [hookleftarrowfill]      ["21A9] % not in fonts
1370%defineextensiblefiller [hookrightarrowfill]     ["21AA] % not in fonts
1371\defineextensiblefiller [leftharpoondownfill]    ["21BD]
1372\defineextensiblefiller [leftharpoonupfill]      ["21BC]
1373\defineextensiblefiller [rightharpoondownfill]   ["21C1]
1374\defineextensiblefiller [rightharpoonupfill]     ["21C0]
1375\defineextensiblefiller [rightoverleftarrowfill] ["21C4]
1376\defineextensiblefiller [leftoverrightarrowfill] ["21C6]
1377%defineextensiblefiller [leftrightharpoonsfill]  ["21CB] % yet undefined
1378%defineextensiblefiller [rightleftharpoonsfill]  ["21CC] % yet undefined
1379\defineextensiblefiller [triplerelfill]          ["2261]
1380\defineextensiblefiller [leftrightarrowfill]     ["27F7]
1381\defineextensiblefiller [Leftarrowfill]          ["27F8]
1382\defineextensiblefiller [Rightarrowfill]         ["27F9]
1383\defineextensiblefiller [Leftrightarrowfill]     ["27FA]
1384\defineextensiblefiller [Rightleftarrowfill]     ["27FA]
1385
1386%D Extra:
1387
1388\permanent\protected\edef\singlebond{\mathematics{\mathsurround\zeropoint\char\number"002D\relax}}
1389\permanent\protected\edef\doublebond{\mathematics{\mathsurround\zeropoint\char\number"003D\relax}}
1390\permanent\protected\edef\triplebond{\mathematics{\mathsurround\zeropoint\char\number"2261\relax}}
1391
1392% \mathchardef\singlebond"002D
1393% \mathchardef\doublebond"003D
1394% \mathchardef\triplebond"2261
1395
1396%D Also handy:
1397
1398\permanent\tolerant\protected\def\definemathunstacked[#1]#*[#2]#*[#3]% category name unicode
1399  {\ifarguments\or\or
1400     \frozen\protected\edefcsname#1\endcsname{\math_stackers_unstacked_normal\noexpand\currentmathstackers{\number#2}}%
1401   \or
1402     \frozen\protected\edefcsname#2\endcsname{\math_stackers_unstacked_normal{#1}{\number#3}}%
1403   \fi}
1404
1405\protected\def\math_stackers_unstacked_normal#category#codepoint%
1406  {\begingroup
1407   \cdef\currentmathstackers{#category}%
1408   \scratchdistance\zeropoint
1409   \scratchcounter\ifchknum\mathstackersparameter\c!sample\or\mathstackersparameter\c!sample\else\zerocount\fi
1410   \scratchunicode#codepoint\relax
1411   \scratchclass\mathcodechecked{\mathstackersparameter\c!mathclass}\relax
1412   \ifconditional\indisplaymath\ifcase\scratchcounter\orelse\ifnum\lastatomclass=\mathbegincode
1413     \scratchdistance{%
1414       \fontcharwd\mathstylefont\mathstyle\scratchcounter
1415      -\fontcharwd\mathstylefont\mathstyle\scratchunicode
1416     }%
1417   \fi\fi
1418   \math_atom_by_parameter\mathstackersparameter
1419     {\usemathstackerscolorparameter\c!color
1420      \Umathchar\scratchclass\fam\scratchunicode\relax
1421      \ifzeropt\scratchdistance\else
1422        \kern\scratchdistance
1423      \fi}%
1424   \endgroup}
1425
1426\definemathstackers
1427  [\s!implication]
1428  [\c!mathclass=\s!implication,
1429   \c!sample="27FA]
1430
1431\definemathunstacked [\s!implication] [impliedby] ["27F8]
1432\definemathunstacked [\s!implication] [implies]   ["27F9]
1433\definemathunstacked [\s!implication] [iff]       ["27FA] % \ifandonlyif
1434\definemathunstacked [\s!implication] [impliesby] ["27FA]
1435
1436% This is a weird one:
1437
1438\definemathstackers
1439  [\v!wide]
1440  [\c!mathclass=\s!implication]
1441
1442\definemathunstacked [\v!wide] [And]["0026] % \mathrel{\;&\;}
1443
1444% New (an example of using \mathexheight):
1445
1446\definemathstackers
1447  [\v!symbol]
1448  [\c!voffset=-.3\mathexheight,
1449   \c!hoffset=\zeropoint,
1450   \c!mathclass=\s!ordinary,
1451   \c!topoffset=.4\mathemwidth, % poor man's italic correction
1452   \c!middlecommand=\mathematics]
1453
1454\definemathover[\v!symbol][interiorset]["2218]
1455
1456\protect \endinput
1457
1458% \mathrel{\mathop{\hbox to \dimen0{\hss\copy4\hss}}
1459% \limits\normalsuperscript{\box0}\normalsubscript{\box2}}%
1460
1461% $\Uoverdelimiter \zerocount "2194 {xxxx}$
1462% $\Uunderdelimiter\zerocount "2194 {xxxx}$
1463% $\Udelimiterover \zerocount "2194 {xxxx}$
1464% $\Udelimiterunder\zerocount "2194 {xxxx}$
1465% $\Udelimiterover \zerocount "219A {\Udelimiterunder \zerocount "219B {xxxx}}$
1466
1467% $a \mathrel{\mathop{\filledhboxr{mid}}}\limits^{\filledhboxg{\strut top}}_{\filledhboxb{\strut bottom}} b$
1468