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