• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from fontTools.misc.testTools import getXML, parseXML
2from fontTools.misc.textTools import deHexStr, hexStr
3from fontTools.ttLib import TTLibError, getTableModule, newTable
4from fontTools.ttLib.tables.TupleVariation import TupleVariation
5
6import unittest
7
8
9CVAR_DATA = deHexStr(
10    "0001 0000 "  #  0: majorVersion=1 minorVersion=0
11    "8002 0018 "  #  4: tupleVariationCount=2|TUPLES_SHARE_POINT_NUMBERS offsetToData=24
12    "0004 "  #  8: tvHeader[0].variationDataSize=4
13    "8000 "  # 10: tvHeader[0].tupleIndex=EMBEDDED_PEAK
14    "4000 0000 "  # 12: tvHeader[0].peakTuple=[1.0, 0.0]
15    "0004 "  # 16: tvHeader[1].variationDataSize=4
16    "8000 "  # 18: tvHeader[1].tupleIndex=EMBEDDED_PEAK
17    "C000 3333 "  # 20: tvHeader[1].peakTuple=[-1.0, 0.8]
18    "03 02 02 01 01"  # 24: shared_pointCount=03, run_count=2 cvt=[2, 3, 4]
19    "02 03 01 04 "  # 25: deltas=[3, 1, 4]
20    "02 09 07 08"
21)  # 29: deltas=[9, 7, 8]
22
23CVAR_PRIVATE_POINT_DATA = deHexStr(
24    "0001 0000 "  #  0: majorVersion=1 minorVersion=0
25    "0002 0018 "  #  4: tupleVariationCount=2 offsetToData=24
26    "0009 "  #  8: tvHeader[0].variationDataSize=9
27    "A000 "  # 10: tvHeader[0].tupleIndex=EMBEDDED_PEAK|PRIVATE_POINT_NUMBERS
28    "4000 0000 "  # 12: tvHeader[0].peakTuple=[1.0, 0.0]
29    "0009 "  # 16: tvHeader[1].variationDataSize=9
30    "A000 "  # 18: tvHeader[1].tupleIndex=EMBEDDED_PEAK|PRIVATE_POINT_NUMBERS
31    "C000 3333 "  # 20: tvHeader[1].peakTuple=[-1.0, 0.8]
32    "03 02 02 01 01 02 03 01 04 "  # 24: pointCount=3 run_count=2 cvt=2 1 1 run_count=2 deltas=[3, 1, 4]
33    "03 02 02 01 01 02 09 07 08 "
34)  # 33: pointCount=3 run_count=2 cvt=2 1 1 run_count=2 deltas=[9, 7, 8]
35
36CVAR_XML = [
37    '<version major="1" minor="0"/>',
38    "<tuple>",
39    '  <coord axis="wght" value="1.0"/>',
40    '  <delta cvt="2" value="3"/>',
41    '  <delta cvt="3" value="1"/>',
42    '  <delta cvt="4" value="4"/>',
43    "</tuple>",
44    "<tuple>",
45    '  <coord axis="wght" value="-1.0"/>',
46    '  <coord axis="wdth" value="0.8"/>',
47    '  <delta cvt="2" value="9"/>',
48    '  <delta cvt="3" value="7"/>',
49    '  <delta cvt="4" value="8"/>',
50    "</tuple>",
51]
52
53CVAR_VARIATIONS = [
54    TupleVariation({"wght": (0.0, 1.0, 1.0)}, [None, None, 3, 1, 4]),
55    TupleVariation(
56        {"wght": (-1, -1.0, 0.0), "wdth": (0.0, 0.7999878, 0.7999878)},
57        [None, None, 9, 7, 8],
58    ),
59]
60
61
62class CVARTableTest(unittest.TestCase):
63    def assertVariationsAlmostEqual(self, variations1, variations2):
64        self.assertEqual(len(variations1), len(variations2))
65        for v1, v2 in zip(variations1, variations2):
66            self.assertSetEqual(set(v1.axes), set(v2.axes))
67            for axisTag, support1 in v1.axes.items():
68                support2 = v2.axes[axisTag]
69                self.assertEqual(len(support1), len(support2))
70                for s1, s2 in zip(support1, support2):
71                    self.assertAlmostEqual(s1, s2)
72                self.assertEqual(v1.coordinates, v2.coordinates)
73
74    def makeFont(self):
75        cvt, cvar, fvar = newTable("cvt "), newTable("cvar"), newTable("fvar")
76        font = {"cvt ": cvt, "cvar": cvar, "fvar": fvar}
77        cvt.values = [0, 0, 0, 1000, -2000]
78        Axis = getTableModule("fvar").Axis
79        fvar.axes = [Axis(), Axis()]
80        fvar.axes[0].axisTag, fvar.axes[1].axisTag = "wght", "wdth"
81        return font, cvar
82
83    def test_compile(self):
84        font, cvar = self.makeFont()
85        cvar.variations = CVAR_VARIATIONS
86        self.assertEqual(hexStr(cvar.compile(font)), hexStr(CVAR_PRIVATE_POINT_DATA))
87
88    def test_compile_shared_points(self):
89        font, cvar = self.makeFont()
90        cvar.variations = CVAR_VARIATIONS
91        self.assertEqual(
92            hexStr(cvar.compile(font, useSharedPoints=True)), hexStr(CVAR_DATA)
93        )
94
95    def test_decompile(self):
96        font, cvar = self.makeFont()
97        cvar.decompile(CVAR_PRIVATE_POINT_DATA, font)
98        self.assertEqual(cvar.majorVersion, 1)
99        self.assertEqual(cvar.minorVersion, 0)
100        self.assertVariationsAlmostEqual(cvar.variations, CVAR_VARIATIONS)
101
102    def test_decompile_shared_points(self):
103        font, cvar = self.makeFont()
104        cvar.decompile(CVAR_DATA, font)
105        self.assertEqual(cvar.majorVersion, 1)
106        self.assertEqual(cvar.minorVersion, 0)
107        self.assertVariationsAlmostEqual(cvar.variations, CVAR_VARIATIONS)
108
109    def test_fromXML(self):
110        font, cvar = self.makeFont()
111        for name, attrs, content in parseXML(CVAR_XML):
112            cvar.fromXML(name, attrs, content, ttFont=font)
113        self.assertEqual(cvar.majorVersion, 1)
114        self.assertEqual(cvar.minorVersion, 0)
115        self.assertVariationsAlmostEqual(cvar.variations, CVAR_VARIATIONS)
116
117    def test_toXML(self):
118        font, cvar = self.makeFont()
119        cvar.variations = CVAR_VARIATIONS
120        self.assertEqual(getXML(cvar.toXML, font), CVAR_XML)
121
122
123if __name__ == "__main__":
124    import sys
125
126    sys.exit(unittest.main())
127