[instancer] Ensure hhea vertical metrics stay in sync with OS/2 ones after instancing

Fixes https://github.com/fonttools/fonttools/issues/3297
This commit is contained in:
Cosimo Lupo 2023-11-15 13:56:22 +00:00
parent a92b2b0725
commit 69636098bd
No known key found for this signature in database
GPG Key ID: DF65A8A5A119C9A8

View File

@ -105,6 +105,7 @@ from fontTools.misc.cliTools import makeOutputFileName
from fontTools.varLib.instancer import solver
import collections
import dataclasses
from contextlib import contextmanager
from copy import deepcopy
from enum import IntEnum
import logging
@ -694,6 +695,43 @@ def setMvarDeltas(varfont, deltas):
)
@contextmanager
def verticalMetricsKeptInSync(varfont):
"""Ensure hhea vertical metrics stay in sync with OS/2 ones after instancing.
When applying MVAR deltas to the OS/2 table, if the ascender, descender and
line gap change but they were the same as the respective hhea metrics in the
original font, this context manager ensures that hhea metrcs also get updated
accordingly.
The MVAR spec only has tags for the OS/2 metrics, but it is common in fonts
to have the hhea metrics be equal to those for compat reasons.
https://learn.microsoft.com/en-us/typography/opentype/spec/mvar
https://googlefonts.github.io/gf-guide/metrics.html#7-hhea-and-typo-metrics-should-be-equal
https://github.com/fonttools/fonttools/issues/3297
"""
current_os2_vmetrics = [
getattr(varfont["OS/2"], attr)
for attr in ("sTypoAscender", "sTypoDescender", "sTypoLineGap")
]
metrics_are_synced = current_os2_vmetrics == [
getattr(varfont["hhea"], attr) for attr in ("ascender", "descender", "lineGap")
]
yield metrics_are_synced
if metrics_are_synced:
new_os2_vmetrics = [
getattr(varfont["OS/2"], attr)
for attr in ("sTypoAscender", "sTypoDescender", "sTypoLineGap")
]
if current_os2_vmetrics != new_os2_vmetrics:
for attr, value in zip(
("ascender", "descender", "lineGap"), new_os2_vmetrics
):
setattr(varfont["hhea"], attr, value)
def instantiateMVAR(varfont, axisLimits):
log.info("Instantiating MVAR table")
@ -701,7 +739,9 @@ def instantiateMVAR(varfont, axisLimits):
fvarAxes = varfont["fvar"].axes
varStore = mvar.VarStore
defaultDeltas = instantiateItemVariationStore(varStore, fvarAxes, axisLimits)
setMvarDeltas(varfont, defaultDeltas)
with verticalMetricsKeptInSync(varfont):
setMvarDeltas(varfont, defaultDeltas)
if varStore.VarRegionList.Region:
varIndexMapping = varStore.optimize()