From fd0c4577a4b6e85ca2db664906e1a03807ce133f Mon Sep 17 00:00:00 2001 From: Hans Hagen Date: Sun, 14 May 2017 19:58:50 +0200 Subject: 2017-05-14 19:15:00 --- .../general/manuals/still/still-opentypemath.tex | 921 +++++++++++++++++++++ 1 file changed, 921 insertions(+) create mode 100644 doc/context/sources/general/manuals/still/still-opentypemath.tex (limited to 'doc/context/sources/general/manuals/still/still-opentypemath.tex') diff --git a/doc/context/sources/general/manuals/still/still-opentypemath.tex b/doc/context/sources/general/manuals/still/still-opentypemath.tex new file mode 100644 index 000000000..43a340866 --- /dev/null +++ b/doc/context/sources/general/manuals/still/still-opentypemath.tex @@ -0,0 +1,921 @@ +% language=uk + +\environment still-environment + +\starttext + +\startchapter[title=Opentype math] + +\startsection[title=Introduction] + +When \TEX\ typesets mathematics it makes some assumptions about the properties of +fonts and dimensions of glyphs. Due to practical limitations in the traditional +eight|-|bit fonts, such as the number of available characters in a font and a +limited number of heights and depths, some juggling takes place. For instance, +\TEX\ sometimes uses dimensions as a signal to treat some characters as special. +This is not a problem as long as one knows how to make a font and in practice +that was done by looking at the properties of Computer Modern to implement +similar shapes. After all, there are not that many math fonts around and +basically there is only one engine that can deal with them properly. + +However, when Microsoft set the standard for \OPENTYPE\ math fonts it also +steered the direction of their use in rendering mathematics. This means that the +\LUATEX\ engine, which handles \OPENTYPE\ fonts, has to implement some +alternative code paths. At the start, this involved a bit of gambling because +there was no real specification; since then we now have a better picture. One of +the more complex changes that took place is in the way italic correction is +applied. A dirty way out of this dilemma would be to turn the math fonts into +virtual ones that match traditional \TEX\ properties, but this would not be a +nice solution. + +It must be noted that in the process of implementing support for the new fonts, +Taco (Hoekwater) turned some noad types (see below) into a generic noad with a subtype. This +simplified the transition. At the same time, a lot of detailed control was added +in the way successive characters are spaced. + +In \LUATEX\ before 0.85, the italic correction was always added when a character got +boxed (a frequently used preparation in the math builder). Now this is only done +for the traditional fonts because, concerning italic correction, the \OPENTYPE\ +standard states: \footnote {Recently version 1.8 has been published on the Microsoft +website.} + +\startitemize[n] + \startitem + When a run of slanted characters is followed by a straight character + (such as an operator or a delimiter), the italics correction of the last + glyph is added to its advance width. + \stopitem + \startitem + When positioning limits on an N-ary operator (e.g., integral sign), the + horizontal position of the upper limit is moved to the right by half of the + italics correction, while the position of the lower limit is moved to the + left by the same distance. + \stopitem + \startitem + When positioning superscripts and subscripts, their default horizontal + positions are also different by the amount of the italics correction of + the preceding glyph. + \stopitem +\stopitemize + +And, with respect to kerning: + +\startitemize[continue] + \startitem + Set the default horizontal position for the superscript as shifted + relative to the position of the subscript by the italics correction of + the base glyph. + \stopitem +\stopitemize + +I must admit that when the first implementation showed up, my natural reaction to +unexpected behaviour was just to compensate for it. One such solution was simply not +to pass the italic correction to the engine and deal with it in \LUA. In +practice, that didn't work well for all cases; one reason was that the engine +saw the combination of old fonts as a new one and followed a mixed code path. +\footnote {\CONTEXT\ employed \UNICODE\ math right from the start of \LUATEX.} +Another approach I tried was a mix of manipulated italic values and \LUA, but +finally, as specifications settled I decided to leave it to the engine completely, +if only because successive versions of \LUATEX\ behaved much better. + +So, as we were closing in on the first stable release of \LUATEX\ (1.0.0 +was released on September~27, 2016; this note was mostly written in the +early part of 2016), I decided to fix the +pending issues and sat down to look at the math|-|related code. I must admit that I +had never looked in depth into that part of the machinery. In the next sections I +will discuss some of the outcomes of this exercise. + +I will also discuss some extensions that have been on the agenda for years. They +are rather generic and handy, but I must also admit that the \MKIV\ code related +to math has so many options to control rendering that I'm not sure if they will +ever be used in \CONTEXT. Nevertheless, these generic extensions fit well into +the set of basic features of \LUATEX. + +\stopsection + +\startsection[title=Italic correction] + +As stated above, the normal code path included italic correction in all the math +boxes made. This meant that, in some places, the correction had to be +removed and/or moved to another place in the chain. This is a natural side effect +of the fact that \TEX\ runs over the intermediate list of math nodes (noads) and +turns them into regular nodes, mostly glyphs, kerns, glue and boxes. + +The complication is not so much the italic corrections themselves, because we +could just continue to do the same, but the fact that these corrections are to be +interpreted differently in case of integrals. There, the problem is that we have +to (kind of) look backward at what is done in order to determine what italic +corrections are to be applied. + +The original solution was to keep track of the applied correction via variables +but that still made some analysis necessary. In the new implementation, more +information is stored in the processed noads. This is a logical choice given that +we have already added other information. It also makes it possible to fix cases +that will (for sure) show up in the future. + +\startbuffer[ic-1] +\ruledhbox\bgroup + \showglyphs\showboxes + \hbox{$\int ^2 $}\quad + \hbox{$\int _2$}\quad + \hbox{$\int ^2_2$}\quad + \hbox{$f ^2 $}\quad + \hbox{$f _2$}\quad + \hbox{$f ^2_2$}% +\egroup +\stopbuffer + +\startbuffer[ic-2] +\ruledhbox\bgroup + \showglyphs\showboxes + \hbox{$\normalint ^2 $}\quad + \hbox{$\normalint _2$}\quad + \hbox{$\normalint ^2_2$}\quad + \hbox{$\int ^2 $}\quad + \hbox{$\int _2$}\quad + \hbox{$\int ^2_2$}% +\egroup +\stopbuffer + +\placefigure + [here] + [fig:italic-correction-1] + {Italic correction examples (1): superscripts shifted right and subscripts left.} + {\scale[width=\textwidth]{\getbuffer[ic-1]}} + +In \in {figure} [fig:italic-correction-1] we show two examples of inline italic +correction. The superscripts are shifted to the right and the subscripts to the +left. In the case of an integral sign, we need to move half the correction. This +is triggered by the \type {\nolimits} primitive. In \in {figure} +[fig:italic-correction-2] we show the difference between just an integral +character and one tagged as having limits. \footnote {We show some boxes so that +you can get an idea what \TEX\ is doing. Essentially, \TEX\ puts superscripts and +subscripts on top of each other with some kern in between and then corrects the +dimensions.} + +\placefigure + [here] + [fig:italic-correction-2] + {Italic correction examples (2): plain integral vs.\ integral with limits} + {\scale[width=\textwidth]{\getbuffer[ic-2]}} + +The amount of correction, if present at all, depends on the font, and in this +document we use DejaVu math. \in {Figure} [fig:italic-correction-3] shows a few +variants. As you can see, the amount of correction is highly font dependent. + +\placefigure + [here] + [fig:italic-correction-3] + {Italic correction examples (3): correction amounts are font-dependent.} + {\startcombination[1*4] + {\switchtobodyfont [pagella]\scale[width=\textwidth]{\getbuffer[ic-1]}} {cambria} + {\switchtobodyfont [cambria]\scale[width=\textwidth]{\getbuffer[ic-1]}} {pagella} + {\switchtobodyfont [modern]\scale[width=\textwidth]{\getbuffer[ic-1]}} {latin modern} + {\switchtobodyfont[lucidaot]\scale[width=\textwidth]{\getbuffer[ic-1]}} {lucida ot} + \stopcombination} + +\startsection[title=Vertical delimiters] + +When we go into display math, there is a good chance that an integral has to be +enlarged. The integral sign in \UNICODE\ has slot \type {0x222B}, so we can +define a bigger one as follows: + +\startbuffer[nocontext] +\let\int\normalint +\stopbuffer + +\startbuffer[cambria] +\switchtobodyfont[cambria]% +\stopbuffer + +\startbuffer[pagella] +\switchtobodyfont[pagella]% +\stopbuffer + +\startbuffer[modern] +\switchtobodyfont[modern]% +\stopbuffer + +\startbuffer[lucidaot] +\switchtobodyfont[lucidaot]% +\stopbuffer + +\startbuffer[xits] +\switchtobodyfont[xits]% +\stopbuffer + +\startbuffer[largerint] +\def\standardint{ + \Umathchar "1 "0 "222B +} +\def\wrappedint{\mathop{ + \Umathchar "1 "0 "222B +}} +\def\biggerint{\mathop{ + \Uleft height 3ex depth 3ex axis \Udelimiter "0 "0 "222B + \Uright . +}} +\def\evenbiggerint{\mathop{ + \Uleft height 6ex depth 6ex axis \Udelimiter "0 "0 "222B + \Uright . +}} +\stopbuffer + +\typebuffer[largerint] + +\startbuffer[demoint] +$ +\displaystyle\standardint ^a_b\enspace +\displaystyle\wrappedint ^a_b\enspace +\displaystyle\biggerint ^a_b\enspace +\displaystyle\evenbiggerint^a_b\enspace +$ +\stopbuffer + +The \type {axis} keyword will apply a shift up over the size of the current +styles math axis. We use this in some examples as: + +\typebuffer[demoint] + +In \in {figure} [fig:demoint] you can see some subtle differences. The wrapped +version doesn't shift the superscript and subscript. The reason is that the +operator is hidden in its own wrapper and the scripts attach at an outer level. +So, unless we start analyzing the innermost noad and apply that to the outer, we +cannot know the shift. Such analyzing is asking for problems: where do we stop +and what slight variations do we take into account? It's better to be +predictable. + +\startbuffer + \ruledhbox \bgroup + \showglyphs \showboxes + \getbuffer[nocontext,pagella, largerint,demoint] + \getbuffer[nocontext,cambria, largerint,demoint] + \getbuffer[nocontext,modern, largerint,demoint] + \getbuffer[nocontext,lucidaot,largerint,demoint] + \egroup +\stopbuffer + +\placefigure + [here] + [fig:demoint] + {Comparison of integral variants (standard, wrapped, bigger, even + bigger) among fonts: \TeX\ Gyre Pagella, Cambria, Latin Modern, and + Lucida OT.} + {\scale[width=\textwidth]{\getbuffer}} + +Another observation is that Latin Modern does not provide (at least not yet) +large integrals at all. + +The following four cases are equivalent: + +\starttyping +\Uleft height 3ex depth 3ex axis \Udelimiter "0 "0 "222B +\Uright . + +\Uleft . +\Uright height 3ex depth 3ex axis \Udelimiter "0 "0 "222B + +\Uleft . +\Umiddle height 3ex depth 3ex axis \Udelimiter "0 "0 "222B +\Uright . + +\Uleft . +\Umiddle height 3ex depth 3ex axis \Udelimiter "0 "0 "222B +\Uright . +\stoptyping + +However, because this all looks a bit clumsy, we now provide a new +primitive: + +\starttyping +\Uvextensible + height + depth + axis + exact + +\stoptyping + +The symbol to be constructed will have size \type {height} plus \type {depth}. +When an \type {axis} is specified, the symbol will be shifted up, which is +normally the case for such symbols. The keyword \type {exact} will correct the +dimensions when no exact match is made, and this can be the case as long as we +use the stepwise larger glyphs and before we end up using the composed shapes. +When no dimensions are specified, the normal construction takes place and the +only keyword that can be used then is \type {noaxis} which keeps the axis out of +the calculations. After about a week of experimenting and exploring options, this +combination made most sense, read: no fuzzy heuristics but predictable behaviour. +After all, one might need different solutions for different fonts or +circumstances and the applied logic (and expectations) can (and will, for sure) +differ per macro package. + +\def\SampleRule#1#2% + {\blackrule[height=#1,depth=#2,width=1mm,color=maincolor]} + +% \def\SampleDelimiterSpec#1#2% +% {\ruledhbox \bgroup +% \SampleRule{20mm}{20mm}\enspace +% \ruledhbox{$\maincolor\char"#1$}\enspace +% \ruledhbox{$\Uleft height 1mm depth 1mm #2 \Udelimiter 0 0 "#1\Uright .$}\enspace +% \ruledhbox{$\Uleft height 2mm depth 2mm #2 \Udelimiter 0 0 "#1\Uright .$}\enspace +% \ruledhbox{$\Uleft height 5mm depth 5mm #2 \Udelimiter 0 0 "#1\Uright .$}\enspace +% \ruledhbox{$\Uleft height 20mm depth 20mm #2 \Udelimiter 0 0 "#1\Uright .$}\enspace +% \ruledhbox{$\Uleft height 20mm depth 10mm #2 \Udelimiter 0 0 "#1\Uright .$}% +% \egroup} + +\def\SampleDelimiterSpec#1#2% + {\ruledhbox \bgroup + \SampleRule{20mm}{20mm}\enspace + \ruledhbox{$\maincolor\char"#1$}\enspace + \ruledhbox{$\Uvextensible height 1mm depth 1mm #2 \Udelimiter 0 0 "#1$}\enspace + \ruledhbox{$\Uvextensible height 2mm depth 2mm #2 \Udelimiter 0 0 "#1$}\enspace + \ruledhbox{$\Uvextensible height 5mm depth 5mm #2 \Udelimiter 0 0 "#1$}\enspace + \ruledhbox{$\Uvextensible height 20mm depth 20mm #2 \Udelimiter 0 0 "#1$}\enspace + \ruledhbox{$\Uvextensible height 20mm depth 10mm #2 \Udelimiter 0 0 "#1$}% + \egroup} + +\startbuffer[delimiter-integral-spec] +\startcombination[4*1] + {\SampleDelimiterSpec{222B}{}} {} + {\SampleDelimiterSpec{222B}{axis}} {axis} + {\SampleDelimiterSpec{222B}{exact}} {exact} + {\SampleDelimiterSpec{222B}{axis exact}} {axis exact} +\stopcombination +\stopbuffer + +\startbuffer[delimiter-leftparent-spec] +\startcombination[4*1] + {\SampleDelimiterSpec{0028}{}} {} + {\SampleDelimiterSpec{0028}{axis}} {axis} + {\SampleDelimiterSpec{0028}{exact}} {exact} + {\SampleDelimiterSpec{0028}{axis exact}} {axis exact} +\stopcombination +\stopbuffer + +\placefigure + [here] + [fig:integral-spec] + {Cambria integrals, with dimensions.} + {\getbuffer[nocontext,cambria,delimiter-integral-spec]} + +\placefigure + [here] + [fig:leftparent-spec] + {Cambria left parenthesis, with dimensions.} + {\getbuffer[nocontext,cambria,delimiter-leftparent-spec]} + +\def\SampleDelimiterAuto#1#2% + {\ruledhbox \bgroup + \ruledhbox{$\maincolor\char"#1$}\enspace + \ruledhbox{$\Uleft #2 \Udelimiter 0 0 "#1\SampleRule{ 1mm}{ 1mm}\Uright .$}\enspace + \ruledhbox{$\Uleft #2 \Udelimiter 0 0 "#1\SampleRule{ 2mm}{ 2mm}\Uright .$}\enspace + \ruledhbox{$\Uleft #2 \Udelimiter 0 0 "#1\SampleRule{ 5mm}{ 5mm}\Uright .$}\enspace + \ruledhbox{$\Uleft #2 \Udelimiter 0 0 "#1\SampleRule{10mm}{10mm}\Uright .$}\enspace + \ruledhbox{$\Uleft #2 \Udelimiter 0 0 "#1\SampleRule{15mm}{15mm}\Uright .$}\enspace + \ruledhbox{$\Uleft #2 \Udelimiter 0 0 "#1\SampleRule{20mm}{20mm}\Uright .$}\enspace + \ruledhbox{$\Uleft #2 \Udelimiter 0 0 "#1\SampleRule{20mm}{10mm}\Uright .$}% + \egroup} + +\startbuffer[delimiter-integral-auto] +\startcombination[2*1] + {\SampleDelimiterAuto{222B}{}} {} + {\SampleDelimiterAuto{222B}{noaxis}} {noaxis} +\stopcombination +\stopbuffer + +\startbuffer[delimiter-leftparent-auto] +\startcombination[4*1] + {\SampleDelimiterAuto{0028}{}} {} + {\SampleDelimiterAuto{0028}{noaxis}} {noaxis} +\stopcombination +\stopbuffer + +\placefigure + [here] + [fig:integral] + {Cambria integrals, adaptive: \type {axis} left and \type {noaxis} right.} + {\getbuffer[nocontext,cambria,delimiter-integral-auto]} + +\placefigure + [here] + [fig:leftparent] + {Cambria left parenthesis, adaptive: \type {axis} left and \type {noaxis} right.} + {\getbuffer[nocontext,cambria,delimiter-leftparent-auto]} +\stopsection + +\startsection[title=Horizontal delimiters] + +Horizontal extenders also have some new options. Although one can achieve similar +results with macros, the following might look a bit more natural. Also, some +properties are lost once the delimiter is constructed, so macros can become +complex when trying to determine the original dimensions involved. + +We start with the new \type {\Uhextensible} primitive that accepts a dimension. +It's just a variant of the over and under delimiters with no content part. + +\starttyping +\Uhextensible + height + depth + left | middle | right + + +\stoptyping + +So for example you can say: + +\starttyping +$\Uhextensible width 30pt 0 "2194$ +\stoptyping + +The \type {left}, \type {middle} and \type {right} keywords are only interpreted +when the requested size can't be met due to stepwise larger glyph selection +(i.e., before we start using arbitrary sizes made of snippets). \in {Figure} +[fig:hextensible] shows what we get when we step from 2--20 points by +increments of 2 points in Cambria. + +\unexpanded\def\ExtensibleFunA#1% + {\switchtobodyfont[cambria,17.3pt]% + \hbox\bgroup + \dostepwiserecurse{2}{20}{2} + {\backgroundline + [maincolor] + {\white$\Uhextensible width \recurselevel pt #1 0 "2194$}% + \quad}% + \unskip + \egroup} + +\unexpanded\def\ExtensibleFunB#1% + {\switchtobodyfont[cambria,17.3pt]% + \hbox\bgroup + \dostepwiserecurse{2}{20}{2} + {\ruledhbox + {$\Uhextensible width \recurselevel pt #1 0 "2194$}% + \quad}% + \unskip + \egroup} + +\startbuffer +\starttabulate[|l|p|] + \NC (default) \NC \ExtensibleFunA{} \par \ExtensibleFunB{} \NC \NR + \NC \type{left} \NC \ExtensibleFunA{left} \par \ExtensibleFunB{left} \NC \NR + \NC \type{middle} \NC \ExtensibleFunA{middle} \par \ExtensibleFunB{middle} \NC \NR + \NC \type{right} \NC \ExtensibleFunA{right} \par \ExtensibleFunB{right} \NC \NR +\stoptabulate +\stopbuffer + +\placefigure + [here] + [fig:hextensible] + {Stepwise wider \type {\Uhextensible} with options (cambria).} + {\getbuffer} + +The dimensions and options can also be given to the four primitives \type {\Uoverdelimiter}, +\type {\Uunderdelimiter}, \type {\Udelimiterover} and \type {\Udelimiterunder}. \in {Figure} [fig:delimiterunder] shows what happens when the +delimiter is smaller than requested. The samples look like this: + +\starttyping +$\Udelimiterunder width 1pt 0 "2194 {\hbox{\strut !}} +\stoptyping + +When no dimension is given the keywords are ignored as it makes no sense to +mess with the extensible in that case. + +\unexpanded\def\DelimiterFunA#1% + {\switchtobodyfont[cambria,20.7pt]% + \hbox\bgroup + \dostepwiserecurse{1}{10}{1} + {\backgroundline + [maincolor] + {\white$\Udelimiterunder width ##1pt #1 0 "2194 {\hbox{\strut !}}$}% + \quad}% + \unskip + \egroup} + +\unexpanded\def\DelimiterFunB#1% + {\switchtobodyfont[cambria,20.7pt]% + \hbox\bgroup + \dostepwiserecurse{1}{10}{1} + {\ruledhbox + {$\Udelimiterunder width ##1pt #1 0 "2194 {\hbox{\strut !}}$}% + \quad}% + \unskip + \egroup} + +\startbuffer +\starttabulate[|l|p|] + \NC (default) \NC \DelimiterFunA{} \par \DelimiterFunB{} \NC \NR + \NC \type{left} \NC \DelimiterFunA{left} \par \DelimiterFunB{left} \NC \NR + \NC \type{middle} \NC \DelimiterFunA{middle} \par \DelimiterFunB{middle} \NC \NR + \NC \type{right} \NC \DelimiterFunA{right} \par \DelimiterFunB{right} \NC \NR + \NC \NR +\stoptabulate +\stopbuffer + +\placefigure + [here] + [fig:delimiterunder] + {Stepwise wider \type {\Udelimiterunder} with options (cambria).} + {\getbuffer} + +\stopsection + +\startsection[title=Accents] + +Many years ago, I observed that overlaying characters (which happens when +we negate an operator which has no composed negation glyph) didn't always give nice results +and, therefore, a tracker item was created. When going over the todo list, I ran +across a suggested patch by Khaled Hosny that added an overlay accent type. As +the suggested solution fits in with the other extensions, a variant has been +implemented. + +The results definitely depend on the quality and completeness of the font, so here we +will show \type {xits}. The placement of an \type {overlay} also depends on the top +accent shift as specified in the font for the used glyph. Instead of a fixed +criterion for trying to find the best match, an additional \type {fraction} +(numerator) parameter can be specified. A value of $800$ means that the target +width is $800/1000$. + +The \type {\Umathaccent} command now has the following syntax: + +\starttyping +\Umathaccent + [top|bottom|overlay] + [fixed] + [fraction ] + + {content} +\stoptyping + +When we have an overlay, the fraction concerns the height; otherwise it concerns +the width of the nucleus. In both cases, it is only applied when searching for +stepwise larger glyphs, as extensibles are not influenced. An example of a +specification is: + +\starttyping +\Umathaccent + overlay "0 "0 "0338 + fraction 950 + {\Umathchar"1"0"2211} +\stoptyping + +\in {Figure} [fig:accent-1] shows what we get when we use different fractions +(from 800 up to 1500 with a step of 100). We see that \type {\overlay} is not +always useful. + +\startbuffer[accents-1] +\dostepwiserecurse{800}{1500}{100}{% +$\Umathaccent + overlay "0 "0 "0338 + fraction #1 + {\Umathchar"1"0"2211} #1 +$\quad +}\unskip +\stopbuffer + +\startbuffer +\startcombination[1*3] + {\getbuffer[xits,accents-1]} {xits \endash\ has variants} + {\getbuffer[cambria,accents-1]} {cambria \endash\ lacks variants} + {\getbuffer[pagella,accents-1]} {pagella \endash\ lacks variants} +\stopcombination +\stopbuffer + +\placefigure + [here] + [fig:accent-1] + {Using \type {overlay} in \type {\Umathaccent}.} + {\getbuffer} + +\startbuffer[accents-2] +$\Umathaccent overlay "0 "0 "0338 {x}$ +$\Umathaccent overlay "0 "0 "0338 {\tf x}$ +$\Umathaccent overlay "0 "0 "0338 {\tf xxx}$ +\stopbuffer + +Normally you can forget about the factor because overlays make most sense for +inline math, which uses relatively small glyphs, so we can get \getbuffer +[accents-2] with the following code: + +\typebuffer[accents-2] + +A normal accent can also be influenced by \type {fraction}: + +\startbuffer[accents-4] +\dostepwiserecurse{500}{1500}{250}{% +$ + \Umathaccent + top "0 "0 "23DE + fraction #1 + {a\times b} +$\quad +}\unskip +\stopbuffer + +\blank \start \getbuffer[accents-4] \stop \blank + +\stopsection + +\startsection[title=Fractions] + +A normal fraction has a reasonable thick rule but as soon as you make it bigger you +will notice a peculiar effect: + +\startlinecorrection +\startcombination[5*1] + {$\displaystyle x + {{a} \abovewithdelims() 1pt {b}}$} {1pt} + {$\displaystyle x + {{a} \abovewithdelims() 2pt {b}}$} {2pt} + {$\displaystyle x + {{a} \abovewithdelims() 3pt {b}}$} {3pt} + {$\displaystyle x + {{a} \abovewithdelims() 4pt {b}}$} {4pt} + {$\displaystyle x + {{a} \abovewithdelims() 5pt {b}}$} {5pt} +\stopcombination +\stoplinecorrection + +Such a fraction is specified as: + +\starttyping +x + { {a} \abovewithdelims () 5pt {b} } +\stoptyping + +A new keyword \type {exact} avoids the excessive spacing: + +\starttyping +x + { {a} \abovewithdelims () exact 5pt {b} } +\stoptyping + +Now we get: + +\startlinecorrection +\startcombination[5*1] + {$\displaystyle x + {{a} \abovewithdelims() exact 1pt {b}}$} {1pt} + {$\displaystyle x + {{a} \abovewithdelims() exact 2pt {b}}$} {2pt} + {$\displaystyle x + {{a} \abovewithdelims() exact 3pt {b}}$} {3pt} + {$\displaystyle x + {{a} \abovewithdelims() exact 4pt {b}}$} {4pt} + {$\displaystyle x + {{a} \abovewithdelims() exact 5pt {b}}$} {5pt} +\stopcombination +\stoplinecorrection + +One way to get consistent spacing in such fractions is to use struts: + +\starttyping +x + { {\strut a} \abovewithdelims () exact 5pt {\strut b} } +\stoptyping + +Now we get: + +\startlinecorrection +\startcombination[5*1] + {$\displaystyle x + {{\strut a} \abovewithdelims() exact 1pt {\strut b}}$} {1pt} + {$\displaystyle x + {{\strut a} \abovewithdelims() exact 2pt {\strut b}}$} {2pt} + {$\displaystyle x + {{\strut a} \abovewithdelims() exact 3pt {\strut b}}$} {3pt} + {$\displaystyle x + {{\strut a} \abovewithdelims() exact 4pt {\strut b}}$} {4pt} + {$\displaystyle x + {{\strut a} \abovewithdelims() exact 5pt {\strut b}}$} {5pt} +\stopcombination +\stoplinecorrection + +Yet another way to increase the distance between the rule and text a bit is: + +\starttyping +\Umathfractionnumvgap \displaystyle4pt +\Umathfractiondenomvgap\displaystyle4pt +\stoptyping + +This looks quite consistent: + +\startlinecorrection +\Umathfractionnumvgap \displaystyle4pt +\Umathfractiondenomvgap\displaystyle4pt +\startcombination[5*1] + {$\displaystyle x + {{a} \abovewithdelims() exact 1pt {b}}$} {1pt} + {$\displaystyle x + {{a} \abovewithdelims() exact 2pt {b}}$} {2pt} + {$\displaystyle x + {{a} \abovewithdelims() exact 3pt {b}}$} {3pt} + {$\displaystyle x + {{a} \abovewithdelims() exact 4pt {b}}$} {4pt} + {$\displaystyle x + {{a} \abovewithdelims() exact 5pt {b}}$} {5pt} +\stopcombination +\stoplinecorrection + +Here we use code like: + +\starttyping +$\displaystyle x + {{a} \abovewithdelims() exact 2pt {b}}$ +\stoptyping + +Using struts, it is best to zero the gap: + +\startlinecorrection +\Umathfractionnumvgap \displaystyle0pt +\Umathfractiondenomvgap\displaystyle0pt +\startcombination[5*1] + {$\displaystyle x + {{\strut a} \abovewithdelims() exact 1pt {\strut b}}$} {1pt} + {$\displaystyle x + {{\strut a} \abovewithdelims() exact 2pt {\strut b}}$} {2pt} + {$\displaystyle x + {{\strut a} \abovewithdelims() exact 3pt {\strut b}}$} {3pt} + {$\displaystyle x + {{\strut a} \abovewithdelims() exact 4pt {\strut b}}$} {4pt} + {$\displaystyle x + {{\strut a} \abovewithdelims() exact 5pt {\strut b}}$} {5pt} +\stopcombination +\stoplinecorrection + +Here we use code like: + +\starttyping +$\displaystyle x + {{\strut a} \abovewithdelims() exact 2pt {\strut b}}$ +\stoptyping + +\stopsection + +\startsection[title=Skewed fractions] + +The math parameter table contains values specifying horizontal and +vertical gaps for skewed fractions. Some guessing is needed in order to implement +something that uses them, so we now provide a primitive similar to the other +fraction related ones but with a few options that one can use to influence the +rendering. Of course, a user can mess around directly with the parameters \type +{\Umathskewedfractionhgap} and \type {\Umathskewedfractionvgap}. + +The syntax used here is: + +\starttyping +{ {1} \Uskewed / {2} } +{ {1} \Uskewedwithdelims / () {2} } +\stoptyping + +The options can be \type {noaxis} and \type {exact}, a combination of them or +just nothing. By default we add half the axis to the shifts and also by default +we zero the width of the middle character. For Latin Modern, the result looks as +follows: + +\def\ShowA#1#2#3{$x + { {#1} \Uskewed / #3 {#2} } + x$} +\def\ShowB#1#2#3{$x + { {#1} \Uskewedwithdelims / () #3 {#2} } + x$} + +\start + \switchtobodyfont[modern] + \starttabulate[||||||] + \NC \NC + \ShowA{a}{b}{} \NC + \ShowA{1}{2}{} \NC + \ShowB{a}{b}{} \NC + \ShowB{1}{2}{} \NC + \NR + \NC \type{exact} \NC + \ShowA{a}{b}{exact} \NC + \ShowA{1}{2}{exact} \NC + \ShowB{a}{b}{exact} \NC + \ShowB{1}{2}{exact} \NC + \NR + \NC \type{noaxis} \NC + \ShowA{a}{b}{noaxis} \NC + \ShowA{1}{2}{noaxis} \NC + \ShowB{a}{b}{noaxis} \NC + \ShowB{1}{2}{noaxis} \NC + \NR + \NC \type{exact noaxis} \NC + \ShowA{a}{b}{exact noaxis} \NC + \ShowA{1}{2}{exact noaxis} \NC + \ShowB{a}{b}{exact noaxis} \NC + \ShowB{1}{2}{exact noaxis} \NC + \NR + \stoptabulate +\stop + +\stopsection + +\startsection[title=Side effects] + +Not all bugs reported as such are really bugs. Here is one that came from a +misunderstanding: In Eijkhout's \quotation {\TEX\ by Topic}, the rules for +handling styles in scripts are described as follows: + +\startitemize +\startitem + In any style superscripts and subscripts are taken from the next smaller + style. Exception: in display style they are taken in script style. +\stopitem +\startitem + Subscripts are always in the cramped variant of the style; superscripts are + only cramped if the original style was cramped. +\stopitem +\startitem + In an \type {..\over..} formula in any style the numerator and denominator + are taken from the next smaller style. +\stopitem +\startitem + The denominator is always in cramped style; the numerator is only in cramped + style if the original style was cramped. +\stopitem +\startitem + Formulas under a \type {\sqrt} or \type {\overline} are in cramped style. +\stopitem +\stopitemize + +In \LUATEX, one can set the styles in more detail, which means that you sometimes +have to set both normal and cramped styles to get the effect you want. If we +force styles in the script using \type {\scriptstyle} and \type +{\crampedscriptstyle} we get the following (all render the same): + +\startbuffer[demo] +\starttabulate +\NC default \NC $b_{x=xx}^{x=xx}$ \NC \NR +\NC script \NC $b_{\scriptstyle x=xx}^{\scriptstyle x=xx}$ \NC \NR +\NC crampedscript \NC $b_{\crampedscriptstyle x=xx}^{\crampedscriptstyle x=xx}$ \NC \NR +\stoptabulate +\stopbuffer + +\getbuffer[demo] + +This is coded like: + +\starttyping +$b_{x=xx}^{x=xx}$ +$b_{\scriptstyle x=xx}^{\scriptstyle x=xx}$ +$b_{\crampedscriptstyle x=xx}^{\crampedscriptstyle x=xx}$ +\stoptyping + +Now we set the following parameters: + +\startbuffer[setup] +\Umathordrelspacing\scriptstyle=30mu +\Umathordordspacing\scriptstyle=30mu +\stopbuffer + +\typebuffer[setup] + +This gives: + +\start\getbuffer[setup,demo]\stop + +Since the result is not what is expected (visually), we should say: + +\startbuffer[setup] +\Umathordrelspacing\scriptstyle=30mu +\Umathordordspacing\scriptstyle=30mu +\Umathordrelspacing\crampedscriptstyle=30mu +\Umathordordspacing\crampedscriptstyle=30mu +\stopbuffer + +\typebuffer[setup] + +Now we get: + +\start\getbuffer[setup,demo]\stop + +\stopsection + +\startsection[title=Fixed scripts] + +We have three parameters that are used for anchoring superscripts and subscripts, +alone or in combinations. + +\starttabulate[|l|l|] +\NC $d$ \NC \type {\Umathsubshiftdown} \NC \NR +\NC $u$ \NC \type {\Umathsupshiftup} \NC \NR +\NC $s$ \NC \type {\Umathsubsupshiftdown} \NC \NR +\stoptabulate + +When we set \type {\mathscriptsmode} to a value other than zero, these are used +for calculating fixed positions. This is something that is needed in, for +instance, chemical equations. You can manipulate the mentioned variables to +achieve different effects, and the specifications are shown in the following table. In +order to see the differences in more detail, they are enlarged in \in {figure} +[fig:mathscriptsmode]. + +\def\SampleMath#1% + {\ruledhbox{$\mathscriptsmode#1\mathupright CH_2 + CH^+_2 + CH^2_2$}} + +\starttabulate[|c|c|c|l|] + \NC \bf mode \NC \bf down \NC \bf up \NC \NC \NR + \NC 0 \NC dynamic \NC dynamic \NC \SampleMath{0} \NC \NR + \NC 1 \NC $d$ \NC $u$ \NC \SampleMath{1} \NC \NR + \NC 2 \NC $s$ \NC $u$ \NC \SampleMath{2} \NC \NR + \NC 3 \NC $s$ \NC $u + s - d$ \NC \SampleMath{3} \NC \NR + \NC 4 \NC $d + (s-d)/2$ \NC $u + (s-d)/2$ \NC \SampleMath{4} \NC \NR + \NC 5 \NC $d$ \NC $u + s - d$ \NC \SampleMath{5} \NC \NR +\stoptabulate + +\placefigure + [here] + [fig:mathscriptsmode] + {The effect of setting \type {\mathscriptsmode}.} + {\startcombination[nx=3,ny=2,distance=1em] + {\scale[width=\dimexpr(\textwidth-2em)/3\relax]{\SampleMath{0}}} {0} + {\scale[width=\dimexpr(\textwidth-2em)/3\relax]{\SampleMath{1}}} {1} + {\scale[width=\dimexpr(\textwidth-2em)/3\relax]{\SampleMath{2}}} {2} + {\scale[width=\dimexpr(\textwidth-2em)/3\relax]{\SampleMath{3}}} {3} + {\scale[width=\dimexpr(\textwidth-2em)/3\relax]{\SampleMath{4}}} {4} + {\scale[width=\dimexpr(\textwidth-2em)/3\relax]{\SampleMath{5}}} {5} + \stopcombination} + +\stopsection + +\startsection[title=Remark] + +The changes that we have made are hopefully not too intrusive. Instead of +extending existing commands, new ones were introduced so that compatibility +should not be a significant problem. To some extent, these extensions violate the +principle that extensions should be done in \LUA, but \TEX\ being a math renderer +and \OPENTYPE\ replacing old font technology, we felt that we should make an +exception here. Hopefully, not too many bugs were introduced. + +\stopsection + +\stopchapter + +\stoptext -- cgit v1.2.3