From c1717224da1c0bea24b52a99184515eca18b1e67 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Fri, 1 Jul 2016 15:31:00 -0700 Subject: [PATCH] [varLib] Generate direct HVAR --- Lib/fontTools/ttLib/tables/otConverters.py | 18 +++++++-- Lib/fontTools/ttLib/tables/otData.py | 6 +-- Lib/fontTools/varLib/__init__.py | 47 +++++++++++++++++----- Lib/fontTools/varLib/builder.py | 11 ++--- 4 files changed, 62 insertions(+), 20 deletions(-) diff --git a/Lib/fontTools/ttLib/tables/otConverters.py b/Lib/fontTools/ttLib/tables/otConverters.py index c16f9042b..c3ce9fccd 100644 --- a/Lib/fontTools/ttLib/tables/otConverters.py +++ b/Lib/fontTools/ttLib/tables/otConverters.py @@ -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, } diff --git a/Lib/fontTools/ttLib/tables/otData.py b/Lib/fontTools/ttLib/tables/otData.py index 53d72fdd7..8fc55b797 100644 --- a/Lib/fontTools/ttLib/tables/otData.py +++ b/Lib/fontTools/ttLib/tables/otData.py @@ -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', [ diff --git a/Lib/fontTools/varLib/__init__.py b/Lib/fontTools/varLib/__init__.py index ca6184c85..fe3827aac 100644 --- a/Lib/fontTools/varLib/__init__.py +++ b/Lib/fontTools/varLib/__init__.py @@ -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 diff --git a/Lib/fontTools/varLib/builder.py b/Lib/fontTools/varLib/builder.py index 960541fac..4ca61b078 100644 --- a/Lib/fontTools/varLib/builder.py +++ b/Lib/fontTools/varLib/builder.py @@ -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