def test_onlineVarStoreBuilder(locations, masterValues): axisTags = sorted({k for loc in locations for k in loc}) model = VariationModel(locations) builder = OnlineVarStoreBuilder(axisTags) builder.setModel(model) varIdxs = [] for masters in masterValues: _, varIdx = builder.storeMasters(masters) varIdxs.append(varIdx) varStore = builder.finish() mapping = varStore.optimize() varIdxs = [mapping[varIdx] for varIdx in varIdxs] dummyFont = TTFont() writer = OTTableWriter() varStore.compile(writer, dummyFont) data = writer.getAllData() reader = OTTableReader(data) varStore = VarStore() varStore.decompile(reader, dummyFont) fvarAxes = [buildAxis(axisTag) for axisTag in axisTags] instancer = VarStoreInstancer(varStore, fvarAxes) for masters, varIdx in zip(masterValues, varIdxs): base, *rest = masters for expectedValue, loc in zip(masters, locations): instancer.setLocation(loc) value = base + instancer[varIdx] assert expectedValue == value
def test_write_replace_not_ascii(self): writer = OTTableWriter() with CapturingLogHandler(otConverters.log, "WARNING") as captor: self.converter.write(writer, self.font, {}, "Hello ☃") self.assertEqual(writer.getData(), b"Hello ?" + 57 * b"\0") self.assertIn('replacing non-ASCII characters in "Hello ☃"', [r.msg for r in captor.records])
def test_write_replace_not_ascii(self): writer = OTTableWriter() with CapturingLogHandler(otConverters.log, "WARNING") as captor: self.converter.write(writer, self.font, {}, "Hello ☃") self.assertEqual(writer.getData(), b"Hello ?" + 57 * b"\0") self.assertIn('replacing non-ASCII characters in "Hello ☃"', [r.msg for r in captor.records])
def test_write_truncated(self): writer = OTTableWriter() with CapturingLogHandler(otConverters.log, "WARNING") as captor: self.converter.write(writer, self.font, {}, "A" * 80) self.assertEqual(writer.getData(), b"A" * 64) self.assertIn('truncating overlong "' + "A" * 80 + '" to 64 bytes', [r.msg for r in captor.records])
def test_write_truncated(self): writer = OTTableWriter() with CapturingLogHandler(otConverters.log, "WARNING") as captor: self.converter.write(writer, self.font, {}, "A" * 80) self.assertEqual(writer.getData(), b"A" * 64) self.assertIn('truncating overlong "' + "A" * 80 + '" to 64 bytes', [r.msg for r in captor.records])
def testCompile(self): r = otTables.RearrangementMorphAction() r.NewState = 0x1234 r.MarkFirst = r.DontAdvance = r.MarkLast = True r.ReservedFlags, r.Verb = 0x1FF0, 0xD writer = OTTableWriter() r.compile(writer, self.font, actionIndex=None) self.assertEqual(hexStr(writer.getAllData()), "1234fffd")
def testCompile(self): a = otTables.ContextualMorphAction() a.NewState = 0x1234 a.SetMark, a.DontAdvance, a.ReservedFlags = True, True, 0x3117 a.MarkIndex, a.CurrentIndex = 0xDEAD, 0xBEEF writer = OTTableWriter() a.compile(writer, self.font, actionIndex=None) self.assertEqual(hexStr(writer.getAllData()), "1234f117deadbeef")
def testCompile(self): r = otTables.RearrangementMorphAction() r.NewState = 0x1234 r.MarkFirst = r.DontAdvance = r.MarkLast = True r.ReservedFlags, r.Verb = 0x1FF0, 0xD writer = OTTableWriter() r.compile(writer, self.font, actionIndex=None) self.assertEqual(hexStr(writer.getAllData()), "1234fffd")
def testCompileFromXML(self): a = otTables.InsertionMorphAction() for name, attrs, content in parseXML(self.MORPH_ACTION_XML): a.fromXML(name, attrs, content, self.font) writer = OTTableWriter() a.compile(writer, self.font, actionIndex={('B', 'C'): 9, ('B', 'A', 'D'): 7}) self.assertEqual(hexStr(writer.getAllData()), "1234fc4300090007")
def testCompile(self): a = otTables.ContextualMorphAction() a.NewState = 0x1234 a.SetMark, a.DontAdvance, a.ReservedFlags = True, True, 0x3117 a.MarkIndex, a.CurrentIndex = 0xDEAD, 0xBEEF writer = OTTableWriter() a.compile(writer, self.font, actionIndex=None) self.assertEqual(hexStr(writer.getAllData()), "1234f117deadbeef")
def test_writeFormat0(self): writer = OTTableWriter() font = FakeFont(".notdef A B C".split()) self.converter.write(writer, font, {}, { ".notdef": ".notdef", "A": "C", "B": "C", "C": "A" }) self.assertEqual(writer.getData(), deHexStr("0000 0000 0003 0003 0001"))
def test_writeFormat0(self): writer = OTTableWriter() font = FakeFont(".notdef A B C".split()) self.converter.write(writer, font, {}, { ".notdef": ".notdef", "A": "C", "B": "C", "C": "A" }) self.assertEqual(writer.getData(), deHexStr("0000 0000 0003 0003 0001"))
def testCompileFromXML(self): a = otTables.InsertionMorphAction() for name, attrs, content in parseXML(self.MORPH_ACTION_XML): a.fromXML(name, attrs, content, self.font) writer = OTTableWriter() a.compile(writer, self.font, actionIndex={ ('B', 'C'): 9, ('B', 'A', 'D'): 7 }) self.assertEqual(hexStr(writer.getAllData()), "1234fc4300090007")
def test_writeFormat8(self): writer = OTTableWriter() font = FakeFont(".notdef A B C D E F G H".split()) self.converter.write(writer, font, {}, { "B": "B", "C": "A", "D": "B", "E": "C", "F": "B", "G": "A", }) self.assertEqual(writer.getData(), deHexStr( "0008 " # format=8 "0002 " # firstGlyph=B "0006 " # glyphCount=6 "0002 0001 0002 0003 0002 0001" # valueArray=[B, A, B, C, B, A] ))
def test_writeFormat8(self): writer = OTTableWriter() font = FakeFont(".notdef A B C D E F G H".split()) self.converter.write(writer, font, {}, { "B": "B", "C": "A", "D": "B", "E": "C", "F": "B", "G": "A", }) self.assertEqual( writer.getData(), deHexStr( "0008 " # format=8 "0002 " # firstGlyph=B "0006 " # glyphCount=6 "0002 0001 0002 0003 0002 0001" # valueArray=[B, A, B, C, B, A] ))
def test_writeFormat2(self): writer = OTTableWriter() font = FakeFont(".notdef A B C D E F G H".split()) self.converter.write(writer, font, {}, { "B": "C", "C": "C", "D": "C", "E": "C", "G": "A", "H": "A", }) self.assertEqual(writer.getData(), deHexStr( "0002 " # format=2 "0006 " # binSrchHeader.unitSize=6 "0002 " # binSrchHeader.nUnits=2 "000C " # binSrchHeader.searchRange=12 "0001 " # binSrchHeader.entrySelector=1 "0000 " # binSrchHeader.rangeShift=0 "0005 0002 0003 " # segments[0].lastGlyph=E, firstGlyph=B, value=C "0008 0007 0001 " # segments[1].lastGlyph=H, firstGlyph=G, value=A "FFFF FFFF 0000 " # segments[2]=<END> ))
def test_writeFormat6(self): writer = OTTableWriter() font = FakeFont(".notdef A B C D E".split()) self.converter.write(writer, font, {}, { "A": "C", "C": "B", "D": "D", "E": "E", }) self.assertEqual(writer.getData(), deHexStr( "0006 " # format=6 "0004 " # binSrchHeader.unitSize=4 "0004 " # binSrchHeader.nUnits=4 "0010 " # binSrchHeader.searchRange=16 "0002 " # binSrchHeader.entrySelector=2 "0000 " # binSrchHeader.rangeShift=0 "0001 0003 " # entries[0].glyph=A, .value=C "0003 0002 " # entries[1].glyph=C, .value=B "0004 0004 " # entries[2].glyph=D, .value=D "0005 0005 " # entries[3].glyph=E, .value=E "FFFF 0000 " # entries[4]=<END> ))
def main(args=None): from argparse import ArgumentParser from fontTools import configLogger from fontTools.ttLib import TTFont from fontTools.ttLib.tables.otBase import OTTableWriter parser = ArgumentParser(prog='varLib.varStore') parser.add_argument('fontfile') parser.add_argument('outfile', nargs='?') options = parser.parse_args(args) # TODO: allow user to configure logging via command-line options configLogger(level="INFO") fontfile = options.fontfile outfile = options.outfile font = TTFont(fontfile) gdef = font['GDEF'] store = gdef.table.VarStore writer = OTTableWriter() store.compile(writer, font) size = len(writer.getAllData()) print("Before: %7d bytes" % size) varidx_map = store.optimize() gdef.table.remap_device_varidxes(varidx_map) if 'GPOS' in font: font['GPOS'].table.remap_device_varidxes(varidx_map) writer = OTTableWriter() store.compile(writer, font) size = len(writer.getAllData()) print("After: %7d bytes" % size) if outfile is not None: font.save(outfile)
def test_writeFormat6(self): writer = OTTableWriter() font = FakeFont(".notdef A B C D E".split()) self.converter.write(writer, font, {}, { "A": "C", "C": "B", "D": "D", "E": "E", }) self.assertEqual( writer.getData(), deHexStr("0006 " # format=6 "0004 " # binSrchHeader.unitSize=4 "0004 " # binSrchHeader.nUnits=4 "0010 " # binSrchHeader.searchRange=16 "0002 " # binSrchHeader.entrySelector=2 "0000 " # binSrchHeader.rangeShift=0 "0001 0003 " # entries[0].glyph=A, .value=C "0003 0002 " # entries[1].glyph=C, .value=B "0004 0004 " # entries[2].glyph=D, .value=D "0005 0005 " # entries[3].glyph=E, .value=E "FFFF 0000 " # entries[4]=<END> ))
def test_writeFormat2(self): writer = OTTableWriter() font = FakeFont(".notdef A B C D E F G H".split()) self.converter.write(writer, font, {}, { "B": "C", "C": "C", "D": "C", "E": "C", "G": "A", "H": "A", }) self.assertEqual( writer.getData(), deHexStr( "0002 " # format=2 "0006 " # binSrchHeader.unitSize=6 "0002 " # binSrchHeader.nUnits=2 "000C " # binSrchHeader.searchRange=12 "0001 " # binSrchHeader.entrySelector=1 "0000 " # binSrchHeader.rangeShift=0 "0005 0002 0003 " # segments[0].lastGlyph=E, firstGlyph=B, value=C "0008 0007 0001 " # segments[1].lastGlyph=H, firstGlyph=G, value=A "FFFF FFFF 0000 " # segments[2]=<END> ))
def count_pairpos_bytes(font: TTFont) -> int: bytes = 0 gpos = font["GPOS"] for lookup in font["GPOS"].table.LookupList.Lookup: if lookup.LookupType == 2: w = OTTableWriter(tableTag=gpos.tableTag) lookup.compile(w, font) bytes += len(w.getAllData()) elif lookup.LookupType == 9: if any(subtable.ExtensionLookupType == 2 for subtable in lookup.SubTable): w = OTTableWriter(tableTag=gpos.tableTag) lookup.compile(w, font) bytes += len(w.getAllData()) return bytes
def main(args=None): """Optimize a font's GDEF variation store""" from argparse import ArgumentParser from fontTools import configLogger from fontTools.ttLib import TTFont from fontTools.ttLib.tables.otBase import OTTableWriter parser = ArgumentParser(prog='varLib.varStore', description=main.__doc__) parser.add_argument('fontfile') parser.add_argument('outfile', nargs='?') options = parser.parse_args(args) # TODO: allow user to configure logging via command-line options configLogger(level="INFO") fontfile = options.fontfile outfile = options.outfile font = TTFont(fontfile) gdef = font['GDEF'] store = gdef.table.VarStore writer = OTTableWriter() store.compile(writer, font) size = len(writer.getAllData()) print("Before: %7d bytes" % size) varidx_map = store.optimize() gdef.table.remap_device_varidxes(varidx_map) if 'GPOS' in font: font['GPOS'].table.remap_device_varidxes(varidx_map) writer = OTTableWriter() store.compile(writer, font) size = len(writer.getAllData()) print("After: %7d bytes" % size) if outfile is not None: font.save(outfile)
def test_write(self): writer = OTTableWriter(globalState={}) self.converter.write(writer, self.font, {}, "B") self.assertEqual(writer.getData(), deHexStr("0002"))
def _add_HVAR(font, model, master_ttfs, axisTags): log.info("Generating HVAR") hAdvanceDeltas = {} metricses = [m["hmtx"].metrics for m in master_ttfs] for glyph in font.getGlyphOrder(): hAdvances = [metrics[glyph][0] for metrics in metricses] # TODO move round somewhere else? hAdvanceDeltas[glyph] = tuple(otRound(d) for d in model.getDeltas(hAdvances)[1:]) # Direct mapping supports = model.supports[1:] varTupleList = builder.buildVarRegionList(supports, axisTags) varTupleIndexes = list(range(len(supports))) n = len(supports) items = [] for glyphName in font.getGlyphOrder(): items.append(hAdvanceDeltas[glyphName]) # Build indirect mapping to save on duplicates, compare both sizes uniq = list(set(items)) mapper = {v:i for i,v in enumerate(uniq)} mapping = [mapper[item] for item in items] advanceMapping = builder.buildVarIdxMap(mapping, font.getGlyphOrder()) # Direct varData = builder.buildVarData(varTupleIndexes, items) directStore = builder.buildVarStore(varTupleList, [varData]) # Indirect varData = builder.buildVarData(varTupleIndexes, uniq) indirectStore = builder.buildVarStore(varTupleList, [varData]) mapping = indirectStore.optimize() advanceMapping.mapping = {k:mapping[v] for k,v in advanceMapping.mapping.items()} # Compile both, see which is more compact writer = OTTableWriter() directStore.compile(writer, font) directSize = len(writer.getAllData()) writer = OTTableWriter() indirectStore.compile(writer, font) advanceMapping.compile(writer, font) indirectSize = len(writer.getAllData()) use_direct = directSize < indirectSize # Done; put it all together. assert "HVAR" not in font HVAR = font["HVAR"] = newTable('HVAR') hvar = HVAR.table = ot.HVAR() hvar.Version = 0x00010000 hvar.LsbMap = hvar.RsbMap = None if use_direct: hvar.VarStore = directStore hvar.AdvWidthMap = None else: hvar.VarStore = indirectStore hvar.AdvWidthMap = advanceMapping
def test_writeUInt8(self): writer = OTTableWriter() writer.writeUInt8(0xBE) self.assertEqual(writer.getData(), deHexStr("BE"))
def test_writeLong(self): writer = OTTableWriter(globalState={}) writer.writeLong(-12345678) self.assertEqual(writer.getData(), deHexStr("FF 43 9E B2"))
def test_writeUInt8(self): writer = OTTableWriter() writer.writeUInt8(0xBE) self.assertEqual(writer.getData(), deHexStr("BE"))
def _get_advance_metrics(font, masterModel, master_ttfs, axisTags, glyphOrder, advMetricses, vOrigMetricses=None): vhAdvanceDeltasAndSupports = {} vOrigDeltasAndSupports = {} for glyph in glyphOrder: vhAdvances = [ metrics[glyph][0] if glyph in metrics else None for metrics in advMetricses ] vhAdvanceDeltasAndSupports[glyph] = masterModel.getDeltasAndSupports( vhAdvances, round=round) singleModel = models.allEqual( id(v[1]) for v in vhAdvanceDeltasAndSupports.values()) if vOrigMetricses: singleModel = False for glyph in glyphOrder: # We need to supply a vOrigs tuple with non-None default values # for each glyph. vOrigMetricses contains values only for those # glyphs which have a non-default vOrig. vOrigs = [ metrics[glyph] if glyph in metrics else defaultVOrig for metrics, defaultVOrig in vOrigMetricses ] vOrigDeltasAndSupports[glyph] = masterModel.getDeltasAndSupports( vOrigs, round=round) directStore = None if singleModel: # Build direct mapping supports = next(iter(vhAdvanceDeltasAndSupports.values()))[1][1:] varTupleList = builder.buildVarRegionList(supports, axisTags) varTupleIndexes = list(range(len(supports))) varData = builder.buildVarData(varTupleIndexes, [], optimize=False) for glyphName in glyphOrder: varData.addItem(vhAdvanceDeltasAndSupports[glyphName][0], round=noRound) varData.optimize() directStore = builder.buildVarStore(varTupleList, [varData]) # Build optimized indirect mapping storeBuilder = varStore.OnlineVarStoreBuilder(axisTags) advMapping = {} for glyphName in glyphOrder: deltas, supports = vhAdvanceDeltasAndSupports[glyphName] storeBuilder.setSupports(supports) advMapping[glyphName] = storeBuilder.storeDeltas(deltas, round=noRound) if vOrigMetricses: vOrigMap = {} for glyphName in glyphOrder: deltas, supports = vOrigDeltasAndSupports[glyphName] storeBuilder.setSupports(supports) vOrigMap[glyphName] = storeBuilder.storeDeltas(deltas, round=noRound) indirectStore = storeBuilder.finish() mapping2 = indirectStore.optimize() advMapping = [mapping2[advMapping[g]] for g in glyphOrder] advanceMapping = builder.buildVarIdxMap(advMapping, glyphOrder) if vOrigMetricses: vOrigMap = [mapping2[vOrigMap[g]] for g in glyphOrder] useDirect = False vOrigMapping = None if directStore: # Compile both, see which is more compact writer = OTTableWriter() directStore.compile(writer, font) directSize = len(writer.getAllData()) writer = OTTableWriter() indirectStore.compile(writer, font) advanceMapping.compile(writer, font) indirectSize = len(writer.getAllData()) useDirect = directSize < indirectSize if useDirect: metricsStore = directStore advanceMapping = None else: metricsStore = indirectStore if vOrigMetricses: vOrigMapping = builder.buildVarIdxMap(vOrigMap, glyphOrder) return metricsStore, advanceMapping, vOrigMapping
def _add_HVAR(font, masterModel, master_ttfs, axisTags): log.info("Generating HVAR") glyphOrder = font.getGlyphOrder() hAdvanceDeltasAndSupports = {} metricses = [m["hmtx"].metrics for m in master_ttfs] for glyph in glyphOrder: hAdvances = [ metrics[glyph][0] if glyph in metrics else None for metrics in metricses ] hAdvanceDeltasAndSupports[glyph] = masterModel.getDeltasAndSupports( hAdvances) singleModel = models.allEqual( id(v[1]) for v in hAdvanceDeltasAndSupports.values()) directStore = None if singleModel: # Build direct mapping supports = next(iter(hAdvanceDeltasAndSupports.values()))[1][1:] varTupleList = builder.buildVarRegionList(supports, axisTags) varTupleIndexes = list(range(len(supports))) varData = builder.buildVarData(varTupleIndexes, [], optimize=False) for glyphName in glyphOrder: varData.addItem(hAdvanceDeltasAndSupports[glyphName][0]) varData.optimize() directStore = builder.buildVarStore(varTupleList, [varData]) # Build optimized indirect mapping storeBuilder = varStore.OnlineVarStoreBuilder(axisTags) mapping = {} for glyphName in glyphOrder: deltas, supports = hAdvanceDeltasAndSupports[glyphName] storeBuilder.setSupports(supports) mapping[glyphName] = storeBuilder.storeDeltas(deltas) indirectStore = storeBuilder.finish() mapping2 = indirectStore.optimize() mapping = [mapping2[mapping[g]] for g in glyphOrder] advanceMapping = builder.buildVarIdxMap(mapping, glyphOrder) use_direct = False if directStore: # Compile both, see which is more compact writer = OTTableWriter() directStore.compile(writer, font) directSize = len(writer.getAllData()) writer = OTTableWriter() indirectStore.compile(writer, font) advanceMapping.compile(writer, font) indirectSize = len(writer.getAllData()) use_direct = directSize < indirectSize # Done; put it all together. assert "HVAR" not in font HVAR = font["HVAR"] = newTable('HVAR') hvar = HVAR.table = ot.HVAR() hvar.Version = 0x00010000 hvar.LsbMap = hvar.RsbMap = None if use_direct: hvar.VarStore = directStore hvar.AdvWidthMap = None else: hvar.VarStore = indirectStore hvar.AdvWidthMap = advanceMapping
def test_writeULong(self): writer = OTTableWriter(globalState={}) writer.writeULong(0xBEEFCAFE) self.assertEqual(writer.getData(), deHexStr("BE EF CA FE"))
def test_write(self): writer = OTTableWriter() self.converter.write(writer, self.font, {}, "B") self.assertEqual(writer.getData(), deHexStr("0002"))
def test_write(self): writer = OTTableWriter() self.converter.write(writer, self.makeFont(), {}, 0x123) self.assertEqual(writer.getData(), deHexStr("0123"))
def _add_HVAR(font, model, master_ttfs, axisTags): log.info("Generating HVAR") hAdvanceDeltas = {} metricses = [m["hmtx"].metrics for m in master_ttfs] for glyph in font.getGlyphOrder(): hAdvances = [metrics[glyph][0] for metrics in metricses] # TODO move round somewhere else? hAdvanceDeltas[glyph] = tuple( round(d) for d in model.getDeltas(hAdvances)[1:]) # Direct mapping supports = model.supports[1:] varTupleList = builder.buildVarRegionList(supports, axisTags) varTupleIndexes = list(range(len(supports))) n = len(supports) items = [] for glyphName in font.getGlyphOrder(): items.append(hAdvanceDeltas[glyphName]) # Build indirect mapping to save on duplicates, compare both sizes uniq = list(set(items)) mapper = {v: i for i, v in enumerate(uniq)} mapping = [mapper[item] for item in items] advanceMapping = builder.buildVarIdxMap(mapping, font.getGlyphOrder()) # Direct varData = builder.buildVarData(varTupleIndexes, items) directStore = builder.buildVarStore(varTupleList, [varData]) # Indirect varData = builder.buildVarData(varTupleIndexes, uniq) indirectStore = builder.buildVarStore(varTupleList, [varData]) mapping = indirectStore.optimize() advanceMapping.mapping = { k: mapping[v] for k, v in advanceMapping.mapping.items() } # Compile both, see which is more compact writer = OTTableWriter() directStore.compile(writer, font) directSize = len(writer.getAllData()) writer = OTTableWriter() indirectStore.compile(writer, font) advanceMapping.compile(writer, font) indirectSize = len(writer.getAllData()) use_direct = directSize < indirectSize # Done; put it all together. assert "HVAR" not in font HVAR = font["HVAR"] = newTable('HVAR') hvar = HVAR.table = ot.HVAR() hvar.Version = 0x00010000 hvar.LsbMap = hvar.RsbMap = None if use_direct: hvar.VarStore = directStore hvar.AdvWidthMap = None else: hvar.VarStore = indirectStore hvar.AdvWidthMap = advanceMapping
def _add_HVAR(font, masterModel, master_ttfs, axisTags): log.info("Generating HVAR") glyphOrder = font.getGlyphOrder() hAdvanceDeltasAndSupports = {} metricses = [m["hmtx"].metrics for m in master_ttfs] for glyph in glyphOrder: hAdvances = [metrics[glyph][0] if glyph in metrics else None for metrics in metricses] hAdvanceDeltasAndSupports[glyph] = masterModel.getDeltasAndSupports(hAdvances) singleModel = models.allEqual(id(v[1]) for v in hAdvanceDeltasAndSupports.values()) directStore = None if singleModel: # Build direct mapping supports = next(iter(hAdvanceDeltasAndSupports.values()))[1][1:] varTupleList = builder.buildVarRegionList(supports, axisTags) varTupleIndexes = list(range(len(supports))) varData = builder.buildVarData(varTupleIndexes, [], optimize=False) for glyphName in glyphOrder: varData.addItem(hAdvanceDeltasAndSupports[glyphName][0]) varData.optimize() directStore = builder.buildVarStore(varTupleList, [varData]) # Build optimized indirect mapping storeBuilder = varStore.OnlineVarStoreBuilder(axisTags) mapping = {} for glyphName in glyphOrder: deltas,supports = hAdvanceDeltasAndSupports[glyphName] storeBuilder.setSupports(supports) mapping[glyphName] = storeBuilder.storeDeltas(deltas) indirectStore = storeBuilder.finish() mapping2 = indirectStore.optimize() mapping = [mapping2[mapping[g]] for g in glyphOrder] advanceMapping = builder.buildVarIdxMap(mapping, glyphOrder) use_direct = False if directStore: # Compile both, see which is more compact writer = OTTableWriter() directStore.compile(writer, font) directSize = len(writer.getAllData()) writer = OTTableWriter() indirectStore.compile(writer, font) advanceMapping.compile(writer, font) indirectSize = len(writer.getAllData()) use_direct = directSize < indirectSize # Done; put it all together. assert "HVAR" not in font HVAR = font["HVAR"] = newTable('HVAR') hvar = HVAR.table = ot.HVAR() hvar.Version = 0x00010000 hvar.LsbMap = hvar.RsbMap = None if use_direct: hvar.VarStore = directStore hvar.AdvWidthMap = None else: hvar.VarStore = indirectStore hvar.AdvWidthMap = advanceMapping
def test_write(self): writer = OTTableWriter() self.converter.write(writer, self.font, {}, -16777213) self.assertEqual(writer.getData(), deHexStr("FF000003"))
def test_write(self): writer = OTTableWriter() self.converter.write(writer, self.font, {}, "Hello world") self.assertEqual(writer.getData(), b"Hello world" + 53 * b"\0")
def test_write(self): writer = OTTableWriter() self.converter.write(writer, self.font, {}, "Hello world") self.assertEqual(writer.getData(), b"Hello world" + 53 * b"\0")
def _get_advance_metrics(font, masterModel, master_ttfs, axisTags, glyphOrder, advMetricses, vOrigMetricses=None): vhAdvanceDeltasAndSupports = {} vOrigDeltasAndSupports = {} for glyph in glyphOrder: vhAdvances = [metrics[glyph][0] if glyph in metrics else None for metrics in advMetricses] vhAdvanceDeltasAndSupports[glyph] = masterModel.getDeltasAndSupports(vhAdvances) singleModel = models.allEqual(id(v[1]) for v in vhAdvanceDeltasAndSupports.values()) if vOrigMetricses: singleModel = False for glyph in glyphOrder: # We need to supply a vOrigs tuple with non-None default values # for each glyph. vOrigMetricses contains values only for those # glyphs which have a non-default vOrig. vOrigs = [metrics[glyph] if glyph in metrics else defaultVOrig for metrics, defaultVOrig in vOrigMetricses] vOrigDeltasAndSupports[glyph] = masterModel.getDeltasAndSupports(vOrigs) directStore = None if singleModel: # Build direct mapping supports = next(iter(vhAdvanceDeltasAndSupports.values()))[1][1:] varTupleList = builder.buildVarRegionList(supports, axisTags) varTupleIndexes = list(range(len(supports))) varData = builder.buildVarData(varTupleIndexes, [], optimize=False) for glyphName in glyphOrder: varData.addItem(vhAdvanceDeltasAndSupports[glyphName][0]) varData.optimize() directStore = builder.buildVarStore(varTupleList, [varData]) # Build optimized indirect mapping storeBuilder = varStore.OnlineVarStoreBuilder(axisTags) advMapping = {} for glyphName in glyphOrder: deltas, supports = vhAdvanceDeltasAndSupports[glyphName] storeBuilder.setSupports(supports) advMapping[glyphName] = storeBuilder.storeDeltas(deltas) if vOrigMetricses: vOrigMap = {} for glyphName in glyphOrder: deltas, supports = vOrigDeltasAndSupports[glyphName] storeBuilder.setSupports(supports) vOrigMap[glyphName] = storeBuilder.storeDeltas(deltas) indirectStore = storeBuilder.finish() mapping2 = indirectStore.optimize() advMapping = [mapping2[advMapping[g]] for g in glyphOrder] advanceMapping = builder.buildVarIdxMap(advMapping, glyphOrder) if vOrigMetricses: vOrigMap = [mapping2[vOrigMap[g]] for g in glyphOrder] useDirect = False vOrigMapping = None if directStore: # Compile both, see which is more compact writer = OTTableWriter() directStore.compile(writer, font) directSize = len(writer.getAllData()) writer = OTTableWriter() indirectStore.compile(writer, font) advanceMapping.compile(writer, font) indirectSize = len(writer.getAllData()) useDirect = directSize < indirectSize if useDirect: metricsStore = directStore advanceMapping = None else: metricsStore = indirectStore if vOrigMetricses: vOrigMapping = builder.buildVarIdxMap(vOrigMap, glyphOrder) return metricsStore, advanceMapping, vOrigMapping
def test_write(self): writer = OTTableWriter() self.converter.write(writer, self.makeFont(), {}, 0x123) self.assertEqual(writer.getData(), deHexStr("0123"))
def test_writeUShort(self): writer = OTTableWriter(globalState={}) writer.writeUShort(0xBEEF) self.assertEqual(writer.getData(), deHexStr("BE EF"))
def test_writeShort(self): writer = OTTableWriter(globalState={}) writer.writeShort(-12345) self.assertEqual(writer.getData(), deHexStr("CF C7"))
def test_write(self): writer = OTTableWriter() self.converter.write(writer, self.font, {}, -16777213) self.assertEqual(writer.getData(), deHexStr("FF000003"))
def test_writeUInt24(self): writer = OTTableWriter(globalState={}) writer.writeUInt24(0xBEEF77) self.assertEqual(writer.getData(), deHexStr("BE EF 77"))