[varStore] Generate variation for Anchors and store in GDEF

Finally!  Phew...
This commit is contained in:
Behdad Esfahbod 2016-09-08 09:17:45 -07:00
parent cfd7bfbb2c
commit caa353d5dd
3 changed files with 52 additions and 16 deletions

View File

@ -203,6 +203,7 @@ class VarData(BaseTable):
numShorts = 0
count = len(self.VarRegionIndex)
for item in self.Item:
assert len(item) == count, ("Item length mismatch", len(item), count)
for i in range(count - 1, numShorts - 1, -1):
if not (-128 <= item[i] <= 127):
numShorts = i + 1

View File

@ -85,6 +85,8 @@ def _add_fvar(font, axes, instances, axis_map):
inst.coordinates = {axis_map[k][0]:v for k,v in coordinates.items()}
fvar.instances.append(inst)
return fvar
# TODO Move to glyf or gvar table proper
def _GetCoordinates(font, glyphName):
"""font, glyphName --> glyph coordinates as expected by "gvar" table
@ -187,7 +189,7 @@ def _add_gvar(font, model, master_ttfs):
var = GlyphVariation(support, delta)
gvar.variations[glyph].append(var)
def _add_HVAR(font, model, master_ttfs, axes):
def _add_HVAR(font, model, master_ttfs, axisTags):
print("Generating HVAR")
@ -201,7 +203,7 @@ def _add_HVAR(font, model, master_ttfs, axes):
# We only support the direct mapping right now.
supports = model.supports[1:]
varTupleList = builder.buildVarRegionList(supports, axes.keys())
varTupleList = builder.buildVarRegionList(supports, axisTags)
varTupleIndexes = list(range(len(supports)))
n = len(supports)
items = []
@ -249,8 +251,8 @@ def _all_equal(lst):
def buildVarDevTable(store_builder, master_values):
if _all_equal(master_values):
return None
deltas = master_values
return builder.buildVarDevTable(0xdeadbeef)
varIdx = store_builder.storeMasters(master_values)
return builder.buildVarDevTable(varIdx)
class VariationMerger(Merger):
@ -269,15 +271,13 @@ def merge(merger, self, lst):
self.XDeviceTable = XDeviceTable
self.YDeviceTable = YDeviceTable
def _merge_OTL(font, model, master_fonts, axes, base_idx):
def _merge_OTL(font, model, master_fonts, axisTags, base_idx):
print("Merging OpenType Layout tables")
axisTags = [] # XXX
merger = VariationMerger(model, axisTags)
print("Building variations tables")
merge_tables(font, merger, master_fonts, axes, base_idx, ['GPOS'])
merge_tables(font, merger, master_fonts, axisTags, base_idx, ['GPOS'])
store = merger.store_builder.finish()
GDEF = font['GDEF'].table
@ -354,7 +354,8 @@ def build(designspace_filename, master_finder=lambda s:s, axisMap=None):
gx = TTFont(master_ttfs[base_idx])
# TODO append masters as named-instances as well; needs .designspace change.
_add_fvar(gx, axes, instances, axis_map)
fvar = _add_fvar(gx, axes, instances, axis_map)
# Normalize master locations
master_locs = [models.normalizeLocation(m, axes) for m in master_locs]
@ -363,8 +364,11 @@ def build(designspace_filename, master_finder=lambda s:s, axisMap=None):
pprint(master_locs)
# TODO Clean this up.
del instances
del axes
master_locs = [{axis_map[k][0]:v for k,v in loc.items()} for loc in master_locs]
#instance_locs = [{axis_map[k][0]:v for k,v in loc.items()} for loc in instance_locs]
axisTags = [axis.axisTag for axis in fvar.axes]
# Assume single-model for now.
model = models.VariationModel(master_locs)
@ -373,8 +377,8 @@ def build(designspace_filename, master_finder=lambda s:s, axisMap=None):
print("Building variations tables")
if 'glyf' in gx:
_add_gvar(gx, model, master_fonts)
_add_HVAR(gx, model, master_fonts, axes)
_merge_OTL(gx, model, master_fonts, axes, base_idx)
_add_HVAR(gx, model, master_fonts, axisTags)
_merge_OTL(gx, model, master_fonts, axisTags, base_idx)
return gx, model, master_ttfs

View File

@ -10,6 +10,7 @@ def buildVarRegionAxis(axisSupport):
return self
def buildVarRegion(support, axisTags):
assert all(tag in axisTags for tag in support.keys()), ("Unknown axis tag found.", support, axisTags)
self = ot.VarRegion()
self.VarRegionAxis = []
for tag in axisTags:
@ -23,7 +24,7 @@ def buildVarRegionList(supports, axisTags):
self.Region = []
for support in supports:
self.Region.append(buildVarRegion(support, axisTags))
self.VarRegionCount = len(self.Region)
self.RegionCount = len(self.Region)
return self
@ -81,18 +82,40 @@ def buildVarStore(varRegionList, varDataList):
return self
def _getLocationKey(loc):
return tuple(sorted(loc.items(), key=lambda kv: kv[0]))
class OnlineVarStoreBuilder(object):
def __init__(self, axisTags):
self._regions = buildVarRegionList([], axisTags)
self._store = buildVarStore(self._regions, [])
self._axisTags = axisTags
self._regionMap = {}
self._regionList = buildVarRegionList([], axisTags)
self._store = buildVarStore(self._regionList, [])
def setModel(self, model):
self._model = model
# Store model's regions
regionMap = self._regionMap
regionList = self._regionList
regions = model.supports[1:]
regionIndices = []
for region in regions:
key = _getLocationKey(region)
idx = regionMap.get(key)
if idx is None:
varRegion = buildVarRegion(region, self._axisTags)
idx = regionMap[key] = len(regionList.Region)
regionList.Region.append(varRegion)
regionIndices.append(idx)
data = self._data = buildVarData(regionIndices, [], optimize=False)
self._outer = len(self._store.VarData)
self._store.VarData.append(data)
def finish(self, optimize=True):
self._regions.VarRegionCount = len(self._regions.Region)
self._regionList.RegionCount = len(self._regionList.Region)
self._store.VarDataCount = len(self._store.VarData)
for data in self._store.VarData:
data.ItemCount = len(data.Item)
@ -100,6 +123,14 @@ class OnlineVarStoreBuilder(object):
optimizeVarData(data)
return self._store
def storeMasters(self, master_values):
deltas = [int(round(d)) for d in self._model.getDeltas(master_values)[1:]]
inner = len(self._data.Item)
self._data.Item.append(deltas)
# TODO Check for full data array?
return (self._outer << 16) + inner
# Variation helpers