aboutsummaryrefslogtreecommitdiff
path: root/Tests/pens/cu2quPen_test.py
diff options
context:
space:
mode:
Diffstat (limited to 'Tests/pens/cu2quPen_test.py')
-rw-r--r--Tests/pens/cu2quPen_test.py386
1 files changed, 210 insertions, 176 deletions
diff --git a/Tests/pens/cu2quPen_test.py b/Tests/pens/cu2quPen_test.py
index 4ce5b512..779254c3 100644
--- a/Tests/pens/cu2quPen_test.py
+++ b/Tests/pens/cu2quPen_test.py
@@ -15,13 +15,19 @@
import sys
import unittest
-from fontTools.pens.cu2quPen import Cu2QuPen, Cu2QuPointPen
-from . import CUBIC_GLYPHS, QUAD_GLYPHS
-from .utils import DummyGlyph, DummyPointGlyph
-from .utils import DummyPen, DummyPointPen
+from fontTools.pens.cu2quPen import Cu2QuPen, Cu2QuPointPen, Cu2QuMultiPen
+from fontTools.pens.recordingPen import RecordingPen, RecordingPointPen
from fontTools.misc.loggingTools import CapturingLogHandler
from textwrap import dedent
import logging
+import pytest
+
+try:
+ from .utils import CUBIC_GLYPHS, QUAD_GLYPHS
+ from .utils import DummyGlyph, DummyPointGlyph
+ from .utils import DummyPen, DummyPointPen
+except ImportError as e:
+ pytest.skip(str(e), allow_module_level=True)
MAX_ERR = 1.0
@@ -36,10 +42,12 @@ class _TestPenMixin(object):
def diff(self, expected, actual):
import difflib
+
expected = str(self.Glyph(expected)).splitlines(True)
actual = str(self.Glyph(actual)).splitlines(True)
diff = difflib.unified_diff(
- expected, actual, fromfile='expected', tofile='actual')
+ expected, actual, fromfile="expected", tofile="actual"
+ )
return "".join(diff)
def convert_glyph(self, glyph, **kwargs):
@@ -58,28 +66,27 @@ class _TestPenMixin(object):
self.fail("converted glyph is different from expected")
def test_convert_simple_glyph(self):
- self.expect_glyph(CUBIC_GLYPHS['a'], QUAD_GLYPHS['a'])
- self.expect_glyph(CUBIC_GLYPHS['A'], QUAD_GLYPHS['A'])
+ self.expect_glyph(CUBIC_GLYPHS["a"], QUAD_GLYPHS["a"])
+ self.expect_glyph(CUBIC_GLYPHS["A"], QUAD_GLYPHS["A"])
def test_convert_composite_glyph(self):
- source = CUBIC_GLYPHS['Aacute']
+ source = CUBIC_GLYPHS["Aacute"]
converted = self.convert_glyph(source)
# components don't change after quadratic conversion
self.assertEqual(converted, source)
def test_convert_mixed_glyph(self):
# this contains a mix of contours and components
- self.expect_glyph(CUBIC_GLYPHS['Eacute'], QUAD_GLYPHS['Eacute'])
+ self.expect_glyph(CUBIC_GLYPHS["Eacute"], QUAD_GLYPHS["Eacute"])
def test_reverse_direction(self):
- for name in ('a', 'A', 'Eacute'):
+ for name in ("a", "A", "Eacute"):
source = CUBIC_GLYPHS[name]
normal_glyph = self.convert_glyph(source)
reversed_glyph = self.convert_glyph(source, reverse_direction=True)
# the number of commands is the same, just their order is iverted
- self.assertTrue(
- len(normal_glyph.outline), len(reversed_glyph.outline))
+ self.assertTrue(len(normal_glyph.outline), len(reversed_glyph.outline))
self.assertNotEqual(normal_glyph, reversed_glyph)
def test_stats(self):
@@ -89,8 +96,8 @@ class _TestPenMixin(object):
self.convert_glyph(source, stats=stats)
self.assertTrue(stats)
- self.assertTrue('1' in stats)
- self.assertEqual(type(stats['1']), int)
+ self.assertTrue("1" in stats)
+ self.assertEqual(type(stats["1"]), int)
def test_addComponent(self):
pen = self.Pen()
@@ -98,65 +105,22 @@ class _TestPenMixin(object):
quadpen.addComponent("a", (1, 2, 3, 4, 5.0, 6.0))
# components are passed through without changes
- self.assertEqual(str(pen).splitlines(), [
- "pen.addComponent('a', (1, 2, 3, 4, 5.0, 6.0))",
- ])
+ self.assertEqual(
+ str(pen).splitlines(),
+ [
+ "pen.addComponent('a', (1, 2, 3, 4, 5.0, 6.0))",
+ ],
+ )
class TestCu2QuPen(unittest.TestCase, _TestPenMixin):
-
def __init__(self, *args, **kwargs):
super(TestCu2QuPen, self).__init__(*args, **kwargs)
self.Glyph = DummyGlyph
self.Pen = DummyPen
self.Cu2QuPen = Cu2QuPen
- self.pen_getter_name = 'getPen'
- 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()
+ self.pen_getter_name = "getPen"
+ self.draw_method_name = "draw"
def test_qCurveTo_1_point(self):
pen = DummyPen()
@@ -164,10 +128,13 @@ class TestCu2QuPen(unittest.TestCase, _TestPenMixin):
quadpen.moveTo((0, 0))
quadpen.qCurveTo((1, 1))
- self.assertEqual(str(pen).splitlines(), [
- "pen.moveTo((0, 0))",
- "pen.lineTo((1, 1))",
- ])
+ self.assertEqual(
+ str(pen).splitlines(),
+ [
+ "pen.moveTo((0, 0))",
+ "pen.qCurveTo((1, 1))",
+ ],
+ )
def test_qCurveTo_more_than_1_point(self):
pen = DummyPen()
@@ -175,18 +142,13 @@ class TestCu2QuPen(unittest.TestCase, _TestPenMixin):
quadpen.moveTo((0, 0))
quadpen.qCurveTo((1, 1), (2, 2))
- self.assertEqual(str(pen).splitlines(), [
- "pen.moveTo((0, 0))",
- "pen.qCurveTo((1, 1), (2, 2))",
- ])
-
- 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()
+ self.assertEqual(
+ str(pen).splitlines(),
+ [
+ "pen.moveTo((0, 0))",
+ "pen.qCurveTo((1, 1), (2, 2))",
+ ],
+ )
def test_curveTo_1_point(self):
pen = DummyPen()
@@ -194,10 +156,13 @@ class TestCu2QuPen(unittest.TestCase, _TestPenMixin):
quadpen.moveTo((0, 0))
quadpen.curveTo((1, 1))
- self.assertEqual(str(pen).splitlines(), [
- "pen.moveTo((0, 0))",
- "pen.lineTo((1, 1))",
- ])
+ self.assertEqual(
+ str(pen).splitlines(),
+ [
+ "pen.moveTo((0, 0))",
+ "pen.qCurveTo((1, 1))",
+ ],
+ )
def test_curveTo_2_points(self):
pen = DummyPen()
@@ -205,10 +170,13 @@ class TestCu2QuPen(unittest.TestCase, _TestPenMixin):
quadpen.moveTo((0, 0))
quadpen.curveTo((1, 1), (2, 2))
- self.assertEqual(str(pen).splitlines(), [
- "pen.moveTo((0, 0))",
- "pen.qCurveTo((1, 1), (2, 2))",
- ])
+ self.assertEqual(
+ str(pen).splitlines(),
+ [
+ "pen.moveTo((0, 0))",
+ "pen.qCurveTo((1, 1), (2, 2))",
+ ],
+ )
def test_curveTo_3_points(self):
pen = DummyPen()
@@ -216,10 +184,13 @@ class TestCu2QuPen(unittest.TestCase, _TestPenMixin):
quadpen.moveTo((0, 0))
quadpen.curveTo((1, 1), (2, 2), (3, 3))
- self.assertEqual(str(pen).splitlines(), [
- "pen.moveTo((0, 0))",
- "pen.qCurveTo((0.75, 0.75), (2.25, 2.25), (3, 3))",
- ])
+ self.assertEqual(
+ str(pen).splitlines(),
+ [
+ "pen.moveTo((0, 0))",
+ "pen.qCurveTo((0.75, 0.75), (2.25, 2.25), (3, 3))",
+ ],
+ )
def test_curveTo_more_than_3_points(self):
# a 'SuperBezier' as described in fontTools.basePen.AbstractPen
@@ -228,71 +199,24 @@ class TestCu2QuPen(unittest.TestCase, _TestPenMixin):
quadpen.moveTo((0, 0))
quadpen.curveTo((1, 1), (2, 2), (3, 3), (4, 4))
- self.assertEqual(str(pen).splitlines(), [
- "pen.moveTo((0, 0))",
- "pen.qCurveTo((0.75, 0.75), (1.625, 1.625), (2, 2))",
- "pen.qCurveTo((2.375, 2.375), (3.25, 3.25), (4, 4))",
- ])
-
- def test_addComponent(self):
- pen = DummyPen()
- quadpen = Cu2QuPen(pen, MAX_ERR)
- quadpen.addComponent("a", (1, 2, 3, 4, 5.0, 6.0))
-
- # components are passed through without changes
- self.assertEqual(str(pen).splitlines(), [
- "pen.addComponent('a', (1, 2, 3, 4, 5.0, 6.0))",
- ])
-
- def test_ignore_single_points(self):
- pen = DummyPen()
- try:
- logging.captureWarnings(True)
- with CapturingLogHandler("py.warnings", level="WARNING") as log:
- quadpen = Cu2QuPen(pen, MAX_ERR, ignore_single_points=True)
- finally:
- logging.captureWarnings(False)
- quadpen.moveTo((0, 0))
- quadpen.endPath()
- quadpen.moveTo((1, 1))
- quadpen.closePath()
-
- self.assertGreaterEqual(len(log.records), 1)
- if sys.version_info < (3, 11):
- self.assertIn("ignore_single_points is deprecated",
- log.records[0].args[0])
- else:
- self.assertIn("ignore_single_points is deprecated",
- log.records[0].msg)
-
- # single-point contours were ignored, so the pen commands are empty
- self.assertFalse(pen.commands)
-
- # redraw without ignoring single points
- quadpen.ignore_single_points = False
- quadpen.moveTo((0, 0))
- quadpen.endPath()
- quadpen.moveTo((1, 1))
- quadpen.closePath()
-
- self.assertTrue(pen.commands)
- self.assertEqual(str(pen).splitlines(), [
- "pen.moveTo((0, 0))",
- "pen.endPath()",
- "pen.moveTo((1, 1))",
- "pen.closePath()"
- ])
+ self.assertEqual(
+ str(pen).splitlines(),
+ [
+ "pen.moveTo((0, 0))",
+ "pen.qCurveTo((0.75, 0.75), (1.625, 1.625), (2, 2))",
+ "pen.qCurveTo((2.375, 2.375), (3.25, 3.25), (4, 4))",
+ ],
+ )
class TestCu2QuPointPen(unittest.TestCase, _TestPenMixin):
-
def __init__(self, *args, **kwargs):
super(TestCu2QuPointPen, self).__init__(*args, **kwargs)
self.Glyph = DummyPointGlyph
self.Pen = DummyPointPen
self.Cu2QuPen = Cu2QuPointPen
- self.pen_getter_name = 'getPointPen'
- self.draw_method_name = 'drawPoints'
+ self.pen_getter_name = "getPointPen"
+ self.draw_method_name = "drawPoints"
def test_super_bezier_curve(self):
pen = DummyPointPen()
@@ -303,10 +227,13 @@ class TestCu2QuPointPen(unittest.TestCase, _TestPenMixin):
quadpen.addPoint((2, 2))
quadpen.addPoint((3, 3))
quadpen.addPoint(
- (4, 4), segmentType="curve", smooth=False, name="up", selected=1)
+ (4, 4), segmentType="curve", smooth=False, name="up", selected=1
+ )
quadpen.endPath()
- self.assertEqual(str(pen).splitlines(), """\
+ self.assertEqual(
+ str(pen).splitlines(),
+ """\
pen.beginPath()
pen.addPoint((0, 0), name=None, segmentType='move', smooth=False)
pen.addPoint((0.75, 0.75), name=None, segmentType=None, smooth=False)
@@ -315,7 +242,8 @@ pen.addPoint((2, 2), name=None, segmentType='qcurve', smooth=True)
pen.addPoint((2.375, 2.375), name=None, segmentType=None, smooth=False)
pen.addPoint((3.25, 3.25), name=None, segmentType=None, smooth=False)
pen.addPoint((4, 4), name='up', segmentType='qcurve', selected=1, smooth=False)
-pen.endPath()""".splitlines())
+pen.endPath()""".splitlines(),
+ )
def test__flushContour_restore_starting_point(self):
pen = DummyPointPen()
@@ -323,24 +251,34 @@ pen.endPath()""".splitlines())
# collect the output of _flushContour before it's sent to _drawPoints
new_segments = []
+
def _drawPoints(segments):
new_segments.extend(segments)
Cu2QuPointPen._drawPoints(quadpen, segments)
+
quadpen._drawPoints = _drawPoints
# a closed path (ie. no "move" segmentType)
- quadpen._flushContour([
- ("curve", [
- ((2, 2), False, None, {}),
- ((1, 1), False, None, {}),
- ((0, 0), False, None, {}),
- ]),
- ("curve", [
- ((1, 1), False, None, {}),
- ((2, 2), False, None, {}),
- ((3, 3), False, None, {}),
- ]),
- ])
+ quadpen._flushContour(
+ [
+ (
+ "curve",
+ [
+ ((2, 2), False, None, {}),
+ ((1, 1), False, None, {}),
+ ((0, 0), False, None, {}),
+ ],
+ ),
+ (
+ "curve",
+ [
+ ((1, 1), False, None, {}),
+ ((2, 2), False, None, {}),
+ ((3, 3), False, None, {}),
+ ],
+ ),
+ ]
+ )
# the original starting point is restored: the last segment has become
# the first
@@ -349,16 +287,24 @@ pen.endPath()""".splitlines())
new_segments = []
# an open path (ie. starting with "move")
- quadpen._flushContour([
- ("move", [
- ((0, 0), False, None, {}),
- ]),
- ("curve", [
- ((1, 1), False, None, {}),
- ((2, 2), False, None, {}),
- ((3, 3), False, None, {}),
- ]),
- ])
+ quadpen._flushContour(
+ [
+ (
+ "move",
+ [
+ ((0, 0), False, None, {}),
+ ],
+ ),
+ (
+ "curve",
+ [
+ ((1, 1), False, None, {}),
+ ((2, 2), False, None, {}),
+ ((3, 3), False, None, {}),
+ ],
+ ),
+ ]
+ )
# the segment order stays the same before and after _flushContour
self.assertEqual(new_segments[0][1][-1][0], (0, 0))
@@ -387,9 +333,97 @@ pen.endPath()""".splitlines())
pen.addPoint((2, 2), name=None, segmentType=None, smooth=False)
pen.addPoint((3, 3), name=None, segmentType=None, smooth=False)
pen.endPath()"""
- )
+ ),
)
+class TestCu2QuMultiPen(unittest.TestCase):
+ def test_multi_pen(self):
+ pens = [RecordingPen(), RecordingPen()]
+ pen = Cu2QuMultiPen(pens, 0.1)
+ pen.moveTo([((0, 0),), ((0, 0),)])
+ pen.lineTo([((0, 1),), ((0, 1),)])
+ pen.qCurveTo([((0, 2),), ((0, 2),)])
+ pen.qCurveTo([((0, 3), (1, 3)), ((0, 3), (1, 4))])
+ pen.curveTo([((2, 3), (0, 3), (0, 0)), ((1.1, 4), (0, 4), (0, 0))])
+ pen.closePath()
+
+ assert len(pens[0].value) == 6
+ assert len(pens[1].value) == 6
+
+ for op0, op1 in zip(pens[0].value, pens[1].value):
+ assert op0[0] == op0[0]
+ assert op0[0] != "curveTo"
+
+
+class TestAllQuadraticFalse(unittest.TestCase):
+ def test_segment_pen_cubic(self):
+ rpen = RecordingPen()
+ pen = Cu2QuPen(rpen, 0.1, all_quadratic=False)
+
+ pen.moveTo((0, 0))
+ pen.curveTo((0, 1), (2, 1), (2, 0))
+ pen.closePath()
+
+ assert rpen.value == [
+ ("moveTo", ((0, 0),)),
+ ("curveTo", ((0, 1), (2, 1), (2, 0))),
+ ("closePath", ()),
+ ]
+
+ def test_segment_pen_quadratic(self):
+ rpen = RecordingPen()
+ pen = Cu2QuPen(rpen, 0.1, all_quadratic=False)
+
+ pen.moveTo((0, 0))
+ pen.curveTo((2, 2), (4, 2), (6, 0))
+ pen.closePath()
+
+ assert rpen.value == [
+ ("moveTo", ((0, 0),)),
+ ("qCurveTo", ((3, 3), (6, 0))),
+ ("closePath", ()),
+ ]
+
+ def test_point_pen_cubic(self):
+ rpen = RecordingPointPen()
+ pen = Cu2QuPointPen(rpen, 0.1, all_quadratic=False)
+
+ pen.beginPath()
+ pen.addPoint((0, 0), "move")
+ pen.addPoint((0, 1))
+ pen.addPoint((2, 1))
+ pen.addPoint((2, 0), "curve")
+ pen.endPath()
+
+ assert rpen.value == [
+ ("beginPath", (), {}),
+ ("addPoint", ((0, 0), "move", False, None), {}),
+ ("addPoint", ((0, 1), None, False, None), {}),
+ ("addPoint", ((2, 1), None, False, None), {}),
+ ("addPoint", ((2, 0), "curve", False, None), {}),
+ ("endPath", (), {}),
+ ]
+
+ def test_point_pen_quadratic(self):
+ rpen = RecordingPointPen()
+ pen = Cu2QuPointPen(rpen, 0.1, all_quadratic=False)
+
+ pen.beginPath()
+ pen.addPoint((0, 0), "move")
+ pen.addPoint((2, 2))
+ pen.addPoint((4, 2))
+ pen.addPoint((6, 0), "curve")
+ pen.endPath()
+
+ assert rpen.value == [
+ ("beginPath", (), {}),
+ ("addPoint", ((0, 0), "move", False, None), {}),
+ ("addPoint", ((3, 3), None, False, None), {}),
+ ("addPoint", ((6, 0), "qcurve", False, None), {}),
+ ("endPath", (), {}),
+ ]
+
+
if __name__ == "__main__":
unittest.main()