A measurement context — how wide a string will be, in any font a document knows.
Tincture.Font.text_width/3 is pure, and can only resolve the standard 14
fonts and AFM files on disk. An embedded TrueType font has no AFM: its
metrics are parsed out of the file at registration time and live on the
Tincture.PDF.t/0 struct. So a pure function cannot measure one, and for a
long time the layout and typography layer — which measured through
text_width/3 — simply raised unknown font for every embedded font.
A context closes that gap. It carries the embedded metrics alongside the static ones, so anything holding a document can measure any font that document can draw:
context = Context.from_pdf(pdf)
Context.text_width(context, "Body", 11, "Hello")Callers that already have a %Tincture.PDF{} — Tincture.text_paragraph/6,
Tincture.Layout.Table.render/6, Tincture.Layout.Box.flow_text/7 — build
one themselves, so using an embedded font for layout needs nothing extra.
Build one by hand only when measuring outside a document, or when
constructing a Tincture.Typography.RichText.t/0 up front.
What it measures
For an embedded font: per-glyph advance widths from hmtx, resolved through
cmap, scaled by the font's units-per-em, with GPOS pair kerning applied and
Unicode variation sequences honoured. That is the same arithmetic the drawing
path uses, so a measured width matches what is actually rendered.
For everything else it defers to Tincture.Font.text_width/3.
Name precedence
A name registered as an embedded font and also naming a standard font
resolves to the standard metrics, which is what the pre-existing drawing
path did. Registering a TTF as "Helvetica" is therefore not a way to
override the built-in metrics.
Summary
Functions
Build a context from a document, carrying every font registered on it.
The codepoint within a grapheme that participates in kerning.
Whether this context can measure the given font without falling back.
Measure text, reporting whether the font could actually be resolved.
An empty context, resolving only the standard 14 fonts and AFM files.
The GPOS kerning adjustment between two codepoints, in font design units.
The width of text in font_name at size, in points.
Types
Functions
Build a context from a document, carrying every font registered on it.
The codepoint within a grapheme that participates in kerning.
A grapheme cluster can carry combining marks and variation selectors, none of which take part in a kerning pair. This picks the base character.
Whether this context can measure the given font without falling back.
Measure text, reporting whether the font could actually be resolved.
Returns {:ok, width} when the width is real, and {:unresolved, estimate}
when this context has never heard of the font — carrying a rough width from
the point size so a caller can carry on and decide later.
This exists because rich text is measured when it is built, which may be
before the document it will be drawn into is known. An embedded font is
unresolvable at that moment but perfectly resolvable at layout time, and is
indistinguishable from a typo until then. Callers use this to hold the
question open rather than guessing, and
Tincture.Typography.RichText.remeasure/2 closes it.
@spec new() :: t()
An empty context, resolving only the standard 14 fonts and AFM files.
Equivalent to measuring through Tincture.Font.text_width/3 directly.
The GPOS kerning adjustment between two codepoints, in font design units.
Exposed because the drawing path positions each grapheme individually when kerning is on, and so needs the adjustment for one pair at a time rather than the total across a string.
The width of text in font_name at size, in points.
Options
:on_unknown— what to do with a font this context cannot resolve.:raise(the default) letsTincture.Font.text_width/3raise, which catches a mistyped font name during layout.:estimatereturns a rough width from the point size instead, which is what the drawing path needs:Tincture.set_font/3does not validate, so a document can already be drawing with a font nothing knows about, and a raise there would turn a cosmetic problem into a crash.