xref: /aosp_15_r20/external/fonttools/Tests/pens/qu2cuPen_test.py (revision e1fe3e4ad2793916b15cccdc4a7da52a7e1dd0e9)
1*e1fe3e4aSElliott Hughes# Copyright 2016 Google Inc. All Rights Reserved.
2*e1fe3e4aSElliott Hughes#
3*e1fe3e4aSElliott Hughes# Licensed under the Apache License, Version 2.0 (the "License");
4*e1fe3e4aSElliott Hughes# you may not use this file except in compliance with the License.
5*e1fe3e4aSElliott Hughes# You may obtain a copy of the License at
6*e1fe3e4aSElliott Hughes#
7*e1fe3e4aSElliott Hughes#     http://www.apache.org/licenses/LICENSE-2.0
8*e1fe3e4aSElliott Hughes#
9*e1fe3e4aSElliott Hughes# Unless required by applicable law or agreed to in writing, software
10*e1fe3e4aSElliott Hughes# distributed under the License is distributed on an "AS IS" BASIS,
11*e1fe3e4aSElliott Hughes# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e1fe3e4aSElliott Hughes# See the License for the specific language governing permissions and
13*e1fe3e4aSElliott Hughes# limitations under the License.
14*e1fe3e4aSElliott Hughes
15*e1fe3e4aSElliott Hughesimport sys
16*e1fe3e4aSElliott Hughesimport unittest
17*e1fe3e4aSElliott Hughes
18*e1fe3e4aSElliott Hughesfrom fontTools.pens.qu2cuPen import Qu2CuPen
19*e1fe3e4aSElliott Hughesfrom fontTools.pens.recordingPen import RecordingPen
20*e1fe3e4aSElliott Hughesfrom textwrap import dedent
21*e1fe3e4aSElliott Hughesimport pytest
22*e1fe3e4aSElliott Hughes
23*e1fe3e4aSElliott Hughestry:
24*e1fe3e4aSElliott Hughes    from .utils import CUBIC_GLYPHS, QUAD_GLYPHS
25*e1fe3e4aSElliott Hughes    from .utils import DummyGlyph
26*e1fe3e4aSElliott Hughes    from .utils import DummyPen
27*e1fe3e4aSElliott Hughesexcept ImportError as e:
28*e1fe3e4aSElliott Hughes    pytest.skip(str(e), allow_module_level=True)
29*e1fe3e4aSElliott Hughes
30*e1fe3e4aSElliott HughesMAX_ERR = 1.0
31*e1fe3e4aSElliott Hughes
32*e1fe3e4aSElliott Hughes
33*e1fe3e4aSElliott Hughesclass _TestPenMixin(object):
34*e1fe3e4aSElliott Hughes    """Collection of tests that are shared by both the SegmentPen and the
35*e1fe3e4aSElliott Hughes    PointPen test cases, plus some helper methods.
36*e1fe3e4aSElliott Hughes    Note: We currently don't have a PointPen.
37*e1fe3e4aSElliott Hughes    """
38*e1fe3e4aSElliott Hughes
39*e1fe3e4aSElliott Hughes    maxDiff = None
40*e1fe3e4aSElliott Hughes
41*e1fe3e4aSElliott Hughes    def diff(self, expected, actual):
42*e1fe3e4aSElliott Hughes        import difflib
43*e1fe3e4aSElliott Hughes
44*e1fe3e4aSElliott Hughes        expected = str(self.Glyph(expected)).splitlines(True)
45*e1fe3e4aSElliott Hughes        actual = str(self.Glyph(actual)).splitlines(True)
46*e1fe3e4aSElliott Hughes        diff = difflib.unified_diff(
47*e1fe3e4aSElliott Hughes            expected, actual, fromfile="expected", tofile="actual"
48*e1fe3e4aSElliott Hughes        )
49*e1fe3e4aSElliott Hughes        return "".join(diff)
50*e1fe3e4aSElliott Hughes
51*e1fe3e4aSElliott Hughes    def convert_glyph(self, glyph, **kwargs):
52*e1fe3e4aSElliott Hughes        # draw source glyph onto a new glyph using a Cu2Qu pen and return it
53*e1fe3e4aSElliott Hughes        converted = self.Glyph()
54*e1fe3e4aSElliott Hughes        pen = getattr(converted, self.pen_getter_name)()
55*e1fe3e4aSElliott Hughes        cubicpen = self.Qu2CuPen(pen, MAX_ERR, all_cubic=True, **kwargs)
56*e1fe3e4aSElliott Hughes        getattr(glyph, self.draw_method_name)(cubicpen)
57*e1fe3e4aSElliott Hughes        return converted
58*e1fe3e4aSElliott Hughes
59*e1fe3e4aSElliott Hughes    def expect_glyph(self, source, expected):
60*e1fe3e4aSElliott Hughes        converted = self.convert_glyph(source)
61*e1fe3e4aSElliott Hughes        self.assertNotEqual(converted, source)
62*e1fe3e4aSElliott Hughes        if not converted.approx(expected):
63*e1fe3e4aSElliott Hughes            print(self.diff(expected, converted))
64*e1fe3e4aSElliott Hughes            self.fail("converted glyph is different from expected")
65*e1fe3e4aSElliott Hughes
66*e1fe3e4aSElliott Hughes    def test_convert_simple_glyph(self):
67*e1fe3e4aSElliott Hughes        self.expect_glyph(QUAD_GLYPHS["a"], CUBIC_GLYPHS["a"])
68*e1fe3e4aSElliott Hughes        self.expect_glyph(QUAD_GLYPHS["A"], CUBIC_GLYPHS["A"])
69*e1fe3e4aSElliott Hughes
70*e1fe3e4aSElliott Hughes    def test_convert_composite_glyph(self):
71*e1fe3e4aSElliott Hughes        source = CUBIC_GLYPHS["Aacute"]
72*e1fe3e4aSElliott Hughes        converted = self.convert_glyph(source)
73*e1fe3e4aSElliott Hughes        # components don't change after quadratic conversion
74*e1fe3e4aSElliott Hughes        self.assertEqual(converted, source)
75*e1fe3e4aSElliott Hughes
76*e1fe3e4aSElliott Hughes    def test_reverse_direction(self):
77*e1fe3e4aSElliott Hughes        for name in ("a", "A", "Eacute"):
78*e1fe3e4aSElliott Hughes            source = QUAD_GLYPHS[name]
79*e1fe3e4aSElliott Hughes            normal_glyph = self.convert_glyph(source)
80*e1fe3e4aSElliott Hughes            reversed_glyph = self.convert_glyph(source, reverse_direction=True)
81*e1fe3e4aSElliott Hughes
82*e1fe3e4aSElliott Hughes            # the number of commands is the same, just their order is iverted
83*e1fe3e4aSElliott Hughes            self.assertTrue(len(normal_glyph.outline), len(reversed_glyph.outline))
84*e1fe3e4aSElliott Hughes            self.assertNotEqual(normal_glyph, reversed_glyph)
85*e1fe3e4aSElliott Hughes
86*e1fe3e4aSElliott Hughes    def test_stats(self):
87*e1fe3e4aSElliott Hughes        stats = {}
88*e1fe3e4aSElliott Hughes        for name in QUAD_GLYPHS.keys():
89*e1fe3e4aSElliott Hughes            source = QUAD_GLYPHS[name]
90*e1fe3e4aSElliott Hughes            self.convert_glyph(source, stats=stats)
91*e1fe3e4aSElliott Hughes
92*e1fe3e4aSElliott Hughes        self.assertTrue(stats)
93*e1fe3e4aSElliott Hughes        self.assertTrue("2" in stats)
94*e1fe3e4aSElliott Hughes        self.assertEqual(type(stats["2"]), int)
95*e1fe3e4aSElliott Hughes
96*e1fe3e4aSElliott Hughes    def test_addComponent(self):
97*e1fe3e4aSElliott Hughes        pen = self.Pen()
98*e1fe3e4aSElliott Hughes        cubicpen = self.Qu2CuPen(pen, MAX_ERR)
99*e1fe3e4aSElliott Hughes        cubicpen.addComponent("a", (1, 2, 3, 4, 5.0, 6.0))
100*e1fe3e4aSElliott Hughes
101*e1fe3e4aSElliott Hughes        # components are passed through without changes
102*e1fe3e4aSElliott Hughes        self.assertEqual(
103*e1fe3e4aSElliott Hughes            str(pen).splitlines(),
104*e1fe3e4aSElliott Hughes            [
105*e1fe3e4aSElliott Hughes                "pen.addComponent('a', (1, 2, 3, 4, 5.0, 6.0))",
106*e1fe3e4aSElliott Hughes            ],
107*e1fe3e4aSElliott Hughes        )
108*e1fe3e4aSElliott Hughes
109*e1fe3e4aSElliott Hughes
110*e1fe3e4aSElliott Hughesclass TestQu2CuPen(unittest.TestCase, _TestPenMixin):
111*e1fe3e4aSElliott Hughes    def __init__(self, *args, **kwargs):
112*e1fe3e4aSElliott Hughes        super(TestQu2CuPen, self).__init__(*args, **kwargs)
113*e1fe3e4aSElliott Hughes        self.Glyph = DummyGlyph
114*e1fe3e4aSElliott Hughes        self.Pen = DummyPen
115*e1fe3e4aSElliott Hughes        self.Qu2CuPen = Qu2CuPen
116*e1fe3e4aSElliott Hughes        self.pen_getter_name = "getPen"
117*e1fe3e4aSElliott Hughes        self.draw_method_name = "draw"
118*e1fe3e4aSElliott Hughes
119*e1fe3e4aSElliott Hughes    def test_qCurveTo_1_point(self):
120*e1fe3e4aSElliott Hughes        pen = DummyPen()
121*e1fe3e4aSElliott Hughes        cubicpen = Qu2CuPen(pen, MAX_ERR)
122*e1fe3e4aSElliott Hughes        cubicpen.moveTo((0, 0))
123*e1fe3e4aSElliott Hughes        cubicpen.qCurveTo((1, 1))
124*e1fe3e4aSElliott Hughes        cubicpen.closePath()
125*e1fe3e4aSElliott Hughes
126*e1fe3e4aSElliott Hughes        self.assertEqual(
127*e1fe3e4aSElliott Hughes            str(pen).splitlines(),
128*e1fe3e4aSElliott Hughes            [
129*e1fe3e4aSElliott Hughes                "pen.moveTo((0, 0))",
130*e1fe3e4aSElliott Hughes                "pen.qCurveTo((1, 1))",
131*e1fe3e4aSElliott Hughes                "pen.closePath()",
132*e1fe3e4aSElliott Hughes            ],
133*e1fe3e4aSElliott Hughes        )
134*e1fe3e4aSElliott Hughes
135*e1fe3e4aSElliott Hughes    def test_qCurveTo_2_points(self):
136*e1fe3e4aSElliott Hughes        pen = DummyPen()
137*e1fe3e4aSElliott Hughes        cubicpen = Qu2CuPen(pen, MAX_ERR)
138*e1fe3e4aSElliott Hughes        cubicpen.moveTo((0, 0))
139*e1fe3e4aSElliott Hughes        cubicpen.qCurveTo((1, 1), (2, 2))
140*e1fe3e4aSElliott Hughes        cubicpen.closePath()
141*e1fe3e4aSElliott Hughes
142*e1fe3e4aSElliott Hughes        self.assertEqual(
143*e1fe3e4aSElliott Hughes            str(pen).splitlines(),
144*e1fe3e4aSElliott Hughes            [
145*e1fe3e4aSElliott Hughes                "pen.moveTo((0, 0))",
146*e1fe3e4aSElliott Hughes                "pen.qCurveTo((1, 1), (2, 2))",
147*e1fe3e4aSElliott Hughes                "pen.closePath()",
148*e1fe3e4aSElliott Hughes            ],
149*e1fe3e4aSElliott Hughes        )
150*e1fe3e4aSElliott Hughes
151*e1fe3e4aSElliott Hughes    def test_qCurveTo_3_points_no_conversion(self):
152*e1fe3e4aSElliott Hughes        pen = DummyPen()
153*e1fe3e4aSElliott Hughes        cubicpen = Qu2CuPen(pen, MAX_ERR)
154*e1fe3e4aSElliott Hughes        cubicpen.moveTo((0, 0))
155*e1fe3e4aSElliott Hughes        cubicpen.qCurveTo((0, 3), (1, 3), (1, 0))
156*e1fe3e4aSElliott Hughes        cubicpen.closePath()
157*e1fe3e4aSElliott Hughes
158*e1fe3e4aSElliott Hughes        self.assertEqual(
159*e1fe3e4aSElliott Hughes            str(pen).splitlines(),
160*e1fe3e4aSElliott Hughes            [
161*e1fe3e4aSElliott Hughes                "pen.moveTo((0, 0))",
162*e1fe3e4aSElliott Hughes                "pen.qCurveTo((0, 3), (1, 3), (1, 0))",
163*e1fe3e4aSElliott Hughes                "pen.closePath()",
164*e1fe3e4aSElliott Hughes            ],
165*e1fe3e4aSElliott Hughes        )
166*e1fe3e4aSElliott Hughes
167*e1fe3e4aSElliott Hughes    def test_qCurveTo_no_oncurve_points(self):
168*e1fe3e4aSElliott Hughes        pen = DummyPen()
169*e1fe3e4aSElliott Hughes        cubicpen = Qu2CuPen(pen, MAX_ERR)
170*e1fe3e4aSElliott Hughes        cubicpen.qCurveTo((0, 0), (1, 0), (1, 1), (0, 1), None)
171*e1fe3e4aSElliott Hughes        cubicpen.closePath()
172*e1fe3e4aSElliott Hughes
173*e1fe3e4aSElliott Hughes        self.assertEqual(
174*e1fe3e4aSElliott Hughes            str(pen).splitlines(),
175*e1fe3e4aSElliott Hughes            ["pen.qCurveTo((0, 0), (1, 0), (1, 1), (0, 1), None)", "pen.closePath()"],
176*e1fe3e4aSElliott Hughes        )
177*e1fe3e4aSElliott Hughes
178*e1fe3e4aSElliott Hughes    def test_curveTo_1_point(self):
179*e1fe3e4aSElliott Hughes        pen = DummyPen()
180*e1fe3e4aSElliott Hughes        cubicpen = Qu2CuPen(pen, MAX_ERR)
181*e1fe3e4aSElliott Hughes        cubicpen.moveTo((0, 0))
182*e1fe3e4aSElliott Hughes        cubicpen.curveTo((1, 1))
183*e1fe3e4aSElliott Hughes        cubicpen.closePath()
184*e1fe3e4aSElliott Hughes
185*e1fe3e4aSElliott Hughes        self.assertEqual(
186*e1fe3e4aSElliott Hughes            str(pen).splitlines(),
187*e1fe3e4aSElliott Hughes            [
188*e1fe3e4aSElliott Hughes                "pen.moveTo((0, 0))",
189*e1fe3e4aSElliott Hughes                "pen.curveTo((1, 1))",
190*e1fe3e4aSElliott Hughes                "pen.closePath()",
191*e1fe3e4aSElliott Hughes            ],
192*e1fe3e4aSElliott Hughes        )
193*e1fe3e4aSElliott Hughes
194*e1fe3e4aSElliott Hughes    def test_curveTo_2_points(self):
195*e1fe3e4aSElliott Hughes        pen = DummyPen()
196*e1fe3e4aSElliott Hughes        cubicpen = Qu2CuPen(pen, MAX_ERR)
197*e1fe3e4aSElliott Hughes        cubicpen.moveTo((0, 0))
198*e1fe3e4aSElliott Hughes        cubicpen.curveTo((1, 1), (2, 2))
199*e1fe3e4aSElliott Hughes        cubicpen.closePath()
200*e1fe3e4aSElliott Hughes
201*e1fe3e4aSElliott Hughes        self.assertEqual(
202*e1fe3e4aSElliott Hughes            str(pen).splitlines(),
203*e1fe3e4aSElliott Hughes            [
204*e1fe3e4aSElliott Hughes                "pen.moveTo((0, 0))",
205*e1fe3e4aSElliott Hughes                "pen.curveTo((1, 1), (2, 2))",
206*e1fe3e4aSElliott Hughes                "pen.closePath()",
207*e1fe3e4aSElliott Hughes            ],
208*e1fe3e4aSElliott Hughes        )
209*e1fe3e4aSElliott Hughes
210*e1fe3e4aSElliott Hughes    def test_curveTo_3_points(self):
211*e1fe3e4aSElliott Hughes        pen = DummyPen()
212*e1fe3e4aSElliott Hughes        cubicpen = Qu2CuPen(pen, MAX_ERR)
213*e1fe3e4aSElliott Hughes        cubicpen.moveTo((0, 0))
214*e1fe3e4aSElliott Hughes        cubicpen.curveTo((1, 1), (2, 2), (3, 3))
215*e1fe3e4aSElliott Hughes        cubicpen.closePath()
216*e1fe3e4aSElliott Hughes
217*e1fe3e4aSElliott Hughes        self.assertEqual(
218*e1fe3e4aSElliott Hughes            str(pen).splitlines(),
219*e1fe3e4aSElliott Hughes            [
220*e1fe3e4aSElliott Hughes                "pen.moveTo((0, 0))",
221*e1fe3e4aSElliott Hughes                "pen.curveTo((1, 1), (2, 2), (3, 3))",
222*e1fe3e4aSElliott Hughes                "pen.closePath()",
223*e1fe3e4aSElliott Hughes            ],
224*e1fe3e4aSElliott Hughes        )
225*e1fe3e4aSElliott Hughes
226*e1fe3e4aSElliott Hughes    def test_all_cubic(self):
227*e1fe3e4aSElliott Hughes        inPen = RecordingPen()
228*e1fe3e4aSElliott Hughes        inPen.value = [
229*e1fe3e4aSElliott Hughes            ("moveTo", ((1204, 347),)),
230*e1fe3e4aSElliott Hughes            ("qCurveTo", ((1255, 347), (1323, 433), (1323, 467))),
231*e1fe3e4aSElliott Hughes            ("qCurveTo", ((1323, 478), (1310, 492), (1302, 492))),
232*e1fe3e4aSElliott Hughes            ("qCurveTo", ((1295, 492), (1289, 484))),
233*e1fe3e4aSElliott Hughes            ("lineTo", ((1272, 461),)),
234*e1fe3e4aSElliott Hughes            ("qCurveTo", ((1256, 439), (1221, 416), (1200, 416))),
235*e1fe3e4aSElliott Hughes            ("qCurveTo", ((1181, 416), (1141, 440), (1141, 462))),
236*e1fe3e4aSElliott Hughes            ("qCurveTo", ((1141, 484), (1190, 565), (1190, 594))),
237*e1fe3e4aSElliott Hughes            ("qCurveTo", ((1190, 607), (1181, 634), (1168, 634))),
238*e1fe3e4aSElliott Hughes            ("qCurveTo", ((1149, 634), (1146, 583), (1081, 496), (1081, 463))),
239*e1fe3e4aSElliott Hughes            ("qCurveTo", ((1081, 417), (1164, 347), (1204, 347))),
240*e1fe3e4aSElliott Hughes            ("closePath", ()),
241*e1fe3e4aSElliott Hughes        ]
242*e1fe3e4aSElliott Hughes
243*e1fe3e4aSElliott Hughes        outPen = RecordingPen()
244*e1fe3e4aSElliott Hughes        q2cPen = Qu2CuPen(outPen, 1.0, all_cubic=True)
245*e1fe3e4aSElliott Hughes        inPen.replay(q2cPen)
246*e1fe3e4aSElliott Hughes
247*e1fe3e4aSElliott Hughes        print(outPen.value)
248*e1fe3e4aSElliott Hughes
249*e1fe3e4aSElliott Hughes        assert not any(typ == "qCurveTo" for typ, _ in outPen.value)
250*e1fe3e4aSElliott Hughes
251*e1fe3e4aSElliott Hughes
252*e1fe3e4aSElliott Hughesif __name__ == "__main__":
253*e1fe3e4aSElliott Hughes    unittest.main()
254