[reverseContourPen] Add outputImpliedClosingLine
Fixes https://github.com/fonttools/fonttools/issues/2914
This commit is contained in:
parent
6aca5be9b7
commit
ddbbef2257
@ -14,11 +14,15 @@ class ReverseContourPen(ContourFilterPen):
|
|||||||
the first point.
|
the first point.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def __init__(self, outPen, outputImpliedClosingLine=False):
|
||||||
|
super().__init__(outPen)
|
||||||
|
self.outputImpliedClosingLine = outputImpliedClosingLine
|
||||||
|
|
||||||
def filterContour(self, contour):
|
def filterContour(self, contour):
|
||||||
return reversedContour(contour)
|
return reversedContour(contour, self.outputImpliedClosingLine)
|
||||||
|
|
||||||
|
|
||||||
def reversedContour(contour):
|
def reversedContour(contour, outputImpliedClosingLine=False):
|
||||||
""" Generator that takes a list of pen's (operator, operands) tuples,
|
""" Generator that takes a list of pen's (operator, operands) tuples,
|
||||||
and yields them with the winding direction reversed.
|
and yields them with the winding direction reversed.
|
||||||
"""
|
"""
|
||||||
@ -60,7 +64,7 @@ def reversedContour(contour):
|
|||||||
if closed:
|
if closed:
|
||||||
# for closed paths, we keep the starting point
|
# for closed paths, we keep the starting point
|
||||||
yield firstType, firstPts
|
yield firstType, firstPts
|
||||||
if firstOnCurve != lastOnCurve:
|
if outputImpliedClosingLine or firstOnCurve != lastOnCurve:
|
||||||
# emit an implied line between the last and first points
|
# emit an implied line between the last and first points
|
||||||
yield "lineTo", (lastOnCurve,)
|
yield "lineTo", (lastOnCurve,)
|
||||||
contour[-1] = (lastType,
|
contour[-1] = (lastType,
|
||||||
@ -71,15 +75,17 @@ def reversedContour(contour):
|
|||||||
else:
|
else:
|
||||||
# contour has only two points, the second and last are the same
|
# contour has only two points, the second and last are the same
|
||||||
secondType, secondPts = lastType, lastPts
|
secondType, secondPts = lastType, lastPts
|
||||||
# if a lineTo follows the initial moveTo, after reversing it
|
|
||||||
# will be implied by the closePath, so we don't emit one;
|
if not outputImpliedClosingLine:
|
||||||
# unless the lineTo and moveTo overlap, in which case we keep the
|
# if a lineTo follows the initial moveTo, after reversing it
|
||||||
# duplicate points
|
# will be implied by the closePath, so we don't emit one;
|
||||||
if secondType == "lineTo" and firstPts != secondPts:
|
# unless the lineTo and moveTo overlap, in which case we keep the
|
||||||
del contour[0]
|
# duplicate points
|
||||||
if contour:
|
if secondType == "lineTo" and firstPts != secondPts:
|
||||||
contour[-1] = (lastType,
|
del contour[0]
|
||||||
tuple(lastPts[:-1]) + secondPts)
|
if contour:
|
||||||
|
contour[-1] = (lastType,
|
||||||
|
tuple(lastPts[:-1]) + secondPts)
|
||||||
else:
|
else:
|
||||||
# for open paths, the last point will become the first
|
# for open paths, the last point will become the first
|
||||||
yield firstType, (lastOnCurve,)
|
yield firstType, (lastOnCurve,)
|
||||||
|
@ -310,6 +310,24 @@ def test_reverse_pen(contour, expected):
|
|||||||
getattr(revpen, operator)(*operands)
|
getattr(revpen, operator)(*operands)
|
||||||
assert recpen.value == expected
|
assert recpen.value == expected
|
||||||
|
|
||||||
|
def test_reverse_pen_outputImpliedClosingLine():
|
||||||
|
recpen = RecordingPen()
|
||||||
|
revpen = ReverseContourPen(recpen)
|
||||||
|
revpen.moveTo((0, 0))
|
||||||
|
revpen.lineTo((10, 0))
|
||||||
|
revpen.lineTo((0, 10))
|
||||||
|
revpen.lineTo((0, 0))
|
||||||
|
revpen.closePath()
|
||||||
|
assert len(recpen.value) == 4
|
||||||
|
|
||||||
|
recpen = RecordingPen()
|
||||||
|
revpen = ReverseContourPen(recpen, outputImpliedClosingLine=True)
|
||||||
|
revpen.moveTo((0, 0))
|
||||||
|
revpen.lineTo((10, 0))
|
||||||
|
revpen.lineTo((0, 10))
|
||||||
|
revpen.lineTo((0, 0))
|
||||||
|
revpen.closePath()
|
||||||
|
assert len(recpen.value) == 6
|
||||||
|
|
||||||
@pytest.mark.parametrize("contour, expected", TEST_DATA)
|
@pytest.mark.parametrize("contour, expected", TEST_DATA)
|
||||||
def test_reverse_point_pen(contour, expected):
|
def test_reverse_point_pen(contour, expected):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user