aboutsummaryrefslogtreecommitdiff
path: root/Lib/fontTools/pens/basePen.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/fontTools/pens/basePen.py')
-rw-r--r--Lib/fontTools/pens/basePen.py683
1 files changed, 358 insertions, 325 deletions
diff --git a/Lib/fontTools/pens/basePen.py b/Lib/fontTools/pens/basePen.py
index f981f806..ac8abd40 100644
--- a/Lib/fontTools/pens/basePen.py
+++ b/Lib/fontTools/pens/basePen.py
@@ -36,376 +36,409 @@ Coordinates are usually expressed as (x, y) tuples, but generally any
sequence of length 2 will do.
"""
-from typing import Tuple
+from typing import Tuple, Dict
from fontTools.misc.loggingTools import LogMixin
+from fontTools.misc.transform import DecomposedTransform
-__all__ = ["AbstractPen", "NullPen", "BasePen", "PenError",
- "decomposeSuperBezierSegment", "decomposeQuadraticSegment"]
+__all__ = [
+ "AbstractPen",
+ "NullPen",
+ "BasePen",
+ "PenError",
+ "decomposeSuperBezierSegment",
+ "decomposeQuadraticSegment",
+]
class PenError(Exception):
- """Represents an error during penning."""
+ """Represents an error during penning."""
+
class OpenContourError(PenError):
- pass
+ pass
class AbstractPen:
-
- def moveTo(self, pt: Tuple[float, float]) -> None:
- """Begin a new sub path, set the current point to 'pt'. You must
- end each sub path with a call to pen.closePath() or pen.endPath().
- """
- raise NotImplementedError
-
- def lineTo(self, pt: Tuple[float, float]) -> None:
- """Draw a straight line from the current point to 'pt'."""
- raise NotImplementedError
-
- def curveTo(self, *points: Tuple[float, float]) -> None:
- """Draw a cubic bezier with an arbitrary number of control points.
-
- The last point specified is on-curve, all others are off-curve
- (control) points. If the number of control points is > 2, the
- segment is split into multiple bezier segments. This works
- like this:
-
- Let n be the number of control points (which is the number of
- arguments to this call minus 1). If n==2, a plain vanilla cubic
- bezier is drawn. If n==1, we fall back to a quadratic segment and
- if n==0 we draw a straight line. It gets interesting when n>2:
- n-1 PostScript-style cubic segments will be drawn as if it were
- one curve. See decomposeSuperBezierSegment().
-
- The conversion algorithm used for n>2 is inspired by NURB
- splines, and is conceptually equivalent to the TrueType "implied
- points" principle. See also decomposeQuadraticSegment().
- """
- raise NotImplementedError
-
- def qCurveTo(self, *points: Tuple[float, float]) -> None:
- """Draw a whole string of quadratic curve segments.
-
- The last point specified is on-curve, all others are off-curve
- points.
-
- This method implements TrueType-style curves, breaking up curves
- using 'implied points': between each two consequtive off-curve points,
- there is one implied point exactly in the middle between them. See
- also decomposeQuadraticSegment().
-
- The last argument (normally the on-curve point) may be None.
- This is to support contours that have NO on-curve points (a rarely
- seen feature of TrueType outlines).
- """
- raise NotImplementedError
-
- def closePath(self) -> None:
- """Close the current sub path. You must call either pen.closePath()
- or pen.endPath() after each sub path.
- """
- pass
-
- def endPath(self) -> None:
- """End the current sub path, but don't close it. You must call
- either pen.closePath() or pen.endPath() after each sub path.
- """
- pass
-
- def addComponent(
- self,
- glyphName: str,
- transformation: Tuple[float, float, float, float, float, float]
- ) -> None:
- """Add a sub glyph. The 'transformation' argument must be a 6-tuple
- containing an affine transformation, or a Transform object from the
- fontTools.misc.transform module. More precisely: it should be a
- sequence containing 6 numbers.
- """
- raise NotImplementedError
+ def moveTo(self, pt: Tuple[float, float]) -> None:
+ """Begin a new sub path, set the current point to 'pt'. You must
+ end each sub path with a call to pen.closePath() or pen.endPath().
+ """
+ raise NotImplementedError
+
+ def lineTo(self, pt: Tuple[float, float]) -> None:
+ """Draw a straight line from the current point to 'pt'."""
+ raise NotImplementedError
+
+ def curveTo(self, *points: Tuple[float, float]) -> None:
+ """Draw a cubic bezier with an arbitrary number of control points.
+
+ The last point specified is on-curve, all others are off-curve
+ (control) points. If the number of control points is > 2, the
+ segment is split into multiple bezier segments. This works
+ like this:
+
+ Let n be the number of control points (which is the number of
+ arguments to this call minus 1). If n==2, a plain vanilla cubic
+ bezier is drawn. If n==1, we fall back to a quadratic segment and
+ if n==0 we draw a straight line. It gets interesting when n>2:
+ n-1 PostScript-style cubic segments will be drawn as if it were
+ one curve. See decomposeSuperBezierSegment().
+
+ The conversion algorithm used for n>2 is inspired by NURB
+ splines, and is conceptually equivalent to the TrueType "implied
+ points" principle. See also decomposeQuadraticSegment().
+ """
+ raise NotImplementedError
+
+ def qCurveTo(self, *points: Tuple[float, float]) -> None:
+ """Draw a whole string of quadratic curve segments.
+
+ The last point specified is on-curve, all others are off-curve
+ points.
+
+ This method implements TrueType-style curves, breaking up curves
+ using 'implied points': between each two consequtive off-curve points,
+ there is one implied point exactly in the middle between them. See
+ also decomposeQuadraticSegment().
+
+ The last argument (normally the on-curve point) may be None.
+ This is to support contours that have NO on-curve points (a rarely
+ seen feature of TrueType outlines).
+ """
+ raise NotImplementedError
+
+ def closePath(self) -> None:
+ """Close the current sub path. You must call either pen.closePath()
+ or pen.endPath() after each sub path.
+ """
+ pass
+
+ def endPath(self) -> None:
+ """End the current sub path, but don't close it. You must call
+ either pen.closePath() or pen.endPath() after each sub path.
+ """
+ pass
+
+ def addComponent(
+ self,
+ glyphName: str,
+ transformation: Tuple[float, float, float, float, float, float],
+ ) -> None:
+ """Add a sub glyph. The 'transformation' argument must be a 6-tuple
+ containing an affine transformation, or a Transform object from the
+ fontTools.misc.transform module. More precisely: it should be a
+ sequence containing 6 numbers.
+ """
+ raise NotImplementedError
+
+ def addVarComponent(
+ self,
+ glyphName: str,
+ transformation: DecomposedTransform,
+ location: Dict[str, float],
+ ) -> None:
+ """Add a VarComponent sub glyph. The 'transformation' argument
+ must be a DecomposedTransform from the fontTools.misc.transform module,
+ and the 'location' argument must be a dictionary mapping axis tags
+ to their locations.
+ """
+ # GlyphSet decomposes for us
+ raise AttributeError
class NullPen(AbstractPen):
- """A pen that does nothing.
- """
+ """A pen that does nothing."""
- def moveTo(self, pt):
- pass
+ def moveTo(self, pt):
+ pass
- def lineTo(self, pt):
- pass
+ def lineTo(self, pt):
+ pass
- def curveTo(self, *points):
- pass
+ def curveTo(self, *points):
+ pass
- def qCurveTo(self, *points):
- pass
+ def qCurveTo(self, *points):
+ pass
- def closePath(self):
- pass
+ def closePath(self):
+ pass
- def endPath(self):
- pass
+ def endPath(self):
+ pass
- def addComponent(self, glyphName, transformation):
- pass
+ def addComponent(self, glyphName, transformation):
+ pass
+
+ def addVarComponent(self, glyphName, transformation, location):
+ pass
class LoggingPen(LogMixin, AbstractPen):
- """A pen with a ``log`` property (see fontTools.misc.loggingTools.LogMixin)
- """
- pass
+ """A pen with a ``log`` property (see fontTools.misc.loggingTools.LogMixin)"""
+
+ pass
class MissingComponentError(KeyError):
- """Indicates a component pointing to a non-existent glyph in the glyphset."""
+ """Indicates a component pointing to a non-existent glyph in the glyphset."""
class DecomposingPen(LoggingPen):
- """ Implements a 'addComponent' method that decomposes components
- (i.e. draws them onto self as simple contours).
- It can also be used as a mixin class (e.g. see ContourRecordingPen).
-
- You must override moveTo, lineTo, curveTo and qCurveTo. You may
- additionally override closePath, endPath and addComponent.
-
- By default a warning message is logged when a base glyph is missing;
- set the class variable ``skipMissingComponents`` to False if you want
- to raise a :class:`MissingComponentError` exception.
- """
-
- skipMissingComponents = True
-
- def __init__(self, glyphSet):
- """ Takes a single 'glyphSet' argument (dict), in which the glyphs
- that are referenced as components are looked up by their name.
- """
- super(DecomposingPen, self).__init__()
- self.glyphSet = glyphSet
-
- def addComponent(self, glyphName, transformation):
- """ Transform the points of the base glyph and draw it onto self.
- """
- from fontTools.pens.transformPen import TransformPen
- try:
- glyph = self.glyphSet[glyphName]
- except KeyError:
- if not self.skipMissingComponents:
- raise MissingComponentError(glyphName)
- self.log.warning(
- "glyph '%s' is missing from glyphSet; skipped" % glyphName)
- else:
- tPen = TransformPen(self, transformation)
- glyph.draw(tPen)
+ """Implements a 'addComponent' method that decomposes components
+ (i.e. draws them onto self as simple contours).
+ It can also be used as a mixin class (e.g. see ContourRecordingPen).
+
+ You must override moveTo, lineTo, curveTo and qCurveTo. You may
+ additionally override closePath, endPath and addComponent.
+
+ By default a warning message is logged when a base glyph is missing;
+ set the class variable ``skipMissingComponents`` to False if you want
+ to raise a :class:`MissingComponentError` exception.
+ """
+
+ skipMissingComponents = True
+
+ def __init__(self, glyphSet):
+ """Takes a single 'glyphSet' argument (dict), in which the glyphs
+ that are referenced as components are looked up by their name.
+ """
+ super(DecomposingPen, self).__init__()
+ self.glyphSet = glyphSet
+
+ def addComponent(self, glyphName, transformation):
+ """Transform the points of the base glyph and draw it onto self."""
+ from fontTools.pens.transformPen import TransformPen
+
+ try:
+ glyph = self.glyphSet[glyphName]
+ except KeyError:
+ if not self.skipMissingComponents:
+ raise MissingComponentError(glyphName)
+ self.log.warning("glyph '%s' is missing from glyphSet; skipped" % glyphName)
+ else:
+ tPen = TransformPen(self, transformation)
+ glyph.draw(tPen)
+
+ def addVarComponent(self, glyphName, transformation, location):
+ # GlyphSet decomposes for us
+ raise AttributeError
class BasePen(DecomposingPen):
- """Base class for drawing pens. You must override _moveTo, _lineTo and
- _curveToOne. You may additionally override _closePath, _endPath,
- addComponent and/or _qCurveToOne. You should not override any other
- methods.
- """
-
- def __init__(self, glyphSet=None):
- super(BasePen, self).__init__(glyphSet)
- self.__currentPoint = None
-
- # must override
-
- def _moveTo(self, pt):
- raise NotImplementedError
-
- def _lineTo(self, pt):
- raise NotImplementedError
-
- def _curveToOne(self, pt1, pt2, pt3):
- raise NotImplementedError
-
- # may override
-
- def _closePath(self):
- pass
-
- def _endPath(self):
- pass
-
- def _qCurveToOne(self, pt1, pt2):
- """This method implements the basic quadratic curve type. The
- default implementation delegates the work to the cubic curve
- function. Optionally override with a native implementation.
- """
- pt0x, pt0y = self.__currentPoint
- pt1x, pt1y = pt1
- pt2x, pt2y = pt2
- mid1x = pt0x + 0.66666666666666667 * (pt1x - pt0x)
- mid1y = pt0y + 0.66666666666666667 * (pt1y - pt0y)
- mid2x = pt2x + 0.66666666666666667 * (pt1x - pt2x)
- mid2y = pt2y + 0.66666666666666667 * (pt1y - pt2y)
- self._curveToOne((mid1x, mid1y), (mid2x, mid2y), pt2)
-
- # don't override
-
- def _getCurrentPoint(self):
- """Return the current point. This is not part of the public
- interface, yet is useful for subclasses.
- """
- return self.__currentPoint
-
- def closePath(self):
- self._closePath()
- self.__currentPoint = None
-
- def endPath(self):
- self._endPath()
- self.__currentPoint = None
-
- def moveTo(self, pt):
- self._moveTo(pt)
- self.__currentPoint = pt
-
- def lineTo(self, pt):
- self._lineTo(pt)
- self.__currentPoint = pt
-
- def curveTo(self, *points):
- n = len(points) - 1 # 'n' is the number of control points
- assert n >= 0
- if n == 2:
- # The common case, we have exactly two BCP's, so this is a standard
- # cubic bezier. Even though decomposeSuperBezierSegment() handles
- # this case just fine, we special-case it anyway since it's so
- # common.
- self._curveToOne(*points)
- self.__currentPoint = points[-1]
- elif n > 2:
- # n is the number of control points; split curve into n-1 cubic
- # bezier segments. The algorithm used here is inspired by NURB
- # splines and the TrueType "implied point" principle, and ensures
- # the smoothest possible connection between two curve segments,
- # with no disruption in the curvature. It is practical since it
- # allows one to construct multiple bezier segments with a much
- # smaller amount of points.
- _curveToOne = self._curveToOne
- for pt1, pt2, pt3 in decomposeSuperBezierSegment(points):
- _curveToOne(pt1, pt2, pt3)
- self.__currentPoint = pt3
- elif n == 1:
- self.qCurveTo(*points)
- elif n == 0:
- self.lineTo(points[0])
- else:
- raise AssertionError("can't get there from here")
-
- def qCurveTo(self, *points):
- n = len(points) - 1 # 'n' is the number of control points
- assert n >= 0
- if points[-1] is None:
- # Special case for TrueType quadratics: it is possible to
- # define a contour with NO on-curve points. BasePen supports
- # this by allowing the final argument (the expected on-curve
- # point) to be None. We simulate the feature by making the implied
- # on-curve point between the last and the first off-curve points
- # explicit.
- x, y = points[-2] # last off-curve point
- nx, ny = points[0] # first off-curve point
- impliedStartPoint = (0.5 * (x + nx), 0.5 * (y + ny))
- self.__currentPoint = impliedStartPoint
- self._moveTo(impliedStartPoint)
- points = points[:-1] + (impliedStartPoint,)
- if n > 0:
- # Split the string of points into discrete quadratic curve
- # segments. Between any two consecutive off-curve points
- # there's an implied on-curve point exactly in the middle.
- # This is where the segment splits.
- _qCurveToOne = self._qCurveToOne
- for pt1, pt2 in decomposeQuadraticSegment(points):
- _qCurveToOne(pt1, pt2)
- self.__currentPoint = pt2
- else:
- self.lineTo(points[0])
+ """Base class for drawing pens. You must override _moveTo, _lineTo and
+ _curveToOne. You may additionally override _closePath, _endPath,
+ addComponent, addVarComponent, and/or _qCurveToOne. You should not
+ override any other methods.
+ """
+
+ def __init__(self, glyphSet=None):
+ super(BasePen, self).__init__(glyphSet)
+ self.__currentPoint = None
+
+ # must override
+
+ def _moveTo(self, pt):
+ raise NotImplementedError
+
+ def _lineTo(self, pt):
+ raise NotImplementedError
+
+ def _curveToOne(self, pt1, pt2, pt3):
+ raise NotImplementedError
+
+ # may override
+
+ def _closePath(self):
+ pass
+
+ def _endPath(self):
+ pass
+
+ def _qCurveToOne(self, pt1, pt2):
+ """This method implements the basic quadratic curve type. The
+ default implementation delegates the work to the cubic curve
+ function. Optionally override with a native implementation.
+ """
+ pt0x, pt0y = self.__currentPoint
+ pt1x, pt1y = pt1
+ pt2x, pt2y = pt2
+ mid1x = pt0x + 0.66666666666666667 * (pt1x - pt0x)
+ mid1y = pt0y + 0.66666666666666667 * (pt1y - pt0y)
+ mid2x = pt2x + 0.66666666666666667 * (pt1x - pt2x)
+ mid2y = pt2y + 0.66666666666666667 * (pt1y - pt2y)
+ self._curveToOne((mid1x, mid1y), (mid2x, mid2y), pt2)
+
+ # don't override
+
+ def _getCurrentPoint(self):
+ """Return the current point. This is not part of the public
+ interface, yet is useful for subclasses.
+ """
+ return self.__currentPoint
+
+ def closePath(self):
+ self._closePath()
+ self.__currentPoint = None
+
+ def endPath(self):
+ self._endPath()
+ self.__currentPoint = None
+
+ def moveTo(self, pt):
+ self._moveTo(pt)
+ self.__currentPoint = pt
+
+ def lineTo(self, pt):
+ self._lineTo(pt)
+ self.__currentPoint = pt
+
+ def curveTo(self, *points):
+ n = len(points) - 1 # 'n' is the number of control points
+ assert n >= 0
+ if n == 2:
+ # The common case, we have exactly two BCP's, so this is a standard
+ # cubic bezier. Even though decomposeSuperBezierSegment() handles
+ # this case just fine, we special-case it anyway since it's so
+ # common.
+ self._curveToOne(*points)
+ self.__currentPoint = points[-1]
+ elif n > 2:
+ # n is the number of control points; split curve into n-1 cubic
+ # bezier segments. The algorithm used here is inspired by NURB
+ # splines and the TrueType "implied point" principle, and ensures
+ # the smoothest possible connection between two curve segments,
+ # with no disruption in the curvature. It is practical since it
+ # allows one to construct multiple bezier segments with a much
+ # smaller amount of points.
+ _curveToOne = self._curveToOne
+ for pt1, pt2, pt3 in decomposeSuperBezierSegment(points):
+ _curveToOne(pt1, pt2, pt3)
+ self.__currentPoint = pt3
+ elif n == 1:
+ self.qCurveTo(*points)
+ elif n == 0:
+ self.lineTo(points[0])
+ else:
+ raise AssertionError("can't get there from here")
+
+ def qCurveTo(self, *points):
+ n = len(points) - 1 # 'n' is the number of control points
+ assert n >= 0
+ if points[-1] is None:
+ # Special case for TrueType quadratics: it is possible to
+ # define a contour with NO on-curve points. BasePen supports
+ # this by allowing the final argument (the expected on-curve
+ # point) to be None. We simulate the feature by making the implied
+ # on-curve point between the last and the first off-curve points
+ # explicit.
+ x, y = points[-2] # last off-curve point
+ nx, ny = points[0] # first off-curve point
+ impliedStartPoint = (0.5 * (x + nx), 0.5 * (y + ny))
+ self.__currentPoint = impliedStartPoint
+ self._moveTo(impliedStartPoint)
+ points = points[:-1] + (impliedStartPoint,)
+ if n > 0:
+ # Split the string of points into discrete quadratic curve
+ # segments. Between any two consecutive off-curve points
+ # there's an implied on-curve point exactly in the middle.
+ # This is where the segment splits.
+ _qCurveToOne = self._qCurveToOne
+ for pt1, pt2 in decomposeQuadraticSegment(points):
+ _qCurveToOne(pt1, pt2)
+ self.__currentPoint = pt2
+ else:
+ self.lineTo(points[0])
def decomposeSuperBezierSegment(points):
- """Split the SuperBezier described by 'points' into a list of regular
- bezier segments. The 'points' argument must be a sequence with length
- 3 or greater, containing (x, y) coordinates. The last point is the
- destination on-curve point, the rest of the points are off-curve points.
- The start point should not be supplied.
-
- This function returns a list of (pt1, pt2, pt3) tuples, which each
- specify a regular curveto-style bezier segment.
- """
- n = len(points) - 1
- assert n > 1
- bezierSegments = []
- pt1, pt2, pt3 = points[0], None, None
- for i in range(2, n+1):
- # calculate points in between control points.
- nDivisions = min(i, 3, n-i+2)
- for j in range(1, nDivisions):
- factor = j / nDivisions
- temp1 = points[i-1]
- temp2 = points[i-2]
- temp = (temp2[0] + factor * (temp1[0] - temp2[0]),
- temp2[1] + factor * (temp1[1] - temp2[1]))
- if pt2 is None:
- pt2 = temp
- else:
- pt3 = (0.5 * (pt2[0] + temp[0]),
- 0.5 * (pt2[1] + temp[1]))
- bezierSegments.append((pt1, pt2, pt3))
- pt1, pt2, pt3 = temp, None, None
- bezierSegments.append((pt1, points[-2], points[-1]))
- return bezierSegments
+ """Split the SuperBezier described by 'points' into a list of regular
+ bezier segments. The 'points' argument must be a sequence with length
+ 3 or greater, containing (x, y) coordinates. The last point is the
+ destination on-curve point, the rest of the points are off-curve points.
+ The start point should not be supplied.
+
+ This function returns a list of (pt1, pt2, pt3) tuples, which each
+ specify a regular curveto-style bezier segment.
+ """
+ n = len(points) - 1
+ assert n > 1
+ bezierSegments = []
+ pt1, pt2, pt3 = points[0], None, None
+ for i in range(2, n + 1):
+ # calculate points in between control points.
+ nDivisions = min(i, 3, n - i + 2)
+ for j in range(1, nDivisions):
+ factor = j / nDivisions
+ temp1 = points[i - 1]
+ temp2 = points[i - 2]
+ temp = (
+ temp2[0] + factor * (temp1[0] - temp2[0]),
+ temp2[1] + factor * (temp1[1] - temp2[1]),
+ )
+ if pt2 is None:
+ pt2 = temp
+ else:
+ pt3 = (0.5 * (pt2[0] + temp[0]), 0.5 * (pt2[1] + temp[1]))
+ bezierSegments.append((pt1, pt2, pt3))
+ pt1, pt2, pt3 = temp, None, None
+ bezierSegments.append((pt1, points[-2], points[-1]))
+ return bezierSegments
def decomposeQuadraticSegment(points):
- """Split the quadratic curve segment described by 'points' into a list
- of "atomic" quadratic segments. The 'points' argument must be a sequence
- with length 2 or greater, containing (x, y) coordinates. The last point
- is the destination on-curve point, the rest of the points are off-curve
- points. The start point should not be supplied.
-
- This function returns a list of (pt1, pt2) tuples, which each specify a
- plain quadratic bezier segment.
- """
- n = len(points) - 1
- assert n > 0
- quadSegments = []
- for i in range(n - 1):
- x, y = points[i]
- nx, ny = points[i+1]
- impliedPt = (0.5 * (x + nx), 0.5 * (y + ny))
- quadSegments.append((points[i], impliedPt))
- quadSegments.append((points[-2], points[-1]))
- return quadSegments
+ """Split the quadratic curve segment described by 'points' into a list
+ of "atomic" quadratic segments. The 'points' argument must be a sequence
+ with length 2 or greater, containing (x, y) coordinates. The last point
+ is the destination on-curve point, the rest of the points are off-curve
+ points. The start point should not be supplied.
+
+ This function returns a list of (pt1, pt2) tuples, which each specify a
+ plain quadratic bezier segment.
+ """
+ n = len(points) - 1
+ assert n > 0
+ quadSegments = []
+ for i in range(n - 1):
+ x, y = points[i]
+ nx, ny = points[i + 1]
+ impliedPt = (0.5 * (x + nx), 0.5 * (y + ny))
+ quadSegments.append((points[i], impliedPt))
+ quadSegments.append((points[-2], points[-1]))
+ return quadSegments
class _TestPen(BasePen):
- """Test class that prints PostScript to stdout."""
- def _moveTo(self, pt):
- print("%s %s moveto" % (pt[0], pt[1]))
- def _lineTo(self, pt):
- print("%s %s lineto" % (pt[0], pt[1]))
- def _curveToOne(self, bcp1, bcp2, pt):
- print("%s %s %s %s %s %s curveto" % (bcp1[0], bcp1[1],
- bcp2[0], bcp2[1], pt[0], pt[1]))
- def _closePath(self):
- print("closepath")
+ """Test class that prints PostScript to stdout."""
+
+ def _moveTo(self, pt):
+ print("%s %s moveto" % (pt[0], pt[1]))
+
+ def _lineTo(self, pt):
+ print("%s %s lineto" % (pt[0], pt[1]))
+
+ def _curveToOne(self, bcp1, bcp2, pt):
+ print(
+ "%s %s %s %s %s %s curveto"
+ % (bcp1[0], bcp1[1], bcp2[0], bcp2[1], pt[0], pt[1])
+ )
+
+ def _closePath(self):
+ print("closepath")
if __name__ == "__main__":
- pen = _TestPen(None)
- pen.moveTo((0, 0))
- pen.lineTo((0, 100))
- pen.curveTo((50, 75), (60, 50), (50, 25), (0, 0))
- pen.closePath()
-
- pen = _TestPen(None)
- # testing the "no on-curve point" scenario
- pen.qCurveTo((0, 0), (0, 100), (100, 100), (100, 0), None)
- pen.closePath()
+ pen = _TestPen(None)
+ pen.moveTo((0, 0))
+ pen.lineTo((0, 100))
+ pen.curveTo((50, 75), (60, 50), (50, 25), (0, 0))
+ pen.closePath()
+
+ pen = _TestPen(None)
+ # testing the "no on-curve point" scenario
+ pen.qCurveTo((0, 0), (0, 100), (100, 100), (100, 0), None)
+ pen.closePath()