% language=us

\startcomponent about-mathstackers

\environment about-environment

\startchapter[title=Math stackers]

\startsection[title=Introduction]

In the next sections I will discuss the way we deal with stacked content in
\CONTEXT\ \MKIV\ and in particular extensible characters. The mechanism describe
here is actually more generic and can also deal with regular text. The stacker
code is an evolution of the mechanisms that combine math arrows with text. From
the users perspective there is not that much difference with the old methods
because in practice \quote {defined} commands are used and their name stayed.
However, we use different definition and setup commands and provide much more
control. The new implementation is leaner but not meaner and fits the way \MKIV\
is set up.

How does \LUA\ fits in? We use a helper in order to determine some
characteristics of extensibles, but we could have done without. We also use some
new \LUATEX\ math primitives and of course we depend on \OPENTYPE\ font
technoloygy.

\stopsection

\startsection[title=Extensibles]

The command \type {\leftarrowfill} was introduced in plain \TEX\ and gives, as
the name indicates, a \leftarrowfill\ that stretches itself so that it takes the
available space. Take the following example:

\starttyping
\hbox to 4cm{\leftarrowfill}
\stoptyping

This will make an arrow of length 4cm:

\blank \mathstylehbox{\Umathaccent\fam\zerocount"2190{\hskip4cm}} \blank

This arrow is made out of small snippets:

\blank {\showglyphs\scale[width=\textwidth]{\mathstylehbox{\Umathaccent\fam\zerocount"2190{\hskip4cm}}}} \blank

Here is another one:

\starttyping
\hbox to 4cm{\rightoverleftarrowfill}
\stoptyping

or:

\blank {\mathstylehbox{\Umathaccent\fam\zerocount"21C4{\hskip4cm}}} \blank

This time we have three different snippets:

\blank {\showglyphs\scale[width=\textwidth]{\mathstylehbox{\Umathaccent\fam\zerocount"21C4{\hskip4cm}}}} \blank

The \TEX\ engine has a concept of extensible characters. In fact there are two
mechanisms: there is a list of larger glyphs and when that list is exhausted
larger characters can be constructed out of snippets. Examples are left and right
fences in math like braces and brackets, and, also in math, some top and bottom
accents.

For reasons unknown to me, some of these extensibles are handled by the engine
directly, using properties of a font, while others are composed using macros.
Given that \TEX\ is quite popular for typesetting scientific articles it is
beyond my understanding why no one decided to provide some more fonts and|/|or
extend the \TEX\ engine. After all, the whole idea of Donald Knuth with \TEX\ was
that it could be adapted to future needs by its users. And so, more that 30 years
after \TEX\ and macro packages showed up we're stuck with not only incomplete
fonts, but also an engine that was never adapted to demands.

\stopsection

\startsection[title=The traditional way]

In \CONTEXT\ we have support for extensibles built into the core but it uses the
traditional approach: take some snippets and paste them together, making sure to
achieve some overlap and get rid of side bearings. In terms of \TEX\ code this can
best be illustrated with the plain \TEX\ definition of such a command:

\starttyping
\def\leftarrowfill
  {$%
   \mathsurround0pt%
   \mathord\leftarrow\mkern-7mu%
   \cleaders\hbox{$\mkern-2mu\smash-\mkern-2mu$}\hfill
   \mkern-7mu\smash-%
   $}
\stoptyping

Here we create a tight formula starting with a \type {leftarrow}, ending with a
minus sign and glued together with the number of minus signs that are needed to
fill the available space. This macro eventually expands to something like this (a
bit spaced out):

\starttyping
\def\leftarrowfill { $
  % \leftarrow = \mathchardef\leftarrow="3220 in plain but in
  % unicode it's character 0x2190 so we use that one here
  \mathsurround=0pt
  \mathord{\mathchar"2190}
  \mkern-7mu
  \cleaders
   \hbox { $
     \mkern-2mu
     \mathchoice
      {\setbox0\hbox{$\displaystyle     -$}\ht0=0pt\dp0=0pt\box0}
      {\setbox0\hbox{$\textstyle        -$}\ht0=0pt\dp0=0pt\box0}
      {\setbox0\hbox{$\scriptstyle      -$}\ht0=0pt\dp0=0pt\box0}
      {\setbox0\hbox{$\scriptscriptstyle-$}\ht0=0pt\dp0=0pt\box0}
     \mkern-2mu
    $ }
   \hfill
  \mkern-7mu
  \mathchoice
   {\setbox0\hbox{$\displaystyle     -$}\ht0=0pt\dp0=0pt\box0}
   {\setbox0\hbox{$\textstyle        -$}\ht0=0pt\dp0=0pt\box0}
   {\setbox0\hbox{$\scriptstyle      -$}\ht0=0pt\dp0=0pt\box0}
   {\setbox0\hbox{$\scriptscriptstyle-$}\ht0=0pt\dp0=0pt\box0}
$ }
\stoptyping

If you look at the code you see a few hacks. First of all we see that we need to
add kerns in order to make the symbols overlap. For the middle shapes this is
understandable as there we don't want rounding errors to lead to gaps. Also,
because the minus in Computer Modern (and therefore Latin Modern) has rounded
tips, we need to make sure that we end up beyond the tips. Next we see two blobs
of \type {mathchoice}. This primitive chooses one of the four variants and
switches to the right math style. It packages the minus and smashes it. In our
case smashing makes not much sense as the arrowhead has height and depth anyway,
but it's a side effect of using general purpose macros that there can be some
unneeded overhead.

\blank
\hbox \bgroup \quad
    \scale[sx=5,sy=5]{\hbox{\showglyphs$\mathsurround\zeropoint\char"2190$}}\quad
    \scale[sx=5,sy=5]{\hbox{\showglyphs$\mathsurround\zeropoint\char"002D$}}\quad
    \scale[sx=5,sy=5]{\hbox{\showglyphs$\mathsurround\zeropoint\char"27F8$}}\quad
    \scale[sx=5,sy=5]{\hbox{\showglyphs$\mathsurround\zeropoint\char"003D$}}\quad
\egroup
\blank

Above you see the two characters that traditionally are combined into a leftward
pointing arrows. Watch the whitespace on the left and right of the actual glyph.

\stopsection

\startsection[title=The new way]

These zero height and depth don't show up in our rendered examples. Why is this?
The reason is that I cheated a bit. I used this to get the arrow: \footnote {In
this example I misuse the accent placement mechanism. Upto \LUATEX\ 0.75 that was
the way to go.}

\starttyping
\mathstylehbox{\Umathaccent\fam\zerocount"21C4{\hskip4cm}}
\stoptyping

The \CONTEXT\ support macro \type {\mathstylehbox} is an efficient variant of
\type {\mathchoice}. More significant is that we don't assemble the arrow, but
just put it as an accent on top of a skip. The \type {\Umathaccent} primitive
will assemble the long arrow for us, using information in the font. If we look
into the definition of the (Latin Modern) font in \MKIV\ we see this:

\starttyping
[8592]={
 ["boundingbox"]={ 57, -10, 942, 510 },
 ["class"]="base",
 ["index"]=1852,
 ["math"]={
  ["horiz_parts"]={
   {
    ["advance"]=507,
    ["end"]=169,
    ["extender"]=0,
    ["glyph"]=984274,
    ["start"]=0,
   },
   {
    ["advance"]=337,
    ["end"]=337,
    ["extender"]=1,
    ["glyph"]=984275,
    ["start"]=337,
   },
   {
    ["advance"]=507,
    ["end"]=0,
    ["extender"]=0,
    ["glyph"]=984276,
    ["start"]=169,
   },
  },
  ["horiz_variants"]={ 10229 },
 },
 ["name"]="arrowleft",
 ["width"]=1000,
}
\stoptyping

This arrow symbol comes in two sizes. The extra size is mentioned in \type
{horiz_variants}. When no more variants are seen, it switches to the extensible
definition, that uses \type {horiz_parts}. The dimensions are in basepoints, the
references to glyphs are decimal. The \type {end} and \type {start} fields
specify the overlap. When \type {extender} equals 1 it signals a repeatable
snippet.

In the \TEX\ engine the slot allocated for the left arrow symbol has a \type
{next} pointer to a larger shape. Here there is only one such shape but when
there are more they form a linked list. The the last one in such a list gets the
specification of the extenders.

We hard|-|coded the width to 4cm so how does it work when the arrow has to adapt
itself? There are two cases there. When we are putting text on top of or below an
arrow, we know what the width is because we can measure the text. But when we use
the arrow as a filler, we have to leave it to the engine to arrange it. In recent
\LUATEX\ the definition can be as simple as:

\starttyping
\def\leftarrowfill{\leaders "2190 \hfill}
\stoptyping

or:

\starttyping
\def\leftarrowfill{\mathstylehbox{\leaders"2190\hfill}}
\stoptyping

In fact, we can use this new \LUATEX\ extension to \type {\leaders} to
replace the accent hacks as well.

\stopsection

\startsection[title=Wrapping it in macros]

If this was all, we would be done in a few lines of definitions but as usual
there is more involved: especially text. The prerequisites can be summarized as
follows:

\startitemize[packed]
\startitem
    The width of the extensible need to adapt itself automatically.
\stopitem
\startitem
    We need to be able to control horizontal and vertical offsets.
\stopitem
\startitem
    We best have a math as well as a text variant (which is handy for chemistry).
\stopitem
\startitem
    For historic reasons we need to deal with optional arguments in a special
    (reverse) way.
\stopitem
\startitem
    We need alternatives for extensibles on top, in the middle and at the bottom.
\stopitem
\stopitemize

Using a low level command we can do this:

\startbuffer[math]
$x \directmathextensible{"2192}{top}{bottom} x$
\stopbuffer

\typebuffer[math] \blank \getbuffer[math] \blank

This is not that exiting too look at, but the next might be:

\enabletrackers[math.stackers.texts]

\blank \getbuffer[math] \blank

Here we have turned on a tracker:

\starttyping
\enabletrackers[math.stackers.texts]
\stoptyping

The toppart is transparent blue, the middlepart transparent red and the bottom
part becomes transparent green. When the areas overlap you see the mixed color.

Before we explore some options, we show some variants. Often extensibles are used
in math mode, if only because they originate in math and come from math fonts.

\startbuffer[text]
$x \textstacker{"2192}{top}{bottom} x$
\stopbuffer

\typebuffer[text] \blank \getbuffer[text] \blank

These commands also work outside math mode:

\startbuffer[none]
x \textstacker{"2192}{top}{bottom} x
\stopbuffer

\typebuffer[none] \blank \getbuffer[none] \blank

and to some extend can adapt themselves:

\startbuffer[high]
x\high{x \textstacker{"2192}{top}{bottom} x} x
\stopbuffer

\typebuffer[high] \blank[2*big] \getbuffer[high] \blank

\stopsection

\startsection[title=Influencing the spacing]

We will use the text example to illustrate some options.

\startbuffer[demo]
\ruledhbox \bgroup \quad
    \setupmathstackers[location=top]%
    \textstacker{"21C4}{top}{bottom}\quad
    \setupmathstackers[location=high]%
    \textstacker{"21C4}{top}{bottom}\quad
    \setupmathstackers[location=middle]%
    \textstacker{"21C4}{top}{bottom}\quad
    \setupmathstackers[location=low]%
    \textstacker{"21C4}{top}{bottom}\quad
    \setupmathstackers[location=bottom]%
    \textstacker{"21C4}{top}{bottom}\quad
\egroup
\stopbuffer

\typebuffer[demo]

You can set up extensibles to be shifted up and down.

\blank \getbuffer[demo] \blank

The above rendering uses the default spacing. When we set all values to zero we
get this:

\startbuffer[setup]
\setupmathstackers
  [voffset=\zeropoint,
   hoffset=\zeropoint,
   minheight=\exheight,
   mindepth=\zeropoint,
   minwidth=\zeropoint]
\stopbuffer

\blank \start \getbuffer[setup,demo] \stop \blank

The setup looks like this:

\typebuffer[setup]

and gives a pretty tight rendering. The default values are:

\starttyping
\setupmathstackers
  [voffset=.25\exheight,
   hoffset=.5\emwidth,
   minheight=\exheight,
   mindepth=\zeropoint,
   minwidth=\emwidth]
\stoptyping

\startbuffer[setup]
\setupmathstackers
  [voffset=2\exheight,
   hoffset=\emwidth,
   minheight=\exheight,
   mindepth=\zeropoint,
   minwidth=\zeropoint]
\stopbuffer

When we set \type {voffset} to twice the ex|-|height and \type {hoffset} to
the em|-|width we get:

\blank \start \getbuffer[setup,demo] \stop \blank

We can enforce a (consistent) height and depth of the extensible by setting the
minimum values:

\startbuffer[setup]
\setupmathstackers
  [voffset=\zeropoint,
   hoffset=\zeropoint,
   minheight=5\exheight,
   mindepth=3\exheight,
   minwidth=6\emwidth]
\stopbuffer

\typebuffer

\blank \start \getbuffer[setup,demo] \stop \blank

\stopsection

\startsection[title=A neat feature]

A more obscure feature relates to the visual appearance. When we put something
on top of for instance an arrow, it sometimes looks better when we only consider
the middle part. Watch the following:

\startbuffer[setup]
\setupmathstackers
  [voffset=\zeropoint,
   hoffset=\zeropoint,
   minheight=\zeropoint,
   mindepth=\zeropoint,
   minwidth=\zeropoint]
\stopbuffer

\startbuffer[demo]
\ruledhbox \bgroup \quad
    \setupmathstackers[offset=normal]%
    \textstacker{"21C4}{top}{bottom}\quad
    \setupmathstackers[offset=min]%
    \textstacker{"21C4}{top}{bottom}\quad
    \setupmathstackers[offset=max]%
    \textstacker{"21C4}{top}{bottom}\quad
\egroup
\stopbuffer

\typebuffer[demo]

The \type {min} and \type {max} values will add extra offsets that relate to the
width of the edge snippets.

\blank \start \getbuffer[setup,demo] \stop \blank

In this case both have the same result but the difference becomes clear when we
set the \type {hoffset} to the em|-|width. In the case of \type {min} we don't
add some extra space if the \type {hoffset} is applied.

\startbuffer[setup]
\setupmathstackers
  [voffset=\zeropoint,
   hoffset=\emwidth,
   minheight=\zeropoint,
   mindepth=\zeropoint,
   minwidth=\zeropoint]
\stopbuffer

\startbuffer[demo]
\ruledhbox \bgroup \quad
    \setupmathstackers[offset=normal]%
    \textstacker{"21C4}{top}{bottom}\quad
    \setupmathstackers[offset=min]%
    \textstacker{"21C4}{top}{bottom}\quad
    \setupmathstackers[offset=max]%
    \textstacker{"21C4}{top}{bottom}\quad
\egroup
\stopbuffer

\typebuffer[demo]

Of course in this example we have a symmetrical correction.

\blank \start \getbuffer[setup,demo] \stop \blank

A one sided arrow behaves different:

\startbuffer[demo]
\ruledhbox \bgroup \quad
    \setupmathstackers[offset=normal]%
    \textstacker{"2192}{top}{bottom}\quad
    \setupmathstackers[offset=min]%
    \textstacker{"2192}{top}{bottom}\quad
    \setupmathstackers[offset=max]%
    \textstacker{"2192}{top}{bottom}\quad
\egroup
\stopbuffer

\blank \start \getbuffer[setup,demo] \stop \blank

\stopsection

\startsection[title=The user interface]

It all starts out with categories. We have a couple of predefined categories in
the core. The \type {mathematics} category typesets the top and bottom texts in
mathmode, while the \type {text} category doesn't. The \type {reverse} category
swaps its arguments. There are \type {upper} and \type {under} categories too.

As with most \CONTEXT\ mechanisms inheritance is part of the picture:

\starttyping
\definemathextensibles [mine] [big] [offset=min]
\stoptyping

You can change settings with:

\starttyping
\setupmathstackers [mine] [big] [voffset=\exheight]
\stoptyping

For downward compatibility we also provide these:

\starttyping
\definemathextensibles [normal] [hoffset=0.5\emwidth]
\definemathextensibles [none]   [hoffset=\zeropoint]
\definemathextensibles [small]  [hoffset=1\emwidth]
\definemathextensibles [medium] [hoffset=1.5\emwidth]
\definemathextensibles [big]    [hoffset=2\emwidth]
\stoptyping

They inherit from \type {mathematics} so choosing this also forces the top and
bottomtexts to be typeset in math mode.

These commands don't define extensibles, they only provide a way to categorize
them. There are couple of definers and one reason for that is that we want to
define downward compatible commands.

\starttyping
\definemathextensible [reverse] [xleftarrow]  ["2190]
\definemathextensible [reverse] [xrightarrow] ["2192]
\stoptyping

The \type {x} in the name is sort of standard for an extensible symbol with
optionally some text on top or below. The reverse forced compatible behaviour.

\startbuffer
\xrightarrow{stuff below} {stuff on top} \quad
\xrightarrow{stuff on top}               \quad
\xrightarrow{}            {stuff on top} \quad
\xrightarrow{stuff below} {}             \quad
\xrightarrow{}            {}             \quad
\xrightarrow                             \quad
\stopbuffer

\typebuffer \getbuffer

New in \MKIV\ is the \type {t} variant that typesets the text as (indeed) text.
In addition we have a normal|-|order \type {m} variant:

\starttyping
\definemathextensible [text] [tleftarrow]  ["2190]
\definemathextensible [text] [trightarrow] ["2192]

\definemathextensible [mathematics] [mleftarrow]  ["2190]
\definemathextensible [mathematics] [mrightarrow] ["2192]
\stoptyping

This time the order is always top first and bottom next:

\startbuffer
\trightarrow{stuff on top} {stuff below} \quad
\trightarrow{stuff on top} {}            \quad
\trightarrow{stuff on top}               \quad
\trightarrow{}             {stuff below} \quad
\trightarrow                             \quad
\stopbuffer

\typebuffer

So we get:

\getbuffer

As you can see, there is an optional first argument that specifies the category
that applies. This permits you to define extra commands that have their own
(spacing) properties.

Earlier on we saw that defined commands can be forced into a category:

\startbuffer
\trightarrow[big]   {stuff on top} {stuff below} \quad
\trightarrow[medium]{stuff on top} {stuff below} \quad
\trightarrow[small] {stuff on top} {stuff below}
\stopbuffer

\typebuffer

Here we get:

\getbuffer

A variation on this kind of extensibles are over- and underarrows. This time the
text is the nucleus.

\starttyping
\definemathoverextensible  [top]    [overleftarrow]   ["2190]
\definemathoverextensible  [top]    [overrightarrow]  ["2192]

\definemathunderextensible [bottom] [underleftarrow]  ["2190]
\definemathunderextensible [bottom] [underrightarrow] ["2192]
\stoptyping

In action this looks like:

\startbuffer
\ruledhbox \bgroup $ \quad
     \overleftarrow {a}  \quad    \overleftarrow {ABC}  $ \quad
  x_{\overleftarrow {a}} \quad x_{\overleftarrow {ABC}} $ \quad
     \underleftarrow{a}  \quad    \underleftarrow{ABC}  $ \quad
  x_{\underleftarrow{a}} \quad x_{\underleftarrow{ABC}} $ \quad
$ \egroup
\stopbuffer

\typebuffer

Here we also have tracing enabled, and we also show the bounding box:

\blank \getbuffer \blank

This leaves us one command: the one that defines the basic filler:

\starttyping
\definemathextensiblefiller [leftarrowfill]  ["2190]
\definemathextensiblefiller [rightarrowfill] ["2192]
\stoptyping

Commands defined like this will stretch themselves to fit the circumstances,
and normally they will fill op the available space.

\startbuffer
\hbox to 4cm {from here \leftarrowfill\ to there}
\hbox to 8cm {from there \rightarrowfill\ to here}
\stopbuffer

\typebuffer

These commands (like the others) work in text mode as well as in math mode.

\blank \getbuffer \blank

\stopsection

\startsection[title=Special cases]

One of the reasons why the arrows mechanism has always been somewhat
configureable is that we need arrows in the chemistry code.

\starttyping
\definemathextensibles
  [chemistry]
  [offset=max,
   left=\enspace,
   right=\enspace,
   hoffset=.5\emwidth]

\definemathextensible [chemistry] [cleftarrow]          ["2190]
\definemathextensible [chemistry] [crightarrow]         ["2192]
\definemathextensible [chemistry] [crightoverleftarrow] ["21C4]
\stoptyping

\startbuffer
2H + O \crightarrow{explosive}\ H\low{2}O
\stopbuffer

\typebuffer

Of course normally such code is wrapped into the chemistry enviroments and
support macros.

\blank \getbuffer \blank

If you want something else than an extensible you can use definitions like the
following:

\startbuffer
\definemathtriplet [tripleta]
\definemathtriplet [text] [tripletb]
\definemathtriplet [text] [tripletc] [\otimes]
\stopbuffer

\typebuffer \getbuffer

\startbuffer
\tripleta{\ominus}{top}{botom} and
\tripletb{\oplus} {top}{botom} and
\tripletc         {top}{botom}
\stopbuffer

\typebuffer

\blank \hbox{\getbuffer} \blank

As optional first argument you can pass a category.

\startbuffer
\tripleta[mathematics]{\ominus}{top}{botom} and
\tripletb[mathematics]{\oplus}{top}{botom} and
\tripletc[mathematics]{top}{botom}
\stopbuffer

\typebuffer

Which gives:

\blank \hbox{\getbuffer} \blank

Instead of \type {mathematics} you could have given its synonym \type {math}.
Keep in mind that categories are shared among stackers. There is also a direct
command:

\starttyping
before \mathtriplet{\otimes}{top}{botom} after
\stoptyping

\stopsection

\startsection[title=An overview]

We end with showing a list of extensibles that come with the font used here, the
\TEX Gyre Pagella. First we load a module:

\startbuffer
\usemodule[s][math-extensibles]
\stopbuffer

\typebuffer \getbuffer

This module provides a couple of commands that typesets a table with the
extensibles as known in \CONTEXT. Beware: not all fonts have all those
characters.

\startbuffer
\showmathextensibles[alternative=a]
\stopbuffer

A second command is:

\typebuffer

This commands shows the base glyph, and the stretched variant with text on top
and below. When no symbol is found in the font a rule is rendered.

\getbuffer

\startbuffer
\showmathextensibles[alternative=b]
\stopbuffer

\typebuffer

This command typesets a list with \UNICODE\ entries and defined commands. There
are empty entries due to lack of glyphs in the used font. Not all characters have
an associated command. Some have multiple commands with different math classes.

\getbuffer

\stopsection

\startsection[title=Remark]

The number of extensions to the \LUATEX\ core math engine is not that large and
mostly involves more control over spacing and support for \UNICODE\ math as
\OPENTYPE\ math extensibles. However, a few years after writing this chapter the
machinery was cleaned up a bit and in the process some more control was added to
constructors for radicals, fractions and delimiters. The spacing and composition
can be controlled in a bit more detail using keywords (and dimensions). Because
in \CONTEXT\ we already have mechanisms in place not much of that new
functionality is used (yet). Also, in the meantime \CONTEXT\ evolved further.
This chapter is just a snapshot and it might even render a bit different in more
recent versions of \CONTEXT\ and|/|or \LUATEX. After all, it was written as part
of the development story.

\stopsection

\stopchapter

\disabletrackers[math.extensibles.texts]

\stopcomponent
