def test_buildSinglePos_ValueFormat0(self): subtables = builder.buildSinglePos({"zero": builder.buildValue({})}, self.GLYPHMAP) assert sum([getXML(t.toXML) for t in subtables], []) == [ '<SinglePos Format="1">', " <Coverage>", ' <Glyph value="zero"/>', " </Coverage>", ' <ValueFormat value="0"/>', "</SinglePos>", ]
def test_buildSinglePos_ValueFormat0(self): subtables = builder.buildSinglePos({ "zero": builder.buildValue({}) }, self.GLYPHMAP) self.assertEqual(''.join([getXML(t.toXML) for t in subtables]), '<SinglePos Format="1">' ' <Coverage>' ' <Glyph value="zero"/>' ' </Coverage>' ' <ValueFormat value="0"/>' '</SinglePos>')
def test_buildSinglePos(self): subtables = builder.buildSinglePos( { "one": builder.buildValue({"XPlacement": 500}), "two": builder.buildValue({"XPlacement": 500}), "three": builder.buildValue({"XPlacement": 200}), "four": builder.buildValue({"XPlacement": 400}), "five": builder.buildValue({"XPlacement": 500}), "six": builder.buildValue({"YPlacement": -6}), }, self.GLYPHMAP) self.assertEqual( ''.join([getXML(t.toXML) for t in subtables]), '<SinglePos Format="1">' ' <Coverage>' ' <Glyph value="one"/>' ' <Glyph value="two"/>' ' <Glyph value="five"/>' ' </Coverage>' ' <ValueFormat value="1"/>' ' <Value XPlacement="500"/>' '</SinglePos>' '<SinglePos Format="2">' ' <Coverage>' ' <Glyph value="three"/>' ' <Glyph value="four"/>' ' </Coverage>' ' <ValueFormat value="1"/>' ' <!-- ValueCount=2 -->' ' <Value index="0" XPlacement="200"/>' ' <Value index="1" XPlacement="400"/>' '</SinglePos>' '<SinglePos Format="1">' ' <Coverage>' ' <Glyph value="six"/>' ' </Coverage>' ' <ValueFormat value="2"/>' ' <Value YPlacement="-6"/>' '</SinglePos>')
def test_buildSinglePos(self): subtables = builder.buildSinglePos( { "one": builder.buildValue({"XPlacement": 500}), "two": builder.buildValue({"XPlacement": 500}), "three": builder.buildValue({"XPlacement": 200}), "four": builder.buildValue({"XPlacement": 400}), "five": builder.buildValue({"XPlacement": 500}), "six": builder.buildValue({"YPlacement": -6}), }, self.GLYPHMAP, ) assert sum([getXML(t.toXML) for t in subtables], []) == [ '<SinglePos Format="2">', " <Coverage>", ' <Glyph value="one"/>', ' <Glyph value="two"/>', ' <Glyph value="three"/>', ' <Glyph value="four"/>', ' <Glyph value="five"/>', " </Coverage>", ' <ValueFormat value="1"/>', " <!-- ValueCount=5 -->", ' <Value index="0" XPlacement="500"/>', ' <Value index="1" XPlacement="500"/>', ' <Value index="2" XPlacement="200"/>', ' <Value index="3" XPlacement="400"/>', ' <Value index="4" XPlacement="500"/>', "</SinglePos>", '<SinglePos Format="1">', " <Coverage>", ' <Glyph value="six"/>', " </Coverage>", ' <ValueFormat value="2"/>', ' <Value YPlacement="-6"/>', "</SinglePos>", ]
def test_buildSinglePos(self): subtables = builder.buildSinglePos({ "one": builder.buildValue({"XPlacement": 500}), "two": builder.buildValue({"XPlacement": 500}), "three": builder.buildValue({"XPlacement": 200}), "four": builder.buildValue({"XPlacement": 400}), "five": builder.buildValue({"XPlacement": 500}), "six": builder.buildValue({"YPlacement": -6}), }, self.GLYPHMAP) self.assertEqual(''.join([getXML(t.toXML) for t in subtables]), '<SinglePos Format="1">' ' <Coverage>' ' <Glyph value="one"/>' ' <Glyph value="two"/>' ' <Glyph value="five"/>' ' </Coverage>' ' <ValueFormat value="1"/>' ' <Value XPlacement="500"/>' '</SinglePos>' '<SinglePos Format="2">' ' <Coverage>' ' <Glyph value="three"/>' ' <Glyph value="four"/>' ' </Coverage>' ' <ValueFormat value="1"/>' ' <!-- ValueCount=2 -->' ' <Value index="0" XPlacement="200"/>' ' <Value index="1" XPlacement="400"/>' '</SinglePos>' '<SinglePos Format="1">' ' <Coverage>' ' <Glyph value="six"/>' ' </Coverage>' ' <ValueFormat value="2"/>' ' <Value YPlacement="-6"/>' '</SinglePos>')
def merge(merger, self, lst): subtables = merger.lookup_subtables = [l.SubTable for l in lst] # Remove Extension subtables for l, sts in list(zip(lst, subtables)) + [(self, self.SubTable)]: if not sts: continue if sts[0].__class__.__name__.startswith('Extension'): if not allEqual([st.__class__ for st in sts]): raise InconsistentExtensions( self, expected="Extension", got=[st.__class__.__name__ for st in sts]) if not allEqual([st.ExtensionLookupType for st in sts]): raise InconsistentExtensions(self) l.LookupType = sts[0].ExtensionLookupType new_sts = [st.ExtSubTable for st in sts] del sts[:] sts.extend(new_sts) isPairPos = self.SubTable and isinstance(self.SubTable[0], ot.PairPos) if isPairPos: # AFDKO and feaLib sometimes generate two Format1 subtables instead of one. # Merge those before continuing. # https://github.com/fonttools/fonttools/issues/719 self.SubTable = _Lookup_PairPos_subtables_canonicalize( self.SubTable, merger.font) subtables = merger.lookup_subtables = [ _Lookup_PairPos_subtables_canonicalize(st, merger.font) for st in subtables ] else: isSinglePos = self.SubTable and isinstance(self.SubTable[0], ot.SinglePos) if isSinglePos: numSubtables = [len(st) for st in subtables] if not all([nums == numSubtables[0] for nums in numSubtables]): # Flatten list of SinglePos subtables to single Format 2 subtable, # with all value records set to the rec format type. # We use buildSinglePos() to optimize the lookup after merging. valueFormatList = [ t.ValueFormat for st in subtables for t in st ] # Find the minimum value record that can accomodate all the singlePos subtables. mirf = reduce(ior, valueFormatList) self.SubTable = _Lookup_SinglePos_subtables_flatten( self.SubTable, merger.font, mirf) subtables = merger.lookup_subtables = [ _Lookup_SinglePos_subtables_flatten(st, merger.font, mirf) for st in subtables ] flattened = True else: flattened = False merger.mergeLists(self.SubTable, subtables) self.SubTableCount = len(self.SubTable) if isPairPos: # If format-1 subtable created during canonicalization is empty, remove it. assert len(self.SubTable) >= 1 and self.SubTable[0].Format == 1 if not self.SubTable[0].Coverage.glyphs: self.SubTable.pop(0) self.SubTableCount -= 1 # If format-2 subtable created during canonicalization is empty, remove it. assert len(self.SubTable) >= 1 and self.SubTable[-1].Format == 2 if not self.SubTable[-1].Coverage.glyphs: self.SubTable.pop(-1) self.SubTableCount -= 1 elif isSinglePos and flattened: singlePosTable = self.SubTable[0] glyphs = singlePosTable.Coverage.glyphs # We know that singlePosTable is Format 2, as this is set # in _Lookup_SinglePos_subtables_flatten. singlePosMapping = { gname: valRecord for gname, valRecord in zip(glyphs, singlePosTable.Value) } self.SubTable = buildSinglePos(singlePosMapping, merger.font.getReverseGlyphMap()) merger.mergeObjects(self, lst, exclude=['SubTable', 'SubTableCount']) del merger.lookup_subtables
def build(self): subtables = otl.buildSinglePos(self.mapping, self.glyphMap) return self.buildLookup_(subtables)
def merge(merger, self, lst): subtables = merger.lookup_subtables = [l.SubTable for l in lst] # Remove Extension subtables for l,sts in list(zip(lst,subtables))+[(self,self.SubTable)]: if not sts: continue if sts[0].__class__.__name__.startswith('Extension'): if not allEqual([st.__class__ for st in sts]): raise InconsistentExtensions( merger, expected="Extension", got=[st.__class__.__name__ for st in sts] ) if not allEqual([st.ExtensionLookupType for st in sts]): raise InconsistentExtensions(merger) l.LookupType = sts[0].ExtensionLookupType new_sts = [st.ExtSubTable for st in sts] del sts[:] sts.extend(new_sts) isPairPos = self.SubTable and isinstance(self.SubTable[0], ot.PairPos) if isPairPos: # AFDKO and feaLib sometimes generate two Format1 subtables instead of one. # Merge those before continuing. # https://github.com/fonttools/fonttools/issues/719 self.SubTable = _Lookup_PairPos_subtables_canonicalize(self.SubTable, merger.font) subtables = merger.lookup_subtables = [_Lookup_PairPos_subtables_canonicalize(st, merger.font) for st in subtables] else: isSinglePos = self.SubTable and isinstance(self.SubTable[0], ot.SinglePos) if isSinglePos: numSubtables = [len(st) for st in subtables] if not all([nums == numSubtables[0] for nums in numSubtables]): # Flatten list of SinglePos subtables to single Format 2 subtable, # with all value records set to the rec format type. # We use buildSinglePos() to optimize the lookup after merging. valueFormatList = [t.ValueFormat for st in subtables for t in st] # Find the minimum value record that can accomodate all the singlePos subtables. mirf = reduce(ior, valueFormatList) self.SubTable = _Lookup_SinglePos_subtables_flatten(self.SubTable, merger.font, mirf) subtables = merger.lookup_subtables = [ _Lookup_SinglePos_subtables_flatten(st, merger.font, mirf) for st in subtables] flattened = True else: flattened = False merger.mergeLists(self.SubTable, subtables) self.SubTableCount = len(self.SubTable) if isPairPos: # If format-1 subtable created during canonicalization is empty, remove it. assert len(self.SubTable) >= 1 and self.SubTable[0].Format == 1 if not self.SubTable[0].Coverage.glyphs: self.SubTable.pop(0) self.SubTableCount -= 1 # If format-2 subtable created during canonicalization is empty, remove it. assert len(self.SubTable) >= 1 and self.SubTable[-1].Format == 2 if not self.SubTable[-1].Coverage.glyphs: self.SubTable.pop(-1) self.SubTableCount -= 1 # Compact the merged subtables # This is a good moment to do it because the compaction should create # smaller subtables, which may prevent overflows from happening. # Keep reading the value from the ENV until ufo2ft switches to the config system level = merger.font.cfg.get( "fontTools.otlLib.optimize.gpos:COMPRESSION_LEVEL", default=_compression_level_from_env(), ) if level != 0: log.info("Compacting GPOS...") self.SubTable = compact_pair_pos(merger.font, level, self.SubTable) self.SubTableCount = len(self.SubTable) elif isSinglePos and flattened: singlePosTable = self.SubTable[0] glyphs = singlePosTable.Coverage.glyphs # We know that singlePosTable is Format 2, as this is set # in _Lookup_SinglePos_subtables_flatten. singlePosMapping = { gname: valRecord for gname, valRecord in zip(glyphs, singlePosTable.Value) } self.SubTable = buildSinglePos(singlePosMapping, merger.font.getReverseGlyphMap()) merger.mergeObjects(self, lst, exclude=['SubTable', 'SubTableCount']) del merger.lookup_subtables