1from fontTools.pens.filterPen import ContourFilterPen 2 3 4class ExplicitClosingLinePen(ContourFilterPen): 5 """A filter pen that adds an explicit lineTo to the first point of each closed 6 contour if the end point of the last segment is not already the same as the first point. 7 Otherwise, it passes the contour through unchanged. 8 9 >>> from pprint import pprint 10 >>> from fontTools.pens.recordingPen import RecordingPen 11 >>> rec = RecordingPen() 12 >>> pen = ExplicitClosingLinePen(rec) 13 >>> pen.moveTo((0, 0)) 14 >>> pen.lineTo((100, 0)) 15 >>> pen.lineTo((100, 100)) 16 >>> pen.closePath() 17 >>> pprint(rec.value) 18 [('moveTo', ((0, 0),)), 19 ('lineTo', ((100, 0),)), 20 ('lineTo', ((100, 100),)), 21 ('lineTo', ((0, 0),)), 22 ('closePath', ())] 23 >>> rec = RecordingPen() 24 >>> pen = ExplicitClosingLinePen(rec) 25 >>> pen.moveTo((0, 0)) 26 >>> pen.lineTo((100, 0)) 27 >>> pen.lineTo((100, 100)) 28 >>> pen.lineTo((0, 0)) 29 >>> pen.closePath() 30 >>> pprint(rec.value) 31 [('moveTo', ((0, 0),)), 32 ('lineTo', ((100, 0),)), 33 ('lineTo', ((100, 100),)), 34 ('lineTo', ((0, 0),)), 35 ('closePath', ())] 36 >>> rec = RecordingPen() 37 >>> pen = ExplicitClosingLinePen(rec) 38 >>> pen.moveTo((0, 0)) 39 >>> pen.curveTo((100, 0), (0, 100), (100, 100)) 40 >>> pen.closePath() 41 >>> pprint(rec.value) 42 [('moveTo', ((0, 0),)), 43 ('curveTo', ((100, 0), (0, 100), (100, 100))), 44 ('lineTo', ((0, 0),)), 45 ('closePath', ())] 46 >>> rec = RecordingPen() 47 >>> pen = ExplicitClosingLinePen(rec) 48 >>> pen.moveTo((0, 0)) 49 >>> pen.curveTo((100, 0), (0, 100), (100, 100)) 50 >>> pen.lineTo((0, 0)) 51 >>> pen.closePath() 52 >>> pprint(rec.value) 53 [('moveTo', ((0, 0),)), 54 ('curveTo', ((100, 0), (0, 100), (100, 100))), 55 ('lineTo', ((0, 0),)), 56 ('closePath', ())] 57 >>> rec = RecordingPen() 58 >>> pen = ExplicitClosingLinePen(rec) 59 >>> pen.moveTo((0, 0)) 60 >>> pen.curveTo((100, 0), (0, 100), (0, 0)) 61 >>> pen.closePath() 62 >>> pprint(rec.value) 63 [('moveTo', ((0, 0),)), 64 ('curveTo', ((100, 0), (0, 100), (0, 0))), 65 ('closePath', ())] 66 >>> rec = RecordingPen() 67 >>> pen = ExplicitClosingLinePen(rec) 68 >>> pen.moveTo((0, 0)) 69 >>> pen.closePath() 70 >>> pprint(rec.value) 71 [('moveTo', ((0, 0),)), ('closePath', ())] 72 >>> rec = RecordingPen() 73 >>> pen = ExplicitClosingLinePen(rec) 74 >>> pen.closePath() 75 >>> pprint(rec.value) 76 [('closePath', ())] 77 >>> rec = RecordingPen() 78 >>> pen = ExplicitClosingLinePen(rec) 79 >>> pen.moveTo((0, 0)) 80 >>> pen.lineTo((100, 0)) 81 >>> pen.lineTo((100, 100)) 82 >>> pen.endPath() 83 >>> pprint(rec.value) 84 [('moveTo', ((0, 0),)), 85 ('lineTo', ((100, 0),)), 86 ('lineTo', ((100, 100),)), 87 ('endPath', ())] 88 """ 89 90 def filterContour(self, contour): 91 if ( 92 not contour 93 or contour[0][0] != "moveTo" 94 or contour[-1][0] != "closePath" 95 or len(contour) < 3 96 ): 97 return 98 movePt = contour[0][1][0] 99 lastSeg = contour[-2][1] 100 if lastSeg and movePt != lastSeg[-1]: 101 contour[-1:] = [("lineTo", (movePt,)), ("closePath", ())] 102