[Cu2QuPen] Use FilterPen

This commit is contained in:
Behdad Esfahbod 2023-02-17 11:54:35 -07:00
parent e18fca76ef
commit ac94ee9949
2 changed files with 8 additions and 113 deletions

View File

@ -13,13 +13,14 @@
# limitations under the License. # limitations under the License.
from fontTools.cu2qu import curve_to_quadratic, curves_to_quadratic from fontTools.cu2qu import curve_to_quadratic, curves_to_quadratic
from fontTools.pens.basePen import AbstractPen, decomposeSuperBezierSegment from fontTools.pens.basePen import decomposeSuperBezierSegment
from fontTools.pens.filterPen import FilterPen
from fontTools.pens.reverseContourPen import ReverseContourPen from fontTools.pens.reverseContourPen import ReverseContourPen
from fontTools.pens.pointPen import BasePointToSegmentPen from fontTools.pens.pointPen import BasePointToSegmentPen
from fontTools.pens.pointPen import ReverseContourPointPen from fontTools.pens.pointPen import ReverseContourPointPen
class Cu2QuPen(AbstractPen): class Cu2QuPen(FilterPen):
"""A filter pen to convert cubic bezier curves to quadratic b-splines """A filter pen to convert cubic bezier curves to quadratic b-splines
using the FontTools SegmentPen protocol. using the FontTools SegmentPen protocol.
@ -41,42 +42,10 @@ class Cu2QuPen(AbstractPen):
stats=None, stats=None,
): ):
if reverse_direction: if reverse_direction:
self.pen = ReverseContourPen(other_pen) other_pen = ReverseContourPen(other_pen)
else: super().__init__(other_pen)
self.pen = other_pen
self.max_err = max_err self.max_err = max_err
self.stats = stats self.stats = stats
self.current_pt = None
def _check_contour_is_open(self):
if self.current_pt is None:
raise AssertionError("moveTo is required")
def _check_contour_is_closed(self):
if self.current_pt is not None:
raise AssertionError("closePath or endPath is required")
def moveTo(self, pt):
self._check_contour_is_closed()
self.current_pt = pt
self.pen.moveTo(pt)
self.current_pt = pt
def lineTo(self, pt):
self._check_contour_is_open()
self.pen.lineTo(pt)
self.current_pt = pt
def qCurveTo(self, *points):
self._check_contour_is_open()
n = len(points)
if n == 1:
self.lineTo(points[0])
elif n > 1:
self.pen.qCurveTo(*points)
self.current_pt = points[-1]
else:
raise AssertionError("illegal qcurve segment point count: %d" % n)
def _curve_to_quadratic(self, pt1, pt2, pt3): def _curve_to_quadratic(self, pt1, pt2, pt3):
curve = (self.current_pt, pt1, pt2, pt3) curve = (self.current_pt, pt1, pt2, pt3)
@ -87,7 +56,6 @@ class Cu2QuPen(AbstractPen):
self.qCurveTo(*quadratic[1:]) self.qCurveTo(*quadratic[1:])
def curveTo(self, *points): def curveTo(self, *points):
self._check_contour_is_open()
n = len(points) n = len(points)
if n == 3: if n == 3:
# this is the most common case, so we special-case it # this is the most common case, so we special-case it
@ -95,26 +63,8 @@ class Cu2QuPen(AbstractPen):
elif n > 3: elif n > 3:
for segment in decomposeSuperBezierSegment(points): for segment in decomposeSuperBezierSegment(points):
self._curve_to_quadratic(*segment) self._curve_to_quadratic(*segment)
elif n == 2:
self.qCurveTo(*points)
elif n == 1:
self.lineTo(points[0])
else: else:
raise AssertionError("illegal curve segment point count: %d" % n) self.qCurveTo(*points)
def closePath(self):
self._check_contour_is_open()
self.pen.closePath()
self.current_pt = None
def endPath(self):
self._check_contour_is_open()
self.pen.endPath()
self.current_pt = None
def addComponent(self, glyphName, transformation):
self._check_contour_is_closed()
self.pen.addComponent(glyphName, transformation)
class Cu2QuPointPen(BasePointToSegmentPen): class Cu2QuPointPen(BasePointToSegmentPen):

