from fontTools.misc.testTools import FakeFont, getXML, parseXML from fontTools.misc.textTools import deHexStr, hexStr from fontTools.ttLib import newTable import unittest # Glyph Metamorphosis Table Examples # Example 1: Non-contextual Glyph Substitution # https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6mort.html # The example given by Apple's 'mort' specification is suboptimally # encoded: it uses AAT lookup format 6 even though format 8 would be # more compact. Because our encoder always uses the most compact # encoding, this breaks our round-trip testing. Therefore, we changed # the example to use GlyphID 13 instead of 12 for the 'parenright' # character; the non-contiguous glyph range for the AAT lookup makes # format 6 to be most compact. MORT_NONCONTEXTUAL_DATA = deHexStr( "0001 0000 " # 0: Version=1.0 "0000 0001 " # 4: MorphChainCount=1 "0000 0001 " # 8: DefaultFlags=1 "0000 0050 " # 12: StructLength=80 "0003 0001 " # 16: MorphFeatureCount=3, MorphSubtableCount=1 "0004 0000 " # 20: Feature[0].FeatureType=4/VertSubst, .FeatureSetting=on "0000 0001 " # 24: Feature[0].EnableFlags=0x00000001 "FFFF FFFF " # 28: Feature[0].DisableFlags=0xFFFFFFFF "0004 0001 " # 32: Feature[1].FeatureType=4/VertSubst, .FeatureSetting=off "0000 0000 " # 36: Feature[1].EnableFlags=0x00000000 "FFFF FFFE " # 40: Feature[1].DisableFlags=0xFFFFFFFE "0000 0001 " # 44: Feature[2].FeatureType=0/GlyphEffects, .FeatSetting=off "0000 0000 " # 48: Feature[2].EnableFlags=0 (required for last feature) "0000 0000 " # 52: Feature[2].EnableFlags=0 (required for last feature) "0020 " # 56: Subtable[0].StructLength=32 "80 " # 58: Subtable[0].CoverageFlags=0x80 "04 " # 59: Subtable[0].MorphType=4/NoncontextualMorph "0000 0001 " # 60: Subtable[0].SubFeatureFlags=0x1 "0006 0004 " # 64: LookupFormat=6, UnitSize=4 "0002 0008 " # 68: NUnits=2, SearchRange=8 "0001 0000 " # 72: EntrySelector=1, RangeShift=0 "000B 0087 " # 76: Glyph=11 (parenleft); Value=135 (parenleft.vertical) "000D 0088 " # 80: Glyph=13 (parenright); Value=136 (parenright.vertical) "FFFF 0000 " # 84: Glyph=; Value=0 ) # 88: assert len(MORT_NONCONTEXTUAL_DATA) == 88 MORT_NONCONTEXTUAL_XML = [ '', "", '', ' ', " ", " ", " ", ' ', ' ', ' ', ' ', ' ', " ", ' ', ' ', ' ', ' ', ' ', " ", ' ', ' ', ' ', ' ', ' ', " ", ' ', " ", ' ', " ", ' ', " ", " ", ' ', ' ', " ", " ", " ", "", ] class MORTNoncontextualGlyphSubstitutionTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.maxDiff = None glyphs = [".notdef"] + ["g.%d" % i for i in range(1, 140)] glyphs[11], glyphs[13] = "parenleft", "parenright" glyphs[135], glyphs[136] = "parenleft.vertical", "parenright.vertical" cls.font = FakeFont(glyphs) def test_decompile_toXML(self): table = newTable("mort") table.decompile(MORT_NONCONTEXTUAL_DATA, self.font) self.assertEqual(getXML(table.toXML), MORT_NONCONTEXTUAL_XML) def test_compile_fromXML(self): table = newTable("mort") for name, attrs, content in parseXML(MORT_NONCONTEXTUAL_XML): table.fromXML(name, attrs, content, font=self.font) self.assertEqual( hexStr(table.compile(self.font)), hexStr(MORT_NONCONTEXTUAL_DATA) ) if __name__ == "__main__": import sys sys.exit(unittest.main())