• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from fontTools.misc.loggingTools import CapturingLogHandler
2from fontTools.misc.testTools import parseXML, getXML
3from fontTools.misc.textTools import deHexStr
4from fontTools.ttLib import TTFont, newTable
5from fontTools.misc.fixedTools import log
6import os
7import unittest
8
9
10CURR_DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__)))
11DATA_DIR = os.path.join(CURR_DIR, "data")
12
13HHEA_DATA = deHexStr(
14    "0001 0000 "  # 1.0   version
15    "02EE "  # 750   ascent
16    "FF06 "  # -250  descent
17    "00C8 "  # 200   lineGap
18    "03E8 "  # 1000  advanceWidthMax
19    "FFE7 "  # -25   minLeftSideBearing
20    "FFEC "  # -20   minRightSideBearing
21    "03D1 "  # 977   xMaxExtent
22    "0000 "  # 0     caretSlopeRise
23    "0001 "  # 1     caretSlopeRun
24    "0010 "  # 16    caretOffset
25    "0000 "  # 0     reserved0
26    "0000 "  # 0     reserved1
27    "0000 "  # 0     reserved2
28    "0000 "  # 0     reserved3
29    "0000 "  # 0     metricDataFormat
30    "002A "  # 42    numberOfHMetrics
31)
32
33HHEA_AS_DICT = {
34    "tableTag": "hhea",
35    "tableVersion": 0x00010000,
36    "ascent": 750,
37    "descent": -250,
38    "lineGap": 200,
39    "advanceWidthMax": 1000,
40    "minLeftSideBearing": -25,
41    "minRightSideBearing": -20,
42    "xMaxExtent": 977,
43    "caretSlopeRise": 0,
44    "caretSlopeRun": 1,
45    "caretOffset": 16,
46    "reserved0": 0,
47    "reserved1": 0,
48    "reserved2": 0,
49    "reserved3": 0,
50    "metricDataFormat": 0,
51    "numberOfHMetrics": 42,
52}
53
54HHEA_XML = [
55    '<tableVersion value="0x00010000"/>',
56    '<ascent value="750"/>',
57    '<descent value="-250"/>',
58    '<lineGap value="200"/>',
59    '<advanceWidthMax value="1000"/>',
60    '<minLeftSideBearing value="-25"/>',
61    '<minRightSideBearing value="-20"/>',
62    '<xMaxExtent value="977"/>',
63    '<caretSlopeRise value="0"/>',
64    '<caretSlopeRun value="1"/>',
65    '<caretOffset value="16"/>',
66    '<reserved0 value="0"/>',
67    '<reserved1 value="0"/>',
68    '<reserved2 value="0"/>',
69    '<reserved3 value="0"/>',
70    '<metricDataFormat value="0"/>',
71    '<numberOfHMetrics value="42"/>',
72]
73
74HHEA_XML_VERSION_AS_FLOAT = [
75    '<tableVersion value="1.0"/>',
76] + HHEA_XML[1:]
77
78
79class HheaCompileOrToXMLTest(unittest.TestCase):
80    def setUp(self):
81        hhea = newTable("hhea")
82        hhea.tableVersion = 0x00010000
83        hhea.ascent = 750
84        hhea.descent = -250
85        hhea.lineGap = 200
86        hhea.advanceWidthMax = 1000
87        hhea.minLeftSideBearing = -25
88        hhea.minRightSideBearing = -20
89        hhea.xMaxExtent = 977
90        hhea.caretSlopeRise = 0
91        hhea.caretSlopeRun = 1
92        hhea.caretOffset = 16
93        hhea.metricDataFormat = 0
94        hhea.numberOfHMetrics = 42
95        hhea.reserved0 = hhea.reserved1 = hhea.reserved2 = hhea.reserved3 = 0
96        self.font = TTFont(sfntVersion="OTTO")
97        self.font["hhea"] = hhea
98
99    def test_compile(self):
100        hhea = self.font["hhea"]
101        hhea.tableVersion = 0x00010000
102        self.assertEqual(HHEA_DATA, hhea.compile(self.font))
103
104    def test_compile_version_10_as_float(self):
105        hhea = self.font["hhea"]
106        hhea.tableVersion = 1.0
107        with CapturingLogHandler(log, "WARNING") as captor:
108            self.assertEqual(HHEA_DATA, hhea.compile(self.font))
109        self.assertTrue(
110            len(
111                [r for r in captor.records if "Table version value is a float" in r.msg]
112            )
113            == 1
114        )
115
116    def test_toXML(self):
117        hhea = self.font["hhea"]
118        self.font["hhea"].tableVersion = 0x00010000
119        self.assertEqual(getXML(hhea.toXML), HHEA_XML)
120
121    def test_toXML_version_as_float(self):
122        hhea = self.font["hhea"]
123        hhea.tableVersion = 1.0
124        with CapturingLogHandler(log, "WARNING") as captor:
125            self.assertEqual(getXML(hhea.toXML), HHEA_XML)
126        self.assertTrue(
127            len(
128                [r for r in captor.records if "Table version value is a float" in r.msg]
129            )
130            == 1
131        )
132
133    def test_aliases(self):
134        hhea = self.font["hhea"]
135        self.assertEqual(hhea.ascent, hhea.ascender)
136        self.assertEqual(hhea.descent, hhea.descender)
137        hhea.ascender = 800
138        self.assertEqual(hhea.ascent, 800)
139        hhea.ascent = 750
140        self.assertEqual(hhea.ascender, 750)
141        hhea.descender = -300
142        self.assertEqual(hhea.descent, -300)
143        hhea.descent = -299
144        self.assertEqual(hhea.descender, -299)
145
146
147class HheaDecompileOrFromXMLTest(unittest.TestCase):
148    def setUp(self):
149        hhea = newTable("hhea")
150        self.font = TTFont(sfntVersion="OTTO")
151        self.font["hhea"] = hhea
152
153    def test_decompile(self):
154        hhea = self.font["hhea"]
155        hhea.decompile(HHEA_DATA, self.font)
156        for key in hhea.__dict__:
157            self.assertEqual(getattr(hhea, key), HHEA_AS_DICT[key])
158
159    def test_fromXML(self):
160        hhea = self.font["hhea"]
161        for name, attrs, content in parseXML(HHEA_XML):
162            hhea.fromXML(name, attrs, content, self.font)
163        for key in hhea.__dict__:
164            self.assertEqual(getattr(hhea, key), HHEA_AS_DICT[key])
165
166    def test_fromXML_version_as_float(self):
167        hhea = self.font["hhea"]
168        with CapturingLogHandler(log, "WARNING") as captor:
169            for name, attrs, content in parseXML(HHEA_XML_VERSION_AS_FLOAT):
170                hhea.fromXML(name, attrs, content, self.font)
171        self.assertTrue(
172            len(
173                [r for r in captor.records if "Table version value is a float" in r.msg]
174            )
175            == 1
176        )
177        for key in hhea.__dict__:
178            self.assertEqual(getattr(hhea, key), HHEA_AS_DICT[key])
179
180
181class HheaRecalcTest(unittest.TestCase):
182    def test_recalc_TTF(self):
183        font = TTFont()
184        font.importXML(os.path.join(DATA_DIR, "_h_h_e_a_recalc_TTF.ttx"))
185        hhea = font["hhea"]
186        hhea.recalc(font)
187        self.assertEqual(hhea.advanceWidthMax, 600)
188        self.assertEqual(hhea.minLeftSideBearing, -56)
189        self.assertEqual(hhea.minRightSideBearing, 100)
190        self.assertEqual(hhea.xMaxExtent, 400)
191
192    def test_recalc_OTF(self):
193        font = TTFont()
194        font.importXML(os.path.join(DATA_DIR, "_h_h_e_a_recalc_OTF.ttx"))
195        hhea = font["hhea"]
196        hhea.recalc(font)
197        self.assertEqual(hhea.advanceWidthMax, 600)
198        self.assertEqual(hhea.minLeftSideBearing, -56)
199        self.assertEqual(hhea.minRightSideBearing, 100)
200        self.assertEqual(hhea.xMaxExtent, 400)
201
202    def test_recalc_empty(self):
203        font = TTFont()
204        font.importXML(os.path.join(DATA_DIR, "_h_h_e_a_recalc_empty.ttx"))
205        hhea = font["hhea"]
206        hhea.recalc(font)
207        self.assertEqual(hhea.advanceWidthMax, 600)
208        self.assertEqual(hhea.minLeftSideBearing, 0)
209        self.assertEqual(hhea.minRightSideBearing, 0)
210        self.assertEqual(hhea.xMaxExtent, 0)
211
212
213if __name__ == "__main__":
214    import sys
215
216    sys.exit(unittest.main())
217