View File

@ -117,52 +117,6 @@ class TestCu2QuPen(unittest.TestCase, _TestPenMixin):
self.pen_getter_name = "getPen" self.pen_getter_name = "getPen"
self.draw_method_name = "draw" self.draw_method_name = "draw"
def test__check_contour_is_open(self):
msg = "moveTo is required"
quadpen = Cu2QuPen(DummyPen(), MAX_ERR)
with self.assertRaisesRegex(AssertionError, msg):
quadpen.lineTo((0, 0))
with self.assertRaisesRegex(AssertionError, msg):
quadpen.qCurveTo((0, 0), (1, 1))
with self.assertRaisesRegex(AssertionError, msg):
quadpen.curveTo((0, 0), (1, 1), (2, 2))
with self.assertRaisesRegex(AssertionError, msg):
quadpen.closePath()
with self.assertRaisesRegex(AssertionError, msg):
quadpen.endPath()
quadpen.moveTo((0, 0)) # now it works
quadpen.lineTo((1, 1))
quadpen.qCurveTo((2, 2), (3, 3))
quadpen.curveTo((4, 4), (5, 5), (6, 6))
quadpen.closePath()
def test__check_contour_closed(self):
msg = "closePath or endPath is required"
quadpen = Cu2QuPen(DummyPen(), MAX_ERR)
quadpen.moveTo((0, 0))
with self.assertRaisesRegex(AssertionError, msg):
quadpen.moveTo((1, 1))
with self.assertRaisesRegex(AssertionError, msg):
quadpen.addComponent("a", (1, 0, 0, 1, 0, 0))
# it works if contour is closed
quadpen.closePath()
quadpen.moveTo((1, 1))
quadpen.endPath()
quadpen.addComponent("a", (1, 0, 0, 1, 0, 0))
def test_qCurveTo_no_points(self):
quadpen = Cu2QuPen(DummyPen(), MAX_ERR)
quadpen.moveTo((0, 0))
with self.assertRaisesRegex(
AssertionError, "illegal qcurve segment point count: 0"
):
quadpen.qCurveTo()
def test_qCurveTo_1_point(self): def test_qCurveTo_1_point(self):
pen = DummyPen() pen = DummyPen()
quadpen = Cu2QuPen(pen, MAX_ERR) quadpen = Cu2QuPen(pen, MAX_ERR)
@ -173,7 +127,7 @@ class TestCu2QuPen(unittest.TestCase, _TestPenMixin):
str(pen).splitlines(), str(pen).splitlines(),
[ [
"pen.moveTo((0, 0))", "pen.moveTo((0, 0))",
"pen.lineTo((1, 1))", "pen.qCurveTo((1, 1))",
], ],
) )
@ -191,15 +145,6 @@ class TestCu2QuPen(unittest.TestCase, _TestPenMixin):
], ],
) )
def test_curveTo_no_points(self):
quadpen = Cu2QuPen(DummyPen(), MAX_ERR)
quadpen.moveTo((0, 0))
with self.assertRaisesRegex(
AssertionError, "illegal curve segment point count: 0"
):
quadpen.curveTo()
def test_curveTo_1_point(self): def test_curveTo_1_point(self):
pen = DummyPen() pen = DummyPen()
quadpen = Cu2QuPen(pen, MAX_ERR) quadpen = Cu2QuPen(pen, MAX_ERR)
@ -210,7 +155,7 @@ class TestCu2QuPen(unittest.TestCase, _TestPenMixin):
str(pen).splitlines(), str(pen).splitlines(),
[ [
"pen.moveTo((0, 0))", "pen.moveTo((0, 0))",
"pen.lineTo((1, 1))", "pen.qCurveTo((1, 1))",
], ],
) )