Exemplo n.º 1
0
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
Exemplo n.º 2
0
 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])
Exemplo n.º 3
0
 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])
Exemplo n.º 4
0
 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])
Exemplo n.º 5
0
 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])
Exemplo n.º 6
0
 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")
Exemplo n.º 7
0
 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")
Exemplo n.º 8
0
 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")
Exemplo n.º 9
0
    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")
Exemplo n.º 10
0
 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")
Exemplo n.º 11
0
 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"))
Exemplo n.º 12
0
 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"))
Exemplo n.º 13
0
 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")
Exemplo n.º 14
0
 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]
     ))
Exemplo n.º 15
0
 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]
         ))
Exemplo n.º 16
0
 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>
     ))
Exemplo n.º 17
0
 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>
     ))
Exemplo n.º 18
0
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)
Exemplo n.º 19
0
 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>
                  ))
Exemplo n.º 20
0
 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>
         ))
Exemplo n.º 21
0
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
Exemplo n.º 22
0
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)
Exemplo n.º 23
0
 def test_write(self):
     writer = OTTableWriter(globalState={})
     self.converter.write(writer, self.font, {}, "B")
     self.assertEqual(writer.getData(), deHexStr("0002"))
Exemplo n.º 24
0
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
Exemplo n.º 25
0
 def test_writeUInt8(self):
     writer = OTTableWriter()
     writer.writeUInt8(0xBE)
     self.assertEqual(writer.getData(), deHexStr("BE"))
Exemplo n.º 26
0
 def test_writeLong(self):
     writer = OTTableWriter(globalState={})
     writer.writeLong(-12345678)
     self.assertEqual(writer.getData(), deHexStr("FF 43 9E B2"))
Exemplo n.º 27
0
 def test_writeUInt8(self):
     writer = OTTableWriter()
     writer.writeUInt8(0xBE)
     self.assertEqual(writer.getData(), deHexStr("BE"))
Exemplo n.º 28
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, 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
Exemplo n.º 29
0
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
Exemplo n.º 30
0
 def test_writeULong(self):
     writer = OTTableWriter(globalState={})
     writer.writeULong(0xBEEFCAFE)
     self.assertEqual(writer.getData(), deHexStr("BE EF CA FE"))
Exemplo n.º 31
0
 def test_write(self):
     writer = OTTableWriter()
     self.converter.write(writer, self.font, {}, "B")
     self.assertEqual(writer.getData(), deHexStr("0002"))
Exemplo n.º 32
0
 def test_write(self):
     writer = OTTableWriter()
     self.converter.write(writer, self.makeFont(), {}, 0x123)
     self.assertEqual(writer.getData(), deHexStr("0123"))
Exemplo n.º 33
0
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
Exemplo n.º 34
0
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
Exemplo n.º 35
0
 def test_write(self):
     writer = OTTableWriter()
     self.converter.write(writer, self.font, {}, -16777213)
     self.assertEqual(writer.getData(), deHexStr("FF000003"))
Exemplo n.º 36
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")
Exemplo n.º 37
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")
Exemplo n.º 38
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
Exemplo n.º 39
0
 def test_write(self):
     writer = OTTableWriter()
     self.converter.write(writer, self.makeFont(), {}, 0x123)
     self.assertEqual(writer.getData(), deHexStr("0123"))
Exemplo n.º 40
0
 def test_writeUShort(self):
     writer = OTTableWriter(globalState={})
     writer.writeUShort(0xBEEF)
     self.assertEqual(writer.getData(), deHexStr("BE EF"))
Exemplo n.º 41
0
 def test_writeShort(self):
     writer = OTTableWriter(globalState={})
     writer.writeShort(-12345)
     self.assertEqual(writer.getData(), deHexStr("CF C7"))
Exemplo n.º 42
0
 def test_write(self):
     writer = OTTableWriter()
     self.converter.write(writer, self.font, {}, -16777213)
     self.assertEqual(writer.getData(), deHexStr("FF000003"))
Exemplo n.º 43
0
 def test_writeUInt24(self):
     writer = OTTableWriter(globalState={})
     writer.writeUInt24(0xBEEF77)
     self.assertEqual(writer.getData(), deHexStr("BE EF 77"))