xref: /aosp_15_r20/external/fonttools/Tests/pens/ttGlyphPen_test.py (revision e1fe3e4ad2793916b15cccdc4a7da52a7e1dd0e9)
1*e1fe3e4aSElliott Hughesimport os
2*e1fe3e4aSElliott Hughesimport pytest
3*e1fe3e4aSElliott Hughesimport struct
4*e1fe3e4aSElliott Hughes
5*e1fe3e4aSElliott Hughesfrom fontTools import ttLib
6*e1fe3e4aSElliott Hughesfrom fontTools.pens.basePen import PenError
7*e1fe3e4aSElliott Hughesfrom fontTools.pens.recordingPen import RecordingPen, RecordingPointPen
8*e1fe3e4aSElliott Hughesfrom fontTools.pens.ttGlyphPen import TTGlyphPen, TTGlyphPointPen, MAX_F2DOT14
9*e1fe3e4aSElliott Hughes
10*e1fe3e4aSElliott Hughes
11*e1fe3e4aSElliott Hughesclass TTGlyphPenTestBase:
12*e1fe3e4aSElliott Hughes    def runEndToEnd(self, filename):
13*e1fe3e4aSElliott Hughes        font = ttLib.TTFont()
14*e1fe3e4aSElliott Hughes        ttx_path = os.path.join(
15*e1fe3e4aSElliott Hughes            os.path.abspath(os.path.dirname(os.path.realpath(__file__))),
16*e1fe3e4aSElliott Hughes            "..",
17*e1fe3e4aSElliott Hughes            "ttLib",
18*e1fe3e4aSElliott Hughes            "data",
19*e1fe3e4aSElliott Hughes            filename,
20*e1fe3e4aSElliott Hughes        )
21*e1fe3e4aSElliott Hughes        font.importXML(ttx_path)
22*e1fe3e4aSElliott Hughes
23*e1fe3e4aSElliott Hughes        glyphSet = font.getGlyphSet()
24*e1fe3e4aSElliott Hughes        glyfTable = font["glyf"]
25*e1fe3e4aSElliott Hughes        pen = self.penClass(glyphSet)
26*e1fe3e4aSElliott Hughes
27*e1fe3e4aSElliott Hughes        for name in font.getGlyphOrder():
28*e1fe3e4aSElliott Hughes            getattr(glyphSet[name], self.drawMethod)(pen)
29*e1fe3e4aSElliott Hughes            oldGlyph = glyfTable[name]
30*e1fe3e4aSElliott Hughes            newGlyph = pen.glyph()
31*e1fe3e4aSElliott Hughes
32*e1fe3e4aSElliott Hughes            if hasattr(oldGlyph, "program"):
33*e1fe3e4aSElliott Hughes                newGlyph.program = oldGlyph.program
34*e1fe3e4aSElliott Hughes
35*e1fe3e4aSElliott Hughes            assert oldGlyph.compile(glyfTable) == newGlyph.compile(glyfTable)
36*e1fe3e4aSElliott Hughes
37*e1fe3e4aSElliott Hughes    def test_e2e_linesAndSimpleComponents(self):
38*e1fe3e4aSElliott Hughes        self.runEndToEnd("TestTTF-Regular.ttx")
39*e1fe3e4aSElliott Hughes
40*e1fe3e4aSElliott Hughes    def test_e2e_curvesAndComponentTransforms(self):
41*e1fe3e4aSElliott Hughes        self.runEndToEnd("TestTTFComplex-Regular.ttx")
42*e1fe3e4aSElliott Hughes
43*e1fe3e4aSElliott Hughes
44*e1fe3e4aSElliott Hughesclass TTGlyphPenTest(TTGlyphPenTestBase):
45*e1fe3e4aSElliott Hughes    penClass = TTGlyphPen
46*e1fe3e4aSElliott Hughes    drawMethod = "draw"
47*e1fe3e4aSElliott Hughes
48*e1fe3e4aSElliott Hughes    def test_moveTo_errorWithinContour(self):
49*e1fe3e4aSElliott Hughes        pen = TTGlyphPen(None)
50*e1fe3e4aSElliott Hughes        pen.moveTo((0, 0))
51*e1fe3e4aSElliott Hughes        with pytest.raises(PenError):
52*e1fe3e4aSElliott Hughes            pen.moveTo((1, 0))
53*e1fe3e4aSElliott Hughes
54*e1fe3e4aSElliott Hughes    def test_closePath_ignoresAnchors(self):
55*e1fe3e4aSElliott Hughes        pen = TTGlyphPen(None)
56*e1fe3e4aSElliott Hughes        pen.moveTo((0, 0))
57*e1fe3e4aSElliott Hughes        pen.closePath()
58*e1fe3e4aSElliott Hughes        assert not pen.points
59*e1fe3e4aSElliott Hughes        assert not pen.types
60*e1fe3e4aSElliott Hughes        assert not pen.endPts
61*e1fe3e4aSElliott Hughes
62*e1fe3e4aSElliott Hughes    def test_endPath_sameAsClosePath(self):
63*e1fe3e4aSElliott Hughes        pen = TTGlyphPen(None)
64*e1fe3e4aSElliott Hughes
65*e1fe3e4aSElliott Hughes        pen.moveTo((0, 0))
66*e1fe3e4aSElliott Hughes        pen.lineTo((0, 1))
67*e1fe3e4aSElliott Hughes        pen.lineTo((1, 0))
68*e1fe3e4aSElliott Hughes        pen.closePath()
69*e1fe3e4aSElliott Hughes        closePathGlyph = pen.glyph()
70*e1fe3e4aSElliott Hughes
71*e1fe3e4aSElliott Hughes        pen.moveTo((0, 0))
72*e1fe3e4aSElliott Hughes        pen.lineTo((0, 1))
73*e1fe3e4aSElliott Hughes        pen.lineTo((1, 0))
74*e1fe3e4aSElliott Hughes        pen.endPath()
75*e1fe3e4aSElliott Hughes        endPathGlyph = pen.glyph()
76*e1fe3e4aSElliott Hughes
77*e1fe3e4aSElliott Hughes        assert closePathGlyph == endPathGlyph
78*e1fe3e4aSElliott Hughes
79*e1fe3e4aSElliott Hughes    def test_glyph_errorOnUnendedContour(self):
80*e1fe3e4aSElliott Hughes        pen = TTGlyphPen(None)
81*e1fe3e4aSElliott Hughes        pen.moveTo((0, 0))
82*e1fe3e4aSElliott Hughes        with pytest.raises(PenError):
83*e1fe3e4aSElliott Hughes            pen.glyph()
84*e1fe3e4aSElliott Hughes
85*e1fe3e4aSElliott Hughes    def test_glyph_decomposes(self):
86*e1fe3e4aSElliott Hughes        componentName = "a"
87*e1fe3e4aSElliott Hughes        glyphSet = {}
88*e1fe3e4aSElliott Hughes        pen = TTGlyphPen(glyphSet)
89*e1fe3e4aSElliott Hughes
90*e1fe3e4aSElliott Hughes        pen.moveTo((0, 0))
91*e1fe3e4aSElliott Hughes        pen.lineTo((0, 1))
92*e1fe3e4aSElliott Hughes        pen.lineTo((1, 0))
93*e1fe3e4aSElliott Hughes        pen.closePath()
94*e1fe3e4aSElliott Hughes        glyphSet[componentName] = _TestGlyph(pen.glyph())
95*e1fe3e4aSElliott Hughes
96*e1fe3e4aSElliott Hughes        pen.moveTo((0, 0))
97*e1fe3e4aSElliott Hughes        pen.lineTo((0, 1))
98*e1fe3e4aSElliott Hughes        pen.lineTo((1, 0))
99*e1fe3e4aSElliott Hughes        pen.closePath()
100*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1, 0, 0, 1, 2, 0))
101*e1fe3e4aSElliott Hughes        pen.addComponent("missing", (1, 0, 0, 1, 0, 0))  # skipped
102*e1fe3e4aSElliott Hughes        compositeGlyph = pen.glyph()
103*e1fe3e4aSElliott Hughes
104*e1fe3e4aSElliott Hughes        pen.moveTo((0, 0))
105*e1fe3e4aSElliott Hughes        pen.lineTo((0, 1))
106*e1fe3e4aSElliott Hughes        pen.lineTo((1, 0))
107*e1fe3e4aSElliott Hughes        pen.closePath()
108*e1fe3e4aSElliott Hughes        pen.moveTo((2, 0))
109*e1fe3e4aSElliott Hughes        pen.lineTo((2, 1))
110*e1fe3e4aSElliott Hughes        pen.lineTo((3, 0))
111*e1fe3e4aSElliott Hughes        pen.closePath()
112*e1fe3e4aSElliott Hughes        plainGlyph = pen.glyph()
113*e1fe3e4aSElliott Hughes
114*e1fe3e4aSElliott Hughes        assert plainGlyph == compositeGlyph
115*e1fe3e4aSElliott Hughes
116*e1fe3e4aSElliott Hughes    def test_remove_extra_move_points(self):
117*e1fe3e4aSElliott Hughes        pen = TTGlyphPen(None)
118*e1fe3e4aSElliott Hughes        pen.moveTo((0, 0))
119*e1fe3e4aSElliott Hughes        pen.lineTo((100, 0))
120*e1fe3e4aSElliott Hughes        pen.qCurveTo((100, 50), (50, 100), (0, 0))
121*e1fe3e4aSElliott Hughes        pen.closePath()
122*e1fe3e4aSElliott Hughes        assert len(pen.points) == 4
123*e1fe3e4aSElliott Hughes        assert pen.points[0] == (0, 0)
124*e1fe3e4aSElliott Hughes
125*e1fe3e4aSElliott Hughes    def test_keep_move_point(self):
126*e1fe3e4aSElliott Hughes        pen = TTGlyphPen(None)
127*e1fe3e4aSElliott Hughes        pen.moveTo((0, 0))
128*e1fe3e4aSElliott Hughes        pen.lineTo((100, 0))
129*e1fe3e4aSElliott Hughes        pen.qCurveTo((100, 50), (50, 100), (30, 30))
130*e1fe3e4aSElliott Hughes        # when last and move pts are different, closePath() implies a lineTo
131*e1fe3e4aSElliott Hughes        pen.closePath()
132*e1fe3e4aSElliott Hughes        assert len(pen.points) == 5
133*e1fe3e4aSElliott Hughes        assert pen.points[0] == (0, 0)
134*e1fe3e4aSElliott Hughes
135*e1fe3e4aSElliott Hughes    def test_keep_duplicate_end_point(self):
136*e1fe3e4aSElliott Hughes        pen = TTGlyphPen(None)
137*e1fe3e4aSElliott Hughes        pen.moveTo((0, 0))
138*e1fe3e4aSElliott Hughes        pen.lineTo((100, 0))
139*e1fe3e4aSElliott Hughes        pen.qCurveTo((100, 50), (50, 100), (0, 0))
140*e1fe3e4aSElliott Hughes        pen.lineTo((0, 0))  # the duplicate point is not removed
141*e1fe3e4aSElliott Hughes        pen.closePath()
142*e1fe3e4aSElliott Hughes        assert len(pen.points) == 5
143*e1fe3e4aSElliott Hughes        assert pen.points[0] == (0, 0)
144*e1fe3e4aSElliott Hughes
145*e1fe3e4aSElliott Hughes    def test_within_range_component_transform(self):
146*e1fe3e4aSElliott Hughes        componentName = "a"
147*e1fe3e4aSElliott Hughes        glyphSet = {}
148*e1fe3e4aSElliott Hughes        pen = TTGlyphPen(glyphSet)
149*e1fe3e4aSElliott Hughes
150*e1fe3e4aSElliott Hughes        pen.moveTo((0, 0))
151*e1fe3e4aSElliott Hughes        pen.lineTo((0, 1))
152*e1fe3e4aSElliott Hughes        pen.lineTo((1, 0))
153*e1fe3e4aSElliott Hughes        pen.closePath()
154*e1fe3e4aSElliott Hughes        glyphSet[componentName] = _TestGlyph(pen.glyph())
155*e1fe3e4aSElliott Hughes
156*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1.5, 0, 0, 1, 0, 0))
157*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1, 0, 0, -1.5, 0, 0))
158*e1fe3e4aSElliott Hughes        compositeGlyph = pen.glyph()
159*e1fe3e4aSElliott Hughes
160*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1.5, 0, 0, 1, 0, 0))
161*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1, 0, 0, -1.5, 0, 0))
162*e1fe3e4aSElliott Hughes        expectedGlyph = pen.glyph()
163*e1fe3e4aSElliott Hughes
164*e1fe3e4aSElliott Hughes        assert expectedGlyph == compositeGlyph
165*e1fe3e4aSElliott Hughes
166*e1fe3e4aSElliott Hughes    def test_clamp_to_almost_2_component_transform(self):
167*e1fe3e4aSElliott Hughes        componentName = "a"
168*e1fe3e4aSElliott Hughes        glyphSet = {}
169*e1fe3e4aSElliott Hughes        pen = TTGlyphPen(glyphSet)
170*e1fe3e4aSElliott Hughes
171*e1fe3e4aSElliott Hughes        pen.moveTo((0, 0))
172*e1fe3e4aSElliott Hughes        pen.lineTo((0, 1))
173*e1fe3e4aSElliott Hughes        pen.lineTo((1, 0))
174*e1fe3e4aSElliott Hughes        pen.closePath()
175*e1fe3e4aSElliott Hughes        glyphSet[componentName] = _TestGlyph(pen.glyph())
176*e1fe3e4aSElliott Hughes
177*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1.99999, 0, 0, 1, 0, 0))
178*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1, 2, 0, 1, 0, 0))
179*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1, 0, 2, 1, 0, 0))
180*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1, 0, 0, 2, 0, 0))
181*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (-2, 0, 0, -2, 0, 0))
182*e1fe3e4aSElliott Hughes        compositeGlyph = pen.glyph()
183*e1fe3e4aSElliott Hughes
184*e1fe3e4aSElliott Hughes        almost2 = MAX_F2DOT14  # 0b1.11111111111111
185*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (almost2, 0, 0, 1, 0, 0))
186*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1, almost2, 0, 1, 0, 0))
187*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1, 0, almost2, 1, 0, 0))
188*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1, 0, 0, almost2, 0, 0))
189*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (-2, 0, 0, -2, 0, 0))
190*e1fe3e4aSElliott Hughes        expectedGlyph = pen.glyph()
191*e1fe3e4aSElliott Hughes
192*e1fe3e4aSElliott Hughes        assert expectedGlyph == compositeGlyph
193*e1fe3e4aSElliott Hughes
194*e1fe3e4aSElliott Hughes    def test_out_of_range_transform_decomposed(self):
195*e1fe3e4aSElliott Hughes        componentName = "a"
196*e1fe3e4aSElliott Hughes        glyphSet = {}
197*e1fe3e4aSElliott Hughes        pen = TTGlyphPen(glyphSet)
198*e1fe3e4aSElliott Hughes
199*e1fe3e4aSElliott Hughes        pen.moveTo((0, 0))
200*e1fe3e4aSElliott Hughes        pen.lineTo((0, 1))
201*e1fe3e4aSElliott Hughes        pen.lineTo((1, 0))
202*e1fe3e4aSElliott Hughes        pen.closePath()
203*e1fe3e4aSElliott Hughes        glyphSet[componentName] = _TestGlyph(pen.glyph())
204*e1fe3e4aSElliott Hughes
205*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (3, 0, 0, 2, 0, 0))
206*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1, 0, 0, 1, -1, 2))
207*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (2, 0, 0, -3, 0, 0))
208*e1fe3e4aSElliott Hughes        compositeGlyph = pen.glyph()
209*e1fe3e4aSElliott Hughes
210*e1fe3e4aSElliott Hughes        pen.moveTo((0, 0))
211*e1fe3e4aSElliott Hughes        pen.lineTo((0, 2))
212*e1fe3e4aSElliott Hughes        pen.lineTo((3, 0))
213*e1fe3e4aSElliott Hughes        pen.closePath()
214*e1fe3e4aSElliott Hughes        pen.moveTo((-1, 2))
215*e1fe3e4aSElliott Hughes        pen.lineTo((-1, 3))
216*e1fe3e4aSElliott Hughes        pen.lineTo((0, 2))
217*e1fe3e4aSElliott Hughes        pen.closePath()
218*e1fe3e4aSElliott Hughes        pen.moveTo((0, 0))
219*e1fe3e4aSElliott Hughes        pen.lineTo((0, -3))
220*e1fe3e4aSElliott Hughes        pen.lineTo((2, 0))
221*e1fe3e4aSElliott Hughes        pen.closePath()
222*e1fe3e4aSElliott Hughes        expectedGlyph = pen.glyph()
223*e1fe3e4aSElliott Hughes
224*e1fe3e4aSElliott Hughes        assert expectedGlyph == compositeGlyph
225*e1fe3e4aSElliott Hughes
226*e1fe3e4aSElliott Hughes    def test_no_handle_overflowing_transform(self):
227*e1fe3e4aSElliott Hughes        componentName = "a"
228*e1fe3e4aSElliott Hughes        glyphSet = {}
229*e1fe3e4aSElliott Hughes        pen = TTGlyphPen(glyphSet, handleOverflowingTransforms=False)
230*e1fe3e4aSElliott Hughes
231*e1fe3e4aSElliott Hughes        pen.moveTo((0, 0))
232*e1fe3e4aSElliott Hughes        pen.lineTo((0, 1))
233*e1fe3e4aSElliott Hughes        pen.lineTo((1, 0))
234*e1fe3e4aSElliott Hughes        pen.closePath()
235*e1fe3e4aSElliott Hughes        baseGlyph = pen.glyph()
236*e1fe3e4aSElliott Hughes        glyphSet[componentName] = _TestGlyph(baseGlyph)
237*e1fe3e4aSElliott Hughes
238*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (3, 0, 0, 1, 0, 0))
239*e1fe3e4aSElliott Hughes        compositeGlyph = pen.glyph()
240*e1fe3e4aSElliott Hughes
241*e1fe3e4aSElliott Hughes        assert compositeGlyph.components[0].transform == ((3, 0), (0, 1))
242*e1fe3e4aSElliott Hughes
243*e1fe3e4aSElliott Hughes        with pytest.raises(struct.error):
244*e1fe3e4aSElliott Hughes            compositeGlyph.compile({"a": baseGlyph})
245*e1fe3e4aSElliott Hughes
246*e1fe3e4aSElliott Hughes    def assertGlyphBoundsEqual(self, glyph, bounds):
247*e1fe3e4aSElliott Hughes        assert (glyph.xMin, glyph.yMin, glyph.xMax, glyph.yMax) == bounds
248*e1fe3e4aSElliott Hughes
249*e1fe3e4aSElliott Hughes    def test_round_float_coordinates_and_component_offsets(self):
250*e1fe3e4aSElliott Hughes        glyphSet = {}
251*e1fe3e4aSElliott Hughes        pen = TTGlyphPen(glyphSet)
252*e1fe3e4aSElliott Hughes
253*e1fe3e4aSElliott Hughes        pen.moveTo((0, 0))
254*e1fe3e4aSElliott Hughes        pen.lineTo((0, 1))
255*e1fe3e4aSElliott Hughes        pen.lineTo((367.6, 0))
256*e1fe3e4aSElliott Hughes        pen.closePath()
257*e1fe3e4aSElliott Hughes        simpleGlyph = pen.glyph()
258*e1fe3e4aSElliott Hughes
259*e1fe3e4aSElliott Hughes        simpleGlyph.recalcBounds(glyphSet)
260*e1fe3e4aSElliott Hughes        self.assertGlyphBoundsEqual(simpleGlyph, (0, 0, 368, 1))
261*e1fe3e4aSElliott Hughes
262*e1fe3e4aSElliott Hughes        componentName = "a"
263*e1fe3e4aSElliott Hughes        glyphSet[componentName] = simpleGlyph
264*e1fe3e4aSElliott Hughes
265*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1, 0, 0, 1, -86.4, 0))
266*e1fe3e4aSElliott Hughes        compositeGlyph = pen.glyph()
267*e1fe3e4aSElliott Hughes
268*e1fe3e4aSElliott Hughes        compositeGlyph.recalcBounds(glyphSet)
269*e1fe3e4aSElliott Hughes        self.assertGlyphBoundsEqual(compositeGlyph, (-86, 0, 282, 1))
270*e1fe3e4aSElliott Hughes
271*e1fe3e4aSElliott Hughes    def test_scaled_component_bounds(self):
272*e1fe3e4aSElliott Hughes        glyphSet = {}
273*e1fe3e4aSElliott Hughes
274*e1fe3e4aSElliott Hughes        pen = TTGlyphPen(glyphSet)
275*e1fe3e4aSElliott Hughes        pen.moveTo((-231, 939))
276*e1fe3e4aSElliott Hughes        pen.lineTo((-55, 939))
277*e1fe3e4aSElliott Hughes        pen.lineTo((-55, 745))
278*e1fe3e4aSElliott Hughes        pen.lineTo((-231, 745))
279*e1fe3e4aSElliott Hughes        pen.closePath()
280*e1fe3e4aSElliott Hughes        glyphSet["gravecomb"] = pen.glyph()
281*e1fe3e4aSElliott Hughes
282*e1fe3e4aSElliott Hughes        pen = TTGlyphPen(glyphSet)
283*e1fe3e4aSElliott Hughes        pen.moveTo((-278, 939))
284*e1fe3e4aSElliott Hughes        pen.lineTo((8, 939))
285*e1fe3e4aSElliott Hughes        pen.lineTo((8, 745))
286*e1fe3e4aSElliott Hughes        pen.lineTo((-278, 745))
287*e1fe3e4aSElliott Hughes        pen.closePath()
288*e1fe3e4aSElliott Hughes        glyphSet["circumflexcomb"] = pen.glyph()
289*e1fe3e4aSElliott Hughes
290*e1fe3e4aSElliott Hughes        pen = TTGlyphPen(glyphSet)
291*e1fe3e4aSElliott Hughes        pen.addComponent("circumflexcomb", (1, 0, 0, 1, 0, 0))
292*e1fe3e4aSElliott Hughes        pen.addComponent("gravecomb", (0.9, 0, 0, 0.9, 198, 180))
293*e1fe3e4aSElliott Hughes        glyphSet["uni0302_uni0300"] = uni0302_uni0300 = pen.glyph()
294*e1fe3e4aSElliott Hughes
295*e1fe3e4aSElliott Hughes        uni0302_uni0300.recalcBounds(glyphSet)
296*e1fe3e4aSElliott Hughes        self.assertGlyphBoundsEqual(uni0302_uni0300, (-278, 745, 148, 1025))
297*e1fe3e4aSElliott Hughes
298*e1fe3e4aSElliott Hughes    def test_outputImpliedClosingLine(self):
299*e1fe3e4aSElliott Hughes        glyphSet = {}
300*e1fe3e4aSElliott Hughes
301*e1fe3e4aSElliott Hughes        pen = TTGlyphPen(glyphSet)
302*e1fe3e4aSElliott Hughes        pen.moveTo((0, 0))
303*e1fe3e4aSElliott Hughes        pen.lineTo((10, 0))
304*e1fe3e4aSElliott Hughes        pen.lineTo((0, 10))
305*e1fe3e4aSElliott Hughes        pen.lineTo((0, 0))
306*e1fe3e4aSElliott Hughes        pen.closePath()
307*e1fe3e4aSElliott Hughes        glyph = pen.glyph()
308*e1fe3e4aSElliott Hughes        assert len(glyph.coordinates) == 3
309*e1fe3e4aSElliott Hughes
310*e1fe3e4aSElliott Hughes        pen = TTGlyphPen(glyphSet, outputImpliedClosingLine=True)
311*e1fe3e4aSElliott Hughes        pen.moveTo((0, 0))
312*e1fe3e4aSElliott Hughes        pen.lineTo((10, 0))
313*e1fe3e4aSElliott Hughes        pen.lineTo((0, 10))
314*e1fe3e4aSElliott Hughes        pen.lineTo((0, 0))
315*e1fe3e4aSElliott Hughes        pen.closePath()
316*e1fe3e4aSElliott Hughes        glyph = pen.glyph()
317*e1fe3e4aSElliott Hughes        assert len(glyph.coordinates) == 4
318*e1fe3e4aSElliott Hughes
319*e1fe3e4aSElliott Hughes
320*e1fe3e4aSElliott Hughesclass TTGlyphPointPenTest(TTGlyphPenTestBase):
321*e1fe3e4aSElliott Hughes    penClass = TTGlyphPointPen
322*e1fe3e4aSElliott Hughes    drawMethod = "drawPoints"
323*e1fe3e4aSElliott Hughes
324*e1fe3e4aSElliott Hughes    def test_glyph_simple(self):
325*e1fe3e4aSElliott Hughes        pen = TTGlyphPointPen(None)
326*e1fe3e4aSElliott Hughes        pen.beginPath()
327*e1fe3e4aSElliott Hughes        pen.addPoint((50, 0), "line")
328*e1fe3e4aSElliott Hughes        pen.addPoint((450, 0), "line")
329*e1fe3e4aSElliott Hughes        pen.addPoint((450, 700), "line")
330*e1fe3e4aSElliott Hughes        pen.addPoint((50, 700), "line")
331*e1fe3e4aSElliott Hughes        pen.endPath()
332*e1fe3e4aSElliott Hughes        glyph = pen.glyph()
333*e1fe3e4aSElliott Hughes        assert glyph.numberOfContours == 1
334*e1fe3e4aSElliott Hughes        assert glyph.endPtsOfContours == [3]
335*e1fe3e4aSElliott Hughes
336*e1fe3e4aSElliott Hughes    def test_addPoint_noErrorOnCurve(self):
337*e1fe3e4aSElliott Hughes        pen = TTGlyphPointPen(None)
338*e1fe3e4aSElliott Hughes        pen.beginPath()
339*e1fe3e4aSElliott Hughes        pen.addPoint((0, 0), "curve")
340*e1fe3e4aSElliott Hughes        pen.endPath()
341*e1fe3e4aSElliott Hughes
342*e1fe3e4aSElliott Hughes    def test_beginPath_beginPathOnOpenPath(self):
343*e1fe3e4aSElliott Hughes        pen = TTGlyphPointPen(None)
344*e1fe3e4aSElliott Hughes        pen.beginPath()
345*e1fe3e4aSElliott Hughes        pen.addPoint((0, 0))
346*e1fe3e4aSElliott Hughes        with pytest.raises(PenError):
347*e1fe3e4aSElliott Hughes            pen.beginPath()
348*e1fe3e4aSElliott Hughes
349*e1fe3e4aSElliott Hughes    def test_glyph_errorOnUnendedContour(self):
350*e1fe3e4aSElliott Hughes        pen = TTGlyphPointPen(None)
351*e1fe3e4aSElliott Hughes        pen.beginPath()
352*e1fe3e4aSElliott Hughes        pen.addPoint((0, 0))
353*e1fe3e4aSElliott Hughes        with pytest.raises(PenError):
354*e1fe3e4aSElliott Hughes            pen.glyph()
355*e1fe3e4aSElliott Hughes
356*e1fe3e4aSElliott Hughes    def test_glyph_decomposes(self):
357*e1fe3e4aSElliott Hughes        componentName = "a"
358*e1fe3e4aSElliott Hughes        glyphSet = {}
359*e1fe3e4aSElliott Hughes        pen = TTGlyphPointPen(glyphSet)
360*e1fe3e4aSElliott Hughes
361*e1fe3e4aSElliott Hughes        pen.beginPath()
362*e1fe3e4aSElliott Hughes        pen.addPoint((0, 0), "line")
363*e1fe3e4aSElliott Hughes        pen.addPoint((0, 1), "line")
364*e1fe3e4aSElliott Hughes        pen.addPoint((1, 0), "line")
365*e1fe3e4aSElliott Hughes        pen.endPath()
366*e1fe3e4aSElliott Hughes        glyphSet[componentName] = _TestGlyph(pen.glyph())
367*e1fe3e4aSElliott Hughes
368*e1fe3e4aSElliott Hughes        pen.beginPath()
369*e1fe3e4aSElliott Hughes        pen.addPoint((0, 0), "line")
370*e1fe3e4aSElliott Hughes        pen.addPoint((0, 1), "line")
371*e1fe3e4aSElliott Hughes        pen.addPoint((1, 0), "line")
372*e1fe3e4aSElliott Hughes        pen.endPath()
373*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1, 0, 0, 1, 2, 0))
374*e1fe3e4aSElliott Hughes        pen.addComponent("missing", (1, 0, 0, 1, 0, 0))  # skipped
375*e1fe3e4aSElliott Hughes        compositeGlyph = pen.glyph()
376*e1fe3e4aSElliott Hughes
377*e1fe3e4aSElliott Hughes        pen.beginPath()
378*e1fe3e4aSElliott Hughes        pen.addPoint((0, 0), "line")
379*e1fe3e4aSElliott Hughes        pen.addPoint((0, 1), "line")
380*e1fe3e4aSElliott Hughes        pen.addPoint((1, 0), "line")
381*e1fe3e4aSElliott Hughes        pen.endPath()
382*e1fe3e4aSElliott Hughes        pen.beginPath()
383*e1fe3e4aSElliott Hughes        pen.addPoint((2, 0), "line")
384*e1fe3e4aSElliott Hughes        pen.addPoint((2, 1), "line")
385*e1fe3e4aSElliott Hughes        pen.addPoint((3, 0), "line")
386*e1fe3e4aSElliott Hughes        pen.endPath()
387*e1fe3e4aSElliott Hughes        plainGlyph = pen.glyph()
388*e1fe3e4aSElliott Hughes
389*e1fe3e4aSElliott Hughes        assert plainGlyph == compositeGlyph
390*e1fe3e4aSElliott Hughes
391*e1fe3e4aSElliott Hughes    def test_keep_duplicate_end_point(self):
392*e1fe3e4aSElliott Hughes        pen = TTGlyphPointPen(None)
393*e1fe3e4aSElliott Hughes        pen.beginPath()
394*e1fe3e4aSElliott Hughes        pen.addPoint((0, 0), "line")
395*e1fe3e4aSElliott Hughes        pen.addPoint((100, 0), "line")
396*e1fe3e4aSElliott Hughes        pen.addPoint((100, 50))
397*e1fe3e4aSElliott Hughes        pen.addPoint((50, 100))
398*e1fe3e4aSElliott Hughes        pen.addPoint((0, 0), "qcurve")
399*e1fe3e4aSElliott Hughes        pen.addPoint((0, 0), "line")  # the duplicate point is not removed
400*e1fe3e4aSElliott Hughes        pen.endPath()
401*e1fe3e4aSElliott Hughes        assert len(pen.points) == 6
402*e1fe3e4aSElliott Hughes        assert pen.points[0] == (0, 0)
403*e1fe3e4aSElliott Hughes
404*e1fe3e4aSElliott Hughes    def test_within_range_component_transform(self):
405*e1fe3e4aSElliott Hughes        componentName = "a"
406*e1fe3e4aSElliott Hughes        glyphSet = {}
407*e1fe3e4aSElliott Hughes        pen = TTGlyphPointPen(glyphSet)
408*e1fe3e4aSElliott Hughes
409*e1fe3e4aSElliott Hughes        pen.beginPath()
410*e1fe3e4aSElliott Hughes        pen.addPoint((0, 0), "line")
411*e1fe3e4aSElliott Hughes        pen.addPoint((0, 1), "line")
412*e1fe3e4aSElliott Hughes        pen.addPoint((1, 0), "line")
413*e1fe3e4aSElliott Hughes        pen.endPath()
414*e1fe3e4aSElliott Hughes        glyphSet[componentName] = _TestGlyph(pen.glyph())
415*e1fe3e4aSElliott Hughes
416*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1.5, 0, 0, 1, 0, 0))
417*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1, 0, 0, -1.5, 0, 0))
418*e1fe3e4aSElliott Hughes        compositeGlyph = pen.glyph()
419*e1fe3e4aSElliott Hughes
420*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1.5, 0, 0, 1, 0, 0))
421*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1, 0, 0, -1.5, 0, 0))
422*e1fe3e4aSElliott Hughes        expectedGlyph = pen.glyph()
423*e1fe3e4aSElliott Hughes
424*e1fe3e4aSElliott Hughes        assert expectedGlyph == compositeGlyph
425*e1fe3e4aSElliott Hughes
426*e1fe3e4aSElliott Hughes    def test_clamp_to_almost_2_component_transform(self):
427*e1fe3e4aSElliott Hughes        componentName = "a"
428*e1fe3e4aSElliott Hughes        glyphSet = {}
429*e1fe3e4aSElliott Hughes        pen = TTGlyphPointPen(glyphSet)
430*e1fe3e4aSElliott Hughes
431*e1fe3e4aSElliott Hughes        pen.beginPath()
432*e1fe3e4aSElliott Hughes        pen.addPoint((0, 0), "line")
433*e1fe3e4aSElliott Hughes        pen.addPoint((0, 1), "line")
434*e1fe3e4aSElliott Hughes        pen.addPoint((1, 0), "line")
435*e1fe3e4aSElliott Hughes        pen.endPath()
436*e1fe3e4aSElliott Hughes        glyphSet[componentName] = _TestGlyph(pen.glyph())
437*e1fe3e4aSElliott Hughes
438*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1.99999, 0, 0, 1, 0, 0))
439*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1, 2, 0, 1, 0, 0))
440*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1, 0, 2, 1, 0, 0))
441*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1, 0, 0, 2, 0, 0))
442*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (-2, 0, 0, -2, 0, 0))
443*e1fe3e4aSElliott Hughes        compositeGlyph = pen.glyph()
444*e1fe3e4aSElliott Hughes
445*e1fe3e4aSElliott Hughes        almost2 = MAX_F2DOT14  # 0b1.11111111111111
446*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (almost2, 0, 0, 1, 0, 0))
447*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1, almost2, 0, 1, 0, 0))
448*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1, 0, almost2, 1, 0, 0))
449*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1, 0, 0, almost2, 0, 0))
450*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (-2, 0, 0, -2, 0, 0))
451*e1fe3e4aSElliott Hughes        expectedGlyph = pen.glyph()
452*e1fe3e4aSElliott Hughes
453*e1fe3e4aSElliott Hughes        assert expectedGlyph == compositeGlyph
454*e1fe3e4aSElliott Hughes
455*e1fe3e4aSElliott Hughes    def test_out_of_range_transform_decomposed(self):
456*e1fe3e4aSElliott Hughes        componentName = "a"
457*e1fe3e4aSElliott Hughes        glyphSet = {}
458*e1fe3e4aSElliott Hughes        pen = TTGlyphPointPen(glyphSet)
459*e1fe3e4aSElliott Hughes
460*e1fe3e4aSElliott Hughes        pen.beginPath()
461*e1fe3e4aSElliott Hughes        pen.addPoint((0, 0), "line")
462*e1fe3e4aSElliott Hughes        pen.addPoint((0, 1), "line")
463*e1fe3e4aSElliott Hughes        pen.addPoint((1, 0), "line")
464*e1fe3e4aSElliott Hughes        pen.endPath()
465*e1fe3e4aSElliott Hughes        glyphSet[componentName] = _TestGlyph(pen.glyph())
466*e1fe3e4aSElliott Hughes
467*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (3, 0, 0, 2, 0, 0))
468*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1, 0, 0, 1, -1, 2))
469*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (2, 0, 0, -3, 0, 0))
470*e1fe3e4aSElliott Hughes        compositeGlyph = pen.glyph()
471*e1fe3e4aSElliott Hughes
472*e1fe3e4aSElliott Hughes        pen.beginPath()
473*e1fe3e4aSElliott Hughes        pen.addPoint((0, 0), "line")
474*e1fe3e4aSElliott Hughes        pen.addPoint((0, 2), "line")
475*e1fe3e4aSElliott Hughes        pen.addPoint((3, 0), "line")
476*e1fe3e4aSElliott Hughes        pen.endPath()
477*e1fe3e4aSElliott Hughes        pen.beginPath()
478*e1fe3e4aSElliott Hughes        pen.addPoint((-1, 2), "line")
479*e1fe3e4aSElliott Hughes        pen.addPoint((-1, 3), "line")
480*e1fe3e4aSElliott Hughes        pen.addPoint((0, 2), "line")
481*e1fe3e4aSElliott Hughes        pen.endPath()
482*e1fe3e4aSElliott Hughes        pen.beginPath()
483*e1fe3e4aSElliott Hughes        pen.addPoint((0, 0), "line")
484*e1fe3e4aSElliott Hughes        pen.addPoint((0, -3), "line")
485*e1fe3e4aSElliott Hughes        pen.addPoint((2, 0), "line")
486*e1fe3e4aSElliott Hughes        pen.endPath()
487*e1fe3e4aSElliott Hughes        expectedGlyph = pen.glyph()
488*e1fe3e4aSElliott Hughes
489*e1fe3e4aSElliott Hughes        assert expectedGlyph == compositeGlyph
490*e1fe3e4aSElliott Hughes
491*e1fe3e4aSElliott Hughes    def test_no_handle_overflowing_transform(self):
492*e1fe3e4aSElliott Hughes        componentName = "a"
493*e1fe3e4aSElliott Hughes        glyphSet = {}
494*e1fe3e4aSElliott Hughes        pen = TTGlyphPointPen(glyphSet, handleOverflowingTransforms=False)
495*e1fe3e4aSElliott Hughes
496*e1fe3e4aSElliott Hughes        pen.beginPath()
497*e1fe3e4aSElliott Hughes        pen.addPoint((0, 0), "line")
498*e1fe3e4aSElliott Hughes        pen.addPoint((0, 1), "line")
499*e1fe3e4aSElliott Hughes        pen.addPoint((1, 0), "line")
500*e1fe3e4aSElliott Hughes        pen.endPath()
501*e1fe3e4aSElliott Hughes        baseGlyph = pen.glyph()
502*e1fe3e4aSElliott Hughes        glyphSet[componentName] = _TestGlyph(baseGlyph)
503*e1fe3e4aSElliott Hughes
504*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (3, 0, 0, 1, 0, 0))
505*e1fe3e4aSElliott Hughes        compositeGlyph = pen.glyph()
506*e1fe3e4aSElliott Hughes
507*e1fe3e4aSElliott Hughes        assert compositeGlyph.components[0].transform == ((3, 0), (0, 1))
508*e1fe3e4aSElliott Hughes
509*e1fe3e4aSElliott Hughes        with pytest.raises(struct.error):
510*e1fe3e4aSElliott Hughes            compositeGlyph.compile({"a": baseGlyph})
511*e1fe3e4aSElliott Hughes
512*e1fe3e4aSElliott Hughes    def assertGlyphBoundsEqual(self, glyph, bounds):
513*e1fe3e4aSElliott Hughes        assert (glyph.xMin, glyph.yMin, glyph.xMax, glyph.yMax) == bounds
514*e1fe3e4aSElliott Hughes
515*e1fe3e4aSElliott Hughes    def test_round_float_coordinates_and_component_offsets(self):
516*e1fe3e4aSElliott Hughes        glyphSet = {}
517*e1fe3e4aSElliott Hughes        pen = TTGlyphPointPen(glyphSet)
518*e1fe3e4aSElliott Hughes
519*e1fe3e4aSElliott Hughes        pen.beginPath()
520*e1fe3e4aSElliott Hughes        pen.addPoint((0, 0), "line")
521*e1fe3e4aSElliott Hughes        pen.addPoint((0, 1), "line")
522*e1fe3e4aSElliott Hughes        pen.addPoint((367.6, 0), "line")
523*e1fe3e4aSElliott Hughes        pen.endPath()
524*e1fe3e4aSElliott Hughes        simpleGlyph = pen.glyph()
525*e1fe3e4aSElliott Hughes
526*e1fe3e4aSElliott Hughes        simpleGlyph.recalcBounds(glyphSet)
527*e1fe3e4aSElliott Hughes        self.assertGlyphBoundsEqual(simpleGlyph, (0, 0, 368, 1))
528*e1fe3e4aSElliott Hughes
529*e1fe3e4aSElliott Hughes        componentName = "a"
530*e1fe3e4aSElliott Hughes        glyphSet[componentName] = simpleGlyph
531*e1fe3e4aSElliott Hughes
532*e1fe3e4aSElliott Hughes        pen.addComponent(componentName, (1, 0, 0, 1, -86.4, 0))
533*e1fe3e4aSElliott Hughes        compositeGlyph = pen.glyph()
534*e1fe3e4aSElliott Hughes
535*e1fe3e4aSElliott Hughes        compositeGlyph.recalcBounds(glyphSet)
536*e1fe3e4aSElliott Hughes        self.assertGlyphBoundsEqual(compositeGlyph, (-86, 0, 282, 1))
537*e1fe3e4aSElliott Hughes
538*e1fe3e4aSElliott Hughes    def test_scaled_component_bounds(self):
539*e1fe3e4aSElliott Hughes        glyphSet = {}
540*e1fe3e4aSElliott Hughes
541*e1fe3e4aSElliott Hughes        pen = TTGlyphPointPen(glyphSet)
542*e1fe3e4aSElliott Hughes        pen.beginPath()
543*e1fe3e4aSElliott Hughes        pen.addPoint((-231, 939), "line")
544*e1fe3e4aSElliott Hughes        pen.addPoint((-55, 939), "line")
545*e1fe3e4aSElliott Hughes        pen.addPoint((-55, 745), "line")
546*e1fe3e4aSElliott Hughes        pen.addPoint((-231, 745), "line")
547*e1fe3e4aSElliott Hughes        pen.endPath()
548*e1fe3e4aSElliott Hughes        glyphSet["gravecomb"] = pen.glyph()
549*e1fe3e4aSElliott Hughes
550*e1fe3e4aSElliott Hughes        pen = TTGlyphPointPen(glyphSet)
551*e1fe3e4aSElliott Hughes        pen.beginPath()
552*e1fe3e4aSElliott Hughes        pen.addPoint((-278, 939), "line")
553*e1fe3e4aSElliott Hughes        pen.addPoint((8, 939), "line")
554*e1fe3e4aSElliott Hughes        pen.addPoint((8, 745), "line")
555*e1fe3e4aSElliott Hughes        pen.addPoint((-278, 745), "line")
556*e1fe3e4aSElliott Hughes        pen.endPath()
557*e1fe3e4aSElliott Hughes        glyphSet["circumflexcomb"] = pen.glyph()
558*e1fe3e4aSElliott Hughes
559*e1fe3e4aSElliott Hughes        pen = TTGlyphPointPen(glyphSet)
560*e1fe3e4aSElliott Hughes        pen.addComponent("circumflexcomb", (1, 0, 0, 1, 0, 0))
561*e1fe3e4aSElliott Hughes        pen.addComponent("gravecomb", (0.9, 0, 0, 0.9, 198, 180))
562*e1fe3e4aSElliott Hughes        glyphSet["uni0302_uni0300"] = uni0302_uni0300 = pen.glyph()
563*e1fe3e4aSElliott Hughes
564*e1fe3e4aSElliott Hughes        uni0302_uni0300.recalcBounds(glyphSet)
565*e1fe3e4aSElliott Hughes        self.assertGlyphBoundsEqual(uni0302_uni0300, (-278, 745, 148, 1025))
566*e1fe3e4aSElliott Hughes
567*e1fe3e4aSElliott Hughes    def test_open_path_starting_with_move(self):
568*e1fe3e4aSElliott Hughes        # when a contour starts with a 'move' point, it signifies the beginnig
569*e1fe3e4aSElliott Hughes        # of an open contour.
570*e1fe3e4aSElliott Hughes        # https://unifiedfontobject.org/versions/ufo3/glyphs/glif/#point-types
571*e1fe3e4aSElliott Hughes        pen1 = TTGlyphPointPen(None)
572*e1fe3e4aSElliott Hughes        pen1.beginPath()
573*e1fe3e4aSElliott Hughes        pen1.addPoint((0, 0), "move")  # contour is open
574*e1fe3e4aSElliott Hughes        pen1.addPoint((10, 10), "line")
575*e1fe3e4aSElliott Hughes        pen1.addPoint((20, 20))
576*e1fe3e4aSElliott Hughes        pen1.addPoint((20, 0), "qcurve")
577*e1fe3e4aSElliott Hughes        pen1.endPath()
578*e1fe3e4aSElliott Hughes
579*e1fe3e4aSElliott Hughes        pen2 = TTGlyphPointPen(None)
580*e1fe3e4aSElliott Hughes        pen2.beginPath()
581*e1fe3e4aSElliott Hughes        pen2.addPoint((0, 0), "line")  # contour is closed
582*e1fe3e4aSElliott Hughes        pen2.addPoint((10, 10), "line")
583*e1fe3e4aSElliott Hughes        pen2.addPoint((20, 20))
584*e1fe3e4aSElliott Hughes        pen2.addPoint((20, 0), "qcurve")
585*e1fe3e4aSElliott Hughes        pen2.endPath()
586*e1fe3e4aSElliott Hughes
587*e1fe3e4aSElliott Hughes        # Since TrueType contours are always implicitly closed, the pen will
588*e1fe3e4aSElliott Hughes        # interpret both these paths as equivalent
589*e1fe3e4aSElliott Hughes        assert pen1.points == pen2.points == [(0, 0), (10, 10), (20, 20), (20, 0)]
590*e1fe3e4aSElliott Hughes        assert pen1.types == pen2.types == [1, 1, 0, 1]
591*e1fe3e4aSElliott Hughes
592*e1fe3e4aSElliott Hughes    def test_skip_empty_contours(self):
593*e1fe3e4aSElliott Hughes        pen = TTGlyphPointPen(None)
594*e1fe3e4aSElliott Hughes        pen.beginPath()
595*e1fe3e4aSElliott Hughes        pen.endPath()
596*e1fe3e4aSElliott Hughes        pen.beginPath()
597*e1fe3e4aSElliott Hughes        pen.endPath()
598*e1fe3e4aSElliott Hughes        glyph = pen.glyph()
599*e1fe3e4aSElliott Hughes        assert glyph.numberOfContours == 0
600*e1fe3e4aSElliott Hughes
601*e1fe3e4aSElliott Hughes
602*e1fe3e4aSElliott Hughesclass CubicGlyfTest:
603*e1fe3e4aSElliott Hughes    def test_cubic_simple(self):
604*e1fe3e4aSElliott Hughes        spen = TTGlyphPen(None)
605*e1fe3e4aSElliott Hughes        spen.moveTo((0, 0))
606*e1fe3e4aSElliott Hughes        spen.curveTo((0, 1), (1, 1), (1, 0))
607*e1fe3e4aSElliott Hughes        spen.closePath()
608*e1fe3e4aSElliott Hughes
609*e1fe3e4aSElliott Hughes        ppen = TTGlyphPointPen(None)
610*e1fe3e4aSElliott Hughes        ppen.beginPath()
611*e1fe3e4aSElliott Hughes        ppen.addPoint((0, 0), "line")
612*e1fe3e4aSElliott Hughes        ppen.addPoint((0, 1))
613*e1fe3e4aSElliott Hughes        ppen.addPoint((1, 1))
614*e1fe3e4aSElliott Hughes        ppen.addPoint((1, 0), "curve")
615*e1fe3e4aSElliott Hughes        ppen.endPath()
616*e1fe3e4aSElliott Hughes
617*e1fe3e4aSElliott Hughes        for pen in (spen, ppen):
618*e1fe3e4aSElliott Hughes            glyph = pen.glyph()
619*e1fe3e4aSElliott Hughes
620*e1fe3e4aSElliott Hughes            for i in range(2):
621*e1fe3e4aSElliott Hughes                if i == 1:
622*e1fe3e4aSElliott Hughes                    glyph.compile(None)
623*e1fe3e4aSElliott Hughes
624*e1fe3e4aSElliott Hughes                assert list(glyph.coordinates) == [(0, 0), (0, 1), (1, 1), (1, 0)]
625*e1fe3e4aSElliott Hughes                assert list(glyph.flags) == [0x01, 0x80, 0x80, 0x01]
626*e1fe3e4aSElliott Hughes
627*e1fe3e4aSElliott Hughes                rpen = RecordingPen()
628*e1fe3e4aSElliott Hughes                glyph.draw(rpen, None)
629*e1fe3e4aSElliott Hughes                assert rpen.value == [
630*e1fe3e4aSElliott Hughes                    ("moveTo", ((0, 0),)),
631*e1fe3e4aSElliott Hughes                    (
632*e1fe3e4aSElliott Hughes                        "curveTo",
633*e1fe3e4aSElliott Hughes                        (
634*e1fe3e4aSElliott Hughes                            (0, 1),
635*e1fe3e4aSElliott Hughes                            (1, 1),
636*e1fe3e4aSElliott Hughes                            (1, 0),
637*e1fe3e4aSElliott Hughes                        ),
638*e1fe3e4aSElliott Hughes                    ),
639*e1fe3e4aSElliott Hughes                    ("closePath", ()),
640*e1fe3e4aSElliott Hughes                ]
641*e1fe3e4aSElliott Hughes
642*e1fe3e4aSElliott Hughes    @pytest.mark.parametrize(
643*e1fe3e4aSElliott Hughes        "dropImpliedOnCurves, segment_pen_commands, point_pen_commands, expected_coordinates, expected_flags, expected_endPts",
644*e1fe3e4aSElliott Hughes        [
645*e1fe3e4aSElliott Hughes            (  # Two curves that do NOT merge; request merging
646*e1fe3e4aSElliott Hughes                True,
647*e1fe3e4aSElliott Hughes                [
648*e1fe3e4aSElliott Hughes                    ("moveTo", ((0, 0),)),
649*e1fe3e4aSElliott Hughes                    ("curveTo", ((0, 1), (1, 2), (2, 2))),
650*e1fe3e4aSElliott Hughes                    ("curveTo", ((3, 3), (4, 1), (4, 0))),
651*e1fe3e4aSElliott Hughes                    ("closePath", ()),
652*e1fe3e4aSElliott Hughes                ],
653*e1fe3e4aSElliott Hughes                [
654*e1fe3e4aSElliott Hughes                    ("beginPath", (), {}),
655*e1fe3e4aSElliott Hughes                    ("addPoint", ((0, 0), "line", None, None), {}),
656*e1fe3e4aSElliott Hughes                    ("addPoint", ((0, 1), None, None, None), {}),
657*e1fe3e4aSElliott Hughes                    ("addPoint", ((1, 2), None, None, None), {}),
658*e1fe3e4aSElliott Hughes                    ("addPoint", ((2, 2), "curve", None, None), {}),
659*e1fe3e4aSElliott Hughes                    ("addPoint", ((3, 3), None, None, None), {}),
660*e1fe3e4aSElliott Hughes                    ("addPoint", ((4, 1), None, None, None), {}),
661*e1fe3e4aSElliott Hughes                    ("addPoint", ((4, 0), "curve", None, None), {}),
662*e1fe3e4aSElliott Hughes                    ("endPath", (), {}),
663*e1fe3e4aSElliott Hughes                ],
664*e1fe3e4aSElliott Hughes                [(0, 0), (0, 1), (1, 2), (2, 2), (3, 3), (4, 1), (4, 0)],
665*e1fe3e4aSElliott Hughes                [0x01, 0x80, 0x80, 0x01, 0x80, 0x80, 0x01],
666*e1fe3e4aSElliott Hughes                [6],
667*e1fe3e4aSElliott Hughes            ),
668*e1fe3e4aSElliott Hughes            (  # Two curves that merge; request merging
669*e1fe3e4aSElliott Hughes                True,
670*e1fe3e4aSElliott Hughes                [
671*e1fe3e4aSElliott Hughes                    ("moveTo", ((0, 0),)),
672*e1fe3e4aSElliott Hughes                    ("curveTo", ((0, 1), (1, 2), (2, 2))),
673*e1fe3e4aSElliott Hughes                    ("curveTo", ((3, 2), (4, 1), (4, 0))),
674*e1fe3e4aSElliott Hughes                    ("closePath", ()),
675*e1fe3e4aSElliott Hughes                ],
676*e1fe3e4aSElliott Hughes                [
677*e1fe3e4aSElliott Hughes                    ("beginPath", (), {}),
678*e1fe3e4aSElliott Hughes                    ("addPoint", ((0, 0), "line", None, None), {}),
679*e1fe3e4aSElliott Hughes                    ("addPoint", ((0, 1), None, None, None), {}),
680*e1fe3e4aSElliott Hughes                    ("addPoint", ((1, 2), None, None, None), {}),
681*e1fe3e4aSElliott Hughes                    ("addPoint", ((2, 2), "curve", None, None), {}),
682*e1fe3e4aSElliott Hughes                    ("addPoint", ((3, 2), None, None, None), {}),
683*e1fe3e4aSElliott Hughes                    ("addPoint", ((4, 1), None, None, None), {}),
684*e1fe3e4aSElliott Hughes                    ("addPoint", ((4, 0), "curve", None, None), {}),
685*e1fe3e4aSElliott Hughes                    ("endPath", (), {}),
686*e1fe3e4aSElliott Hughes                ],
687*e1fe3e4aSElliott Hughes                [(0, 0), (0, 1), (1, 2), (3, 2), (4, 1), (4, 0)],
688*e1fe3e4aSElliott Hughes                [0x01, 0x80, 0x80, 0x80, 0x80, 0x01],
689*e1fe3e4aSElliott Hughes                [5],
690*e1fe3e4aSElliott Hughes            ),
691*e1fe3e4aSElliott Hughes            (  # Two curves that merge; request NOT merging
692*e1fe3e4aSElliott Hughes                False,
693*e1fe3e4aSElliott Hughes                [
694*e1fe3e4aSElliott Hughes                    ("moveTo", ((0, 0),)),
695*e1fe3e4aSElliott Hughes                    ("curveTo", ((0, 1), (1, 2), (2, 2))),
696*e1fe3e4aSElliott Hughes                    ("curveTo", ((3, 2), (4, 1), (4, 0))),
697*e1fe3e4aSElliott Hughes                    ("closePath", ()),
698*e1fe3e4aSElliott Hughes                ],
699*e1fe3e4aSElliott Hughes                [
700*e1fe3e4aSElliott Hughes                    ("beginPath", (), {}),
701*e1fe3e4aSElliott Hughes                    ("addPoint", ((0, 0), "line", None, None), {}),
702*e1fe3e4aSElliott Hughes                    ("addPoint", ((0, 1), None, None, None), {}),
703*e1fe3e4aSElliott Hughes                    ("addPoint", ((1, 2), None, None, None), {}),
704*e1fe3e4aSElliott Hughes                    ("addPoint", ((2, 2), "curve", None, None), {}),
705*e1fe3e4aSElliott Hughes                    ("addPoint", ((3, 2), None, None, None), {}),
706*e1fe3e4aSElliott Hughes                    ("addPoint", ((4, 1), None, None, None), {}),
707*e1fe3e4aSElliott Hughes                    ("addPoint", ((4, 0), "curve", None, None), {}),
708*e1fe3e4aSElliott Hughes                    ("endPath", (), {}),
709*e1fe3e4aSElliott Hughes                ],
710*e1fe3e4aSElliott Hughes                [(0, 0), (0, 1), (1, 2), (2, 2), (3, 2), (4, 1), (4, 0)],
711*e1fe3e4aSElliott Hughes                [0x01, 0x80, 0x80, 0x01, 0x80, 0x80, 0x01],
712*e1fe3e4aSElliott Hughes                [6],
713*e1fe3e4aSElliott Hughes            ),
714*e1fe3e4aSElliott Hughes            (  # Two (duplicate) contours
715*e1fe3e4aSElliott Hughes                True,
716*e1fe3e4aSElliott Hughes                [
717*e1fe3e4aSElliott Hughes                    ("moveTo", ((0, 0),)),
718*e1fe3e4aSElliott Hughes                    ("curveTo", ((0, 1), (1, 2), (2, 2))),
719*e1fe3e4aSElliott Hughes                    ("curveTo", ((3, 2), (4, 1), (4, 0))),
720*e1fe3e4aSElliott Hughes                    ("closePath", ()),
721*e1fe3e4aSElliott Hughes                    ("moveTo", ((0, 0),)),
722*e1fe3e4aSElliott Hughes                    ("curveTo", ((0, 1), (1, 2), (2, 2))),
723*e1fe3e4aSElliott Hughes                    ("curveTo", ((3, 2), (4, 1), (4, 0))),
724*e1fe3e4aSElliott Hughes                    ("closePath", ()),
725*e1fe3e4aSElliott Hughes                ],
726*e1fe3e4aSElliott Hughes                [
727*e1fe3e4aSElliott Hughes                    ("beginPath", (), {}),
728*e1fe3e4aSElliott Hughes                    ("addPoint", ((0, 0), "line", None, None), {}),
729*e1fe3e4aSElliott Hughes                    ("addPoint", ((0, 1), None, None, None), {}),
730*e1fe3e4aSElliott Hughes                    ("addPoint", ((1, 2), None, None, None), {}),
731*e1fe3e4aSElliott Hughes                    ("addPoint", ((2, 2), "curve", None, None), {}),
732*e1fe3e4aSElliott Hughes                    ("addPoint", ((3, 2), None, None, None), {}),
733*e1fe3e4aSElliott Hughes                    ("addPoint", ((4, 1), None, None, None), {}),
734*e1fe3e4aSElliott Hughes                    ("addPoint", ((4, 0), "curve", None, None), {}),
735*e1fe3e4aSElliott Hughes                    ("endPath", (), {}),
736*e1fe3e4aSElliott Hughes                    ("beginPath", (), {}),
737*e1fe3e4aSElliott Hughes                    ("addPoint", ((0, 0), "line", None, None), {}),
738*e1fe3e4aSElliott Hughes                    ("addPoint", ((0, 1), None, None, None), {}),
739*e1fe3e4aSElliott Hughes                    ("addPoint", ((1, 2), None, None, None), {}),
740*e1fe3e4aSElliott Hughes                    ("addPoint", ((2, 2), "curve", None, None), {}),
741*e1fe3e4aSElliott Hughes                    ("addPoint", ((3, 2), None, None, None), {}),
742*e1fe3e4aSElliott Hughes                    ("addPoint", ((4, 1), None, None, None), {}),
743*e1fe3e4aSElliott Hughes                    ("addPoint", ((4, 0), "curve", None, None), {}),
744*e1fe3e4aSElliott Hughes                    ("endPath", (), {}),
745*e1fe3e4aSElliott Hughes                ],
746*e1fe3e4aSElliott Hughes                [
747*e1fe3e4aSElliott Hughes                    (0, 0),
748*e1fe3e4aSElliott Hughes                    (0, 1),
749*e1fe3e4aSElliott Hughes                    (1, 2),
750*e1fe3e4aSElliott Hughes                    (3, 2),
751*e1fe3e4aSElliott Hughes                    (4, 1),
752*e1fe3e4aSElliott Hughes                    (4, 0),
753*e1fe3e4aSElliott Hughes                    (0, 0),
754*e1fe3e4aSElliott Hughes                    (0, 1),
755*e1fe3e4aSElliott Hughes                    (1, 2),
756*e1fe3e4aSElliott Hughes                    (3, 2),
757*e1fe3e4aSElliott Hughes                    (4, 1),
758*e1fe3e4aSElliott Hughes                    (4, 0),
759*e1fe3e4aSElliott Hughes                ],
760*e1fe3e4aSElliott Hughes                [
761*e1fe3e4aSElliott Hughes                    0x01,
762*e1fe3e4aSElliott Hughes                    0x80,
763*e1fe3e4aSElliott Hughes                    0x80,
764*e1fe3e4aSElliott Hughes                    0x80,
765*e1fe3e4aSElliott Hughes                    0x80,
766*e1fe3e4aSElliott Hughes                    0x01,
767*e1fe3e4aSElliott Hughes                    0x01,
768*e1fe3e4aSElliott Hughes                    0x80,
769*e1fe3e4aSElliott Hughes                    0x80,
770*e1fe3e4aSElliott Hughes                    0x80,
771*e1fe3e4aSElliott Hughes                    0x80,
772*e1fe3e4aSElliott Hughes                    0x01,
773*e1fe3e4aSElliott Hughes                ],
774*e1fe3e4aSElliott Hughes                [5, 11],
775*e1fe3e4aSElliott Hughes            ),
776*e1fe3e4aSElliott Hughes        ],
777*e1fe3e4aSElliott Hughes    )
778*e1fe3e4aSElliott Hughes    def test_cubic_topology(
779*e1fe3e4aSElliott Hughes        self,
780*e1fe3e4aSElliott Hughes        dropImpliedOnCurves,
781*e1fe3e4aSElliott Hughes        segment_pen_commands,
782*e1fe3e4aSElliott Hughes        point_pen_commands,
783*e1fe3e4aSElliott Hughes        expected_coordinates,
784*e1fe3e4aSElliott Hughes        expected_flags,
785*e1fe3e4aSElliott Hughes        expected_endPts,
786*e1fe3e4aSElliott Hughes    ):
787*e1fe3e4aSElliott Hughes        spen = TTGlyphPen(None)
788*e1fe3e4aSElliott Hughes        rpen = RecordingPen()
789*e1fe3e4aSElliott Hughes        rpen.value = segment_pen_commands
790*e1fe3e4aSElliott Hughes        rpen.replay(spen)
791*e1fe3e4aSElliott Hughes
792*e1fe3e4aSElliott Hughes        ppen = TTGlyphPointPen(None)
793*e1fe3e4aSElliott Hughes        rpen = RecordingPointPen()
794*e1fe3e4aSElliott Hughes        rpen.value = point_pen_commands
795*e1fe3e4aSElliott Hughes        rpen.replay(ppen)
796*e1fe3e4aSElliott Hughes
797*e1fe3e4aSElliott Hughes        for pen in (spen, ppen):
798*e1fe3e4aSElliott Hughes            glyph = pen.glyph(dropImpliedOnCurves=dropImpliedOnCurves)
799*e1fe3e4aSElliott Hughes
800*e1fe3e4aSElliott Hughes            assert list(glyph.coordinates) == expected_coordinates
801*e1fe3e4aSElliott Hughes            assert list(glyph.flags) == expected_flags
802*e1fe3e4aSElliott Hughes            assert list(glyph.endPtsOfContours) == expected_endPts
803*e1fe3e4aSElliott Hughes
804*e1fe3e4aSElliott Hughes            rpen = RecordingPen()
805*e1fe3e4aSElliott Hughes            glyph.draw(rpen, None)
806*e1fe3e4aSElliott Hughes            assert rpen.value == segment_pen_commands
807*e1fe3e4aSElliott Hughes
808*e1fe3e4aSElliott Hughes
809*e1fe3e4aSElliott Hughesclass _TestGlyph(object):
810*e1fe3e4aSElliott Hughes    def __init__(self, glyph):
811*e1fe3e4aSElliott Hughes        self.coordinates = glyph.coordinates
812*e1fe3e4aSElliott Hughes
813*e1fe3e4aSElliott Hughes    def draw(self, pen):
814*e1fe3e4aSElliott Hughes        pen.moveTo(self.coordinates[0])
815*e1fe3e4aSElliott Hughes        for point in self.coordinates[1:]:
816*e1fe3e4aSElliott Hughes            pen.lineTo(point)
817*e1fe3e4aSElliott Hughes        pen.closePath()
818*e1fe3e4aSElliott Hughes
819*e1fe3e4aSElliott Hughes    def drawPoints(self, pen):
820*e1fe3e4aSElliott Hughes        pen.beginPath()
821*e1fe3e4aSElliott Hughes        for point in self.coordinates:
822*e1fe3e4aSElliott Hughes            pen.addPoint(point, "line")
823*e1fe3e4aSElliott Hughes        pen.endPath()
824