[varLib.mutator] Add interpolation of glyph metrics.
Added interpolation of glyph advance width, from HVAR/hmtx, and derivation of new LSB. Updated tests to match. Needed to cherrypick from another branch an update for psCharstrings to allow the CFFSubr.draw() method to work.
This commit is contained in:
parent
6cb84deccf
commit
c2abd045b3
@ -1,7 +1,9 @@
|
||||
from fontTools.misc import psCharStrings
|
||||
from fontTools import ttLib
|
||||
from fontTools.pens.basePen import NullPen
|
||||
from fontTools.pens.boundsPen import BoundsPen
|
||||
from fontTools.misc.fixedTools import otRound
|
||||
from fontTools.varLib.varStore import VarStoreInstancer
|
||||
|
||||
def _add_method(*clazzes):
|
||||
"""Returns a decorator function that adds a new method to one or
|
||||
@ -587,6 +589,7 @@ def interpolate_cff2_PrivateDict(topDict, interpolateFromDeltas):
|
||||
def interpolate_cff2_charstrings(topDict, interpolateFromDeltas, glyphOrder):
|
||||
charstrings = topDict.CharStrings
|
||||
for gname in glyphOrder:
|
||||
# Interpolate charstring
|
||||
charstring = charstrings[gname]
|
||||
pd = charstring.private
|
||||
vsindex = pd.vsindex if (hasattr(pd, 'vsindex')) else 0
|
||||
@ -620,4 +623,50 @@ def interpolate_cff2_charstrings(topDict, interpolateFromDeltas, glyphOrder):
|
||||
charstring.program = new_program
|
||||
|
||||
|
||||
def interpolate_cff2_metrics(varfont, topDict, glyphOrder, loc):
|
||||
"""Unlike TrueType glyphs, neither advance width nor bounding box
|
||||
info is stored in a CFF2 charstring. The width data exists only in
|
||||
the hmtx and HVAR tables. Since LSB data cannot be interpolated
|
||||
reliably from the master LSB values in the hmtx table, we traverse
|
||||
the charstring to determine the actual bound box. """
|
||||
|
||||
charstrings = topDict.CharStrings
|
||||
boundsPen = BoundsPen(glyphOrder)
|
||||
hmtx = varfont['hmtx']
|
||||
hvar_table = None
|
||||
if 'HVAR' in varfont:
|
||||
hvar_table = varfont['HVAR'].table
|
||||
fvar = varfont['fvar']
|
||||
varStoreInstancer = VarStoreInstancer(hvar_table.VarStore, fvar.axes, loc)
|
||||
|
||||
for gid, gname in enumerate(glyphOrder):
|
||||
entry = list(hmtx[gname])
|
||||
# get width delta.
|
||||
if hvar_table:
|
||||
if hvar_table.AdvWidthMap:
|
||||
width_idx = hvar_table.AdvWidthMap.mapping[gname]
|
||||
else:
|
||||
width_idx = gid
|
||||
width_delta = otRound(varStoreInstancer[width_idx])
|
||||
else:
|
||||
width_delta = 0
|
||||
|
||||
# get LSB.
|
||||
boundsPen.init()
|
||||
charstring = charstrings[gname]
|
||||
charstring.draw(boundsPen)
|
||||
if boundsPen.bounds is None:
|
||||
# Happens with non-marking glyphs
|
||||
lsb_delta = 0
|
||||
else:
|
||||
lsb = boundsPen.bounds[0]
|
||||
lsb_delta = entry[1] - lsb
|
||||
|
||||
if lsb_delta or width_delta:
|
||||
if width_delta:
|
||||
entry[0] += width_delta
|
||||
if lsb_delta:
|
||||
entry[1] = lsb
|
||||
hmtx[gname] = tuple(entry)
|
||||
|
||||
|
||||
|
@ -17,7 +17,9 @@ from fontTools.varLib.merger import MutatorMerger
|
||||
from fontTools.varLib.varStore import VarStoreInstancer
|
||||
from fontTools.varLib.mvar import MVAR_ENTRIES
|
||||
from fontTools.varLib.iup import iup_delta
|
||||
from fontTools.subset.cffLib import interpolate_cff2_PrivateDict, interpolate_cff2_charstrings
|
||||
from fontTools.subset.cffLib import (interpolate_cff2_PrivateDict,
|
||||
interpolate_cff2_charstrings,
|
||||
interpolate_cff2_metrics)
|
||||
import os.path
|
||||
import logging
|
||||
|
||||
@ -106,7 +108,7 @@ def instantiateVariableFont(varfont, location, inplace=False):
|
||||
if 'CFF2' in varfont:
|
||||
log.info("Mutating CFF2 table")
|
||||
glyphOrder = varfont.getGlyphOrder()
|
||||
CFF2= varfont['CFF2']
|
||||
CFF2 = varfont['CFF2']
|
||||
topDict = CFF2.cff.topDictIndex[0]
|
||||
vsInstancer = VarStoreInstancer(topDict.VarStore.otVarStore,
|
||||
fvar.axes, loc)
|
||||
@ -115,6 +117,9 @@ def instantiateVariableFont(varfont, location, inplace=False):
|
||||
CFF2.desubroutinize(varfont)
|
||||
interpolate_cff2_charstrings(topDict, interpolateFromDeltas,
|
||||
glyphOrder)
|
||||
interpolate_cff2_metrics(varfont, topDict, glyphOrder, loc)
|
||||
del topDict.rawDict['VarStore']
|
||||
del topDict.VarStore
|
||||
|
||||
if 'MVAR' in varfont:
|
||||
log.info("Mutating MVAR table")
|
||||
|
@ -1,6 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ttFont sfntVersion="OTTO" ttLibVersion="3.32">
|
||||
|
||||
<hmtx>
|
||||
<mtx name=".notdef" width="600" lsb="84"/>
|
||||
<mtx name="A" width="600" lsb="50"/>
|
||||
<mtx name="T" width="600" lsb="50"/>
|
||||
<mtx name="dollar" width="600" lsb="102"/>
|
||||
<mtx name="glyph00003" width="600" lsb="102"/>
|
||||
</hmtx>
|
||||
|
||||
<CFF2>
|
||||
<major value="2"/>
|
||||
<minor value="0"/>
|
||||
@ -89,35 +97,6 @@
|
||||
158 860 -30 4 -158 -860 rlineto
|
||||
</CharString>
|
||||
</CharStrings>
|
||||
<VarStore Format="1">
|
||||
<Format value="1"/>
|
||||
<VarRegionList>
|
||||
<!-- RegionAxisCount=1 -->
|
||||
<!-- RegionCount=2 -->
|
||||
<Region index="0">
|
||||
<VarRegionAxis index="0">
|
||||
<StartCoord value="-1.0"/>
|
||||
<PeakCoord value="-1.0"/>
|
||||
<EndCoord value="0.0"/>
|
||||
</VarRegionAxis>
|
||||
</Region>
|
||||
<Region index="1">
|
||||
<VarRegionAxis index="0">
|
||||
<StartCoord value="0.0"/>
|
||||
<PeakCoord value="1.0"/>
|
||||
<EndCoord value="1.0"/>
|
||||
</VarRegionAxis>
|
||||
</Region>
|
||||
</VarRegionList>
|
||||
<!-- VarDataCount=1 -->
|
||||
<VarData index="0">
|
||||
<!-- ItemCount=0 -->
|
||||
<NumShorts value="0"/>
|
||||
<!-- VarRegionCount=2 -->
|
||||
<VarRegionIndex index="0" value="0"/>
|
||||
<VarRegionIndex index="1" value="1"/>
|
||||
</VarData>
|
||||
</VarStore>
|
||||
</CFFFont>
|
||||
|
||||
<GlobalSubrs>
|
||||
|
@ -165,7 +165,7 @@ class MutatorTest(unittest.TestCase):
|
||||
|
||||
otf_vf_path = self.get_test_input('TestCFF2VF.otf')
|
||||
expected_ttx_name = 'InterpolateTestCFF2VF'
|
||||
tables = ["fvar", "CFF2"]
|
||||
tables = ["hmtx", "CFF2"]
|
||||
loc = {'wght':float(200)}
|
||||
|
||||
varfont = TTFont(otf_vf_path)
|
||||
|
Loading…
x
Reference in New Issue
Block a user