fontations
fontations copied to clipboard
[Skrifa] Low overhead retrieval of adjusted metrics
In Skia, metrics retrieval is a first stage of glyph cache entry initialisation. There are two methods called on a Skia typeface backend: generateMetrics()
and depending on glyph format then generateImage()
, generateDrawable()
or generatePath()
.
Depending on hinting configuration or if the font is variable without variable mvar, in the generateMetrics()
stage, the adjusted metrics from Scaler::outline
may be needed without an actual draw call to draw the glyph.
Currently, the Scaler
call signature is:
pub fn outline(&mut self, glyph_id: GlyphId, pen: &mut impl Pen) -> Result<ScalerMetrics>
One way to retrieve the metrics only is then to perform a call with a Pen
performing only no-ops, but on the Skrifa side the path would be traversed.
For efficiency, it would be useful to have access to only the ScalerMetrics
/AdjustedMetrics
and the hinting or phantom point placement based on var-coords would only execute on phantom points and not the whole contour.
This could be done by wrapping the Pen
argument in Option<>
or providing a separate function.
We could possibly add OutlineGlyph::adjusted_metrics()
that is basically the same as draw()
but without the pen. For TrueType this would save the outline to path conversion cost but not the loading/scaling/hinting cost. I can't think of any low overhead method to compute hinted metrics. We need to run the program over the whole outline.
Matching FreeType here has been a bit of a problem due to the fact that FreeType offers multiple versions of the same metric that are computed in different ways. There is also a bit of an impedance mismatch between what we offer and what Skia expects.
I'd like to propose the following:
Add a new compat_metrics(&self, draw_settings: DrawSettings, glyph_id: GlyphId) -> CompatMetrics
method to OutlineGlyphCollection
. The new CompatMetrics
type will contain advance_width
, linear_advance_width
and bounding_box
which exactly match FT and should be sufficient to support what Skia gathers here. Vertical metrics are still TODO but I can prioritize when necessary. I'd like to gate this behind a compat_metrics
feature as I think it might be confusing for non-Skia users and we should encourage usage of precise linear metrics when FT compatibility is not strictly required.
As a bonus, change GlyphMetrics
to return the most precise values possible, fulfilling point 2 of #693. Maybe we can move Skia to this at some point in the future.
@drott @rsheeter thoughts?
From my point of view,
- I am okay with moving to
CompatMetrics
for FreeType-style scaled metrics. - Is it just me? I find it hard to understand or make sense of the term "linear metrics" and different context seem to attach different meaning to it. Sometimes it's used in Skia to describe metrics that scale with font size without reshaping or applying OpenType features at higher sizes? So unless it's really some kind of appropriate technical term here, can we use different, hopefully more descriptive names?
- As mentioned, Skia has two stages: a)
onGenerateMetrics()
, at which point we have to make a glyph format choice, and identify metrics that will be used for the lifetime of thisSkTypeface
for this glyph b)onGenerateImage
/onGeneratePath
/onGenerateDrawable
: Rasterize or generate anSkPath
/SkDrawable
at which point we have to produce a visual glyph - but we can't change the metrics here anymore - after the call todraw()
and retrievingAdjustedMetrics
.
Metrics Choice
So in the a) stage we need to make a decision on where to get the glyphs from. My understanding is:
- If we choose
glyf
,- we look at hinting mode, and potentially retrieve
AdjustedMetrics
, throughOutlineGlyph::adjusted_metrics()
as @dfrg's suggested above, - otherwise go with
CompatMetrics
.
- we look at hinting mode, and potentially retrieve
- If we choose bitmap glyphs, we use hmtx/hvar from CompatMetrics (right?) or worst case, the advance info that the bitmap strikes provide.
- If we choose COLRv1, we use hmtx/hvar from CompatMetrics (right?)
CC @bungeman
Does that sound reasonable?
Thanks for the additional context.
Linear is the technically correct terminology because the plot of font size vs metric is literally a line :) In practice, the plot becomes discontinuous only when metrics are modified by hinting so maybe “unhinted” would offer more clarity? In FT specifically, linearHoriAdvance
is also scaled and rounded differently with different precision as well.
For outline glyphs, my intention is that we’ll handle the hinted/unhinted case on our end in compat_metrics
(DrawSettings
has enough info for this although fallback to auto hinting might be a bit of a wrinkle. Let me think on this).
For bitmaps, I’ll have to double check but I believe FT uses the metrics from the bitmap tables for EBDT/CBDT. COLRv1 and sbix would use CompatMetrics
.
Ok, so looks like we are roughly on the same page? Yes, linear is "without hinting". As far as I remember from recently looking into it, the bitmap metrics are not used, at least not in Skia - usually hmtx
would be available, so bitmap metrics only as fallback, I'd say? And IIRC, SBIX does not have any - there, it's always htmx
.
Yes, on the same page. I’ll get started on this early next week.
You are correct for sbix but it appears that the other bitmap tables do fill the glyph slot metrics with bitmap specific data: https://github.com/freetype/freetype/blob/546237e1bbbb1269b5f76a878ea5eed3c8e268b5/src/truetype/ttgload.c#L2140. I don’t think this matters so much for color bitmaps but small monochromatic bitmaps really do need the exact values so we should probably support it.