1*e1fe3e4aSElliott Hughesimport unittest 2*e1fe3e4aSElliott Hughes 3*e1fe3e4aSElliott Hughesfrom fontTools.pens.basePen import AbstractPen 4*e1fe3e4aSElliott Hughesfrom fontTools.pens.pointPen import ( 5*e1fe3e4aSElliott Hughes AbstractPointPen, 6*e1fe3e4aSElliott Hughes PointToSegmentPen, 7*e1fe3e4aSElliott Hughes SegmentToPointPen, 8*e1fe3e4aSElliott Hughes GuessSmoothPointPen, 9*e1fe3e4aSElliott Hughes ReverseContourPointPen, 10*e1fe3e4aSElliott Hughes) 11*e1fe3e4aSElliott Hughes 12*e1fe3e4aSElliott Hughes 13*e1fe3e4aSElliott Hughesclass _TestSegmentPen(AbstractPen): 14*e1fe3e4aSElliott Hughes def __init__(self): 15*e1fe3e4aSElliott Hughes self._commands = [] 16*e1fe3e4aSElliott Hughes 17*e1fe3e4aSElliott Hughes def __repr__(self): 18*e1fe3e4aSElliott Hughes return " ".join(self._commands) 19*e1fe3e4aSElliott Hughes 20*e1fe3e4aSElliott Hughes def moveTo(self, pt): 21*e1fe3e4aSElliott Hughes self._commands.append("%s %s moveto" % (pt[0], pt[1])) 22*e1fe3e4aSElliott Hughes 23*e1fe3e4aSElliott Hughes def lineTo(self, pt): 24*e1fe3e4aSElliott Hughes self._commands.append("%s %s lineto" % (pt[0], pt[1])) 25*e1fe3e4aSElliott Hughes 26*e1fe3e4aSElliott Hughes def curveTo(self, *pts): 27*e1fe3e4aSElliott Hughes pts = ["%s %s" % pt for pt in pts] 28*e1fe3e4aSElliott Hughes self._commands.append("%s curveto" % " ".join(pts)) 29*e1fe3e4aSElliott Hughes 30*e1fe3e4aSElliott Hughes def qCurveTo(self, *pts): 31*e1fe3e4aSElliott Hughes pts = ["%s %s" % pt if pt is not None else "None" for pt in pts] 32*e1fe3e4aSElliott Hughes self._commands.append("%s qcurveto" % " ".join(pts)) 33*e1fe3e4aSElliott Hughes 34*e1fe3e4aSElliott Hughes def closePath(self): 35*e1fe3e4aSElliott Hughes self._commands.append("closepath") 36*e1fe3e4aSElliott Hughes 37*e1fe3e4aSElliott Hughes def endPath(self): 38*e1fe3e4aSElliott Hughes self._commands.append("endpath") 39*e1fe3e4aSElliott Hughes 40*e1fe3e4aSElliott Hughes def addComponent(self, glyphName, transformation): 41*e1fe3e4aSElliott Hughes self._commands.append("'%s' %s addcomponent" % (glyphName, transformation)) 42*e1fe3e4aSElliott Hughes 43*e1fe3e4aSElliott Hughes 44*e1fe3e4aSElliott Hughesdef _reprKwargs(kwargs): 45*e1fe3e4aSElliott Hughes items = [] 46*e1fe3e4aSElliott Hughes for key in sorted(kwargs): 47*e1fe3e4aSElliott Hughes value = kwargs[key] 48*e1fe3e4aSElliott Hughes if isinstance(value, str): 49*e1fe3e4aSElliott Hughes items.append("%s='%s'" % (key, value)) 50*e1fe3e4aSElliott Hughes else: 51*e1fe3e4aSElliott Hughes items.append("%s=%s" % (key, value)) 52*e1fe3e4aSElliott Hughes return items 53*e1fe3e4aSElliott Hughes 54*e1fe3e4aSElliott Hughes 55*e1fe3e4aSElliott Hughesclass _TestPointPen(AbstractPointPen): 56*e1fe3e4aSElliott Hughes def __init__(self): 57*e1fe3e4aSElliott Hughes self._commands = [] 58*e1fe3e4aSElliott Hughes 59*e1fe3e4aSElliott Hughes def __repr__(self): 60*e1fe3e4aSElliott Hughes return " ".join(self._commands) 61*e1fe3e4aSElliott Hughes 62*e1fe3e4aSElliott Hughes def beginPath(self, identifier=None, **kwargs): 63*e1fe3e4aSElliott Hughes items = [] 64*e1fe3e4aSElliott Hughes if identifier is not None: 65*e1fe3e4aSElliott Hughes items.append("identifier='%s'" % identifier) 66*e1fe3e4aSElliott Hughes items.extend(_reprKwargs(kwargs)) 67*e1fe3e4aSElliott Hughes self._commands.append("beginPath(%s)" % ", ".join(items)) 68*e1fe3e4aSElliott Hughes 69*e1fe3e4aSElliott Hughes def addPoint( 70*e1fe3e4aSElliott Hughes self, pt, segmentType=None, smooth=False, name=None, identifier=None, **kwargs 71*e1fe3e4aSElliott Hughes ): 72*e1fe3e4aSElliott Hughes items = ["%s" % (pt,)] 73*e1fe3e4aSElliott Hughes if segmentType is not None: 74*e1fe3e4aSElliott Hughes items.append("segmentType='%s'" % segmentType) 75*e1fe3e4aSElliott Hughes if smooth: 76*e1fe3e4aSElliott Hughes items.append("smooth=True") 77*e1fe3e4aSElliott Hughes if name is not None: 78*e1fe3e4aSElliott Hughes items.append("name='%s'" % name) 79*e1fe3e4aSElliott Hughes if identifier is not None: 80*e1fe3e4aSElliott Hughes items.append("identifier='%s'" % identifier) 81*e1fe3e4aSElliott Hughes items.extend(_reprKwargs(kwargs)) 82*e1fe3e4aSElliott Hughes self._commands.append("addPoint(%s)" % ", ".join(items)) 83*e1fe3e4aSElliott Hughes 84*e1fe3e4aSElliott Hughes def endPath(self): 85*e1fe3e4aSElliott Hughes self._commands.append("endPath()") 86*e1fe3e4aSElliott Hughes 87*e1fe3e4aSElliott Hughes def addComponent(self, glyphName, transform, identifier=None, **kwargs): 88*e1fe3e4aSElliott Hughes items = ["'%s'" % glyphName, "%s" % transform] 89*e1fe3e4aSElliott Hughes if identifier is not None: 90*e1fe3e4aSElliott Hughes items.append("identifier='%s'" % identifier) 91*e1fe3e4aSElliott Hughes items.extend(_reprKwargs(kwargs)) 92*e1fe3e4aSElliott Hughes self._commands.append("addComponent(%s)" % ", ".join(items)) 93*e1fe3e4aSElliott Hughes 94*e1fe3e4aSElliott Hughes 95*e1fe3e4aSElliott Hughesclass PointToSegmentPenTest(unittest.TestCase): 96*e1fe3e4aSElliott Hughes def test_open(self): 97*e1fe3e4aSElliott Hughes pen = _TestSegmentPen() 98*e1fe3e4aSElliott Hughes ppen = PointToSegmentPen(pen) 99*e1fe3e4aSElliott Hughes ppen.beginPath() 100*e1fe3e4aSElliott Hughes ppen.addPoint((10, 10), "move") 101*e1fe3e4aSElliott Hughes ppen.addPoint((10, 20), "line") 102*e1fe3e4aSElliott Hughes ppen.endPath() 103*e1fe3e4aSElliott Hughes self.assertEqual("10 10 moveto 10 20 lineto endpath", repr(pen)) 104*e1fe3e4aSElliott Hughes 105*e1fe3e4aSElliott Hughes def test_closed(self): 106*e1fe3e4aSElliott Hughes pen = _TestSegmentPen() 107*e1fe3e4aSElliott Hughes ppen = PointToSegmentPen(pen) 108*e1fe3e4aSElliott Hughes ppen.beginPath() 109*e1fe3e4aSElliott Hughes ppen.addPoint((10, 10), "line") 110*e1fe3e4aSElliott Hughes ppen.addPoint((10, 20), "line") 111*e1fe3e4aSElliott Hughes ppen.addPoint((20, 20), "line") 112*e1fe3e4aSElliott Hughes ppen.endPath() 113*e1fe3e4aSElliott Hughes self.assertEqual("10 10 moveto 10 20 lineto 20 20 lineto closepath", repr(pen)) 114*e1fe3e4aSElliott Hughes 115*e1fe3e4aSElliott Hughes def test_cubic(self): 116*e1fe3e4aSElliott Hughes pen = _TestSegmentPen() 117*e1fe3e4aSElliott Hughes ppen = PointToSegmentPen(pen) 118*e1fe3e4aSElliott Hughes ppen.beginPath() 119*e1fe3e4aSElliott Hughes ppen.addPoint((10, 10), "line") 120*e1fe3e4aSElliott Hughes ppen.addPoint((10, 20)) 121*e1fe3e4aSElliott Hughes ppen.addPoint((20, 20)) 122*e1fe3e4aSElliott Hughes ppen.addPoint((20, 40), "curve") 123*e1fe3e4aSElliott Hughes ppen.endPath() 124*e1fe3e4aSElliott Hughes self.assertEqual("10 10 moveto 10 20 20 20 20 40 curveto closepath", repr(pen)) 125*e1fe3e4aSElliott Hughes 126*e1fe3e4aSElliott Hughes def test_quad(self): 127*e1fe3e4aSElliott Hughes pen = _TestSegmentPen() 128*e1fe3e4aSElliott Hughes ppen = PointToSegmentPen(pen) 129*e1fe3e4aSElliott Hughes ppen.beginPath(identifier="foo") 130*e1fe3e4aSElliott Hughes ppen.addPoint((10, 10), "line") 131*e1fe3e4aSElliott Hughes ppen.addPoint((10, 40)) 132*e1fe3e4aSElliott Hughes ppen.addPoint((40, 40)) 133*e1fe3e4aSElliott Hughes ppen.addPoint((10, 40), "qcurve") 134*e1fe3e4aSElliott Hughes ppen.endPath() 135*e1fe3e4aSElliott Hughes self.assertEqual("10 10 moveto 10 40 40 40 10 40 qcurveto closepath", repr(pen)) 136*e1fe3e4aSElliott Hughes 137*e1fe3e4aSElliott Hughes def test_quad_onlyOffCurvePoints(self): 138*e1fe3e4aSElliott Hughes pen = _TestSegmentPen() 139*e1fe3e4aSElliott Hughes ppen = PointToSegmentPen(pen) 140*e1fe3e4aSElliott Hughes ppen.beginPath() 141*e1fe3e4aSElliott Hughes ppen.addPoint((10, 10)) 142*e1fe3e4aSElliott Hughes ppen.addPoint((10, 40)) 143*e1fe3e4aSElliott Hughes ppen.addPoint((40, 40)) 144*e1fe3e4aSElliott Hughes ppen.endPath() 145*e1fe3e4aSElliott Hughes self.assertEqual("10 10 10 40 40 40 None qcurveto closepath", repr(pen)) 146*e1fe3e4aSElliott Hughes 147*e1fe3e4aSElliott Hughes def test_roundTrip1(self): 148*e1fe3e4aSElliott Hughes tpen = _TestPointPen() 149*e1fe3e4aSElliott Hughes ppen = PointToSegmentPen(SegmentToPointPen(tpen)) 150*e1fe3e4aSElliott Hughes ppen.beginPath() 151*e1fe3e4aSElliott Hughes ppen.addPoint((10, 10), "line") 152*e1fe3e4aSElliott Hughes ppen.addPoint((10, 20)) 153*e1fe3e4aSElliott Hughes ppen.addPoint((20, 20)) 154*e1fe3e4aSElliott Hughes ppen.addPoint((20, 40), "curve") 155*e1fe3e4aSElliott Hughes ppen.endPath() 156*e1fe3e4aSElliott Hughes self.assertEqual( 157*e1fe3e4aSElliott Hughes "beginPath() addPoint((10, 10), segmentType='line') addPoint((10, 20)) " 158*e1fe3e4aSElliott Hughes "addPoint((20, 20)) addPoint((20, 40), segmentType='curve') endPath()", 159*e1fe3e4aSElliott Hughes repr(tpen), 160*e1fe3e4aSElliott Hughes ) 161*e1fe3e4aSElliott Hughes 162*e1fe3e4aSElliott Hughes def test_closed_outputImpliedClosingLine(self): 163*e1fe3e4aSElliott Hughes tpen = _TestSegmentPen() 164*e1fe3e4aSElliott Hughes ppen = PointToSegmentPen(tpen, outputImpliedClosingLine=True) 165*e1fe3e4aSElliott Hughes ppen.beginPath() 166*e1fe3e4aSElliott Hughes ppen.addPoint((10, 10), "line") 167*e1fe3e4aSElliott Hughes ppen.addPoint((10, 20), "line") 168*e1fe3e4aSElliott Hughes ppen.addPoint((20, 20), "line") 169*e1fe3e4aSElliott Hughes ppen.endPath() 170*e1fe3e4aSElliott Hughes self.assertEqual( 171*e1fe3e4aSElliott Hughes "10 10 moveto " 172*e1fe3e4aSElliott Hughes "10 20 lineto " 173*e1fe3e4aSElliott Hughes "20 20 lineto " 174*e1fe3e4aSElliott Hughes "10 10 lineto " # explicit closing line 175*e1fe3e4aSElliott Hughes "closepath", 176*e1fe3e4aSElliott Hughes repr(tpen), 177*e1fe3e4aSElliott Hughes ) 178*e1fe3e4aSElliott Hughes 179*e1fe3e4aSElliott Hughes def test_closed_line_overlapping_start_end_points(self): 180*e1fe3e4aSElliott Hughes # Test case from https://github.com/googlefonts/fontmake/issues/572. 181*e1fe3e4aSElliott Hughes tpen = _TestSegmentPen() 182*e1fe3e4aSElliott Hughes ppen = PointToSegmentPen(tpen, outputImpliedClosingLine=False) 183*e1fe3e4aSElliott Hughes # The last oncurve point on this closed contour is a "line" segment and has 184*e1fe3e4aSElliott Hughes # same coordinates as the starting point. 185*e1fe3e4aSElliott Hughes ppen.beginPath() 186*e1fe3e4aSElliott Hughes ppen.addPoint((0, 651), segmentType="line") 187*e1fe3e4aSElliott Hughes ppen.addPoint((0, 101), segmentType="line") 188*e1fe3e4aSElliott Hughes ppen.addPoint((0, 101), segmentType="line") 189*e1fe3e4aSElliott Hughes ppen.addPoint((0, 651), segmentType="line") 190*e1fe3e4aSElliott Hughes ppen.endPath() 191*e1fe3e4aSElliott Hughes # Check that we always output an explicit 'lineTo' segment at the end, 192*e1fe3e4aSElliott Hughes # regardless of the value of 'outputImpliedClosingLine', to disambiguate 193*e1fe3e4aSElliott Hughes # the duplicate point from the implied closing line. 194*e1fe3e4aSElliott Hughes self.assertEqual( 195*e1fe3e4aSElliott Hughes "0 651 moveto " 196*e1fe3e4aSElliott Hughes "0 101 lineto " 197*e1fe3e4aSElliott Hughes "0 101 lineto " 198*e1fe3e4aSElliott Hughes "0 651 lineto " 199*e1fe3e4aSElliott Hughes "0 651 lineto " 200*e1fe3e4aSElliott Hughes "closepath", 201*e1fe3e4aSElliott Hughes repr(tpen), 202*e1fe3e4aSElliott Hughes ) 203*e1fe3e4aSElliott Hughes 204*e1fe3e4aSElliott Hughes def test_roundTrip2(self): 205*e1fe3e4aSElliott Hughes tpen = _TestPointPen() 206*e1fe3e4aSElliott Hughes ppen = PointToSegmentPen(SegmentToPointPen(tpen)) 207*e1fe3e4aSElliott Hughes ppen.beginPath() 208*e1fe3e4aSElliott Hughes ppen.addPoint((0, 651), segmentType="line") 209*e1fe3e4aSElliott Hughes ppen.addPoint((0, 101), segmentType="line") 210*e1fe3e4aSElliott Hughes ppen.addPoint((0, 101), segmentType="line") 211*e1fe3e4aSElliott Hughes ppen.addPoint((0, 651), segmentType="line") 212*e1fe3e4aSElliott Hughes ppen.endPath() 213*e1fe3e4aSElliott Hughes self.assertEqual( 214*e1fe3e4aSElliott Hughes "beginPath() " 215*e1fe3e4aSElliott Hughes "addPoint((0, 651), segmentType='line') " 216*e1fe3e4aSElliott Hughes "addPoint((0, 101), segmentType='line') " 217*e1fe3e4aSElliott Hughes "addPoint((0, 101), segmentType='line') " 218*e1fe3e4aSElliott Hughes "addPoint((0, 651), segmentType='line') " 219*e1fe3e4aSElliott Hughes "endPath()", 220*e1fe3e4aSElliott Hughes repr(tpen), 221*e1fe3e4aSElliott Hughes ) 222*e1fe3e4aSElliott Hughes 223*e1fe3e4aSElliott Hughes 224*e1fe3e4aSElliott Hughesclass TestSegmentToPointPen(unittest.TestCase): 225*e1fe3e4aSElliott Hughes def test_move(self): 226*e1fe3e4aSElliott Hughes tpen = _TestPointPen() 227*e1fe3e4aSElliott Hughes pen = SegmentToPointPen(tpen) 228*e1fe3e4aSElliott Hughes pen.moveTo((10, 10)) 229*e1fe3e4aSElliott Hughes pen.endPath() 230*e1fe3e4aSElliott Hughes self.assertEqual( 231*e1fe3e4aSElliott Hughes "beginPath() addPoint((10, 10), segmentType='move') endPath()", repr(tpen) 232*e1fe3e4aSElliott Hughes ) 233*e1fe3e4aSElliott Hughes 234*e1fe3e4aSElliott Hughes def test_poly(self): 235*e1fe3e4aSElliott Hughes tpen = _TestPointPen() 236*e1fe3e4aSElliott Hughes pen = SegmentToPointPen(tpen) 237*e1fe3e4aSElliott Hughes pen.moveTo((10, 10)) 238*e1fe3e4aSElliott Hughes pen.lineTo((10, 20)) 239*e1fe3e4aSElliott Hughes pen.lineTo((20, 20)) 240*e1fe3e4aSElliott Hughes pen.closePath() 241*e1fe3e4aSElliott Hughes self.assertEqual( 242*e1fe3e4aSElliott Hughes "beginPath() addPoint((10, 10), segmentType='line') " 243*e1fe3e4aSElliott Hughes "addPoint((10, 20), segmentType='line') " 244*e1fe3e4aSElliott Hughes "addPoint((20, 20), segmentType='line') endPath()", 245*e1fe3e4aSElliott Hughes repr(tpen), 246*e1fe3e4aSElliott Hughes ) 247*e1fe3e4aSElliott Hughes 248*e1fe3e4aSElliott Hughes def test_cubic(self): 249*e1fe3e4aSElliott Hughes tpen = _TestPointPen() 250*e1fe3e4aSElliott Hughes pen = SegmentToPointPen(tpen) 251*e1fe3e4aSElliott Hughes pen.moveTo((10, 10)) 252*e1fe3e4aSElliott Hughes pen.curveTo((10, 20), (20, 20), (20, 10)) 253*e1fe3e4aSElliott Hughes pen.closePath() 254*e1fe3e4aSElliott Hughes self.assertEqual( 255*e1fe3e4aSElliott Hughes "beginPath() addPoint((10, 10), segmentType='line') " 256*e1fe3e4aSElliott Hughes "addPoint((10, 20)) addPoint((20, 20)) addPoint((20, 10), " 257*e1fe3e4aSElliott Hughes "segmentType='curve') endPath()", 258*e1fe3e4aSElliott Hughes repr(tpen), 259*e1fe3e4aSElliott Hughes ) 260*e1fe3e4aSElliott Hughes 261*e1fe3e4aSElliott Hughes def test_quad(self): 262*e1fe3e4aSElliott Hughes tpen = _TestPointPen() 263*e1fe3e4aSElliott Hughes pen = SegmentToPointPen(tpen) 264*e1fe3e4aSElliott Hughes pen.moveTo((10, 10)) 265*e1fe3e4aSElliott Hughes pen.qCurveTo((10, 20), (20, 20), (20, 10)) 266*e1fe3e4aSElliott Hughes pen.closePath() 267*e1fe3e4aSElliott Hughes self.assertEqual( 268*e1fe3e4aSElliott Hughes "beginPath() addPoint((10, 10), segmentType='line') " 269*e1fe3e4aSElliott Hughes "addPoint((10, 20)) addPoint((20, 20)) " 270*e1fe3e4aSElliott Hughes "addPoint((20, 10), segmentType='qcurve') endPath()", 271*e1fe3e4aSElliott Hughes repr(tpen), 272*e1fe3e4aSElliott Hughes ) 273*e1fe3e4aSElliott Hughes 274*e1fe3e4aSElliott Hughes def test_quad2(self): 275*e1fe3e4aSElliott Hughes tpen = _TestPointPen() 276*e1fe3e4aSElliott Hughes pen = SegmentToPointPen(tpen) 277*e1fe3e4aSElliott Hughes pen.qCurveTo((10, 20), (20, 20), (20, 10), (10, 10), None) 278*e1fe3e4aSElliott Hughes pen.closePath() 279*e1fe3e4aSElliott Hughes self.assertEqual( 280*e1fe3e4aSElliott Hughes "beginPath() addPoint((10, 20)) addPoint((20, 20)) " 281*e1fe3e4aSElliott Hughes "addPoint((20, 10)) addPoint((10, 10)) endPath()", 282*e1fe3e4aSElliott Hughes repr(tpen), 283*e1fe3e4aSElliott Hughes ) 284*e1fe3e4aSElliott Hughes 285*e1fe3e4aSElliott Hughes def test_roundTrip1(self): 286*e1fe3e4aSElliott Hughes spen = _TestSegmentPen() 287*e1fe3e4aSElliott Hughes pen = SegmentToPointPen(PointToSegmentPen(spen)) 288*e1fe3e4aSElliott Hughes pen.moveTo((10, 10)) 289*e1fe3e4aSElliott Hughes pen.lineTo((10, 20)) 290*e1fe3e4aSElliott Hughes pen.lineTo((20, 20)) 291*e1fe3e4aSElliott Hughes pen.closePath() 292*e1fe3e4aSElliott Hughes self.assertEqual("10 10 moveto 10 20 lineto 20 20 lineto closepath", repr(spen)) 293*e1fe3e4aSElliott Hughes 294*e1fe3e4aSElliott Hughes def test_roundTrip2(self): 295*e1fe3e4aSElliott Hughes spen = _TestSegmentPen() 296*e1fe3e4aSElliott Hughes pen = SegmentToPointPen(PointToSegmentPen(spen)) 297*e1fe3e4aSElliott Hughes pen.qCurveTo((10, 20), (20, 20), (20, 10), (10, 10), None) 298*e1fe3e4aSElliott Hughes pen.closePath() 299*e1fe3e4aSElliott Hughes pen.addComponent("base", [1, 0, 0, 1, 0, 0]) 300*e1fe3e4aSElliott Hughes self.assertEqual( 301*e1fe3e4aSElliott Hughes "10 20 20 20 20 10 10 10 None qcurveto closepath " 302*e1fe3e4aSElliott Hughes "'base' [1, 0, 0, 1, 0, 0] addcomponent", 303*e1fe3e4aSElliott Hughes repr(spen), 304*e1fe3e4aSElliott Hughes ) 305*e1fe3e4aSElliott Hughes 306*e1fe3e4aSElliott Hughes 307*e1fe3e4aSElliott Hughesclass TestGuessSmoothPointPen(unittest.TestCase): 308*e1fe3e4aSElliott Hughes def test_guessSmooth_exact(self): 309*e1fe3e4aSElliott Hughes tpen = _TestPointPen() 310*e1fe3e4aSElliott Hughes pen = GuessSmoothPointPen(tpen) 311*e1fe3e4aSElliott Hughes pen.beginPath(identifier="foo") 312*e1fe3e4aSElliott Hughes pen.addPoint((0, 100), segmentType="curve") 313*e1fe3e4aSElliott Hughes pen.addPoint((0, 200)) 314*e1fe3e4aSElliott Hughes pen.addPoint((400, 200), identifier="bar") 315*e1fe3e4aSElliott Hughes pen.addPoint((400, 100), segmentType="curve") 316*e1fe3e4aSElliott Hughes pen.addPoint((400, 0)) 317*e1fe3e4aSElliott Hughes pen.addPoint((0, 0)) 318*e1fe3e4aSElliott Hughes pen.endPath() 319*e1fe3e4aSElliott Hughes self.assertEqual( 320*e1fe3e4aSElliott Hughes "beginPath(identifier='foo') " 321*e1fe3e4aSElliott Hughes "addPoint((0, 100), segmentType='curve', smooth=True) " 322*e1fe3e4aSElliott Hughes "addPoint((0, 200)) addPoint((400, 200), identifier='bar') " 323*e1fe3e4aSElliott Hughes "addPoint((400, 100), segmentType='curve', smooth=True) " 324*e1fe3e4aSElliott Hughes "addPoint((400, 0)) addPoint((0, 0)) endPath()", 325*e1fe3e4aSElliott Hughes repr(tpen), 326*e1fe3e4aSElliott Hughes ) 327*e1fe3e4aSElliott Hughes 328*e1fe3e4aSElliott Hughes def test_guessSmooth_almost(self): 329*e1fe3e4aSElliott Hughes tpen = _TestPointPen() 330*e1fe3e4aSElliott Hughes pen = GuessSmoothPointPen(tpen) 331*e1fe3e4aSElliott Hughes pen.beginPath() 332*e1fe3e4aSElliott Hughes pen.addPoint((0, 100), segmentType="curve") 333*e1fe3e4aSElliott Hughes pen.addPoint((1, 200)) 334*e1fe3e4aSElliott Hughes pen.addPoint((395, 200)) 335*e1fe3e4aSElliott Hughes pen.addPoint((400, 100), segmentType="curve") 336*e1fe3e4aSElliott Hughes pen.addPoint((400, 0)) 337*e1fe3e4aSElliott Hughes pen.addPoint((0, 0)) 338*e1fe3e4aSElliott Hughes pen.endPath() 339*e1fe3e4aSElliott Hughes self.assertEqual( 340*e1fe3e4aSElliott Hughes "beginPath() addPoint((0, 100), segmentType='curve', smooth=True) " 341*e1fe3e4aSElliott Hughes "addPoint((1, 200)) addPoint((395, 200)) " 342*e1fe3e4aSElliott Hughes "addPoint((400, 100), segmentType='curve', smooth=True) " 343*e1fe3e4aSElliott Hughes "addPoint((400, 0)) addPoint((0, 0)) endPath()", 344*e1fe3e4aSElliott Hughes repr(tpen), 345*e1fe3e4aSElliott Hughes ) 346*e1fe3e4aSElliott Hughes 347*e1fe3e4aSElliott Hughes def test_guessSmooth_tangent(self): 348*e1fe3e4aSElliott Hughes tpen = _TestPointPen() 349*e1fe3e4aSElliott Hughes pen = GuessSmoothPointPen(tpen) 350*e1fe3e4aSElliott Hughes pen.beginPath() 351*e1fe3e4aSElliott Hughes pen.addPoint((0, 0), segmentType="move") 352*e1fe3e4aSElliott Hughes pen.addPoint((0, 100), segmentType="line") 353*e1fe3e4aSElliott Hughes pen.addPoint((3, 200)) 354*e1fe3e4aSElliott Hughes pen.addPoint((300, 200)) 355*e1fe3e4aSElliott Hughes pen.addPoint((400, 200), segmentType="curve") 356*e1fe3e4aSElliott Hughes pen.endPath() 357*e1fe3e4aSElliott Hughes self.assertEqual( 358*e1fe3e4aSElliott Hughes "beginPath() addPoint((0, 0), segmentType='move') " 359*e1fe3e4aSElliott Hughes "addPoint((0, 100), segmentType='line', smooth=True) " 360*e1fe3e4aSElliott Hughes "addPoint((3, 200)) addPoint((300, 200)) " 361*e1fe3e4aSElliott Hughes "addPoint((400, 200), segmentType='curve') endPath()", 362*e1fe3e4aSElliott Hughes repr(tpen), 363*e1fe3e4aSElliott Hughes ) 364*e1fe3e4aSElliott Hughes 365*e1fe3e4aSElliott Hughes 366*e1fe3e4aSElliott Hughesclass TestReverseContourPointPen(unittest.TestCase): 367*e1fe3e4aSElliott Hughes def test_singlePoint(self): 368*e1fe3e4aSElliott Hughes tpen = _TestPointPen() 369*e1fe3e4aSElliott Hughes pen = ReverseContourPointPen(tpen) 370*e1fe3e4aSElliott Hughes pen.beginPath() 371*e1fe3e4aSElliott Hughes pen.addPoint((0, 0), segmentType="move") 372*e1fe3e4aSElliott Hughes pen.endPath() 373*e1fe3e4aSElliott Hughes self.assertEqual( 374*e1fe3e4aSElliott Hughes "beginPath() " "addPoint((0, 0), segmentType='move') " "endPath()", 375*e1fe3e4aSElliott Hughes repr(tpen), 376*e1fe3e4aSElliott Hughes ) 377*e1fe3e4aSElliott Hughes 378*e1fe3e4aSElliott Hughes def test_line(self): 379*e1fe3e4aSElliott Hughes tpen = _TestPointPen() 380*e1fe3e4aSElliott Hughes pen = ReverseContourPointPen(tpen) 381*e1fe3e4aSElliott Hughes pen.beginPath() 382*e1fe3e4aSElliott Hughes pen.addPoint((0, 0), segmentType="move") 383*e1fe3e4aSElliott Hughes pen.addPoint((0, 100), segmentType="line") 384*e1fe3e4aSElliott Hughes pen.endPath() 385*e1fe3e4aSElliott Hughes self.assertEqual( 386*e1fe3e4aSElliott Hughes "beginPath() " 387*e1fe3e4aSElliott Hughes "addPoint((0, 100), segmentType='move') " 388*e1fe3e4aSElliott Hughes "addPoint((0, 0), segmentType='line') " 389*e1fe3e4aSElliott Hughes "endPath()", 390*e1fe3e4aSElliott Hughes repr(tpen), 391*e1fe3e4aSElliott Hughes ) 392*e1fe3e4aSElliott Hughes 393*e1fe3e4aSElliott Hughes def test_triangle(self): 394*e1fe3e4aSElliott Hughes tpen = _TestPointPen() 395*e1fe3e4aSElliott Hughes pen = ReverseContourPointPen(tpen) 396*e1fe3e4aSElliott Hughes pen.beginPath() 397*e1fe3e4aSElliott Hughes pen.addPoint((0, 0), segmentType="line") 398*e1fe3e4aSElliott Hughes pen.addPoint((0, 100), segmentType="line") 399*e1fe3e4aSElliott Hughes pen.addPoint((100, 100), segmentType="line") 400*e1fe3e4aSElliott Hughes pen.endPath() 401*e1fe3e4aSElliott Hughes self.assertEqual( 402*e1fe3e4aSElliott Hughes "beginPath() " 403*e1fe3e4aSElliott Hughes "addPoint((0, 0), segmentType='line') " 404*e1fe3e4aSElliott Hughes "addPoint((100, 100), segmentType='line') " 405*e1fe3e4aSElliott Hughes "addPoint((0, 100), segmentType='line') " 406*e1fe3e4aSElliott Hughes "endPath()", 407*e1fe3e4aSElliott Hughes repr(tpen), 408*e1fe3e4aSElliott Hughes ) 409*e1fe3e4aSElliott Hughes 410*e1fe3e4aSElliott Hughes def test_cubicOpen(self): 411*e1fe3e4aSElliott Hughes tpen = _TestPointPen() 412*e1fe3e4aSElliott Hughes pen = ReverseContourPointPen(tpen) 413*e1fe3e4aSElliott Hughes pen.beginPath() 414*e1fe3e4aSElliott Hughes pen.addPoint((0, 0), segmentType="move") 415*e1fe3e4aSElliott Hughes pen.addPoint((0, 100)) 416*e1fe3e4aSElliott Hughes pen.addPoint((100, 200)) 417*e1fe3e4aSElliott Hughes pen.addPoint((200, 200), segmentType="curve") 418*e1fe3e4aSElliott Hughes pen.endPath() 419*e1fe3e4aSElliott Hughes self.assertEqual( 420*e1fe3e4aSElliott Hughes "beginPath() " 421*e1fe3e4aSElliott Hughes "addPoint((200, 200), segmentType='move') " 422*e1fe3e4aSElliott Hughes "addPoint((100, 200)) " 423*e1fe3e4aSElliott Hughes "addPoint((0, 100)) " 424*e1fe3e4aSElliott Hughes "addPoint((0, 0), segmentType='curve') " 425*e1fe3e4aSElliott Hughes "endPath()", 426*e1fe3e4aSElliott Hughes repr(tpen), 427*e1fe3e4aSElliott Hughes ) 428*e1fe3e4aSElliott Hughes 429*e1fe3e4aSElliott Hughes def test_quadOpen(self): 430*e1fe3e4aSElliott Hughes tpen = _TestPointPen() 431*e1fe3e4aSElliott Hughes pen = ReverseContourPointPen(tpen) 432*e1fe3e4aSElliott Hughes pen.beginPath() 433*e1fe3e4aSElliott Hughes pen.addPoint((0, 0), segmentType="move") 434*e1fe3e4aSElliott Hughes pen.addPoint((0, 100)) 435*e1fe3e4aSElliott Hughes pen.addPoint((100, 200)) 436*e1fe3e4aSElliott Hughes pen.addPoint((200, 200), segmentType="qcurve") 437*e1fe3e4aSElliott Hughes pen.endPath() 438*e1fe3e4aSElliott Hughes self.assertEqual( 439*e1fe3e4aSElliott Hughes "beginPath() " 440*e1fe3e4aSElliott Hughes "addPoint((200, 200), segmentType='move') " 441*e1fe3e4aSElliott Hughes "addPoint((100, 200)) " 442*e1fe3e4aSElliott Hughes "addPoint((0, 100)) " 443*e1fe3e4aSElliott Hughes "addPoint((0, 0), segmentType='qcurve') " 444*e1fe3e4aSElliott Hughes "endPath()", 445*e1fe3e4aSElliott Hughes repr(tpen), 446*e1fe3e4aSElliott Hughes ) 447*e1fe3e4aSElliott Hughes 448*e1fe3e4aSElliott Hughes def test_cubicClosed(self): 449*e1fe3e4aSElliott Hughes tpen = _TestPointPen() 450*e1fe3e4aSElliott Hughes pen = ReverseContourPointPen(tpen) 451*e1fe3e4aSElliott Hughes pen.beginPath() 452*e1fe3e4aSElliott Hughes pen.addPoint((0, 0), segmentType="line") 453*e1fe3e4aSElliott Hughes pen.addPoint((0, 100)) 454*e1fe3e4aSElliott Hughes pen.addPoint((100, 200)) 455*e1fe3e4aSElliott Hughes pen.addPoint((200, 200), segmentType="curve") 456*e1fe3e4aSElliott Hughes pen.endPath() 457*e1fe3e4aSElliott Hughes self.assertEqual( 458*e1fe3e4aSElliott Hughes "beginPath() " 459*e1fe3e4aSElliott Hughes "addPoint((0, 0), segmentType='curve') " 460*e1fe3e4aSElliott Hughes "addPoint((200, 200), segmentType='line') " 461*e1fe3e4aSElliott Hughes "addPoint((100, 200)) " 462*e1fe3e4aSElliott Hughes "addPoint((0, 100)) " 463*e1fe3e4aSElliott Hughes "endPath()", 464*e1fe3e4aSElliott Hughes repr(tpen), 465*e1fe3e4aSElliott Hughes ) 466*e1fe3e4aSElliott Hughes 467*e1fe3e4aSElliott Hughes def test_quadClosedOffCurveStart(self): 468*e1fe3e4aSElliott Hughes tpen = _TestPointPen() 469*e1fe3e4aSElliott Hughes pen = ReverseContourPointPen(tpen) 470*e1fe3e4aSElliott Hughes pen.beginPath() 471*e1fe3e4aSElliott Hughes pen.addPoint((100, 200)) 472*e1fe3e4aSElliott Hughes pen.addPoint((200, 200), segmentType="qcurve") 473*e1fe3e4aSElliott Hughes pen.addPoint((0, 0), segmentType="line") 474*e1fe3e4aSElliott Hughes pen.addPoint((0, 100)) 475*e1fe3e4aSElliott Hughes pen.endPath() 476*e1fe3e4aSElliott Hughes self.assertEqual( 477*e1fe3e4aSElliott Hughes "beginPath() " 478*e1fe3e4aSElliott Hughes "addPoint((100, 200)) " 479*e1fe3e4aSElliott Hughes "addPoint((0, 100)) " 480*e1fe3e4aSElliott Hughes "addPoint((0, 0), segmentType='qcurve') " 481*e1fe3e4aSElliott Hughes "addPoint((200, 200), segmentType='line') " 482*e1fe3e4aSElliott Hughes "endPath()", 483*e1fe3e4aSElliott Hughes repr(tpen), 484*e1fe3e4aSElliott Hughes ) 485*e1fe3e4aSElliott Hughes 486*e1fe3e4aSElliott Hughes def test_quadNoOnCurve(self): 487*e1fe3e4aSElliott Hughes tpen = _TestPointPen() 488*e1fe3e4aSElliott Hughes pen = ReverseContourPointPen(tpen) 489*e1fe3e4aSElliott Hughes pen.beginPath(identifier="bar") 490*e1fe3e4aSElliott Hughes pen.addPoint((0, 0)) 491*e1fe3e4aSElliott Hughes pen.addPoint((0, 100), identifier="foo", arbitrary="foo") 492*e1fe3e4aSElliott Hughes pen.addPoint((100, 200), arbitrary=123) 493*e1fe3e4aSElliott Hughes pen.addPoint((200, 200)) 494*e1fe3e4aSElliott Hughes pen.endPath() 495*e1fe3e4aSElliott Hughes pen.addComponent("base", [1, 0, 0, 1, 0, 0], identifier="foo") 496*e1fe3e4aSElliott Hughes self.assertEqual( 497*e1fe3e4aSElliott Hughes "beginPath(identifier='bar') " 498*e1fe3e4aSElliott Hughes "addPoint((0, 0)) " 499*e1fe3e4aSElliott Hughes "addPoint((200, 200)) " 500*e1fe3e4aSElliott Hughes "addPoint((100, 200), arbitrary=123) " 501*e1fe3e4aSElliott Hughes "addPoint((0, 100), identifier='foo', arbitrary='foo') " 502*e1fe3e4aSElliott Hughes "endPath() " 503*e1fe3e4aSElliott Hughes "addComponent('base', [1, 0, 0, 1, 0, 0], identifier='foo')", 504*e1fe3e4aSElliott Hughes repr(tpen), 505*e1fe3e4aSElliott Hughes ) 506*e1fe3e4aSElliott Hughes 507*e1fe3e4aSElliott Hughes def test_closed_line_overlapping_start_end_points(self): 508*e1fe3e4aSElliott Hughes # Test case from https://github.com/googlefonts/fontmake/issues/572 509*e1fe3e4aSElliott Hughes tpen = _TestPointPen() 510*e1fe3e4aSElliott Hughes pen = ReverseContourPointPen(tpen) 511*e1fe3e4aSElliott Hughes pen.beginPath() 512*e1fe3e4aSElliott Hughes pen.addPoint((0, 651), segmentType="line") 513*e1fe3e4aSElliott Hughes pen.addPoint((0, 101), segmentType="line") 514*e1fe3e4aSElliott Hughes pen.addPoint((0, 101), segmentType="line") 515*e1fe3e4aSElliott Hughes pen.addPoint((0, 651), segmentType="line") 516*e1fe3e4aSElliott Hughes pen.endPath() 517*e1fe3e4aSElliott Hughes self.assertEqual( 518*e1fe3e4aSElliott Hughes "beginPath() " 519*e1fe3e4aSElliott Hughes "addPoint((0, 651), segmentType='line') " 520*e1fe3e4aSElliott Hughes "addPoint((0, 651), segmentType='line') " 521*e1fe3e4aSElliott Hughes "addPoint((0, 101), segmentType='line') " 522*e1fe3e4aSElliott Hughes "addPoint((0, 101), segmentType='line') " 523*e1fe3e4aSElliott Hughes "endPath()", 524*e1fe3e4aSElliott Hughes repr(tpen), 525*e1fe3e4aSElliott Hughes ) 526