1from fontTools.misc.testTools import parseXML 2from fontTools.misc.textTools import deHexStr 3from fontTools.misc.xmlWriter import XMLWriter 4from fontTools.misc.fixedTools import floatToFixed as fl2fi 5from fontTools.ttLib import TTFont, TTLibError 6import fontTools.ttLib.tables.otTables as otTables 7from fontTools.ttLib.tables._a_v_a_r import table__a_v_a_r 8from fontTools.ttLib.tables._f_v_a_r import table__f_v_a_r, Axis 9import fontTools.varLib.models as models 10import fontTools.varLib.varStore as varStore 11from io import BytesIO 12import unittest 13 14 15TEST_DATA = deHexStr( 16 "00 01 00 00 00 00 00 02 " 17 "00 04 C0 00 C0 00 00 00 00 00 13 33 33 33 40 00 40 00 " 18 "00 03 C0 00 C0 00 00 00 00 00 40 00 40 00" 19) 20 21 22class AxisVariationTableTest(unittest.TestCase): 23 def assertAvarAlmostEqual(self, segments1, segments2): 24 self.assertSetEqual(set(segments1.keys()), set(segments2.keys())) 25 for axisTag, mapping1 in segments1.items(): 26 mapping2 = segments2[axisTag] 27 self.assertEqual(len(mapping1), len(mapping2)) 28 for (k1, v1), (k2, v2) in zip( 29 sorted(mapping1.items()), sorted(mapping2.items()) 30 ): 31 self.assertAlmostEqual(k1, k2) 32 self.assertAlmostEqual(v1, v2) 33 34 def test_compile(self): 35 avar = table__a_v_a_r() 36 avar.segments["wdth"] = {-1.0: -1.0, 0.0: 0.0, 0.3: 0.8, 1.0: 1.0} 37 avar.segments["wght"] = {-1.0: -1.0, 0.0: 0.0, 1.0: 1.0} 38 self.assertEqual(TEST_DATA, avar.compile(self.makeFont(["wdth", "wght"]))) 39 40 def test_decompile(self): 41 avar = table__a_v_a_r() 42 avar.decompile(TEST_DATA, self.makeFont(["wdth", "wght"])) 43 self.assertAvarAlmostEqual( 44 { 45 "wdth": {-1.0: -1.0, 0.0: 0.0, 0.2999878: 0.7999878, 1.0: 1.0}, 46 "wght": {-1.0: -1.0, 0.0: 0.0, 1.0: 1.0}, 47 }, 48 avar.segments, 49 ) 50 51 def test_toXML(self): 52 avar = table__a_v_a_r() 53 avar.segments["opsz"] = {-1.0: -1.0, 0.0: 0.0, 0.2999878: 0.7999878, 1.0: 1.0} 54 writer = XMLWriter(BytesIO()) 55 avar.toXML(writer, self.makeFont(["opsz"])) 56 self.assertEqual( 57 [ 58 '<version major="1" minor="0"/>', 59 '<segment axis="opsz">', 60 '<mapping from="-1.0" to="-1.0"/>', 61 '<mapping from="0.0" to="0.0"/>', 62 '<mapping from="0.3" to="0.8"/>', 63 '<mapping from="1.0" to="1.0"/>', 64 "</segment>", 65 ], 66 self.xml_lines(writer), 67 ) 68 69 def test_fromXML(self): 70 avar = table__a_v_a_r() 71 for name, attrs, content in parseXML( 72 '<segment axis="wdth">' 73 ' <mapping from="-1.0" to="-1.0"/>' 74 ' <mapping from="0.0" to="0.0"/>' 75 ' <mapping from="0.7" to="0.2"/>' 76 ' <mapping from="1.0" to="1.0"/>' 77 "</segment>" 78 ): 79 avar.fromXML(name, attrs, content, ttFont=None) 80 self.assertAvarAlmostEqual( 81 {"wdth": {-1: -1, 0: 0, 0.7000122: 0.2000122, 1.0: 1.0}}, avar.segments 82 ) 83 84 @staticmethod 85 def makeFont(axisTags): 86 """['opsz', 'wdth'] --> ttFont""" 87 fvar = table__f_v_a_r() 88 for tag in axisTags: 89 axis = Axis() 90 axis.axisTag = tag 91 fvar.axes.append(axis) 92 font = TTFont() 93 font["fvar"] = fvar 94 return font 95 96 @staticmethod 97 def xml_lines(writer): 98 content = writer.file.getvalue().decode("utf-8") 99 return [line.strip() for line in content.splitlines()][1:] 100 101 102class Avar2Test(unittest.TestCase): 103 def test(self): 104 axisTags = ["wght", "wdth"] 105 fvar = table__f_v_a_r() 106 for tag in axisTags: 107 axis = Axis() 108 axis.axisTag = tag 109 fvar.axes.append(axis) 110 111 master_locations_normalized = [ 112 {}, 113 {"wght": 1, "wdth": -1}, 114 ] 115 data = [ 116 {}, 117 {"wdth": -0.8}, 118 ] 119 120 model = models.VariationModel(master_locations_normalized, axisTags) 121 store_builder = varStore.OnlineVarStoreBuilder(axisTags) 122 store_builder.setModel(model) 123 varIdxes = {} 124 for axis in axisTags: 125 masters = [fl2fi(m.get(axis, 0), 14) for m in data] 126 varIdxes[axis] = store_builder.storeMasters(masters)[1] 127 store = store_builder.finish() 128 mapping = store.optimize() 129 varIdxes = {axis: mapping[value] for axis, value in varIdxes.items()} 130 del model, store_builder, mapping 131 132 varIdxMap = otTables.DeltaSetIndexMap() 133 varIdxMap.Format = 1 134 varIdxMap.mapping = [] 135 for tag in axisTags: 136 varIdxMap.mapping.append(varIdxes[tag]) 137 138 avar = table__a_v_a_r() 139 avar.segments["wght"] = {} 140 avar.segments["wdth"] = {-1.0: -1.0, 0.0: 0.0, 0.4: 0.5, 1.0: 1.0} 141 142 avar.majorVersion = 2 143 avar.table = otTables.avar() 144 avar.table.VarIdxMap = varIdxMap 145 avar.table.VarStore = store 146 147 font = TTFont() 148 font["fvar"] = fvar 149 font["avar"] = avar 150 151 b = BytesIO() 152 font.save(b) 153 b.seek(0) 154 font2 = TTFont(b) 155 156 assert font2["avar"].table.VarStore.VarRegionList.RegionAxisCount == 2 157 assert font2["avar"].table.VarStore.VarRegionList.RegionCount == 1 158 159 xml1 = BytesIO() 160 writer = XMLWriter(xml1) 161 font["avar"].toXML(writer, font) 162 163 xml2 = BytesIO() 164 writer = XMLWriter(xml2) 165 font2["avar"].toXML(writer, font2) 166 167 assert xml1.getvalue() == xml2.getvalue(), (xml1.getvalue(), xml2.getvalue()) 168 169 avar = table__a_v_a_r() 170 xml = b"".join(xml2.getvalue().splitlines()[1:]) 171 for name, attrs, content in parseXML(xml): 172 avar.fromXML(name, attrs, content, ttFont=TTFont()) 173 assert avar.table.VarStore.VarRegionList.RegionAxisCount == 2 174 assert avar.table.VarStore.VarRegionList.RegionCount == 1 175 176 177if __name__ == "__main__": 178 import sys 179 180 sys.exit(unittest.main()) 181