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