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