mathtext
Mojo module 🡭
mathtext
Mathematical labels: a small expression language for titles, axis captions, legend entries, tick labels and annotations (#371).
A label such as "$\sigma^2$" or "Rate $\frac{\Delta y}{\Delta x}$"
is parsed here, laid out into positioned text runs, and handed to the
same deferred-_TextRequest path every plain label takes. A label with
no $ in it never enters this module: _needs_math() is a byte scan,
and the plain path is byte-for-byte what it was before this existed.
Why the layout lives here and not in canvas
An expression is a tree of runs at different sizes and offsets, and
laying it out needs exactly two things of a backend: measure a string,
and draw a string at an anchor. measure_text and draw_text are on
the DrawTarget trait, so one layout serves every backend, and the
raster, SVG and PDF outputs put each run at the same anchor by
construction rather than by three implementations agreeing. What a
backend would have to add for this to move upstream – a math axis
height, a superscript shift – are typographic conventions rather than
font facts, and the numbers below are those conventions. Canvas already
does the two things that are font facts: it shapes each run with
kerning, and it pulls a glyph the chosen face lacks from another
installed one, which is what makes ∑ and ∂ appear at all.
The subset
Math is delimited by $...$. Inside it:
- Latin letters and lowercase Greek are italic, as variables; digits,
operators and capital Greek are upright.
\mathrm{...}forces upright text. ^and_attach a superscript or subscript to the atom before them:x^2,x_i,x_i^2,e^{-t}.\frac{num}{den}stacks a fraction with a rule at the math axis;\sqrt{x}draws the sign with a rule over its argument.{...}groups.\,is a thin space.\$is a literal dollar sign, inside or outside math.- Named symbols: the Greek alphabet (
\alpha…\omega,\Gamma…\Omega) and the operators listed in_symbol().
A single $ with no partner is a literal (so "Cost $5" stays
plain); three or more that cannot pair raise. An unknown \command,
an unbalanced brace, or a ^/_ with nothing to attach to raise at
render time naming the label and the position, rather than drawing
something that looks almost right.
What is not here
No large operators with limits (\sum_i is a subscript, not a
limit below), no matrices, no line breaks inside math, and a radical
sign that does not grow with a tall argument. Kerning applies within a run, not across the
boundary between a base and its script. Each run is anchored on a
whole pixel, like every other label; on SVG the viewer’s font, not
this layout, advances the pen between runs.