1*e1fe3e4aSElliott Hughesfrom fontTools.misc.testTools import getXML, parseXML, parseXmlInto, FakeFont 2*e1fe3e4aSElliott Hughesfrom fontTools.misc.textTools import deHexStr, hexStr 3*e1fe3e4aSElliott Hughesfrom fontTools.misc.xmlWriter import XMLWriter 4*e1fe3e4aSElliott Hughesfrom fontTools.ttLib.tables.otBase import OTTableReader, OTTableWriter 5*e1fe3e4aSElliott Hughesimport fontTools.ttLib.tables.otTables as otTables 6*e1fe3e4aSElliott Hughesfrom io import StringIO 7*e1fe3e4aSElliott Hughesimport unittest 8*e1fe3e4aSElliott Hughes 9*e1fe3e4aSElliott Hughes 10*e1fe3e4aSElliott Hughesdef makeCoverage(glyphs): 11*e1fe3e4aSElliott Hughes coverage = otTables.Coverage() 12*e1fe3e4aSElliott Hughes coverage.glyphs = glyphs 13*e1fe3e4aSElliott Hughes return coverage 14*e1fe3e4aSElliott Hughes 15*e1fe3e4aSElliott Hughes 16*e1fe3e4aSElliott Hughesclass SingleSubstTest(unittest.TestCase): 17*e1fe3e4aSElliott Hughes def setUp(self): 18*e1fe3e4aSElliott Hughes self.glyphs = ".notdef A B C D E a b c d e".split() 19*e1fe3e4aSElliott Hughes self.font = FakeFont(self.glyphs) 20*e1fe3e4aSElliott Hughes 21*e1fe3e4aSElliott Hughes def test_postRead_format1(self): 22*e1fe3e4aSElliott Hughes table = otTables.SingleSubst() 23*e1fe3e4aSElliott Hughes table.Format = 1 24*e1fe3e4aSElliott Hughes rawTable = {"Coverage": makeCoverage(["A", "B", "C"]), "DeltaGlyphID": 5} 25*e1fe3e4aSElliott Hughes table.postRead(rawTable, self.font) 26*e1fe3e4aSElliott Hughes self.assertEqual(table.mapping, {"A": "a", "B": "b", "C": "c"}) 27*e1fe3e4aSElliott Hughes 28*e1fe3e4aSElliott Hughes def test_postRead_format2(self): 29*e1fe3e4aSElliott Hughes table = otTables.SingleSubst() 30*e1fe3e4aSElliott Hughes table.Format = 2 31*e1fe3e4aSElliott Hughes rawTable = { 32*e1fe3e4aSElliott Hughes "Coverage": makeCoverage(["A", "B", "C"]), 33*e1fe3e4aSElliott Hughes "GlyphCount": 3, 34*e1fe3e4aSElliott Hughes "Substitute": ["c", "b", "a"], 35*e1fe3e4aSElliott Hughes } 36*e1fe3e4aSElliott Hughes table.postRead(rawTable, self.font) 37*e1fe3e4aSElliott Hughes self.assertEqual(table.mapping, {"A": "c", "B": "b", "C": "a"}) 38*e1fe3e4aSElliott Hughes 39*e1fe3e4aSElliott Hughes def test_postRead_formatUnknown(self): 40*e1fe3e4aSElliott Hughes table = otTables.SingleSubst() 41*e1fe3e4aSElliott Hughes table.Format = 987 42*e1fe3e4aSElliott Hughes rawTable = {"Coverage": makeCoverage(["A", "B", "C"])} 43*e1fe3e4aSElliott Hughes self.assertRaises(AssertionError, table.postRead, rawTable, self.font) 44*e1fe3e4aSElliott Hughes 45*e1fe3e4aSElliott Hughes def test_preWrite_format1(self): 46*e1fe3e4aSElliott Hughes table = otTables.SingleSubst() 47*e1fe3e4aSElliott Hughes table.mapping = {"A": "a", "B": "b", "C": "c"} 48*e1fe3e4aSElliott Hughes rawTable = table.preWrite(self.font) 49*e1fe3e4aSElliott Hughes self.assertEqual(table.Format, 1) 50*e1fe3e4aSElliott Hughes self.assertEqual(rawTable["Coverage"].glyphs, ["A", "B", "C"]) 51*e1fe3e4aSElliott Hughes self.assertEqual(rawTable["DeltaGlyphID"], 5) 52*e1fe3e4aSElliott Hughes 53*e1fe3e4aSElliott Hughes def test_preWrite_format2(self): 54*e1fe3e4aSElliott Hughes table = otTables.SingleSubst() 55*e1fe3e4aSElliott Hughes table.mapping = {"A": "c", "B": "b", "C": "a"} 56*e1fe3e4aSElliott Hughes rawTable = table.preWrite(self.font) 57*e1fe3e4aSElliott Hughes self.assertEqual(table.Format, 2) 58*e1fe3e4aSElliott Hughes self.assertEqual(rawTable["Coverage"].glyphs, ["A", "B", "C"]) 59*e1fe3e4aSElliott Hughes self.assertEqual(rawTable["Substitute"], ["c", "b", "a"]) 60*e1fe3e4aSElliott Hughes 61*e1fe3e4aSElliott Hughes def test_preWrite_emptyMapping(self): 62*e1fe3e4aSElliott Hughes table = otTables.SingleSubst() 63*e1fe3e4aSElliott Hughes table.mapping = {} 64*e1fe3e4aSElliott Hughes rawTable = table.preWrite(self.font) 65*e1fe3e4aSElliott Hughes self.assertEqual(table.Format, 2) 66*e1fe3e4aSElliott Hughes self.assertEqual(rawTable["Coverage"].glyphs, []) 67*e1fe3e4aSElliott Hughes self.assertEqual(rawTable["Substitute"], []) 68*e1fe3e4aSElliott Hughes 69*e1fe3e4aSElliott Hughes def test_toXML2(self): 70*e1fe3e4aSElliott Hughes writer = XMLWriter(StringIO()) 71*e1fe3e4aSElliott Hughes table = otTables.SingleSubst() 72*e1fe3e4aSElliott Hughes table.mapping = {"A": "a", "B": "b", "C": "c"} 73*e1fe3e4aSElliott Hughes table.toXML2(writer, self.font) 74*e1fe3e4aSElliott Hughes self.assertEqual( 75*e1fe3e4aSElliott Hughes writer.file.getvalue().splitlines()[1:], 76*e1fe3e4aSElliott Hughes [ 77*e1fe3e4aSElliott Hughes '<Substitution in="A" out="a"/>', 78*e1fe3e4aSElliott Hughes '<Substitution in="B" out="b"/>', 79*e1fe3e4aSElliott Hughes '<Substitution in="C" out="c"/>', 80*e1fe3e4aSElliott Hughes ], 81*e1fe3e4aSElliott Hughes ) 82*e1fe3e4aSElliott Hughes 83*e1fe3e4aSElliott Hughes def test_fromXML(self): 84*e1fe3e4aSElliott Hughes table = otTables.SingleSubst() 85*e1fe3e4aSElliott Hughes for name, attrs, content in parseXML( 86*e1fe3e4aSElliott Hughes '<Substitution in="A" out="a"/>' 87*e1fe3e4aSElliott Hughes '<Substitution in="B" out="b"/>' 88*e1fe3e4aSElliott Hughes '<Substitution in="C" out="c"/>' 89*e1fe3e4aSElliott Hughes ): 90*e1fe3e4aSElliott Hughes table.fromXML(name, attrs, content, self.font) 91*e1fe3e4aSElliott Hughes self.assertEqual(table.mapping, {"A": "a", "B": "b", "C": "c"}) 92*e1fe3e4aSElliott Hughes 93*e1fe3e4aSElliott Hughes 94*e1fe3e4aSElliott Hughesclass MultipleSubstTest(unittest.TestCase): 95*e1fe3e4aSElliott Hughes def setUp(self): 96*e1fe3e4aSElliott Hughes self.glyphs = ".notdef c f i t c_t f_f_i".split() 97*e1fe3e4aSElliott Hughes self.font = FakeFont(self.glyphs) 98*e1fe3e4aSElliott Hughes 99*e1fe3e4aSElliott Hughes def test_postRead_format1(self): 100*e1fe3e4aSElliott Hughes makeSequence = otTables.MultipleSubst.makeSequence_ 101*e1fe3e4aSElliott Hughes table = otTables.MultipleSubst() 102*e1fe3e4aSElliott Hughes table.Format = 1 103*e1fe3e4aSElliott Hughes rawTable = { 104*e1fe3e4aSElliott Hughes "Coverage": makeCoverage(["c_t", "f_f_i"]), 105*e1fe3e4aSElliott Hughes "Sequence": [makeSequence(["c", "t"]), makeSequence(["f", "f", "i"])], 106*e1fe3e4aSElliott Hughes } 107*e1fe3e4aSElliott Hughes table.postRead(rawTable, self.font) 108*e1fe3e4aSElliott Hughes self.assertEqual(table.mapping, {"c_t": ["c", "t"], "f_f_i": ["f", "f", "i"]}) 109*e1fe3e4aSElliott Hughes 110*e1fe3e4aSElliott Hughes def test_postRead_formatUnknown(self): 111*e1fe3e4aSElliott Hughes table = otTables.MultipleSubst() 112*e1fe3e4aSElliott Hughes table.Format = 987 113*e1fe3e4aSElliott Hughes self.assertRaises(AssertionError, table.postRead, {}, self.font) 114*e1fe3e4aSElliott Hughes 115*e1fe3e4aSElliott Hughes def test_preWrite_format1(self): 116*e1fe3e4aSElliott Hughes table = otTables.MultipleSubst() 117*e1fe3e4aSElliott Hughes table.mapping = {"c_t": ["c", "t"], "f_f_i": ["f", "f", "i"]} 118*e1fe3e4aSElliott Hughes rawTable = table.preWrite(self.font) 119*e1fe3e4aSElliott Hughes self.assertEqual(table.Format, 1) 120*e1fe3e4aSElliott Hughes self.assertEqual(rawTable["Coverage"].glyphs, ["c_t", "f_f_i"]) 121*e1fe3e4aSElliott Hughes 122*e1fe3e4aSElliott Hughes def test_toXML2(self): 123*e1fe3e4aSElliott Hughes writer = XMLWriter(StringIO()) 124*e1fe3e4aSElliott Hughes table = otTables.MultipleSubst() 125*e1fe3e4aSElliott Hughes table.mapping = {"c_t": ["c", "t"], "f_f_i": ["f", "f", "i"]} 126*e1fe3e4aSElliott Hughes table.toXML2(writer, self.font) 127*e1fe3e4aSElliott Hughes self.assertEqual( 128*e1fe3e4aSElliott Hughes writer.file.getvalue().splitlines()[1:], 129*e1fe3e4aSElliott Hughes [ 130*e1fe3e4aSElliott Hughes '<Substitution in="c_t" out="c,t"/>', 131*e1fe3e4aSElliott Hughes '<Substitution in="f_f_i" out="f,f,i"/>', 132*e1fe3e4aSElliott Hughes ], 133*e1fe3e4aSElliott Hughes ) 134*e1fe3e4aSElliott Hughes 135*e1fe3e4aSElliott Hughes def test_fromXML(self): 136*e1fe3e4aSElliott Hughes table = otTables.MultipleSubst() 137*e1fe3e4aSElliott Hughes for name, attrs, content in parseXML( 138*e1fe3e4aSElliott Hughes '<Substitution in="c_t" out="c,t"/>' 139*e1fe3e4aSElliott Hughes '<Substitution in="f_f_i" out="f,f,i"/>' 140*e1fe3e4aSElliott Hughes ): 141*e1fe3e4aSElliott Hughes table.fromXML(name, attrs, content, self.font) 142*e1fe3e4aSElliott Hughes self.assertEqual(table.mapping, {"c_t": ["c", "t"], "f_f_i": ["f", "f", "i"]}) 143*e1fe3e4aSElliott Hughes 144*e1fe3e4aSElliott Hughes def test_fromXML_oldFormat(self): 145*e1fe3e4aSElliott Hughes table = otTables.MultipleSubst() 146*e1fe3e4aSElliott Hughes for name, attrs, content in parseXML( 147*e1fe3e4aSElliott Hughes "<Coverage>" 148*e1fe3e4aSElliott Hughes ' <Glyph value="c_t"/>' 149*e1fe3e4aSElliott Hughes ' <Glyph value="f_f_i"/>' 150*e1fe3e4aSElliott Hughes "</Coverage>" 151*e1fe3e4aSElliott Hughes '<Sequence index="0">' 152*e1fe3e4aSElliott Hughes ' <Substitute index="0" value="c"/>' 153*e1fe3e4aSElliott Hughes ' <Substitute index="1" value="t"/>' 154*e1fe3e4aSElliott Hughes "</Sequence>" 155*e1fe3e4aSElliott Hughes '<Sequence index="1">' 156*e1fe3e4aSElliott Hughes ' <Substitute index="0" value="f"/>' 157*e1fe3e4aSElliott Hughes ' <Substitute index="1" value="f"/>' 158*e1fe3e4aSElliott Hughes ' <Substitute index="2" value="i"/>' 159*e1fe3e4aSElliott Hughes "</Sequence>" 160*e1fe3e4aSElliott Hughes ): 161*e1fe3e4aSElliott Hughes table.fromXML(name, attrs, content, self.font) 162*e1fe3e4aSElliott Hughes self.assertEqual(table.mapping, {"c_t": ["c", "t"], "f_f_i": ["f", "f", "i"]}) 163*e1fe3e4aSElliott Hughes 164*e1fe3e4aSElliott Hughes def test_fromXML_oldFormat_bug385(self): 165*e1fe3e4aSElliott Hughes # https://github.com/fonttools/fonttools/issues/385 166*e1fe3e4aSElliott Hughes table = otTables.MultipleSubst() 167*e1fe3e4aSElliott Hughes table.Format = 1 168*e1fe3e4aSElliott Hughes for name, attrs, content in parseXML( 169*e1fe3e4aSElliott Hughes "<Coverage>" 170*e1fe3e4aSElliott Hughes ' <Glyph value="o"/>' 171*e1fe3e4aSElliott Hughes ' <Glyph value="l"/>' 172*e1fe3e4aSElliott Hughes "</Coverage>" 173*e1fe3e4aSElliott Hughes "<Sequence>" 174*e1fe3e4aSElliott Hughes ' <Substitute value="o"/>' 175*e1fe3e4aSElliott Hughes ' <Substitute value="l"/>' 176*e1fe3e4aSElliott Hughes ' <Substitute value="o"/>' 177*e1fe3e4aSElliott Hughes "</Sequence>" 178*e1fe3e4aSElliott Hughes "<Sequence>" 179*e1fe3e4aSElliott Hughes ' <Substitute value="o"/>' 180*e1fe3e4aSElliott Hughes "</Sequence>" 181*e1fe3e4aSElliott Hughes ): 182*e1fe3e4aSElliott Hughes table.fromXML(name, attrs, content, self.font) 183*e1fe3e4aSElliott Hughes self.assertEqual(table.mapping, {"o": ["o", "l", "o"], "l": ["o"]}) 184*e1fe3e4aSElliott Hughes 185*e1fe3e4aSElliott Hughes 186*e1fe3e4aSElliott Hughesclass LigatureSubstTest(unittest.TestCase): 187*e1fe3e4aSElliott Hughes def setUp(self): 188*e1fe3e4aSElliott Hughes self.glyphs = ".notdef c f i t c_t f_f f_i f_f_i".split() 189*e1fe3e4aSElliott Hughes self.font = FakeFont(self.glyphs) 190*e1fe3e4aSElliott Hughes 191*e1fe3e4aSElliott Hughes def makeLigature(self, s): 192*e1fe3e4aSElliott Hughes """'ffi' --> Ligature(LigGlyph='f_f_i', Component=['f', 'f', 'i'])""" 193*e1fe3e4aSElliott Hughes lig = otTables.Ligature() 194*e1fe3e4aSElliott Hughes lig.Component = list(s) 195*e1fe3e4aSElliott Hughes lig.LigGlyph = "_".join(lig.Component) 196*e1fe3e4aSElliott Hughes return lig 197*e1fe3e4aSElliott Hughes 198*e1fe3e4aSElliott Hughes def makeLigatures(self, s): 199*e1fe3e4aSElliott Hughes """'ffi fi' --> [otTables.Ligature, otTables.Ligature]""" 200*e1fe3e4aSElliott Hughes return [self.makeLigature(lig) for lig in s.split()] 201*e1fe3e4aSElliott Hughes 202*e1fe3e4aSElliott Hughes def test_postRead_format1(self): 203*e1fe3e4aSElliott Hughes table = otTables.LigatureSubst() 204*e1fe3e4aSElliott Hughes table.Format = 1 205*e1fe3e4aSElliott Hughes ligs_c = otTables.LigatureSet() 206*e1fe3e4aSElliott Hughes ligs_c.Ligature = self.makeLigatures("ct") 207*e1fe3e4aSElliott Hughes ligs_f = otTables.LigatureSet() 208*e1fe3e4aSElliott Hughes ligs_f.Ligature = self.makeLigatures("ffi ff fi") 209*e1fe3e4aSElliott Hughes rawTable = { 210*e1fe3e4aSElliott Hughes "Coverage": makeCoverage(["c", "f"]), 211*e1fe3e4aSElliott Hughes "LigatureSet": [ligs_c, ligs_f], 212*e1fe3e4aSElliott Hughes } 213*e1fe3e4aSElliott Hughes table.postRead(rawTable, self.font) 214*e1fe3e4aSElliott Hughes self.assertEqual(set(table.ligatures.keys()), {"c", "f"}) 215*e1fe3e4aSElliott Hughes self.assertEqual(len(table.ligatures["c"]), 1) 216*e1fe3e4aSElliott Hughes self.assertEqual(table.ligatures["c"][0].LigGlyph, "c_t") 217*e1fe3e4aSElliott Hughes self.assertEqual(table.ligatures["c"][0].Component, ["c", "t"]) 218*e1fe3e4aSElliott Hughes self.assertEqual(len(table.ligatures["f"]), 3) 219*e1fe3e4aSElliott Hughes self.assertEqual(table.ligatures["f"][0].LigGlyph, "f_f_i") 220*e1fe3e4aSElliott Hughes self.assertEqual(table.ligatures["f"][0].Component, ["f", "f", "i"]) 221*e1fe3e4aSElliott Hughes self.assertEqual(table.ligatures["f"][1].LigGlyph, "f_f") 222*e1fe3e4aSElliott Hughes self.assertEqual(table.ligatures["f"][1].Component, ["f", "f"]) 223*e1fe3e4aSElliott Hughes self.assertEqual(table.ligatures["f"][2].LigGlyph, "f_i") 224*e1fe3e4aSElliott Hughes self.assertEqual(table.ligatures["f"][2].Component, ["f", "i"]) 225*e1fe3e4aSElliott Hughes 226*e1fe3e4aSElliott Hughes def test_postRead_formatUnknown(self): 227*e1fe3e4aSElliott Hughes table = otTables.LigatureSubst() 228*e1fe3e4aSElliott Hughes table.Format = 987 229*e1fe3e4aSElliott Hughes rawTable = {"Coverage": makeCoverage(["f"])} 230*e1fe3e4aSElliott Hughes self.assertRaises(AssertionError, table.postRead, rawTable, self.font) 231*e1fe3e4aSElliott Hughes 232*e1fe3e4aSElliott Hughes def test_preWrite_format1(self): 233*e1fe3e4aSElliott Hughes table = otTables.LigatureSubst() 234*e1fe3e4aSElliott Hughes table.ligatures = { 235*e1fe3e4aSElliott Hughes "c": self.makeLigatures("ct"), 236*e1fe3e4aSElliott Hughes "f": self.makeLigatures("ffi ff fi"), 237*e1fe3e4aSElliott Hughes } 238*e1fe3e4aSElliott Hughes rawTable = table.preWrite(self.font) 239*e1fe3e4aSElliott Hughes self.assertEqual(table.Format, 1) 240*e1fe3e4aSElliott Hughes self.assertEqual(rawTable["Coverage"].glyphs, ["c", "f"]) 241*e1fe3e4aSElliott Hughes [c, f] = rawTable["LigatureSet"] 242*e1fe3e4aSElliott Hughes self.assertIsInstance(c, otTables.LigatureSet) 243*e1fe3e4aSElliott Hughes self.assertIsInstance(f, otTables.LigatureSet) 244*e1fe3e4aSElliott Hughes [ct] = c.Ligature 245*e1fe3e4aSElliott Hughes self.assertIsInstance(ct, otTables.Ligature) 246*e1fe3e4aSElliott Hughes self.assertEqual(ct.LigGlyph, "c_t") 247*e1fe3e4aSElliott Hughes self.assertEqual(ct.Component, ["c", "t"]) 248*e1fe3e4aSElliott Hughes [ffi, ff, fi] = f.Ligature 249*e1fe3e4aSElliott Hughes self.assertIsInstance(ffi, otTables.Ligature) 250*e1fe3e4aSElliott Hughes self.assertEqual(ffi.LigGlyph, "f_f_i") 251*e1fe3e4aSElliott Hughes self.assertEqual(ffi.Component, ["f", "f", "i"]) 252*e1fe3e4aSElliott Hughes self.assertIsInstance(ff, otTables.Ligature) 253*e1fe3e4aSElliott Hughes self.assertEqual(ff.LigGlyph, "f_f") 254*e1fe3e4aSElliott Hughes self.assertEqual(ff.Component, ["f", "f"]) 255*e1fe3e4aSElliott Hughes self.assertIsInstance(fi, otTables.Ligature) 256*e1fe3e4aSElliott Hughes self.assertEqual(fi.LigGlyph, "f_i") 257*e1fe3e4aSElliott Hughes self.assertEqual(fi.Component, ["f", "i"]) 258*e1fe3e4aSElliott Hughes 259*e1fe3e4aSElliott Hughes def test_toXML2(self): 260*e1fe3e4aSElliott Hughes writer = XMLWriter(StringIO()) 261*e1fe3e4aSElliott Hughes table = otTables.LigatureSubst() 262*e1fe3e4aSElliott Hughes table.ligatures = { 263*e1fe3e4aSElliott Hughes "c": self.makeLigatures("ct"), 264*e1fe3e4aSElliott Hughes "f": self.makeLigatures("ffi ff fi"), 265*e1fe3e4aSElliott Hughes } 266*e1fe3e4aSElliott Hughes table.toXML2(writer, self.font) 267*e1fe3e4aSElliott Hughes self.assertEqual( 268*e1fe3e4aSElliott Hughes writer.file.getvalue().splitlines()[1:], 269*e1fe3e4aSElliott Hughes [ 270*e1fe3e4aSElliott Hughes '<LigatureSet glyph="c">', 271*e1fe3e4aSElliott Hughes ' <Ligature components="c,t" glyph="c_t"/>', 272*e1fe3e4aSElliott Hughes "</LigatureSet>", 273*e1fe3e4aSElliott Hughes '<LigatureSet glyph="f">', 274*e1fe3e4aSElliott Hughes ' <Ligature components="f,f,i" glyph="f_f_i"/>', 275*e1fe3e4aSElliott Hughes ' <Ligature components="f,f" glyph="f_f"/>', 276*e1fe3e4aSElliott Hughes ' <Ligature components="f,i" glyph="f_i"/>', 277*e1fe3e4aSElliott Hughes "</LigatureSet>", 278*e1fe3e4aSElliott Hughes ], 279*e1fe3e4aSElliott Hughes ) 280*e1fe3e4aSElliott Hughes 281*e1fe3e4aSElliott Hughes def test_fromXML(self): 282*e1fe3e4aSElliott Hughes table = otTables.LigatureSubst() 283*e1fe3e4aSElliott Hughes for name, attrs, content in parseXML( 284*e1fe3e4aSElliott Hughes '<LigatureSet glyph="f">' 285*e1fe3e4aSElliott Hughes ' <Ligature components="f,f,i" glyph="f_f_i"/>' 286*e1fe3e4aSElliott Hughes ' <Ligature components="f,f" glyph="f_f"/>' 287*e1fe3e4aSElliott Hughes "</LigatureSet>" 288*e1fe3e4aSElliott Hughes ): 289*e1fe3e4aSElliott Hughes table.fromXML(name, attrs, content, self.font) 290*e1fe3e4aSElliott Hughes self.assertEqual(set(table.ligatures.keys()), {"f"}) 291*e1fe3e4aSElliott Hughes [ffi, ff] = table.ligatures["f"] 292*e1fe3e4aSElliott Hughes self.assertEqual(ffi.LigGlyph, "f_f_i") 293*e1fe3e4aSElliott Hughes self.assertEqual(ffi.Component, ["f", "f", "i"]) 294*e1fe3e4aSElliott Hughes self.assertEqual(ff.LigGlyph, "f_f") 295*e1fe3e4aSElliott Hughes self.assertEqual(ff.Component, ["f", "f"]) 296*e1fe3e4aSElliott Hughes 297*e1fe3e4aSElliott Hughes 298*e1fe3e4aSElliott Hughesclass AlternateSubstTest(unittest.TestCase): 299*e1fe3e4aSElliott Hughes def setUp(self): 300*e1fe3e4aSElliott Hughes self.glyphs = ".notdef G G.alt1 G.alt2 Z Z.fina".split() 301*e1fe3e4aSElliott Hughes self.font = FakeFont(self.glyphs) 302*e1fe3e4aSElliott Hughes 303*e1fe3e4aSElliott Hughes def makeAlternateSet(self, s): 304*e1fe3e4aSElliott Hughes result = otTables.AlternateSet() 305*e1fe3e4aSElliott Hughes result.Alternate = s.split() 306*e1fe3e4aSElliott Hughes return result 307*e1fe3e4aSElliott Hughes 308*e1fe3e4aSElliott Hughes def test_postRead_format1(self): 309*e1fe3e4aSElliott Hughes table = otTables.AlternateSubst() 310*e1fe3e4aSElliott Hughes table.Format = 1 311*e1fe3e4aSElliott Hughes rawTable = { 312*e1fe3e4aSElliott Hughes "Coverage": makeCoverage(["G", "Z"]), 313*e1fe3e4aSElliott Hughes "AlternateSet": [ 314*e1fe3e4aSElliott Hughes self.makeAlternateSet("G.alt2 G.alt1"), 315*e1fe3e4aSElliott Hughes self.makeAlternateSet("Z.fina"), 316*e1fe3e4aSElliott Hughes ], 317*e1fe3e4aSElliott Hughes } 318*e1fe3e4aSElliott Hughes table.postRead(rawTable, self.font) 319*e1fe3e4aSElliott Hughes self.assertEqual(table.alternates, {"G": ["G.alt2", "G.alt1"], "Z": ["Z.fina"]}) 320*e1fe3e4aSElliott Hughes 321*e1fe3e4aSElliott Hughes def test_postRead_formatUnknown(self): 322*e1fe3e4aSElliott Hughes table = otTables.AlternateSubst() 323*e1fe3e4aSElliott Hughes table.Format = 987 324*e1fe3e4aSElliott Hughes self.assertRaises(AssertionError, table.postRead, {}, self.font) 325*e1fe3e4aSElliott Hughes 326*e1fe3e4aSElliott Hughes def test_preWrite_format1(self): 327*e1fe3e4aSElliott Hughes table = otTables.AlternateSubst() 328*e1fe3e4aSElliott Hughes table.alternates = {"G": ["G.alt2", "G.alt1"], "Z": ["Z.fina"]} 329*e1fe3e4aSElliott Hughes rawTable = table.preWrite(self.font) 330*e1fe3e4aSElliott Hughes self.assertEqual(table.Format, 1) 331*e1fe3e4aSElliott Hughes self.assertEqual(rawTable["Coverage"].glyphs, ["G", "Z"]) 332*e1fe3e4aSElliott Hughes [g, z] = rawTable["AlternateSet"] 333*e1fe3e4aSElliott Hughes self.assertIsInstance(g, otTables.AlternateSet) 334*e1fe3e4aSElliott Hughes self.assertEqual(g.Alternate, ["G.alt2", "G.alt1"]) 335*e1fe3e4aSElliott Hughes self.assertIsInstance(z, otTables.AlternateSet) 336*e1fe3e4aSElliott Hughes self.assertEqual(z.Alternate, ["Z.fina"]) 337*e1fe3e4aSElliott Hughes 338*e1fe3e4aSElliott Hughes def test_toXML2(self): 339*e1fe3e4aSElliott Hughes writer = XMLWriter(StringIO()) 340*e1fe3e4aSElliott Hughes table = otTables.AlternateSubst() 341*e1fe3e4aSElliott Hughes table.alternates = {"G": ["G.alt2", "G.alt1"], "Z": ["Z.fina"]} 342*e1fe3e4aSElliott Hughes table.toXML2(writer, self.font) 343*e1fe3e4aSElliott Hughes self.assertEqual( 344*e1fe3e4aSElliott Hughes writer.file.getvalue().splitlines()[1:], 345*e1fe3e4aSElliott Hughes [ 346*e1fe3e4aSElliott Hughes '<AlternateSet glyph="G">', 347*e1fe3e4aSElliott Hughes ' <Alternate glyph="G.alt2"/>', 348*e1fe3e4aSElliott Hughes ' <Alternate glyph="G.alt1"/>', 349*e1fe3e4aSElliott Hughes "</AlternateSet>", 350*e1fe3e4aSElliott Hughes '<AlternateSet glyph="Z">', 351*e1fe3e4aSElliott Hughes ' <Alternate glyph="Z.fina"/>', 352*e1fe3e4aSElliott Hughes "</AlternateSet>", 353*e1fe3e4aSElliott Hughes ], 354*e1fe3e4aSElliott Hughes ) 355*e1fe3e4aSElliott Hughes 356*e1fe3e4aSElliott Hughes def test_fromXML(self): 357*e1fe3e4aSElliott Hughes table = otTables.AlternateSubst() 358*e1fe3e4aSElliott Hughes for name, attrs, content in parseXML( 359*e1fe3e4aSElliott Hughes '<AlternateSet glyph="G">' 360*e1fe3e4aSElliott Hughes ' <Alternate glyph="G.alt2"/>' 361*e1fe3e4aSElliott Hughes ' <Alternate glyph="G.alt1"/>' 362*e1fe3e4aSElliott Hughes "</AlternateSet>" 363*e1fe3e4aSElliott Hughes '<AlternateSet glyph="Z">' 364*e1fe3e4aSElliott Hughes ' <Alternate glyph="Z.fina"/>' 365*e1fe3e4aSElliott Hughes "</AlternateSet>" 366*e1fe3e4aSElliott Hughes ): 367*e1fe3e4aSElliott Hughes table.fromXML(name, attrs, content, self.font) 368*e1fe3e4aSElliott Hughes self.assertEqual(table.alternates, {"G": ["G.alt2", "G.alt1"], "Z": ["Z.fina"]}) 369*e1fe3e4aSElliott Hughes 370*e1fe3e4aSElliott Hughes 371*e1fe3e4aSElliott Hughesclass RearrangementMorphActionTest(unittest.TestCase): 372*e1fe3e4aSElliott Hughes def setUp(self): 373*e1fe3e4aSElliott Hughes self.font = FakeFont([".notdef", "A", "B", "C"]) 374*e1fe3e4aSElliott Hughes 375*e1fe3e4aSElliott Hughes def testCompile(self): 376*e1fe3e4aSElliott Hughes r = otTables.RearrangementMorphAction() 377*e1fe3e4aSElliott Hughes r.NewState = 0x1234 378*e1fe3e4aSElliott Hughes r.MarkFirst = r.DontAdvance = r.MarkLast = True 379*e1fe3e4aSElliott Hughes r.ReservedFlags, r.Verb = 0x1FF0, 0xD 380*e1fe3e4aSElliott Hughes writer = OTTableWriter() 381*e1fe3e4aSElliott Hughes r.compile(writer, self.font, actionIndex=None) 382*e1fe3e4aSElliott Hughes self.assertEqual(hexStr(writer.getAllData()), "1234fffd") 383*e1fe3e4aSElliott Hughes 384*e1fe3e4aSElliott Hughes def testCompileActions(self): 385*e1fe3e4aSElliott Hughes act = otTables.RearrangementMorphAction() 386*e1fe3e4aSElliott Hughes self.assertEqual(act.compileActions(self.font, []), (None, None)) 387*e1fe3e4aSElliott Hughes 388*e1fe3e4aSElliott Hughes def testDecompileToXML(self): 389*e1fe3e4aSElliott Hughes r = otTables.RearrangementMorphAction() 390*e1fe3e4aSElliott Hughes r.decompile(OTTableReader(deHexStr("1234fffd")), self.font, actionReader=None) 391*e1fe3e4aSElliott Hughes toXML = lambda w, f: r.toXML(w, f, {"Test": "Foo"}, "Transition") 392*e1fe3e4aSElliott Hughes self.assertEqual( 393*e1fe3e4aSElliott Hughes getXML(toXML, self.font), 394*e1fe3e4aSElliott Hughes [ 395*e1fe3e4aSElliott Hughes '<Transition Test="Foo">', 396*e1fe3e4aSElliott Hughes ' <NewState value="4660"/>', # 0x1234 = 4660 397*e1fe3e4aSElliott Hughes ' <Flags value="MarkFirst,DontAdvance,MarkLast"/>', 398*e1fe3e4aSElliott Hughes ' <ReservedFlags value="0x1FF0"/>', 399*e1fe3e4aSElliott Hughes ' <Verb value="13"/><!-- ABxCD ⇒ CDxBA -->', 400*e1fe3e4aSElliott Hughes "</Transition>", 401*e1fe3e4aSElliott Hughes ], 402*e1fe3e4aSElliott Hughes ) 403*e1fe3e4aSElliott Hughes 404*e1fe3e4aSElliott Hughes 405*e1fe3e4aSElliott Hughesclass ContextualMorphActionTest(unittest.TestCase): 406*e1fe3e4aSElliott Hughes def setUp(self): 407*e1fe3e4aSElliott Hughes self.font = FakeFont([".notdef", "A", "B", "C"]) 408*e1fe3e4aSElliott Hughes 409*e1fe3e4aSElliott Hughes def testCompile(self): 410*e1fe3e4aSElliott Hughes a = otTables.ContextualMorphAction() 411*e1fe3e4aSElliott Hughes a.NewState = 0x1234 412*e1fe3e4aSElliott Hughes a.SetMark, a.DontAdvance, a.ReservedFlags = True, True, 0x3117 413*e1fe3e4aSElliott Hughes a.MarkIndex, a.CurrentIndex = 0xDEAD, 0xBEEF 414*e1fe3e4aSElliott Hughes writer = OTTableWriter() 415*e1fe3e4aSElliott Hughes a.compile(writer, self.font, actionIndex=None) 416*e1fe3e4aSElliott Hughes self.assertEqual(hexStr(writer.getAllData()), "1234f117deadbeef") 417*e1fe3e4aSElliott Hughes 418*e1fe3e4aSElliott Hughes def testCompileActions(self): 419*e1fe3e4aSElliott Hughes act = otTables.ContextualMorphAction() 420*e1fe3e4aSElliott Hughes self.assertEqual(act.compileActions(self.font, []), (None, None)) 421*e1fe3e4aSElliott Hughes 422*e1fe3e4aSElliott Hughes def testDecompileToXML(self): 423*e1fe3e4aSElliott Hughes a = otTables.ContextualMorphAction() 424*e1fe3e4aSElliott Hughes a.decompile( 425*e1fe3e4aSElliott Hughes OTTableReader(deHexStr("1234f117deadbeef")), self.font, actionReader=None 426*e1fe3e4aSElliott Hughes ) 427*e1fe3e4aSElliott Hughes toXML = lambda w, f: a.toXML(w, f, {"Test": "Foo"}, "Transition") 428*e1fe3e4aSElliott Hughes self.assertEqual( 429*e1fe3e4aSElliott Hughes getXML(toXML, self.font), 430*e1fe3e4aSElliott Hughes [ 431*e1fe3e4aSElliott Hughes '<Transition Test="Foo">', 432*e1fe3e4aSElliott Hughes ' <NewState value="4660"/>', # 0x1234 = 4660 433*e1fe3e4aSElliott Hughes ' <Flags value="SetMark,DontAdvance"/>', 434*e1fe3e4aSElliott Hughes ' <ReservedFlags value="0x3117"/>', 435*e1fe3e4aSElliott Hughes ' <MarkIndex value="57005"/>', # 0xDEAD = 57005 436*e1fe3e4aSElliott Hughes ' <CurrentIndex value="48879"/>', # 0xBEEF = 48879 437*e1fe3e4aSElliott Hughes "</Transition>", 438*e1fe3e4aSElliott Hughes ], 439*e1fe3e4aSElliott Hughes ) 440*e1fe3e4aSElliott Hughes 441*e1fe3e4aSElliott Hughes 442*e1fe3e4aSElliott Hughesclass LigatureMorphActionTest(unittest.TestCase): 443*e1fe3e4aSElliott Hughes def setUp(self): 444*e1fe3e4aSElliott Hughes self.font = FakeFont([".notdef", "A", "B", "C"]) 445*e1fe3e4aSElliott Hughes 446*e1fe3e4aSElliott Hughes def testDecompileToXML(self): 447*e1fe3e4aSElliott Hughes a = otTables.LigatureMorphAction() 448*e1fe3e4aSElliott Hughes actionReader = OTTableReader(deHexStr("DEADBEEF 7FFFFFFE 80000003")) 449*e1fe3e4aSElliott Hughes a.decompile(OTTableReader(deHexStr("1234FAB30001")), self.font, actionReader) 450*e1fe3e4aSElliott Hughes toXML = lambda w, f: a.toXML(w, f, {"Test": "Foo"}, "Transition") 451*e1fe3e4aSElliott Hughes self.assertEqual( 452*e1fe3e4aSElliott Hughes getXML(toXML, self.font), 453*e1fe3e4aSElliott Hughes [ 454*e1fe3e4aSElliott Hughes '<Transition Test="Foo">', 455*e1fe3e4aSElliott Hughes ' <NewState value="4660"/>', # 0x1234 = 4660 456*e1fe3e4aSElliott Hughes ' <Flags value="SetComponent,DontAdvance"/>', 457*e1fe3e4aSElliott Hughes ' <ReservedFlags value="0x1AB3"/>', 458*e1fe3e4aSElliott Hughes ' <Action GlyphIndexDelta="-2" Flags="Store"/>', 459*e1fe3e4aSElliott Hughes ' <Action GlyphIndexDelta="3"/>', 460*e1fe3e4aSElliott Hughes "</Transition>", 461*e1fe3e4aSElliott Hughes ], 462*e1fe3e4aSElliott Hughes ) 463*e1fe3e4aSElliott Hughes 464*e1fe3e4aSElliott Hughes def testCompileActions_empty(self): 465*e1fe3e4aSElliott Hughes act = otTables.LigatureMorphAction() 466*e1fe3e4aSElliott Hughes actions, actionIndex = act.compileActions(self.font, []) 467*e1fe3e4aSElliott Hughes self.assertEqual(actions, b"") 468*e1fe3e4aSElliott Hughes self.assertEqual(actionIndex, {}) 469*e1fe3e4aSElliott Hughes 470*e1fe3e4aSElliott Hughes def testCompileActions_shouldShareSubsequences(self): 471*e1fe3e4aSElliott Hughes state = otTables.AATState() 472*e1fe3e4aSElliott Hughes t = state.Transitions = {i: otTables.LigatureMorphAction() for i in range(3)} 473*e1fe3e4aSElliott Hughes ligs = [otTables.LigAction() for _ in range(3)] 474*e1fe3e4aSElliott Hughes for i, lig in enumerate(ligs): 475*e1fe3e4aSElliott Hughes lig.GlyphIndexDelta = i 476*e1fe3e4aSElliott Hughes t[0].Actions = ligs[1:2] 477*e1fe3e4aSElliott Hughes t[1].Actions = ligs[0:3] 478*e1fe3e4aSElliott Hughes t[2].Actions = ligs[1:3] 479*e1fe3e4aSElliott Hughes actions, actionIndex = t[0].compileActions(self.font, [state]) 480*e1fe3e4aSElliott Hughes self.assertEqual(actions, deHexStr("00000000 00000001 80000002 80000001")) 481*e1fe3e4aSElliott Hughes self.assertEqual( 482*e1fe3e4aSElliott Hughes actionIndex, 483*e1fe3e4aSElliott Hughes { 484*e1fe3e4aSElliott Hughes deHexStr("00000000 00000001 80000002"): 0, 485*e1fe3e4aSElliott Hughes deHexStr("00000001 80000002"): 1, 486*e1fe3e4aSElliott Hughes deHexStr("80000002"): 2, 487*e1fe3e4aSElliott Hughes deHexStr("80000001"): 3, 488*e1fe3e4aSElliott Hughes }, 489*e1fe3e4aSElliott Hughes ) 490*e1fe3e4aSElliott Hughes 491*e1fe3e4aSElliott Hughes 492*e1fe3e4aSElliott Hughesclass InsertionMorphActionTest(unittest.TestCase): 493*e1fe3e4aSElliott Hughes MORPH_ACTION_XML = [ 494*e1fe3e4aSElliott Hughes '<Transition Test="Foo">', 495*e1fe3e4aSElliott Hughes ' <NewState value="4660"/>', # 0x1234 = 4660 496*e1fe3e4aSElliott Hughes ' <Flags value="SetMark,DontAdvance,CurrentIsKashidaLike,' 497*e1fe3e4aSElliott Hughes 'MarkedIsKashidaLike,CurrentInsertBefore,MarkedInsertBefore"/>', 498*e1fe3e4aSElliott Hughes ' <CurrentInsertionAction glyph="B"/>', 499*e1fe3e4aSElliott Hughes ' <CurrentInsertionAction glyph="C"/>', 500*e1fe3e4aSElliott Hughes ' <MarkedInsertionAction glyph="B"/>', 501*e1fe3e4aSElliott Hughes ' <MarkedInsertionAction glyph="A"/>', 502*e1fe3e4aSElliott Hughes ' <MarkedInsertionAction glyph="D"/>', 503*e1fe3e4aSElliott Hughes "</Transition>", 504*e1fe3e4aSElliott Hughes ] 505*e1fe3e4aSElliott Hughes 506*e1fe3e4aSElliott Hughes def setUp(self): 507*e1fe3e4aSElliott Hughes self.font = FakeFont([".notdef", "A", "B", "C", "D"]) 508*e1fe3e4aSElliott Hughes self.maxDiff = None 509*e1fe3e4aSElliott Hughes 510*e1fe3e4aSElliott Hughes def testDecompileToXML(self): 511*e1fe3e4aSElliott Hughes a = otTables.InsertionMorphAction() 512*e1fe3e4aSElliott Hughes actionReader = OTTableReader( 513*e1fe3e4aSElliott Hughes deHexStr("DEAD BEEF 0002 0001 0004 0002 0003 DEAD BEEF") 514*e1fe3e4aSElliott Hughes ) 515*e1fe3e4aSElliott Hughes a.decompile( 516*e1fe3e4aSElliott Hughes OTTableReader(deHexStr("1234 FC43 0005 0002")), self.font, actionReader 517*e1fe3e4aSElliott Hughes ) 518*e1fe3e4aSElliott Hughes toXML = lambda w, f: a.toXML(w, f, {"Test": "Foo"}, "Transition") 519*e1fe3e4aSElliott Hughes self.assertEqual(getXML(toXML, self.font), self.MORPH_ACTION_XML) 520*e1fe3e4aSElliott Hughes 521*e1fe3e4aSElliott Hughes def testCompileFromXML(self): 522*e1fe3e4aSElliott Hughes a = otTables.InsertionMorphAction() 523*e1fe3e4aSElliott Hughes for name, attrs, content in parseXML(self.MORPH_ACTION_XML): 524*e1fe3e4aSElliott Hughes a.fromXML(name, attrs, content, self.font) 525*e1fe3e4aSElliott Hughes writer = OTTableWriter() 526*e1fe3e4aSElliott Hughes a.compile( 527*e1fe3e4aSElliott Hughes writer, 528*e1fe3e4aSElliott Hughes self.font, 529*e1fe3e4aSElliott Hughes actionIndex={("B", "C"): 9, ("B", "A", "D"): 7}, 530*e1fe3e4aSElliott Hughes ) 531*e1fe3e4aSElliott Hughes self.assertEqual(hexStr(writer.getAllData()), "1234fc4300090007") 532*e1fe3e4aSElliott Hughes 533*e1fe3e4aSElliott Hughes def testCompileActions_empty(self): 534*e1fe3e4aSElliott Hughes act = otTables.InsertionMorphAction() 535*e1fe3e4aSElliott Hughes actions, actionIndex = act.compileActions(self.font, []) 536*e1fe3e4aSElliott Hughes self.assertEqual(actions, b"") 537*e1fe3e4aSElliott Hughes self.assertEqual(actionIndex, {}) 538*e1fe3e4aSElliott Hughes 539*e1fe3e4aSElliott Hughes def testCompileActions_shouldShareSubsequences(self): 540*e1fe3e4aSElliott Hughes state = otTables.AATState() 541*e1fe3e4aSElliott Hughes t = state.Transitions = {i: otTables.InsertionMorphAction() for i in range(3)} 542*e1fe3e4aSElliott Hughes t[1].CurrentInsertionAction = [] 543*e1fe3e4aSElliott Hughes t[0].MarkedInsertionAction = ["A"] 544*e1fe3e4aSElliott Hughes t[1].CurrentInsertionAction = ["C", "D"] 545*e1fe3e4aSElliott Hughes t[1].MarkedInsertionAction = ["B"] 546*e1fe3e4aSElliott Hughes t[2].CurrentInsertionAction = ["B", "C", "D"] 547*e1fe3e4aSElliott Hughes t[2].MarkedInsertionAction = ["C", "D"] 548*e1fe3e4aSElliott Hughes actions, actionIndex = t[0].compileActions(self.font, [state]) 549*e1fe3e4aSElliott Hughes self.assertEqual(actions, deHexStr("0002 0003 0004 0001")) 550*e1fe3e4aSElliott Hughes self.assertEqual( 551*e1fe3e4aSElliott Hughes actionIndex, 552*e1fe3e4aSElliott Hughes { 553*e1fe3e4aSElliott Hughes ("A",): 3, 554*e1fe3e4aSElliott Hughes ("B",): 0, 555*e1fe3e4aSElliott Hughes ("B", "C"): 0, 556*e1fe3e4aSElliott Hughes ("B", "C", "D"): 0, 557*e1fe3e4aSElliott Hughes ("C",): 1, 558*e1fe3e4aSElliott Hughes ("C", "D"): 1, 559*e1fe3e4aSElliott Hughes ("D",): 2, 560*e1fe3e4aSElliott Hughes }, 561*e1fe3e4aSElliott Hughes ) 562*e1fe3e4aSElliott Hughes 563*e1fe3e4aSElliott Hughes 564*e1fe3e4aSElliott Hughesclass SplitMultipleSubstTest: 565*e1fe3e4aSElliott Hughes def overflow(self, itemName, itemRecord): 566*e1fe3e4aSElliott Hughes from fontTools.otlLib.builder import buildMultipleSubstSubtable 567*e1fe3e4aSElliott Hughes from fontTools.ttLib.tables.otBase import OverflowErrorRecord 568*e1fe3e4aSElliott Hughes 569*e1fe3e4aSElliott Hughes oldSubTable = buildMultipleSubstSubtable( 570*e1fe3e4aSElliott Hughes {"e": 1, "a": 2, "b": 3, "c": 4, "d": 5} 571*e1fe3e4aSElliott Hughes ) 572*e1fe3e4aSElliott Hughes newSubTable = otTables.MultipleSubst() 573*e1fe3e4aSElliott Hughes 574*e1fe3e4aSElliott Hughes ok = otTables.splitMultipleSubst( 575*e1fe3e4aSElliott Hughes oldSubTable, 576*e1fe3e4aSElliott Hughes newSubTable, 577*e1fe3e4aSElliott Hughes OverflowErrorRecord((None, None, None, itemName, itemRecord)), 578*e1fe3e4aSElliott Hughes ) 579*e1fe3e4aSElliott Hughes 580*e1fe3e4aSElliott Hughes assert ok 581*e1fe3e4aSElliott Hughes return oldSubTable.mapping, newSubTable.mapping 582*e1fe3e4aSElliott Hughes 583*e1fe3e4aSElliott Hughes def test_Coverage(self): 584*e1fe3e4aSElliott Hughes oldMapping, newMapping = self.overflow("Coverage", None) 585*e1fe3e4aSElliott Hughes assert oldMapping == {"a": 2, "b": 3} 586*e1fe3e4aSElliott Hughes assert newMapping == {"c": 4, "d": 5, "e": 1} 587*e1fe3e4aSElliott Hughes 588*e1fe3e4aSElliott Hughes def test_RangeRecord(self): 589*e1fe3e4aSElliott Hughes oldMapping, newMapping = self.overflow("RangeRecord", None) 590*e1fe3e4aSElliott Hughes assert oldMapping == {"a": 2, "b": 3} 591*e1fe3e4aSElliott Hughes assert newMapping == {"c": 4, "d": 5, "e": 1} 592*e1fe3e4aSElliott Hughes 593*e1fe3e4aSElliott Hughes def test_Sequence(self): 594*e1fe3e4aSElliott Hughes oldMapping, newMapping = self.overflow("Sequence", 4) 595*e1fe3e4aSElliott Hughes assert oldMapping == {"a": 2, "b": 3, "c": 4} 596*e1fe3e4aSElliott Hughes assert newMapping == {"d": 5, "e": 1} 597*e1fe3e4aSElliott Hughes 598*e1fe3e4aSElliott Hughes 599*e1fe3e4aSElliott Hughesdef test_splitMarkBasePos(): 600*e1fe3e4aSElliott Hughes from fontTools.otlLib.builder import buildAnchor, buildMarkBasePosSubtable 601*e1fe3e4aSElliott Hughes 602*e1fe3e4aSElliott Hughes marks = { 603*e1fe3e4aSElliott Hughes "acutecomb": (0, buildAnchor(0, 600)), 604*e1fe3e4aSElliott Hughes "gravecomb": (0, buildAnchor(0, 590)), 605*e1fe3e4aSElliott Hughes "cedillacomb": (1, buildAnchor(0, 0)), 606*e1fe3e4aSElliott Hughes } 607*e1fe3e4aSElliott Hughes bases = { 608*e1fe3e4aSElliott Hughes "a": { 609*e1fe3e4aSElliott Hughes 0: buildAnchor(350, 500), 610*e1fe3e4aSElliott Hughes 1: None, 611*e1fe3e4aSElliott Hughes }, 612*e1fe3e4aSElliott Hughes "c": { 613*e1fe3e4aSElliott Hughes 0: buildAnchor(300, 700), 614*e1fe3e4aSElliott Hughes 1: buildAnchor(300, 0), 615*e1fe3e4aSElliott Hughes }, 616*e1fe3e4aSElliott Hughes } 617*e1fe3e4aSElliott Hughes glyphOrder = ["a", "c", "acutecomb", "gravecomb", "cedillacomb"] 618*e1fe3e4aSElliott Hughes glyphMap = {g: i for i, g in enumerate(glyphOrder)} 619*e1fe3e4aSElliott Hughes 620*e1fe3e4aSElliott Hughes oldSubTable = buildMarkBasePosSubtable(marks, bases, glyphMap) 621*e1fe3e4aSElliott Hughes newSubTable = otTables.MarkBasePos() 622*e1fe3e4aSElliott Hughes 623*e1fe3e4aSElliott Hughes ok = otTables.splitMarkBasePos(oldSubTable, newSubTable, overflowRecord=None) 624*e1fe3e4aSElliott Hughes 625*e1fe3e4aSElliott Hughes assert ok 626*e1fe3e4aSElliott Hughes 627*e1fe3e4aSElliott Hughes assert getXML(oldSubTable.toXML) == [ 628*e1fe3e4aSElliott Hughes '<MarkBasePos Format="1">', 629*e1fe3e4aSElliott Hughes " <MarkCoverage>", 630*e1fe3e4aSElliott Hughes ' <Glyph value="acutecomb"/>', 631*e1fe3e4aSElliott Hughes ' <Glyph value="gravecomb"/>', 632*e1fe3e4aSElliott Hughes " </MarkCoverage>", 633*e1fe3e4aSElliott Hughes " <BaseCoverage>", 634*e1fe3e4aSElliott Hughes ' <Glyph value="a"/>', 635*e1fe3e4aSElliott Hughes ' <Glyph value="c"/>', 636*e1fe3e4aSElliott Hughes " </BaseCoverage>", 637*e1fe3e4aSElliott Hughes " <!-- ClassCount=1 -->", 638*e1fe3e4aSElliott Hughes " <MarkArray>", 639*e1fe3e4aSElliott Hughes " <!-- MarkCount=2 -->", 640*e1fe3e4aSElliott Hughes ' <MarkRecord index="0">', 641*e1fe3e4aSElliott Hughes ' <Class value="0"/>', 642*e1fe3e4aSElliott Hughes ' <MarkAnchor Format="1">', 643*e1fe3e4aSElliott Hughes ' <XCoordinate value="0"/>', 644*e1fe3e4aSElliott Hughes ' <YCoordinate value="600"/>', 645*e1fe3e4aSElliott Hughes " </MarkAnchor>", 646*e1fe3e4aSElliott Hughes " </MarkRecord>", 647*e1fe3e4aSElliott Hughes ' <MarkRecord index="1">', 648*e1fe3e4aSElliott Hughes ' <Class value="0"/>', 649*e1fe3e4aSElliott Hughes ' <MarkAnchor Format="1">', 650*e1fe3e4aSElliott Hughes ' <XCoordinate value="0"/>', 651*e1fe3e4aSElliott Hughes ' <YCoordinate value="590"/>', 652*e1fe3e4aSElliott Hughes " </MarkAnchor>", 653*e1fe3e4aSElliott Hughes " </MarkRecord>", 654*e1fe3e4aSElliott Hughes " </MarkArray>", 655*e1fe3e4aSElliott Hughes " <BaseArray>", 656*e1fe3e4aSElliott Hughes " <!-- BaseCount=2 -->", 657*e1fe3e4aSElliott Hughes ' <BaseRecord index="0">', 658*e1fe3e4aSElliott Hughes ' <BaseAnchor index="0" Format="1">', 659*e1fe3e4aSElliott Hughes ' <XCoordinate value="350"/>', 660*e1fe3e4aSElliott Hughes ' <YCoordinate value="500"/>', 661*e1fe3e4aSElliott Hughes " </BaseAnchor>", 662*e1fe3e4aSElliott Hughes " </BaseRecord>", 663*e1fe3e4aSElliott Hughes ' <BaseRecord index="1">', 664*e1fe3e4aSElliott Hughes ' <BaseAnchor index="0" Format="1">', 665*e1fe3e4aSElliott Hughes ' <XCoordinate value="300"/>', 666*e1fe3e4aSElliott Hughes ' <YCoordinate value="700"/>', 667*e1fe3e4aSElliott Hughes " </BaseAnchor>", 668*e1fe3e4aSElliott Hughes " </BaseRecord>", 669*e1fe3e4aSElliott Hughes " </BaseArray>", 670*e1fe3e4aSElliott Hughes "</MarkBasePos>", 671*e1fe3e4aSElliott Hughes ] 672*e1fe3e4aSElliott Hughes 673*e1fe3e4aSElliott Hughes assert getXML(newSubTable.toXML) == [ 674*e1fe3e4aSElliott Hughes '<MarkBasePos Format="1">', 675*e1fe3e4aSElliott Hughes " <MarkCoverage>", 676*e1fe3e4aSElliott Hughes ' <Glyph value="cedillacomb"/>', 677*e1fe3e4aSElliott Hughes " </MarkCoverage>", 678*e1fe3e4aSElliott Hughes " <BaseCoverage>", 679*e1fe3e4aSElliott Hughes ' <Glyph value="a"/>', 680*e1fe3e4aSElliott Hughes ' <Glyph value="c"/>', 681*e1fe3e4aSElliott Hughes " </BaseCoverage>", 682*e1fe3e4aSElliott Hughes " <!-- ClassCount=1 -->", 683*e1fe3e4aSElliott Hughes " <MarkArray>", 684*e1fe3e4aSElliott Hughes " <!-- MarkCount=1 -->", 685*e1fe3e4aSElliott Hughes ' <MarkRecord index="0">', 686*e1fe3e4aSElliott Hughes ' <Class value="0"/>', 687*e1fe3e4aSElliott Hughes ' <MarkAnchor Format="1">', 688*e1fe3e4aSElliott Hughes ' <XCoordinate value="0"/>', 689*e1fe3e4aSElliott Hughes ' <YCoordinate value="0"/>', 690*e1fe3e4aSElliott Hughes " </MarkAnchor>", 691*e1fe3e4aSElliott Hughes " </MarkRecord>", 692*e1fe3e4aSElliott Hughes " </MarkArray>", 693*e1fe3e4aSElliott Hughes " <BaseArray>", 694*e1fe3e4aSElliott Hughes " <!-- BaseCount=2 -->", 695*e1fe3e4aSElliott Hughes ' <BaseRecord index="0">', 696*e1fe3e4aSElliott Hughes ' <BaseAnchor index="0" empty="1"/>', 697*e1fe3e4aSElliott Hughes " </BaseRecord>", 698*e1fe3e4aSElliott Hughes ' <BaseRecord index="1">', 699*e1fe3e4aSElliott Hughes ' <BaseAnchor index="0" Format="1">', 700*e1fe3e4aSElliott Hughes ' <XCoordinate value="300"/>', 701*e1fe3e4aSElliott Hughes ' <YCoordinate value="0"/>', 702*e1fe3e4aSElliott Hughes " </BaseAnchor>", 703*e1fe3e4aSElliott Hughes " </BaseRecord>", 704*e1fe3e4aSElliott Hughes " </BaseArray>", 705*e1fe3e4aSElliott Hughes "</MarkBasePos>", 706*e1fe3e4aSElliott Hughes ] 707*e1fe3e4aSElliott Hughes 708*e1fe3e4aSElliott Hughes 709*e1fe3e4aSElliott Hughesclass ColrV1Test(unittest.TestCase): 710*e1fe3e4aSElliott Hughes def setUp(self): 711*e1fe3e4aSElliott Hughes self.font = FakeFont([".notdef", "meh"]) 712*e1fe3e4aSElliott Hughes 713*e1fe3e4aSElliott Hughes def test_traverseEmptyPaintColrLayersNeedsNoLayerList(self): 714*e1fe3e4aSElliott Hughes colr = parseXmlInto( 715*e1fe3e4aSElliott Hughes self.font, 716*e1fe3e4aSElliott Hughes otTables.COLR(), 717*e1fe3e4aSElliott Hughes """ 718*e1fe3e4aSElliott Hughes <Version value="1"/> 719*e1fe3e4aSElliott Hughes <BaseGlyphList> 720*e1fe3e4aSElliott Hughes <BaseGlyphPaintRecord index="0"> 721*e1fe3e4aSElliott Hughes <BaseGlyph value="meh"/> 722*e1fe3e4aSElliott Hughes <Paint Format="1"><!-- PaintColrLayers --> 723*e1fe3e4aSElliott Hughes <NumLayers value="0"/> 724*e1fe3e4aSElliott Hughes <FirstLayerIndex value="42"/> 725*e1fe3e4aSElliott Hughes </Paint> 726*e1fe3e4aSElliott Hughes </BaseGlyphPaintRecord> 727*e1fe3e4aSElliott Hughes </BaseGlyphList> 728*e1fe3e4aSElliott Hughes """, 729*e1fe3e4aSElliott Hughes ) 730*e1fe3e4aSElliott Hughes paint = colr.BaseGlyphList.BaseGlyphPaintRecord[0].Paint 731*e1fe3e4aSElliott Hughes 732*e1fe3e4aSElliott Hughes # Just want to confirm we don't crash 733*e1fe3e4aSElliott Hughes visited = [] 734*e1fe3e4aSElliott Hughes paint.traverse(colr, lambda p: visited.append(p)) 735*e1fe3e4aSElliott Hughes assert len(visited) == 1 736*e1fe3e4aSElliott Hughes 737*e1fe3e4aSElliott Hughes 738*e1fe3e4aSElliott Hughesif __name__ == "__main__": 739*e1fe3e4aSElliott Hughes import sys 740*e1fe3e4aSElliott Hughes 741*e1fe3e4aSElliott Hughes sys.exit(unittest.main()) 742