• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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