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