[varLib] Generate direct HVAR

This commit is contained in:
Behdad Esfahbod 2016-07-01 15:31:00 -07:00
parent e2da17e032
commit c1717224da
4 changed files with 62 additions and 20 deletions

View File

@ -89,7 +89,7 @@ class BaseConverter(object):
self.tableClass = tableClass
self.isCount = name.endswith("Count")
self.isLookupType = name.endswith("LookupType")
self.isPropagated = name in ["ClassCount", "Class2Count", "FeatureTag", "SettingsCount", "AxisCount"]
self.isPropagated = name in ["ClassCount", "Class2Count", "FeatureTag", "SettingsCount", "VarTupleCount"]
def readArray(self, reader, font, tableDict, count):
"""Read an array of values from the reader."""
@ -230,9 +230,19 @@ class GlyphID(SimpleValue):
class VarAxisID(SimpleValue):
staticSize = 2
def read(self, reader, font, tableDict):
return font['fvar'].axes[reader.readUShort()]
idx = reader.readUShort()
try:
return font['fvar'].axes[idx].axisTag
except (KeyError, IndexError):
return idx
def write(self, writer, font, tableDict, value, repeatIndex=None):
writer.writeUShort(font['fvar'].axes.index(value))
if not isinstance(value, int):
value = tobytes(value)
for i,axis in enumerate(font['fvar'].axes):
if axis.axisTag == value:
value = i
break
writer.writeUShort(value)
class FloatValue(SimpleValue):
def xmlRead(self, attrs, content, font):
@ -509,9 +519,11 @@ converterMapping = {
"GlyphID": GlyphID,
"DeciPoints": DeciPoints,
"Fixed": Fixed,
"F2Dot14": F2Dot14,
"struct": Struct,
"Offset": Table,
"LOffset": LTable,
"ValueRecord": ValueRecord,
"VarAxisID": VarAxisID,
"DeltaValue": DeltaValue,
}

View File

@ -845,7 +845,7 @@ otData = [
# VariationStore
('VarAxis', [
('uint16', 'VarAxisID', None, None, ''),
('VarAxisID', 'VarAxisID', None, None, ''),
('F2Dot14', 'StartCoord', None, None, ''),
('F2Dot14', 'PeakCoord', None, None, ''),
('F2Dot14', 'EndCoord', None, None, ''),
@ -862,10 +862,10 @@ otData = [
]),
('VarItemByteRecord', [
('int8', 'deltas', 'VarTupleCount', 0, ''),
('int8', 'Deltas', 'VarTupleCount', 0, ''),
]),
('VarItemShortRecord', [
('int16', 'deltas', 'VarTupleCount', 0, ''),
('int16', 'Deltas', 'VarTupleCount', 0, ''),
]),
('VarDeltasFormat1', [

View File

@ -20,11 +20,12 @@ API *will* change in near future.
"""
from __future__ import print_function, division, absolute_import
from fontTools.misc.py23 import *
from fontTools.ttLib import TTFont
from fontTools.ttLib import TTFont, newTable
from fontTools.ttLib.tables._n_a_m_e import NameRecord
from fontTools.ttLib.tables._f_v_a_r import table__f_v_a_r, Axis, NamedInstance
from fontTools.ttLib.tables._f_v_a_r import Axis, NamedInstance
from fontTools.ttLib.tables._g_l_y_f import GlyphCoordinates
from fontTools.ttLib.tables._g_v_a_r import table__g_v_a_r, GlyphVariation
from fontTools.ttLib.tables._g_v_a_r import GlyphVariation
from fontTools.ttLib.tables import otTables as ot
from fontTools.varLib import builder
import warnings
try:
@ -317,7 +318,7 @@ def _AddName(font, name):
# Move to fvar table proper?
def _add_fvar(font, axes, instances):
assert "fvar" not in font
font['fvar'] = fvar = table__f_v_a_r()
font['fvar'] = fvar = newTable('fvar')
for tag in sorted(axes.keys()):
axis = Axis()
@ -430,7 +431,7 @@ def _add_gvar(font, axes, master_ttfs, master_locs, base_idx):
print("Generating gvar")
assert "gvar" not in font
gvar = font["gvar"] = table__g_v_a_r()
gvar = font["gvar"] = newTable('gvar')
gvar.version = 1
gvar.reserved = 0
gvar.variations = {}
@ -440,28 +441,56 @@ def _add_gvar(font, axes, master_ttfs, master_locs, base_idx):
model_base_idx = model.mapping[base_idx]
assert 0 == model_base_idx
hAdvanceDeltas = {}
for glyph in font.getGlyphOrder():
allData = [_GetCoordinates(m, glyph) for m in master_ttfs]
allCoords = [d[0] for d in allData]
allControls = [d[1] for d in allData]
allHAdvance = [m["hmtx"].metrics[glyph][0] for m in master_ttfs]
control = allControls[0]
if (any(c != control for c in allControls)):
warnings.warn("glyph %s has incompatible masters; skipping" % glyph)
continue
del allControls
# Update gvar
gvar.variations[glyph] = []
deltas = model.getDeltas(allCoords)
supports = model.supports
assert len(deltas) == len(supports)
for i,(delta,support) in enumerate(zip(deltas, supports)):
if i == model_base_idx:
continue
for i,(delta,support) in enumerate(zip(deltas[1:], supports[1:])):
var = GlyphVariation(support, delta)
gvar.variations[glyph].append(var)
hAdvanceDeltas[glyph] = tuple(model.getDeltas(allHAdvance)[1:])
# Build HVAR
# We only support the direct mapping right now.
supports = model.supports[1:]
varTupleList = builder.buildVarTupleList(supports)
varTupleIndexes = list(range(len(supports)))
n = len(supports)
items = []
zeroes = [0]*n
for glyphName in font.getGlyphOrder():
items.append(hAdvanceDeltas.get(glyphName, zeroes))
while items and items[-1] is zeroes:
del items[-1]
varDeltas = builder.buildVarDeltas(varTupleIndexes, items)
varStore = builder.buildVarStore(varTupleList, [varDeltas])
assert "HVAR" not in font
HVAR = font["HVAR"] = newTable('HVAR')
hvar = HVAR.table = ot.HVAR()
hvar.Version = 1.0
hvar.VarIdxMap = None
hvar.VarStore = varStore
def main(args=None):
import sys

View File

@ -28,22 +28,23 @@ def buildVarTupleList(supports):
def buildVarDeltas(varTupleIndexes, items):
self = ot.VarDeltas()
self.format = 1 if all(all(128 <= delta <= 127 for delta in item) for item in items) else 2
self.Format = 1 if all(all(128 <= delta <= 127 for delta in item) for item in items) else 2
self.VarTupleIndex = list(varTupleIndexes)
tupleCount = self.VarTupleCount = len(self.VarTupleIndex)
records = self.Item = []
for item in items:
assert len(item) == tupleCount
record = ot.VarItemByteRecord() if self.format == 1 else ot.VarItemShortRecord()
record.deltas = list(item)
record = ot.VarItemByteRecord() if self.Format == 1 else ot.VarItemShortRecord()
record.Deltas = list(item)
records.append(record)
self.ItemCount = len(self.Item)
return self
def buildVarStore(varTupleList, varDeltas):
def buildVarStore(varTupleList, varDeltasList):
self = ot.VarStore()
self.Format = 1
self.VarTupleList = varTupleList
self.VarDeltas = varDeltas
self.VarDeltas = list(varDeltasList)
self.VarDeltasCount = len(self.VarDeltas)
return self