2015-11-04 18:01:34 -08:00
|
|
|
import os
|
2021-05-17 14:09:36 +02:00
|
|
|
import pytest
|
2018-03-01 20:10:32 +00:00
|
|
|
import struct
|
2015-11-04 18:01:34 -08:00
|
|
|
|
|
|
|
from fontTools import ttLib
|
2021-05-17 14:09:36 +02:00
|
|
|
from fontTools.pens.basePen import PenError
|
2023-02-22 08:41:14 -07:00
|
|
|
from fontTools.pens.recordingPen import RecordingPen, RecordingPointPen
|
2021-05-17 14:09:36 +02:00
|
|
|
from fontTools.pens.ttGlyphPen import TTGlyphPen, TTGlyphPointPen, MAX_F2DOT14
|
2015-11-04 18:01:34 -08:00
|
|
|
|
|
|
|
|
2021-05-17 14:09:36 +02:00
|
|
|
class TTGlyphPenTestBase:
|
2015-11-05 14:01:52 -08:00
|
|
|
def runEndToEnd(self, filename):
|
|
|
|
font = ttLib.TTFont()
|
2015-11-04 18:01:34 -08:00
|
|
|
ttx_path = os.path.join(
|
|
|
|
os.path.abspath(os.path.dirname(os.path.realpath(__file__))),
|
2021-05-17 14:09:36 +02:00
|
|
|
"..",
|
|
|
|
"ttLib",
|
|
|
|
"data",
|
|
|
|
filename,
|
|
|
|
)
|
2016-02-01 13:39:39 +00:00
|
|
|
font.importXML(ttx_path)
|
2015-11-04 18:01:34 -08:00
|
|
|
|
2015-11-05 14:01:52 -08:00
|
|
|
glyphSet = font.getGlyphSet()
|
2021-05-17 14:09:36 +02:00
|
|
|
glyfTable = font["glyf"]
|
2022-08-29 19:55:27 +02:00
|
|
|
pen = self.penClass(glyphSet)
|
2015-11-04 18:01:34 -08:00
|
|
|
|
2015-11-05 14:01:52 -08:00
|
|
|
for name in font.getGlyphOrder():
|
2022-08-29 19:55:27 +02:00
|
|
|
getattr(glyphSet[name], self.drawMethod)(pen)
|
2022-08-29 19:41:30 +02:00
|
|
|
oldGlyph = glyfTable[name]
|
2015-11-05 14:01:52 -08:00
|
|
|
newGlyph = pen.glyph()
|
|
|
|
|
2021-05-17 14:09:36 +02:00
|
|
|
if hasattr(oldGlyph, "program"):
|
2015-11-04 18:01:34 -08:00
|
|
|
newGlyph.program = oldGlyph.program
|
2015-11-05 14:01:52 -08:00
|
|
|
|
2021-05-17 14:09:36 +02:00
|
|
|
assert oldGlyph.compile(glyfTable) == newGlyph.compile(glyfTable)
|
2015-11-04 18:01:34 -08:00
|
|
|
|
2015-11-05 14:01:52 -08:00
|
|
|
def test_e2e_linesAndSimpleComponents(self):
|
2021-05-17 14:09:36 +02:00
|
|
|
self.runEndToEnd("TestTTF-Regular.ttx")
|
2015-11-05 14:01:52 -08:00
|
|
|
|
|
|
|
def test_e2e_curvesAndComponentTransforms(self):
|
2021-05-17 14:09:36 +02:00
|
|
|
self.runEndToEnd("TestTTFComplex-Regular.ttx")
|
|
|
|
|
|
|
|
|
|
|
|
class TTGlyphPenTest(TTGlyphPenTestBase):
|
|
|
|
penClass = TTGlyphPen
|
|
|
|
drawMethod = "draw"
|
2015-11-05 14:01:52 -08:00
|
|
|
|
2015-11-05 15:15:33 -08:00
|
|
|
def test_moveTo_errorWithinContour(self):
|
|
|
|
pen = TTGlyphPen(None)
|
|
|
|
pen.moveTo((0, 0))
|
2021-05-17 14:09:36 +02:00
|
|
|
with pytest.raises(PenError):
|
2015-11-05 15:15:33 -08:00
|
|
|
pen.moveTo((1, 0))
|
|
|
|
|
|
|
|
def test_closePath_ignoresAnchors(self):
|
|
|
|
pen = TTGlyphPen(None)
|
|
|
|
pen.moveTo((0, 0))
|
|
|
|
pen.closePath()
|
2021-05-17 14:09:36 +02:00
|
|
|
assert not pen.points
|
|
|
|
assert not pen.types
|
|
|
|
assert not pen.endPts
|
2015-11-05 15:15:33 -08:00
|
|
|
|
|
|
|
def test_endPath_sameAsClosePath(self):
|
|
|
|
pen = TTGlyphPen(None)
|
|
|
|
|
|
|
|
pen.moveTo((0, 0))
|
|
|
|
pen.lineTo((0, 1))
|
|
|
|
pen.lineTo((1, 0))
|
|
|
|
pen.closePath()
|
|
|
|
closePathGlyph = pen.glyph()
|
|
|
|
|
|
|
|
pen.moveTo((0, 0))
|
|
|
|
pen.lineTo((0, 1))
|
|
|
|
pen.lineTo((1, 0))
|
|
|
|
pen.endPath()
|
|
|
|
endPathGlyph = pen.glyph()
|
|
|
|
|
2021-05-17 14:09:36 +02:00
|
|
|
assert closePathGlyph == endPathGlyph
|
2015-11-05 15:15:33 -08:00
|
|
|
|
|
|
|
def test_glyph_errorOnUnendedContour(self):
|
|
|
|
pen = TTGlyphPen(None)
|
|
|
|
pen.moveTo((0, 0))
|
2021-05-17 14:09:36 +02:00
|
|
|
with pytest.raises(PenError):
|
2015-11-05 15:15:33 -08:00
|
|
|
pen.glyph()
|
|
|
|
|
|
|
|
def test_glyph_decomposes(self):
|
2021-05-17 14:09:36 +02:00
|
|
|
componentName = "a"
|
2015-11-05 15:15:33 -08:00
|
|
|
glyphSet = {}
|
|
|
|
pen = TTGlyphPen(glyphSet)
|
|
|
|
|
|
|
|
pen.moveTo((0, 0))
|
|
|
|
pen.lineTo((0, 1))
|
|
|
|
pen.lineTo((1, 0))
|
|
|
|
pen.closePath()
|
|
|
|
glyphSet[componentName] = _TestGlyph(pen.glyph())
|
|
|
|
|
|
|
|
pen.moveTo((0, 0))
|
|
|
|
pen.lineTo((0, 1))
|
|
|
|
pen.lineTo((1, 0))
|
|
|
|
pen.closePath()
|
|
|
|
pen.addComponent(componentName, (1, 0, 0, 1, 2, 0))
|
2018-06-11 18:40:11 +01:00
|
|
|
pen.addComponent("missing", (1, 0, 0, 1, 0, 0)) # skipped
|
2015-11-05 15:15:33 -08:00
|
|
|
compositeGlyph = pen.glyph()
|
|
|
|
|
|
|
|
pen.moveTo((0, 0))
|
|
|
|
pen.lineTo((0, 1))
|
|
|
|
pen.lineTo((1, 0))
|
|
|
|
pen.closePath()
|
|
|
|
pen.moveTo((2, 0))
|
|
|
|
pen.lineTo((2, 1))
|
|
|
|
pen.lineTo((3, 0))
|
|
|
|
pen.closePath()
|
|
|
|
plainGlyph = pen.glyph()
|
|
|
|
|
2021-05-17 14:09:36 +02:00
|
|
|
assert plainGlyph == compositeGlyph
|
2015-11-05 15:15:33 -08:00
|
|
|
|
2016-09-15 19:11:50 +02:00
|
|
|
def test_remove_extra_move_points(self):
|
|
|
|
pen = TTGlyphPen(None)
|
|
|
|
pen.moveTo((0, 0))
|
|
|
|
pen.lineTo((100, 0))
|
|
|
|
pen.qCurveTo((100, 50), (50, 100), (0, 0))
|
|
|
|
pen.closePath()
|
2021-05-17 14:09:36 +02:00
|
|
|
assert len(pen.points) == 4
|
|
|
|
assert pen.points[0] == (0, 0)
|
2016-09-15 19:11:50 +02:00
|
|
|
|
|
|
|
def test_keep_move_point(self):
|
|
|
|
pen = TTGlyphPen(None)
|
|
|
|
pen.moveTo((0, 0))
|
|
|
|
pen.lineTo((100, 0))
|
|
|
|
pen.qCurveTo((100, 50), (50, 100), (30, 30))
|
|
|
|
# when last and move pts are different, closePath() implies a lineTo
|
|
|
|
pen.closePath()
|
2021-05-17 14:09:36 +02:00
|
|
|
assert len(pen.points) == 5
|
|
|
|
assert pen.points[0] == (0, 0)
|
2016-09-15 19:11:50 +02:00
|
|
|
|
|
|
|
def test_keep_duplicate_end_point(self):
|
|
|
|
pen = TTGlyphPen(None)
|
|
|
|
pen.moveTo((0, 0))
|
|
|
|
pen.lineTo((100, 0))
|
|
|
|
pen.qCurveTo((100, 50), (50, 100), (0, 0))
|
|
|
|
pen.lineTo((0, 0)) # the duplicate point is not removed
|
|
|
|
pen.closePath()
|
2021-05-17 14:09:36 +02:00
|
|
|
assert len(pen.points) == 5
|
|
|
|
assert pen.points[0] == (0, 0)
|
2016-09-15 19:11:50 +02:00
|
|
|
|
2018-03-01 18:52:55 +00:00
|
|
|
def test_within_range_component_transform(self):
|
2021-05-17 14:09:36 +02:00
|
|
|
componentName = "a"
|
2018-03-01 11:53:10 +00:00
|
|
|
glyphSet = {}
|
|
|
|
pen = TTGlyphPen(glyphSet)
|
|
|
|
|
|
|
|
pen.moveTo((0, 0))
|
|
|
|
pen.lineTo((0, 1))
|
|
|
|
pen.lineTo((1, 0))
|
|
|
|
pen.closePath()
|
|
|
|
glyphSet[componentName] = _TestGlyph(pen.glyph())
|
|
|
|
|
|
|
|
pen.addComponent(componentName, (1.5, 0, 0, 1, 0, 0))
|
|
|
|
pen.addComponent(componentName, (1, 0, 0, -1.5, 0, 0))
|
|
|
|
compositeGlyph = pen.glyph()
|
|
|
|
|
|
|
|
pen.addComponent(componentName, (1.5, 0, 0, 1, 0, 0))
|
|
|
|
pen.addComponent(componentName, (1, 0, 0, -1.5, 0, 0))
|
|
|
|
expectedGlyph = pen.glyph()
|
|
|
|
|
2021-05-17 14:09:36 +02:00
|
|
|
assert expectedGlyph == compositeGlyph
|
2018-03-01 11:53:10 +00:00
|
|
|
|
2018-03-01 18:52:55 +00:00
|
|
|
def test_clamp_to_almost_2_component_transform(self):
|
2021-05-17 14:09:36 +02:00
|
|
|
componentName = "a"
|
2018-03-01 11:53:10 +00:00
|
|
|
glyphSet = {}
|
|
|
|
pen = TTGlyphPen(glyphSet)
|
|
|
|
|
|
|
|
pen.moveTo((0, 0))
|
|
|
|
pen.lineTo((0, 1))
|
|
|
|
pen.lineTo((1, 0))
|
|
|
|
pen.closePath()
|
|
|
|
glyphSet[componentName] = _TestGlyph(pen.glyph())
|
|
|
|
|
|
|
|
pen.addComponent(componentName, (1.99999, 0, 0, 1, 0, 0))
|
|
|
|
pen.addComponent(componentName, (1, 2, 0, 1, 0, 0))
|
|
|
|
pen.addComponent(componentName, (1, 0, 2, 1, 0, 0))
|
|
|
|
pen.addComponent(componentName, (1, 0, 0, 2, 0, 0))
|
|
|
|
pen.addComponent(componentName, (-2, 0, 0, -2, 0, 0))
|
|
|
|
compositeGlyph = pen.glyph()
|
|
|
|
|
2018-03-01 18:52:55 +00:00
|
|
|
almost2 = MAX_F2DOT14 # 0b1.11111111111111
|
2018-03-01 11:53:10 +00:00
|
|
|
pen.addComponent(componentName, (almost2, 0, 0, 1, 0, 0))
|
|
|
|
pen.addComponent(componentName, (1, almost2, 0, 1, 0, 0))
|
|
|
|
pen.addComponent(componentName, (1, 0, almost2, 1, 0, 0))
|
|
|
|
pen.addComponent(componentName, (1, 0, 0, almost2, 0, 0))
|
|
|
|
pen.addComponent(componentName, (-2, 0, 0, -2, 0, 0))
|
|
|
|
expectedGlyph = pen.glyph()
|
|
|
|
|
2021-05-17 14:09:36 +02:00
|
|
|
assert expectedGlyph == compositeGlyph
|
2018-03-01 11:53:10 +00:00
|
|
|
|
2018-03-01 19:39:24 +00:00
|
|
|
def test_out_of_range_transform_decomposed(self):
|
2021-05-17 14:09:36 +02:00
|
|
|
componentName = "a"
|
2018-03-01 11:53:10 +00:00
|
|
|
glyphSet = {}
|
|
|
|
pen = TTGlyphPen(glyphSet)
|
|
|
|
|
|
|
|
pen.moveTo((0, 0))
|
|
|
|
pen.lineTo((0, 1))
|
|
|
|
pen.lineTo((1, 0))
|
|
|
|
pen.closePath()
|
|
|
|
glyphSet[componentName] = _TestGlyph(pen.glyph())
|
|
|
|
|
2018-03-01 17:58:44 +00:00
|
|
|
pen.addComponent(componentName, (3, 0, 0, 2, 0, 0))
|
2018-03-01 18:52:55 +00:00
|
|
|
pen.addComponent(componentName, (1, 0, 0, 1, -1, 2))
|
2018-03-01 17:58:44 +00:00
|
|
|
pen.addComponent(componentName, (2, 0, 0, -3, 0, 0))
|
2018-03-01 11:53:10 +00:00
|
|
|
compositeGlyph = pen.glyph()
|
|
|
|
|
|
|
|
pen.moveTo((0, 0))
|
2018-03-01 17:58:44 +00:00
|
|
|
pen.lineTo((0, 2))
|
2018-03-01 11:53:10 +00:00
|
|
|
pen.lineTo((3, 0))
|
|
|
|
pen.closePath()
|
2018-03-01 18:52:55 +00:00
|
|
|
pen.moveTo((-1, 2))
|
|
|
|
pen.lineTo((-1, 3))
|
|
|
|
pen.lineTo((0, 2))
|
|
|
|
pen.closePath()
|
2018-03-01 11:53:10 +00:00
|
|
|
pen.moveTo((0, 0))
|
|
|
|
pen.lineTo((0, -3))
|
2018-03-01 17:58:44 +00:00
|
|
|
pen.lineTo((2, 0))
|
2018-03-01 11:53:10 +00:00
|
|
|
pen.closePath()
|
|
|
|
expectedGlyph = pen.glyph()
|
|
|
|
|
2021-05-17 14:09:36 +02:00
|
|
|
assert expectedGlyph == compositeGlyph
|
2018-03-01 11:53:10 +00:00
|
|
|
|
2018-03-01 20:17:48 +00:00
|
|
|
def test_no_handle_overflowing_transform(self):
|
2021-05-17 14:09:36 +02:00
|
|
|
componentName = "a"
|
2018-03-01 20:10:32 +00:00
|
|
|
glyphSet = {}
|
2018-03-01 20:17:48 +00:00
|
|
|
pen = TTGlyphPen(glyphSet, handleOverflowingTransforms=False)
|
2018-03-01 20:10:32 +00:00
|
|
|
|
|
|
|
pen.moveTo((0, 0))
|
|
|
|
pen.lineTo((0, 1))
|
|
|
|
pen.lineTo((1, 0))
|
|
|
|
pen.closePath()
|
|
|
|
baseGlyph = pen.glyph()
|
|
|
|
glyphSet[componentName] = _TestGlyph(baseGlyph)
|
|
|
|
|
|
|
|
pen.addComponent(componentName, (3, 0, 0, 1, 0, 0))
|
|
|
|
compositeGlyph = pen.glyph()
|
|
|
|
|
2021-05-17 14:09:36 +02:00
|
|
|
assert compositeGlyph.components[0].transform == ((3, 0), (0, 1))
|
2018-03-01 20:10:32 +00:00
|
|
|
|
2021-05-17 14:09:36 +02:00
|
|
|
with pytest.raises(struct.error):
|
|
|
|
compositeGlyph.compile({"a": baseGlyph})
|
2018-03-01 20:10:32 +00:00
|
|
|
|
2019-11-26 16:03:18 +00:00
|
|
|
def assertGlyphBoundsEqual(self, glyph, bounds):
|
2021-05-17 14:09:36 +02:00
|
|
|
assert (glyph.xMin, glyph.yMin, glyph.xMax, glyph.yMax) == bounds
|
2019-11-26 16:03:18 +00:00
|
|
|
|
|
|
|
def test_round_float_coordinates_and_component_offsets(self):
|
|
|
|
glyphSet = {}
|
|
|
|
pen = TTGlyphPen(glyphSet)
|
|
|
|
|
|
|
|
pen.moveTo((0, 0))
|
|
|
|
pen.lineTo((0, 1))
|
|
|
|
pen.lineTo((367.6, 0))
|
|
|
|
pen.closePath()
|
|
|
|
simpleGlyph = pen.glyph()
|
|
|
|
|
|
|
|
simpleGlyph.recalcBounds(glyphSet)
|
|
|
|
self.assertGlyphBoundsEqual(simpleGlyph, (0, 0, 368, 1))
|
|
|
|
|
2021-05-17 14:09:36 +02:00
|
|
|
componentName = "a"
|
2019-11-26 16:03:18 +00:00
|
|
|
glyphSet[componentName] = simpleGlyph
|
|
|
|
|
|
|
|
pen.addComponent(componentName, (1, 0, 0, 1, -86.4, 0))
|
|
|
|
compositeGlyph = pen.glyph()
|
|
|
|
|
|
|
|
compositeGlyph.recalcBounds(glyphSet)
|
|
|
|
self.assertGlyphBoundsEqual(compositeGlyph, (-86, 0, 282, 1))
|
|
|
|
|
2020-02-13 13:49:01 +00:00
|
|
|
def test_scaled_component_bounds(self):
|
|
|
|
glyphSet = {}
|
|
|
|
|
|
|
|
pen = TTGlyphPen(glyphSet)
|
|
|
|
pen.moveTo((-231, 939))
|
|
|
|
pen.lineTo((-55, 939))
|
|
|
|
pen.lineTo((-55, 745))
|
|
|
|
pen.lineTo((-231, 745))
|
|
|
|
pen.closePath()
|
2021-05-17 14:09:36 +02:00
|
|
|
glyphSet["gravecomb"] = pen.glyph()
|
2020-02-13 13:49:01 +00:00
|
|
|
|
|
|
|
pen = TTGlyphPen(glyphSet)
|
|
|
|
pen.moveTo((-278, 939))
|
|
|
|
pen.lineTo((8, 939))
|
|
|
|
pen.lineTo((8, 745))
|
|
|
|
pen.lineTo((-278, 745))
|
|
|
|
pen.closePath()
|
2021-05-17 14:09:36 +02:00
|
|
|
glyphSet["circumflexcomb"] = pen.glyph()
|
2020-02-13 13:49:01 +00:00
|
|
|
|
|
|
|
pen = TTGlyphPen(glyphSet)
|
|
|
|
pen.addComponent("circumflexcomb", (1, 0, 0, 1, 0, 0))
|
|
|
|
pen.addComponent("gravecomb", (0.9, 0, 0, 0.9, 198, 180))
|
|
|
|
glyphSet["uni0302_uni0300"] = uni0302_uni0300 = pen.glyph()
|
|
|
|
|
|
|
|
uni0302_uni0300.recalcBounds(glyphSet)
|
|
|
|
self.assertGlyphBoundsEqual(uni0302_uni0300, (-278, 745, 148, 1025))
|
|
|
|
|
2022-12-09 15:12:06 -07:00
|
|
|
def test_outputImpliedClosingLine(self):
|
|
|
|
glyphSet = {}
|
|
|
|
|
|
|
|
pen = TTGlyphPen(glyphSet)
|
|
|
|
pen.moveTo((0, 0))
|
|
|
|
pen.lineTo((10, 0))
|
|
|
|
pen.lineTo((0, 10))
|
|
|
|
pen.lineTo((0, 0))
|
|
|
|
pen.closePath()
|
|
|
|
glyph = pen.glyph()
|
|
|
|
assert len(glyph.coordinates) == 3
|
|
|
|
|
|
|
|
pen = TTGlyphPen(glyphSet, outputImpliedClosingLine=True)
|
|
|
|
pen.moveTo((0, 0))
|
|
|
|
pen.lineTo((10, 0))
|
|
|
|
pen.lineTo((0, 10))
|
|
|
|
pen.lineTo((0, 0))
|
|
|
|
pen.closePath()
|
|
|
|
glyph = pen.glyph()
|
|
|
|
assert len(glyph.coordinates) == 4
|
|
|
|
|
2015-11-05 15:15:33 -08:00
|
|
|
|
2021-05-17 14:09:36 +02:00
|
|
|
class TTGlyphPointPenTest(TTGlyphPenTestBase):
|
|
|
|
penClass = TTGlyphPointPen
|
|
|
|
drawMethod = "drawPoints"
|
|
|
|
|
|
|
|
def test_glyph_simple(self):
|
|
|
|
pen = TTGlyphPointPen(None)
|
|
|
|
pen.beginPath()
|
|
|
|
pen.addPoint((50, 0), "line")
|
|
|
|
pen.addPoint((450, 0), "line")
|
|
|
|
pen.addPoint((450, 700), "line")
|
|
|
|
pen.addPoint((50, 700), "line")
|
|
|
|
pen.endPath()
|
|
|
|
glyph = pen.glyph()
|
|
|
|
assert glyph.numberOfContours == 1
|
|
|
|
assert glyph.endPtsOfContours == [3]
|
|
|
|
|
2023-02-20 11:05:35 -07:00
|
|
|
def test_addPoint_noErrorOnCurve(self):
|
2021-05-17 14:09:36 +02:00
|
|
|
pen = TTGlyphPointPen(None)
|
|
|
|
pen.beginPath()
|
2023-02-20 11:05:35 -07:00
|
|
|
pen.addPoint((0, 0), "curve")
|
|
|
|
pen.endPath()
|
2021-05-17 14:09:36 +02:00
|
|
|
|
|
|
|
def test_beginPath_beginPathOnOpenPath(self):
|
|
|
|
pen = TTGlyphPointPen(None)
|
|
|
|
pen.beginPath()
|
|
|
|
pen.addPoint((0, 0))
|
|
|
|
with pytest.raises(PenError):
|
|
|
|
pen.beginPath()
|
|
|
|
|
|
|
|
def test_glyph_errorOnUnendedContour(self):
|
|
|
|
pen = TTGlyphPointPen(None)
|
|
|
|
pen.beginPath()
|
|
|
|
pen.addPoint((0, 0))
|
|
|
|
with pytest.raises(PenError):
|
|
|
|
pen.glyph()
|
|
|
|
|
|
|
|
def test_glyph_errorOnEmptyContour(self):
|
|
|
|
pen = TTGlyphPointPen(None)
|
|
|
|
pen.beginPath()
|
|
|
|
with pytest.raises(PenError):
|
|
|
|
pen.endPath()
|
|
|
|
|
|
|
|
def test_glyph_decomposes(self):
|
|
|
|
componentName = "a"
|
|
|
|
glyphSet = {}
|
|
|
|
pen = TTGlyphPointPen(glyphSet)
|
|
|
|
|
|
|
|
pen.beginPath()
|
|
|
|
pen.addPoint((0, 0), "line")
|
|
|
|
pen.addPoint((0, 1), "line")
|
|
|
|
pen.addPoint((1, 0), "line")
|
|
|
|
pen.endPath()
|
|
|
|
glyphSet[componentName] = _TestGlyph(pen.glyph())
|
|
|
|
|
|
|
|
pen.beginPath()
|
|
|
|
pen.addPoint((0, 0), "line")
|
|
|
|
pen.addPoint((0, 1), "line")
|
|
|
|
pen.addPoint((1, 0), "line")
|
|
|
|
pen.endPath()
|
|
|
|
pen.addComponent(componentName, (1, 0, 0, 1, 2, 0))
|
|
|
|
pen.addComponent("missing", (1, 0, 0, 1, 0, 0)) # skipped
|
|
|
|
compositeGlyph = pen.glyph()
|
|
|
|
|
|
|
|
pen.beginPath()
|
|
|
|
pen.addPoint((0, 0), "line")
|
|
|
|
pen.addPoint((0, 1), "line")
|
|
|
|
pen.addPoint((1, 0), "line")
|
|
|
|
pen.endPath()
|
|
|
|
pen.beginPath()
|
|
|
|
pen.addPoint((2, 0), "line")
|
|
|
|
pen.addPoint((2, 1), "line")
|
|
|
|
pen.addPoint((3, 0), "line")
|
|
|
|
pen.endPath()
|
|
|
|
plainGlyph = pen.glyph()
|
|
|
|
|
|
|
|
assert plainGlyph == compositeGlyph
|
|
|
|
|
|
|
|
def test_keep_duplicate_end_point(self):
|
|
|
|
pen = TTGlyphPointPen(None)
|
|
|
|
pen.beginPath()
|
|
|
|
pen.addPoint((0, 0), "line")
|
|
|
|
pen.addPoint((100, 0), "line")
|
|
|
|
pen.addPoint((100, 50))
|
|
|
|
pen.addPoint((50, 100))
|
|
|
|
pen.addPoint((0, 0), "qcurve")
|
|
|
|
pen.addPoint((0, 0), "line") # the duplicate point is not removed
|
|
|
|
pen.endPath()
|
|
|
|
assert len(pen.points) == 6
|
|
|
|
assert pen.points[0] == (0, 0)
|
|
|
|
|
|
|
|
def test_within_range_component_transform(self):
|
|
|
|
componentName = "a"
|
|
|
|
glyphSet = {}
|
|
|
|
pen = TTGlyphPointPen(glyphSet)
|
|
|
|
|
|
|
|
pen.beginPath()
|
|
|
|
pen.addPoint((0, 0), "line")
|
|
|
|
pen.addPoint((0, 1), "line")
|
|
|
|
pen.addPoint((1, 0), "line")
|
|
|
|
pen.endPath()
|
|
|
|
glyphSet[componentName] = _TestGlyph(pen.glyph())
|
|
|
|
|
|
|
|
pen.addComponent(componentName, (1.5, 0, 0, 1, 0, 0))
|
|
|
|
pen.addComponent(componentName, (1, 0, 0, -1.5, 0, 0))
|
|
|
|
compositeGlyph = pen.glyph()
|
|
|
|
|
|
|
|
pen.addComponent(componentName, (1.5, 0, 0, 1, 0, 0))
|
|
|
|
pen.addComponent(componentName, (1, 0, 0, -1.5, 0, 0))
|
|
|
|
expectedGlyph = pen.glyph()
|
|
|
|
|
|
|
|
assert expectedGlyph == compositeGlyph
|
|
|
|
|
|
|
|
def test_clamp_to_almost_2_component_transform(self):
|
|
|
|
componentName = "a"
|
|
|
|
glyphSet = {}
|
|
|
|
pen = TTGlyphPointPen(glyphSet)
|
|
|
|
|
|
|
|
pen.beginPath()
|
|
|
|
pen.addPoint((0, 0), "line")
|
|
|
|
pen.addPoint((0, 1), "line")
|
|
|
|
pen.addPoint((1, 0), "line")
|
|
|
|
pen.endPath()
|
|
|
|
glyphSet[componentName] = _TestGlyph(pen.glyph())
|
|
|
|
|
|
|
|
pen.addComponent(componentName, (1.99999, 0, 0, 1, 0, 0))
|
|
|
|
pen.addComponent(componentName, (1, 2, 0, 1, 0, 0))
|
|
|
|
pen.addComponent(componentName, (1, 0, 2, 1, 0, 0))
|
|
|
|
pen.addComponent(componentName, (1, 0, 0, 2, 0, 0))
|
|
|
|
pen.addComponent(componentName, (-2, 0, 0, -2, 0, 0))
|
|
|
|
compositeGlyph = pen.glyph()
|
|
|
|
|
|
|
|
almost2 = MAX_F2DOT14 # 0b1.11111111111111
|
|
|
|
pen.addComponent(componentName, (almost2, 0, 0, 1, 0, 0))
|
|
|
|
pen.addComponent(componentName, (1, almost2, 0, 1, 0, 0))
|
|
|
|
pen.addComponent(componentName, (1, 0, almost2, 1, 0, 0))
|
|
|
|
pen.addComponent(componentName, (1, 0, 0, almost2, 0, 0))
|
|
|
|
pen.addComponent(componentName, (-2, 0, 0, -2, 0, 0))
|
|
|
|
expectedGlyph = pen.glyph()
|
|
|
|
|
|
|
|
assert expectedGlyph == compositeGlyph
|
|
|
|
|
|
|
|
def test_out_of_range_transform_decomposed(self):
|
|
|
|
componentName = "a"
|
|
|
|
glyphSet = {}
|
|
|
|
pen = TTGlyphPointPen(glyphSet)
|
|
|
|
|
|
|
|
pen.beginPath()
|
|
|
|
pen.addPoint((0, 0), "line")
|
|
|
|
pen.addPoint((0, 1), "line")
|
|
|
|
pen.addPoint((1, 0), "line")
|
|
|
|
pen.endPath()
|
|
|
|
glyphSet[componentName] = _TestGlyph(pen.glyph())
|
|
|
|
|
|
|
|
pen.addComponent(componentName, (3, 0, 0, 2, 0, 0))
|
|
|
|
pen.addComponent(componentName, (1, 0, 0, 1, -1, 2))
|
|
|
|
pen.addComponent(componentName, (2, 0, 0, -3, 0, 0))
|
|
|
|
compositeGlyph = pen.glyph()
|
|
|
|
|
|
|
|
pen.beginPath()
|
|
|
|
pen.addPoint((0, 0), "line")
|
|
|
|
pen.addPoint((0, 2), "line")
|
|
|
|
pen.addPoint((3, 0), "line")
|
|
|
|
pen.endPath()
|
|
|
|
pen.beginPath()
|
|
|
|
pen.addPoint((-1, 2), "line")
|
|
|
|
pen.addPoint((-1, 3), "line")
|
|
|
|
pen.addPoint((0, 2), "line")
|
|
|
|
pen.endPath()
|
|
|
|
pen.beginPath()
|
|
|
|
pen.addPoint((0, 0), "line")
|
|
|
|
pen.addPoint((0, -3), "line")
|
|
|
|
pen.addPoint((2, 0), "line")
|
|
|
|
pen.endPath()
|
|
|
|
expectedGlyph = pen.glyph()
|
|
|
|
|
|
|
|
assert expectedGlyph == compositeGlyph
|
|
|
|
|
|
|
|
def test_no_handle_overflowing_transform(self):
|
|
|
|
componentName = "a"
|
|
|
|
glyphSet = {}
|
|
|
|
pen = TTGlyphPointPen(glyphSet, handleOverflowingTransforms=False)
|
|
|
|
|
|
|
|
pen.beginPath()
|
|
|
|
pen.addPoint((0, 0), "line")
|
|
|
|
pen.addPoint((0, 1), "line")
|
|
|
|
pen.addPoint((1, 0), "line")
|
|
|
|
pen.endPath()
|
|
|
|
baseGlyph = pen.glyph()
|
|
|
|
glyphSet[componentName] = _TestGlyph(baseGlyph)
|
|
|
|
|
|
|
|
pen.addComponent(componentName, (3, 0, 0, 1, 0, 0))
|
|
|
|
compositeGlyph = pen.glyph()
|
|
|
|
|
|
|
|
assert compositeGlyph.components[0].transform == ((3, 0), (0, 1))
|
|
|
|
|
|
|
|
with pytest.raises(struct.error):
|
|
|
|
compositeGlyph.compile({"a": baseGlyph})
|
|
|
|
|
|
|
|
def assertGlyphBoundsEqual(self, glyph, bounds):
|
|
|
|
assert (glyph.xMin, glyph.yMin, glyph.xMax, glyph.yMax) == bounds
|
|
|
|
|
|
|
|
def test_round_float_coordinates_and_component_offsets(self):
|
|
|
|
glyphSet = {}
|
|
|
|
pen = TTGlyphPointPen(glyphSet)
|
|
|
|
|
|
|
|
pen.beginPath()
|
|
|
|
pen.addPoint((0, 0), "line")
|
|
|
|
pen.addPoint((0, 1), "line")
|
|
|
|
pen.addPoint((367.6, 0), "line")
|
|
|
|
pen.endPath()
|
|
|
|
simpleGlyph = pen.glyph()
|
|
|
|
|
|
|
|
simpleGlyph.recalcBounds(glyphSet)
|
|
|
|
self.assertGlyphBoundsEqual(simpleGlyph, (0, 0, 368, 1))
|
|
|
|
|
|
|
|
componentName = "a"
|
|
|
|
glyphSet[componentName] = simpleGlyph
|
|
|
|
|
|
|
|
pen.addComponent(componentName, (1, 0, 0, 1, -86.4, 0))
|
|
|
|
compositeGlyph = pen.glyph()
|
|
|
|
|
|
|
|
compositeGlyph.recalcBounds(glyphSet)
|
|
|
|
self.assertGlyphBoundsEqual(compositeGlyph, (-86, 0, 282, 1))
|
|
|
|
|
|
|
|
def test_scaled_component_bounds(self):
|
|
|
|
glyphSet = {}
|
|
|
|
|
|
|
|
pen = TTGlyphPointPen(glyphSet)
|
|
|
|
pen.beginPath()
|
|
|
|
pen.addPoint((-231, 939), "line")
|
|
|
|
pen.addPoint((-55, 939), "line")
|
|
|
|
pen.addPoint((-55, 745), "line")
|
|
|
|
pen.addPoint((-231, 745), "line")
|
|
|
|
pen.endPath()
|
|
|
|
glyphSet["gravecomb"] = pen.glyph()
|
|
|
|
|
|
|
|
pen = TTGlyphPointPen(glyphSet)
|
|
|
|
pen.beginPath()
|
|
|
|
pen.addPoint((-278, 939), "line")
|
|
|
|
pen.addPoint((8, 939), "line")
|
|
|
|
pen.addPoint((8, 745), "line")
|
|
|
|
pen.addPoint((-278, 745), "line")
|
|
|
|
pen.endPath()
|
|
|
|
glyphSet["circumflexcomb"] = pen.glyph()
|
|
|
|
|
|
|
|
pen = TTGlyphPointPen(glyphSet)
|
|
|
|
pen.addComponent("circumflexcomb", (1, 0, 0, 1, 0, 0))
|
|
|
|
pen.addComponent("gravecomb", (0.9, 0, 0, 0.9, 198, 180))
|
|
|
|
glyphSet["uni0302_uni0300"] = uni0302_uni0300 = pen.glyph()
|
|
|
|
|
|
|
|
uni0302_uni0300.recalcBounds(glyphSet)
|
|
|
|
self.assertGlyphBoundsEqual(uni0302_uni0300, (-278, 745, 148, 1025))
|
|
|
|
|
2021-07-15 18:19:46 +01:00
|
|
|
def test_open_path_starting_with_move(self):
|
|
|
|
# when a contour starts with a 'move' point, it signifies the beginnig
|
|
|
|
# of an open contour.
|
|
|
|
# https://unifiedfontobject.org/versions/ufo3/glyphs/glif/#point-types
|
|
|
|
pen1 = TTGlyphPointPen(None)
|
|
|
|
pen1.beginPath()
|
|
|
|
pen1.addPoint((0, 0), "move") # contour is open
|
|
|
|
pen1.addPoint((10, 10), "line")
|
|
|
|
pen1.addPoint((20, 20))
|
|
|
|
pen1.addPoint((20, 0), "qcurve")
|
|
|
|
pen1.endPath()
|
|
|
|
|
|
|
|
pen2 = TTGlyphPointPen(None)
|
|
|
|
pen2.beginPath()
|
|
|
|
pen2.addPoint((0, 0), "line") # contour is closed
|
|
|
|
pen2.addPoint((10, 10), "line")
|
|
|
|
pen2.addPoint((20, 20))
|
|
|
|
pen2.addPoint((20, 0), "qcurve")
|
|
|
|
pen2.endPath()
|
|
|
|
|
|
|
|
# Since TrueType contours are always implicitly closed, the pen will
|
|
|
|
# interpret both these paths as equivalent
|
|
|
|
assert pen1.points == pen2.points == [(0, 0), (10, 10), (20, 20), (20, 0)]
|
|
|
|
assert pen1.types == pen2.types == [1, 1, 0, 1]
|
|
|
|
|
2023-02-22 07:41:39 -07:00
|
|
|
|
|
|
|
class CubicGlyfTest:
|
2023-02-22 07:51:44 -07:00
|
|
|
def test_cubic_simple(self):
|
2023-02-21 10:25:22 -07:00
|
|
|
spen = TTGlyphPen(None)
|
|
|
|
spen.moveTo((0, 0))
|
|
|
|
spen.curveTo((0, 1), (1, 1), (1, 0))
|
|
|
|
spen.closePath()
|
|
|
|
|
|
|
|
ppen = TTGlyphPointPen(None)
|
|
|
|
ppen.beginPath()
|
2023-02-22 07:51:44 -07:00
|
|
|
ppen.addPoint((0, 0), "line")
|
2023-02-21 10:25:22 -07:00
|
|
|
ppen.addPoint((0, 1))
|
|
|
|
ppen.addPoint((1, 1))
|
|
|
|
ppen.addPoint((1, 0), "curve")
|
|
|
|
ppen.endPath()
|
|
|
|
|
|
|
|
for pen in (spen, ppen):
|
|
|
|
|
2023-02-22 07:51:44 -07:00
|
|
|
glyph = pen.glyph()
|
2023-02-21 10:25:22 -07:00
|
|
|
|
|
|
|
for i in range(2):
|
|
|
|
|
|
|
|
if i == 1:
|
|
|
|
glyph.compile(None)
|
|
|
|
|
|
|
|
assert list(glyph.coordinates) == [(0, 0), (0, 1), (1, 1), (1, 0)]
|
|
|
|
assert list(glyph.flags) == [0x01, 0x80, 0x80, 0x01]
|
|
|
|
|
|
|
|
rpen = RecordingPen()
|
|
|
|
glyph.draw(rpen, None)
|
|
|
|
assert rpen.value == [
|
|
|
|
("moveTo", ((0, 0),)),
|
|
|
|
(
|
|
|
|
"curveTo",
|
|
|
|
(
|
|
|
|
(0, 1),
|
|
|
|
(1, 1),
|
|
|
|
(1, 0),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
("closePath", ()),
|
|
|
|
]
|
|
|
|
|
2023-02-22 08:41:14 -07:00
|
|
|
@pytest.mark.parametrize(
|
2023-02-22 09:08:39 -07:00
|
|
|
"dropImpliedOnCurves, segment_pen_commands, point_pen_commands, expected_coordinates, expected_flags, expected_endPts",
|
2023-02-22 08:41:14 -07:00
|
|
|
[
|
2023-02-22 08:53:35 -07:00
|
|
|
( # Two curves that do NOT merge; request merging
|
2023-02-22 09:08:39 -07:00
|
|
|
True,
|
2023-02-22 08:53:35 -07:00
|
|
|
[
|
|
|
|
("moveTo", ((0, 0),)),
|
|
|
|
("curveTo", ((0, 1), (1, 2), (2, 2))),
|
|
|
|
("curveTo", ((3, 3), (4, 1), (4, 0))),
|
|
|
|
("closePath", ()),
|
|
|
|
],
|
|
|
|
[
|
|
|
|
("beginPath", (), {}),
|
|
|
|
("addPoint", ((0, 0), "line", None, None), {}),
|
|
|
|
("addPoint", ((0, 1), None, None, None), {}),
|
|
|
|
("addPoint", ((1, 2), None, None, None), {}),
|
|
|
|
("addPoint", ((2, 2), "curve", None, None), {}),
|
|
|
|
("addPoint", ((3, 3), None, None, None), {}),
|
|
|
|
("addPoint", ((4, 1), None, None, None), {}),
|
|
|
|
("addPoint", ((4, 0), "curve", None, None), {}),
|
|
|
|
("endPath", (), {}),
|
|
|
|
],
|
|
|
|
[(0, 0), (0, 1), (1, 2), (2, 2), (3, 3), (4, 1), (4, 0)],
|
|
|
|
[0x01, 0x80, 0x80, 0x01, 0x80, 0x80, 0x01],
|
|
|
|
[6],
|
|
|
|
),
|
|
|
|
( # Two curves that merge; request merging
|
2023-02-22 09:08:39 -07:00
|
|
|
True,
|
2023-02-22 07:51:44 -07:00
|
|
|
[
|
2023-02-22 08:41:14 -07:00
|
|
|
("moveTo", ((0, 0),)),
|
|
|
|
("curveTo", ((0, 1), (1, 2), (2, 2))),
|
|
|
|
("curveTo", ((3, 2), (4, 1), (4, 0))),
|
|
|
|
("closePath", ()),
|
|
|
|
],
|
2023-02-22 07:51:44 -07:00
|
|
|
[
|
2023-02-22 08:41:14 -07:00
|
|
|
("beginPath", (), {}),
|
|
|
|
("addPoint", ((0, 0), "line", None, None), {}),
|
|
|
|
("addPoint", ((0, 1), None, None, None), {}),
|
|
|
|
("addPoint", ((1, 2), None, None, None), {}),
|
|
|
|
("addPoint", ((2, 2), "curve", None, None), {}),
|
|
|
|
("addPoint", ((3, 2), None, None, None), {}),
|
|
|
|
("addPoint", ((4, 1), None, None, None), {}),
|
|
|
|
("addPoint", ((4, 0), "curve", None, None), {}),
|
|
|
|
("endPath", (), {}),
|
|
|
|
],
|
|
|
|
[(0, 0), (0, 1), (1, 2), (3, 2), (4, 1), (4, 0)],
|
|
|
|
[0x01, 0x80, 0x80, 0x80, 0x80, 0x01],
|
2023-02-22 08:44:15 -07:00
|
|
|
[5],
|
2023-02-22 08:41:14 -07:00
|
|
|
),
|
2023-02-22 08:53:35 -07:00
|
|
|
( # Two curves that merge; request NOT merging
|
2023-02-22 09:08:39 -07:00
|
|
|
False,
|
2023-02-22 08:41:14 -07:00
|
|
|
[
|
|
|
|
("moveTo", ((0, 0),)),
|
|
|
|
("curveTo", ((0, 1), (1, 2), (2, 2))),
|
|
|
|
("curveTo", ((3, 2), (4, 1), (4, 0))),
|
|
|
|
("closePath", ()),
|
|
|
|
],
|
|
|
|
[
|
|
|
|
("beginPath", (), {}),
|
|
|
|
("addPoint", ((0, 0), "line", None, None), {}),
|
|
|
|
("addPoint", ((0, 1), None, None, None), {}),
|
|
|
|
("addPoint", ((1, 2), None, None, None), {}),
|
|
|
|
("addPoint", ((2, 2), "curve", None, None), {}),
|
|
|
|
("addPoint", ((3, 2), None, None, None), {}),
|
|
|
|
("addPoint", ((4, 1), None, None, None), {}),
|
|
|
|
("addPoint", ((4, 0), "curve", None, None), {}),
|
|
|
|
("endPath", (), {}),
|
|
|
|
],
|
|
|
|
[(0, 0), (0, 1), (1, 2), (2, 2), (3, 2), (4, 1), (4, 0)],
|
|
|
|
[0x01, 0x80, 0x80, 0x01, 0x80, 0x80, 0x01],
|
2023-02-22 08:44:15 -07:00
|
|
|
[6],
|
|
|
|
),
|
|
|
|
( # Two (duplicate) contours
|
2023-02-22 09:08:39 -07:00
|
|
|
True,
|
2023-02-22 08:44:15 -07:00
|
|
|
[
|
|
|
|
("moveTo", ((0, 0),)),
|
|
|
|
("curveTo", ((0, 1), (1, 2), (2, 2))),
|
|
|
|
("curveTo", ((3, 2), (4, 1), (4, 0))),
|
|
|
|
("closePath", ()),
|
|
|
|
("moveTo", ((0, 0),)),
|
|
|
|
("curveTo", ((0, 1), (1, 2), (2, 2))),
|
|
|
|
("curveTo", ((3, 2), (4, 1), (4, 0))),
|
|
|
|
("closePath", ()),
|
|
|
|
],
|
|
|
|
[
|
|
|
|
("beginPath", (), {}),
|
|
|
|
("addPoint", ((0, 0), "line", None, None), {}),
|
|
|
|
("addPoint", ((0, 1), None, None, None), {}),
|
|
|
|
("addPoint", ((1, 2), None, None, None), {}),
|
|
|
|
("addPoint", ((2, 2), "curve", None, None), {}),
|
|
|
|
("addPoint", ((3, 2), None, None, None), {}),
|
|
|
|
("addPoint", ((4, 1), None, None, None), {}),
|
|
|
|
("addPoint", ((4, 0), "curve", None, None), {}),
|
|
|
|
("endPath", (), {}),
|
|
|
|
("beginPath", (), {}),
|
|
|
|
("addPoint", ((0, 0), "line", None, None), {}),
|
|
|
|
("addPoint", ((0, 1), None, None, None), {}),
|
|
|
|
("addPoint", ((1, 2), None, None, None), {}),
|
|
|
|
("addPoint", ((2, 2), "curve", None, None), {}),
|
|
|
|
("addPoint", ((3, 2), None, None, None), {}),
|
|
|
|
("addPoint", ((4, 1), None, None, None), {}),
|
|
|
|
("addPoint", ((4, 0), "curve", None, None), {}),
|
|
|
|
("endPath", (), {}),
|
|
|
|
],
|
|
|
|
[
|
|
|
|
(0, 0),
|
|
|
|
(0, 1),
|
|
|
|
(1, 2),
|
|
|
|
(3, 2),
|
|
|
|
(4, 1),
|
|
|
|
(4, 0),
|
|
|
|
(0, 0),
|
|
|
|
(0, 1),
|
|
|
|
(1, 2),
|
|
|
|
(3, 2),
|
|
|
|
(4, 1),
|
|
|
|
(4, 0),
|
|
|
|
],
|
|
|
|
[
|
|
|
|
0x01,
|
|
|
|
0x80,
|
|
|
|
0x80,
|
|
|
|
0x80,
|
|
|
|
0x80,
|
|
|
|
0x01,
|
|
|
|
0x01,
|
|
|
|
0x80,
|
|
|
|
0x80,
|
|
|
|
0x80,
|
|
|
|
0x80,
|
|
|
|
0x01,
|
|
|
|
],
|
|
|
|
[5, 11],
|
2023-02-22 08:41:14 -07:00
|
|
|
),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
def test_cubic_topology(
|
|
|
|
self,
|
2023-02-22 09:08:39 -07:00
|
|
|
dropImpliedOnCurves,
|
2023-02-22 08:41:14 -07:00
|
|
|
segment_pen_commands,
|
|
|
|
point_pen_commands,
|
|
|
|
expected_coordinates,
|
|
|
|
expected_flags,
|
2023-02-22 08:44:15 -07:00
|
|
|
expected_endPts,
|
2023-02-22 08:41:14 -07:00
|
|
|
):
|
|
|
|
spen = TTGlyphPen(None)
|
|
|
|
rpen = RecordingPen()
|
|
|
|
rpen.value = segment_pen_commands
|
|
|
|
rpen.replay(spen)
|
2023-02-22 07:51:44 -07:00
|
|
|
|
2023-02-22 08:41:14 -07:00
|
|
|
ppen = TTGlyphPointPen(None)
|
|
|
|
rpen = RecordingPointPen()
|
|
|
|
rpen.value = point_pen_commands
|
|
|
|
rpen.replay(ppen)
|
2023-02-22 07:51:44 -07:00
|
|
|
|
2023-02-22 08:41:14 -07:00
|
|
|
for pen in (spen, ppen):
|
2023-02-22 07:51:44 -07:00
|
|
|
|
2023-02-22 09:08:39 -07:00
|
|
|
glyph = pen.glyph(dropImpliedOnCurves=dropImpliedOnCurves)
|
2023-02-22 08:41:14 -07:00
|
|
|
|
|
|
|
assert list(glyph.coordinates) == expected_coordinates
|
|
|
|
assert list(glyph.flags) == expected_flags
|
2023-02-22 08:44:15 -07:00
|
|
|
assert list(glyph.endPtsOfContours) == expected_endPts
|
2023-02-22 08:41:14 -07:00
|
|
|
|
|
|
|
rpen = RecordingPen()
|
|
|
|
glyph.draw(rpen, None)
|
|
|
|
assert rpen.value == segment_pen_commands
|
2023-02-22 07:51:44 -07:00
|
|
|
|
2021-07-15 18:19:46 +01:00
|
|
|
|
2015-11-05 15:15:33 -08:00
|
|
|
class _TestGlyph(object):
|
|
|
|
def __init__(self, glyph):
|
|
|
|
self.coordinates = glyph.coordinates
|
|
|
|
|
|
|
|
def draw(self, pen):
|
|
|
|
pen.moveTo(self.coordinates[0])
|
|
|
|
for point in self.coordinates[1:]:
|
|
|
|
pen.lineTo(point)
|
|
|
|
pen.closePath()
|
|
|
|
|
2021-05-17 14:09:36 +02:00
|
|
|
def drawPoints(self, pen):
|
|
|
|
pen.beginPath()
|
|
|
|
for point in self.coordinates:
|
|
|
|
pen.addPoint(point, "line")
|
|
|
|
pen.endPath()
|