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:
parent
bdef36501f
commit
2b50b94ed7
@ -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
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user