Skip to content

[read-fonts] Add BASE table accessors - #2106

Open
dfrg wants to merge 4 commits into
mainfrom
tables/base
Open

[read-fonts] Add BASE table accessors#2106
dfrg wants to merge 4 commits into
mainfrom
tables/base

Conversation

@dfrg

@dfrg dfrg commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Adds useful helpers for reading the BASE table, specifically those that are required to implement certain HB APIs in Chrome.

Plan for implementing HarfRust C FFI side: harfbuzz/harfrust#467

dfrg added 4 commits September 4, 2026 22:12
MATH describes mathematical typesetting: the constants that position
scripts, fractions and radicals, per-glyph italics correction, top accent
attachment and kerning, and the variants and assemblies that stretch a
delimiter to fit.

Chromium reads all four of those groups through HarfBuzz, so the surface
is not hypothetical.

Two parts of the table needed more than the usual attributes.
MathValueRecord carries a device offset measured from the table that
contains the record rather than from the record itself, which the
generated accessor already handles by taking the parent's offset data.
MathKern holds one more kern value than it has correction heights, since
the first applies below the lowest height and the last above the highest;
`add($height_count, 1)` gives that array its count.

The constants are 51 MathValueRecords in a fixed order, where a
transposition would be silent -- every field has the same type. The test
gives each record a value that encodes its index, so reading them back
through the named accessors checks the whole run.
Most measurements in MATH are a MathValueRecord: a design unit value and
an optional offset to a Device or VariationIndex table. Reading one means
finding the record, resolving its offset against the table it was read
from, and applying the adjustment.

MathValue carries the result, and keeps its two halves apart because they
are in different units. A device table adjusts by whole pixels, so scaling
that into design units needs the units per em, which this table does not
know; returning a single number would have to guess at one. A
VariationIndex contributes nothing at all: the deltas it names live in an
item variation store, and MATH has none.

MathConstant numbers the constants the way HarfBuzz does. One macro list
defines the enum, its numbering, and the arms that read each field, so a
constant cannot be numbered as one field and read from another, and the
matches have no catch-all.

MathKern hands over its bands rather than searching them. Which band a
height falls in depends on whether the comparison happens in design units,
in pixels, or in a scaled position -- the last of which also decides which
way up the vertical axis is -- and only the caller knows that.

has_swapped_min_heights reports the Cambria Math builds that store two
constants the wrong way round. It reports the font and leaves the
substitution to the caller, so the constants keep saying what the font
says.
A device table gives a whole pixel correction for each size in the range
it covers, and looking one up is the table's own business rather than
something each caller should repeat. MATH had it as a private helper;
BASE wants the same, so it moves to Device.
Finding a baseline means walking from an axis to a script to a coordinate:
the axis for the writing direction, the script's own record or the default
one, then the index of the baseline tag among the tags the axis lists.
BaseInstance holds the location that walk resolves against.

Unlike MATH, this table carries its own item variation store, so an
instance needs only the coordinates. A coordinate takes at most one
adjustment and the two kinds land in different units: a variation delta is
in design units and folds into the value, while a device table adjusts by
whole pixels and stays apart, since scaling it needs the units per em.

Languages do not come into it. The BASE table varies its minimum and
maximum extents by language, but not its baselines, so the lookup takes a
script and stops there.

horizontal_baseline_tag_for_script carries the script list HarfBuzz keeps,
so a caller can ask for the baseline a script actually sits on. Note that
the input is a Unicode script code rather than an OpenType script tag, and
that the script Hang is Hangul while the baseline tag hang is the hanging
baseline.
Base automatically changed from tables/math to main September 8, 2026 19:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant