1from __future__ import print_function, division, absolute_import
2from fontTools.misc.py23 import *
3from fontTools.pens.t2CharStringPen import T2CharStringPen
4import unittest
5
6
7class T2CharStringPenTest(unittest.TestCase):
8
9    def __init__(self, methodName):
10        unittest.TestCase.__init__(self, methodName)
11        # Python 3 renamed assertRaisesRegexp to assertRaisesRegex,
12        # and fires deprecation warnings if a program uses the old name.
13        if not hasattr(self, "assertRaisesRegex"):
14            self.assertRaisesRegex = self.assertRaisesRegexp
15
16    def assertAlmostEqualProgram(self, expected, actual):
17        self.assertEqual(len(expected), len(actual))
18        for i1, i2 in zip(expected, actual):
19            if isinstance(i1, basestring):
20                self.assertIsInstance(i2, basestring)
21                self.assertEqual(i1, i2)
22            else:
23                self.assertAlmostEqual(i1, i2)
24
25    def test_draw_h_v_lines(self):
26        pen = T2CharStringPen(100, {})
27        pen.moveTo((0, 0))
28        pen.lineTo((10, 0))
29        pen.lineTo((10, 10))
30        pen.lineTo((0, 10))
31        pen.closePath()  # no-op
32        pen.moveTo((10, 10))
33        pen.lineTo((10, 20))
34        pen.lineTo((0, 20))
35        pen.lineTo((0, 10))
36        pen.closePath()
37        charstring = pen.getCharString(None, None)
38
39        self.assertEqual(
40            [100,
41             0, 'hmoveto',
42             10, 10, -10, 'hlineto',
43             10, 'hmoveto',
44             10, -10, -10, 'vlineto',
45             'endchar'],
46            charstring.program)
47
48    def test_draw_lines(self):
49        pen = T2CharStringPen(100, {})
50        pen.moveTo((5, 5))
51        pen.lineTo((25, 15))
52        pen.lineTo((35, 35))
53        pen.lineTo((15, 25))
54        pen.closePath()  # no-op
55        charstring = pen.getCharString(None, None)
56
57        self.assertEqual(
58            [100,
59             5, 5, 'rmoveto',
60             20, 10, 10, 20, -20, -10, 'rlineto',
61             'endchar'],
62            charstring.program)
63
64    def test_draw_h_v_curves(self):
65        pen = T2CharStringPen(100, {})
66        pen.moveTo((0, 0))
67        pen.curveTo((10, 0), (20, 10), (20, 20))
68        pen.curveTo((20, 30), (10, 40), (0, 40))
69        pen.endPath()  # no-op
70        charstring = pen.getCharString(None, None)
71
72        self.assertEqual(
73            [100,
74             0, 'hmoveto',
75             10, 10, 10, 10, 10, -10, 10, -10, 'hvcurveto',
76             'endchar'],
77            charstring.program)
78
79    def test_draw_curves(self):
80        pen = T2CharStringPen(100, {})
81        pen.moveTo((95, 25))
82        pen.curveTo((115, 44), (115, 76), (95, 95))
83        pen.curveTo((76, 114), (44, 115), (25, 95))
84        pen.endPath()  # no-op
85        charstring = pen.getCharString(None, None)
86
87        self.assertEqual(
88            [100,
89             95, 25, 'rmoveto',
90             20, 19, 0, 32, -20, 19, -19, 19, -32, 1, -19, -20, 'rrcurveto',
91             'endchar'],
92            charstring.program)
93
94    def test_draw_more_curves(self):
95        pen = T2CharStringPen(100, {})
96        pen.moveTo((10, 10))
97        pen.curveTo((20, 10), (50, 10), (60, 10))
98        pen.curveTo((60, 20), (60, 50), (60, 60))
99        pen.curveTo((50, 50), (40, 60), (30, 60))
100        pen.curveTo((40, 50), (30, 40), (30, 30))
101        pen.curveTo((30, 25), (25, 19), (20, 20))
102        pen.curveTo((15, 20), (9, 25), (10, 30))
103        pen.curveTo((7, 25), (6, 15), (10, 10))
104        pen.endPath()  # no-op
105        charstring = pen.getCharString(None, None)
106
107        self.assertEqual(
108            [100,
109             10, 10, 'rmoveto',
110             10, 30, 0, 10, 'hhcurveto',
111             10, 0, 30, 10, 'vvcurveto',
112             -10, -10, -10, 10, -10, 'hhcurveto',
113             10, -10, -10, -10, -10, 'vvcurveto',
114             -5, -5, -6, -5, 1, 'vhcurveto',
115             -5, -6, 5, 5, 1, 'hvcurveto',
116             -3, -5, -1, -10, 4, -5, 'rrcurveto',
117             'endchar'],
118            charstring.program)
119
120    def test_default_width(self):
121        pen = T2CharStringPen(None, {})
122        charstring = pen.getCharString(None, None)
123        self.assertEqual(['endchar'], charstring.program)
124
125    def test_no_round(self):
126        pen = T2CharStringPen(100.1, {}, roundTolerance=0.0)
127        pen.moveTo((0, 0))
128        pen.curveTo((10.1, 0.1), (19.9, 9.9), (20.49, 20.49))
129        pen.curveTo((20.49, 30.49), (9.9, 39.9), (0.1, 40.1))
130        pen.closePath()
131        charstring = pen.getCharString(None, None)
132
133        self.assertAlmostEqualProgram(
134            [100,  # we always round the advance width
135             0, 'hmoveto',
136             10.1, 0.1, 9.8, 9.8, 0.59, 10.59, 'rrcurveto',
137             10, -10.59, 9.41, -9.8, 0.2, 'vhcurveto',
138             'endchar'],
139            charstring.program)
140
141    def test_round_all(self):
142        pen = T2CharStringPen(100.1, {}, roundTolerance=0.5)
143        pen.moveTo((0, 0))
144        pen.curveTo((10.1, 0.1), (19.9, 9.9), (20.49, 20.49))
145        pen.curveTo((20.49, 30.5), (9.9, 39.9), (0.1, 40.1))
146        pen.closePath()
147        charstring = pen.getCharString(None, None)
148
149        self.assertEqual(
150            [100,
151             0, 'hmoveto',
152             10, 10, 10, 10, 11, -10, 9, -10, 'hvcurveto',
153             'endchar'],
154            charstring.program)
155
156    def test_round_some(self):
157        pen = T2CharStringPen(100, {}, roundTolerance=0.2)
158        pen.moveTo((0, 0))
159        # the following two are rounded as within the tolerance
160        pen.lineTo((10.1, 0.1))
161        pen.lineTo((19.9, 9.9))
162        # this one is not rounded as it exceeds the tolerance
163        pen.lineTo((20.49, 20.49))
164        pen.closePath()
165        charstring = pen.getCharString(None, None)
166
167        self.assertAlmostEqualProgram(
168            [100,
169             0, 'hmoveto',
170             10, 'hlineto',
171             10, 10, 0.49, 10.49, 'rlineto',
172             'endchar'],
173            charstring.program)
174
175    def test_invalid_tolerance(self):
176        self.assertRaisesRegex(
177            ValueError,
178            "Rounding tolerance must be positive",
179            T2CharStringPen, None, {}, roundTolerance=-0.1)
180
181
182if __name__ == '__main__':
183    import sys
184    sys.exit(unittest.main())
185