instancer: support partial instancing HVAR

We don't actually apply deltas to hmtx since these have already been applied
from the gvar deltas when we call glyf.setCoordinates method using the glyf
phantom points.

We simply call instantiateItemVariationStore on HVAR.VarStore to remove
regions and scale remaining deltas, but ignore the return value.
We only run VarStore.optimize() if the HVAR originally has an AdvWidthMap,
if it does not then it uses a direct implicit GID->VariationIndex mapping
for advance widths deltas, and we keep the VariationIndex unchanged by
not optimizing VarStore.

If all axes in fvar are being instanced, then we simply delete HVAR
(just like varLib.mutator currently does).

VVAR is not supported yet because we do not set the 3rd and 4th phantom points
from gvar to the vmtx table yet (this should be done in glyf.setCoordinates).

Also, supporting CFF2 would need more work, in that HVAR there is required
and we need to apply the deltas to hmtx/vmtx in here.
This commit is contained in:
Cosimo Lupo 2019-04-20 12:42:31 +01:00
parent bdef36501f
commit 2b50b94ed7
No known key found for this signature in database
GPG Key ID: 179A8F0895A02F4F

View File

@ -17,6 +17,7 @@ from fontTools.varLib.models import supportScalar, normalizeValue, piecewiseLine
from fontTools.ttLib import TTFont
from fontTools.ttLib.tables.TupleVariation import TupleVariation
from fontTools.ttLib.tables._g_l_y_f import GlyphCoordinates
from fontTools import varLib
from fontTools.varLib import builder
from fontTools.varLib.mvar import MVAR_ENTRIES
from fontTools.varLib.merger import MutatorMerger
@ -175,6 +176,54 @@ def instantiateMVAR(varfont, location):
del varfont["MVAR"]
def _remapVarIdxMap(table, attrName, varIndexMapping, glyphOrder):
oldMapping = getattr(table, attrName).mapping
newMapping = [varIndexMapping[oldMapping[glyphName]] for glyphName in glyphOrder]
setattr(table, attrName, builder.buildVarIdxMap(newMapping, glyphOrder))
# TODO(anthrotype) Add support for HVAR/VVAR in CFF2
def _instantiateVHVAR(varfont, location, tableFields):
tableTag = tableFields.tableTag
fvarAxes = varfont["fvar"].axes
# Deltas from gvar table have already been applied to the hmtx/vmtx. For full
# instances (i.e. all axes pinned), we can simply drop HVAR/VVAR and return
if set(location).issuperset(axis.axisTag for axis in fvarAxes):
log.info("Dropping %s table", tableTag)
del varfont[tableTag]
return
log.info("Instantiating %s table", tableTag)
vhvar = varfont[tableTag].table
varStore = vhvar.VarStore
# since deltas were already applied, the return value here is ignored
instantiateItemVariationStore(varStore, fvarAxes, location)
if varStore.VarRegionList.Region:
if getattr(vhvar, tableFields.advMapping):
varIndexMapping = varStore.optimize()
glyphOrder = varfont.getGlyphOrder()
_remapVarIdxMap(vhvar, tableFields.advMapping, varIndexMapping, glyphOrder)
if getattr(vhvar, tableFields.sb1):
_remapVarIdxMap(vhvar, tableFields.sb1, varIndexMapping, glyphOrder)
if getattr(vhvar, tableFields.sb2):
_remapVarIdxMap(vhvar, tableFields.sb2, varIndexMapping, glyphOrder)
if tableFields.vOrigMapping and getattr(vhvar, tableFields.vOrigMapping):
_remapVarIdxMap(
vhvar, tableFields.vOrigMapping, varIndexMapping, glyphOrder
)
else:
del varfont[tableTag]
def instantiateHVAR(varfont, location):
return _instantiateVHVAR(varfont, location, varLib.HVAR_FIELDS)
def instantiateVVAR(varfont, location):
return _instantiateVHVAR(varfont, location, varLib.VVAR_FIELDS)
class _TupleVarStoreAdapter(object):
def __init__(self, regions, axisOrder, tupleVarData, itemCounts):
self.regions = regions
@ -436,9 +485,7 @@ def sanityCheckVariableTables(varfont):
raise ValueError("Can't have gvar without glyf")
# TODO(anthrotype) Remove once we do support partial instancing CFF2
if "CFF2" in varfont:
raise NotImplementedError(
"Instancing CFF2 variable fonts is not supported yet"
)
raise NotImplementedError("Instancing CFF2 variable fonts is not supported yet")
def instantiateVariableFont(varfont, axis_limits, inplace=False, optimize=True):
@ -463,13 +510,17 @@ def instantiateVariableFont(varfont, axis_limits, inplace=False, optimize=True):
if "MVAR" in varfont:
instantiateMVAR(varfont, axis_limits)
if "HVAR" in varfont:
instantiateHVAR(varfont, axis_limits)
# TODO(anthrotype) Uncomment this once we apply gvar deltas to vmtx
# if "VVAR" in varfont:
# instantiateVVAR(varfont, axis_limits)
instantiateOTL(varfont, axis_limits)
instantiateFeatureVariations(varfont, axis_limits)
# TODO: actually process HVAR instead of dropping it
del varfont["HVAR"]
return varfont