Repository navigation
Draw a variable font at the weight, width and slant CSS asks for, not only at its default instance #673
Description
A variable font (OpenType Font Variations: an fvar table plus gvar, HVAR and friends) can be registered in fontdata today, but mPDF only ever draws its default instance.
mPDF reads the glyph outlines from glyf and the advances from hmtx, both of which hold the default instance only. Subsetting then keeps just the tables it knows, so no variation data reaches the PDF. So:
font-weight(or<b>) never selects a heavier or lighter instance. Bold falls back to the artificial bold (falseBoldWeight: text drawn with2 Trand a stroke), and a weight such as 300 draws the default instance.font-stretch,font-style: oblique <angle>andfont-variation-settingshave nothing to act on.
Checked locally with a system variable TrueType font registered as 'R' only, on gravitypdf: Regular was drawn with 0 Tr, <b>Bold</b> with 2 Tr 0.423 w, and a font-weight: 300 span exactly like the regular text.
What supporting them would take
PDF has no font-variation support of its own, so mPDF would have to instance the font: build a static font for each set of axis values the document uses, and embed each one as its own font.
- Read the variation tables.
fvarfor the axes and named instances.avarto normalise axis values.gvarfor per-glyph point deltas in the glyph outlines.HVAR, or the phantom points ingvar, for the advance widths.MVARfor the font-wide metrics: ascender, descender, line gap, underline, x-height and cap height.
- Apply the deltas. Interpolate each glyph's outline and advance at the chosen axis values. That includes the implicit deltas for untouched points (IUP) and composite glyphs. Then write out a static
glyf/loca/hmtx, together with ahead/hhea/OS/2/postthat match the instance. - Instance the layout data. OpenType layout can vary too:
GDEFitem variation stores feed variable anchors and kerning values inGPOS, andFeatureVariationsinGSUB/GPOSswap in other lookups at some axis values.Otlwould need to read them at the instance's coordinates. - Choose the instance. Map the computed
font-weighttowght,font-stretchtowdth, and oblique/italic toslnt/ital. Takefont-variation-settingslast, as CSS Fonts orders them. Font matching treats a variable font as covering its whole axis range (CSS Fonts Level 4 §5.2), so this sits on top of Register a family's faces at any font weight and draw each weight with the face CSS picks #672's face matching. - Keep the font key unique. It needs the family, the instance's axis values and the style. The font cache, subsetting and PDF resource names all need one entry per instance used.
CFF2 variable fonts (.otf with CFF2 outlines) come after CFF support in general. mPDF currently refuses PostScript-outline fonts outright (TTFontFile::readHeader(): "Fonts with postscript outlines are not supported"). So this issue covers TrueType-outline (glyf + gvar) variable fonts first.
Scope
- Standard CSS mode only. Legacy keeps drawing the default instance.
- Tests and fixtures. They need a variable font whose licence allows it in the repository, or one generated for the tests (e.g. a small
glyf+gvarfont built by a script). Test severalwghtvalues against the named instances, advances and kerning at an instance,font-variation-settings, and two instances of one family subset in one document. Add snapshots, simple and complex. - Performance. Instancing is done once per instance per document, so it belongs in the font cache (
tmp/ttfontdata), keyed by the axis values.
Separate from #672, which registers static faces by weight. Follows #545 / #647.
Activity