2022-08-14 12:48:30 -06:00
|
|
|
from fontTools.ttLib import TTFont
|
2022-08-22 16:51:48 +01:00
|
|
|
from fontTools.ttLib import ttGlyphSet
|
2023-12-06 08:34:51 -07:00
|
|
|
from fontTools.ttLib.ttGlyphSet import LerpGlyphSet
|
2023-02-03 10:58:02 -07:00
|
|
|
from fontTools.pens.recordingPen import (
|
|
|
|
RecordingPen,
|
|
|
|
RecordingPointPen,
|
|
|
|
DecomposingRecordingPen,
|
|
|
|
)
|
2023-01-18 16:06:57 -07:00
|
|
|
from fontTools.misc.roundTools import otRound
|
2023-02-03 09:05:55 -07:00
|
|
|
from fontTools.misc.transform import DecomposedTransform
|
2022-08-14 12:48:30 -06:00
|
|
|
import os
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
|
|
|
|
class TTGlyphSetTest(object):
|
|
|
|
@staticmethod
|
|
|
|
def getpath(testfile):
|
2022-08-15 11:06:51 -06:00
|
|
|
path = os.path.dirname(__file__)
|
2022-08-14 12:48:30 -06:00
|
|
|
return os.path.join(path, "data", testfile)
|
|
|
|
|
|
|
|
@pytest.mark.parametrize(
|
2022-08-26 21:38:58 -06:00
|
|
|
"fontfile, location, expected",
|
2022-08-14 12:48:30 -06:00
|
|
|
[
|
2022-08-22 16:51:48 +01:00
|
|
|
(
|
2022-08-26 21:38:58 -06:00
|
|
|
"I.ttf",
|
2022-08-22 16:51:48 +01:00
|
|
|
None,
|
|
|
|
[
|
2022-08-26 21:38:58 -06:00
|
|
|
("moveTo", ((175, 0),)),
|
|
|
|
("lineTo", ((367, 0),)),
|
|
|
|
("lineTo", ((367, 1456),)),
|
|
|
|
("lineTo", ((175, 1456),)),
|
|
|
|
("closePath", ()),
|
|
|
|
],
|
2022-08-22 16:51:48 +01:00
|
|
|
),
|
2022-08-14 12:48:30 -06:00
|
|
|
(
|
2022-08-26 21:38:58 -06:00
|
|
|
"I.ttf",
|
2022-08-14 12:48:30 -06:00
|
|
|
{},
|
|
|
|
[
|
2022-08-26 21:38:58 -06:00
|
|
|
("moveTo", ((175, 0),)),
|
|
|
|
("lineTo", ((367, 0),)),
|
|
|
|
("lineTo", ((367, 1456),)),
|
|
|
|
("lineTo", ((175, 1456),)),
|
|
|
|
("closePath", ()),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"I.ttf",
|
|
|
|
{"wght": 100},
|
|
|
|
[
|
|
|
|
("moveTo", ((175, 0),)),
|
|
|
|
("lineTo", ((271, 0),)),
|
|
|
|
("lineTo", ((271, 1456),)),
|
|
|
|
("lineTo", ((175, 1456),)),
|
|
|
|
("closePath", ()),
|
|
|
|
],
|
2022-08-14 12:48:30 -06:00
|
|
|
),
|
|
|
|
(
|
2022-08-26 21:38:58 -06:00
|
|
|
"I.ttf",
|
|
|
|
{"wght": 1000},
|
2022-08-14 12:48:30 -06:00
|
|
|
[
|
2022-08-26 21:38:58 -06:00
|
|
|
("moveTo", ((128, 0),)),
|
|
|
|
("lineTo", ((550, 0),)),
|
|
|
|
("lineTo", ((550, 1456),)),
|
|
|
|
("lineTo", ((128, 1456),)),
|
|
|
|
("closePath", ()),
|
|
|
|
],
|
2022-08-14 12:48:30 -06:00
|
|
|
),
|
|
|
|
(
|
2022-08-26 21:38:58 -06:00
|
|
|
"I.ttf",
|
|
|
|
{"wght": 1000, "wdth": 25},
|
2022-08-14 12:48:30 -06:00
|
|
|
[
|
2022-08-26 21:38:58 -06:00
|
|
|
("moveTo", ((140, 0),)),
|
|
|
|
("lineTo", ((553, 0),)),
|
|
|
|
("lineTo", ((553, 1456),)),
|
|
|
|
("lineTo", ((140, 1456),)),
|
|
|
|
("closePath", ()),
|
|
|
|
],
|
2022-08-14 12:48:30 -06:00
|
|
|
),
|
|
|
|
(
|
2022-08-26 21:38:58 -06:00
|
|
|
"I.ttf",
|
|
|
|
{"wght": 1000, "wdth": 50},
|
2022-08-14 12:48:30 -06:00
|
|
|
[
|
2022-08-26 21:38:58 -06:00
|
|
|
("moveTo", ((136, 0),)),
|
|
|
|
("lineTo", ((552, 0),)),
|
|
|
|
("lineTo", ((552, 1456),)),
|
|
|
|
("lineTo", ((136, 1456),)),
|
|
|
|
("closePath", ()),
|
|
|
|
],
|
2022-08-14 12:48:30 -06:00
|
|
|
),
|
|
|
|
(
|
2022-08-26 21:38:58 -06:00
|
|
|
"I.otf",
|
|
|
|
{"wght": 1000},
|
2022-08-14 12:48:30 -06:00
|
|
|
[
|
2022-08-26 21:38:58 -06:00
|
|
|
("moveTo", ((179, 74),)),
|
|
|
|
("lineTo", ((28, 59),)),
|
|
|
|
("lineTo", ((28, 0),)),
|
|
|
|
("lineTo", ((367, 0),)),
|
|
|
|
("lineTo", ((367, 59),)),
|
|
|
|
("lineTo", ((212, 74),)),
|
|
|
|
("lineTo", ((179, 74),)),
|
|
|
|
("closePath", ()),
|
|
|
|
("moveTo", ((179, 578),)),
|
|
|
|
("lineTo", ((212, 578),)),
|
|
|
|
("lineTo", ((367, 593),)),
|
|
|
|
("lineTo", ((367, 652),)),
|
|
|
|
("lineTo", ((28, 652),)),
|
|
|
|
("lineTo", ((28, 593),)),
|
|
|
|
("lineTo", ((179, 578),)),
|
|
|
|
("closePath", ()),
|
|
|
|
("moveTo", ((98, 310),)),
|
|
|
|
("curveTo", ((98, 205), (98, 101), (95, 0))),
|
|
|
|
("lineTo", ((299, 0),)),
|
|
|
|
("curveTo", ((296, 103), (296, 207), (296, 311))),
|
|
|
|
("lineTo", ((296, 342),)),
|
|
|
|
("curveTo", ((296, 447), (296, 551), (299, 652))),
|
|
|
|
("lineTo", ((95, 652),)),
|
|
|
|
("curveTo", ((98, 549), (98, 445), (98, 342))),
|
|
|
|
("lineTo", ((98, 310),)),
|
|
|
|
("closePath", ()),
|
|
|
|
],
|
2022-08-14 12:48:30 -06:00
|
|
|
),
|
2022-09-20 10:54:09 +02:00
|
|
|
(
|
2022-09-20 11:17:58 +02:00
|
|
|
# In this font, /I has an lsb of 30, but an xMin of 25, so an
|
|
|
|
# offset of 5 units needs to be applied when drawing the outline.
|
|
|
|
# See https://github.com/fonttools/fonttools/issues/2824
|
2022-09-20 10:54:09 +02:00
|
|
|
"issue2824.ttf",
|
|
|
|
None,
|
|
|
|
[
|
|
|
|
("moveTo", ((309, 180),)),
|
|
|
|
("qCurveTo", ((274, 151), (187, 136), (104, 166), (74, 201))),
|
|
|
|
("qCurveTo", ((45, 236), (30, 323), (59, 407), (95, 436))),
|
|
|
|
("qCurveTo", ((130, 466), (217, 480), (301, 451), (330, 415))),
|
|
|
|
("qCurveTo", ((360, 380), (374, 293), (345, 210), (309, 180))),
|
|
|
|
("closePath", ()),
|
|
|
|
],
|
|
|
|
),
|
2022-08-26 21:38:58 -06:00
|
|
|
],
|
2022-08-14 12:48:30 -06:00
|
|
|
)
|
2022-08-26 21:38:58 -06:00
|
|
|
def test_glyphset(self, fontfile, location, expected):
|
|
|
|
font = TTFont(self.getpath(fontfile))
|
2022-08-14 12:48:30 -06:00
|
|
|
glyphset = font.getGlyphSet(location=location)
|
2022-08-22 16:51:48 +01:00
|
|
|
|
|
|
|
assert isinstance(glyphset, ttGlyphSet._TTGlyphSet)
|
|
|
|
|
|
|
|
assert list(glyphset.keys()) == [".notdef", "I"]
|
|
|
|
|
|
|
|
assert "I" in glyphset
|
2023-05-24 14:34:41 -06:00
|
|
|
with pytest.deprecated_call():
|
|
|
|
assert glyphset.has_key("I") # we should really get rid of this...
|
2022-08-22 16:51:48 +01:00
|
|
|
|
|
|
|
assert len(glyphset) == 2
|
|
|
|
|
2022-08-14 12:48:30 -06:00
|
|
|
pen = RecordingPen()
|
2022-08-26 21:38:58 -06:00
|
|
|
glyph = glyphset["I"]
|
2022-08-22 16:51:48 +01:00
|
|
|
|
|
|
|
assert glyphset.get("foobar") is None
|
|
|
|
|
|
|
|
assert isinstance(glyph, ttGlyphSet._TTGlyph)
|
2022-08-26 21:38:58 -06:00
|
|
|
is_glyf = fontfile.endswith(".ttf")
|
2022-08-29 19:41:30 +02:00
|
|
|
glyphType = ttGlyphSet._TTGlyphGlyf if is_glyf else ttGlyphSet._TTGlyphCFF
|
2022-08-26 21:38:58 -06:00
|
|
|
assert isinstance(glyph, glyphType)
|
2022-08-22 16:51:48 +01:00
|
|
|
|
2022-08-14 12:48:30 -06:00
|
|
|
glyph.draw(pen)
|
|
|
|
actual = pen.value
|
|
|
|
|
|
|
|
assert actual == expected, (location, actual, expected)
|
2023-01-18 16:06:57 -07:00
|
|
|
|
2023-12-06 08:34:51 -07:00
|
|
|
@pytest.mark.parametrize(
|
|
|
|
"fontfile, locations, factor, expected",
|
|
|
|
[
|
|
|
|
(
|
|
|
|
"I.ttf",
|
|
|
|
({"wght": 400}, {"wght": 1000}),
|
|
|
|
0.5,
|
|
|
|
[
|
|
|
|
("moveTo", ((151.5, 0.0),)),
|
|
|
|
("lineTo", ((458.5, 0.0),)),
|
|
|
|
("lineTo", ((458.5, 1456.0),)),
|
|
|
|
("lineTo", ((151.5, 1456.0),)),
|
|
|
|
("closePath", ()),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"I.ttf",
|
|
|
|
({"wght": 400}, {"wght": 1000}),
|
|
|
|
0.25,
|
|
|
|
[
|
|
|
|
("moveTo", ((163.25, 0.0),)),
|
|
|
|
("lineTo", ((412.75, 0.0),)),
|
|
|
|
("lineTo", ((412.75, 1456.0),)),
|
|
|
|
("lineTo", ((163.25, 1456.0),)),
|
|
|
|
("closePath", ()),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
],
|
|
|
|
)
|
|
|
|
def test_lerp_glyphset(self, fontfile, locations, factor, expected):
|
|
|
|
font = TTFont(self.getpath(fontfile))
|
|
|
|
glyphset1 = font.getGlyphSet(location=locations[0])
|
|
|
|
glyphset2 = font.getGlyphSet(location=locations[1])
|
|
|
|
glyphset = LerpGlyphSet(glyphset1, glyphset2, factor)
|
|
|
|
|
|
|
|
assert "I" in glyphset
|
|
|
|
|
|
|
|
pen = RecordingPen()
|
|
|
|
glyph = glyphset["I"]
|
|
|
|
|
|
|
|
assert glyphset.get("foobar") is None
|
|
|
|
|
|
|
|
glyph.draw(pen)
|
|
|
|
actual = pen.value
|
|
|
|
|
|
|
|
assert actual == expected, (locations, actual, expected)
|
|
|
|
|
2023-02-02 14:59:32 -07:00
|
|
|
def test_glyphset_varComposite_components(self):
|
|
|
|
font = TTFont(self.getpath("varc-ac00-ac01.ttf"))
|
|
|
|
glyphset = font.getGlyphSet()
|
|
|
|
|
|
|
|
pen = RecordingPen()
|
|
|
|
glyph = glyphset["uniAC00"]
|
|
|
|
|
|
|
|
glyph.draw(pen)
|
|
|
|
actual = pen.value
|
|
|
|
|
|
|
|
expected = [
|
|
|
|
(
|
|
|
|
"addVarComponent",
|
|
|
|
(
|
2024-03-20 15:36:32 -06:00
|
|
|
"glyph00003",
|
2023-12-17 13:08:12 -07:00
|
|
|
DecomposedTransform(
|
|
|
|
translateX=0,
|
|
|
|
translateY=0,
|
|
|
|
rotation=0,
|
|
|
|
scaleX=1,
|
|
|
|
scaleY=1,
|
|
|
|
skewX=0,
|
|
|
|
skewY=0,
|
|
|
|
tCenterX=0,
|
|
|
|
tCenterY=0,
|
|
|
|
),
|
|
|
|
{},
|
2023-02-02 14:59:32 -07:00
|
|
|
),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"addVarComponent",
|
|
|
|
(
|
2024-03-20 15:36:32 -06:00
|
|
|
"glyph00005",
|
2023-12-17 13:08:12 -07:00
|
|
|
DecomposedTransform(
|
|
|
|
translateX=0,
|
|
|
|
translateY=0,
|
|
|
|
rotation=0,
|
|
|
|
scaleX=1,
|
|
|
|
scaleY=1,
|
|
|
|
skewX=0,
|
|
|
|
skewY=0,
|
|
|
|
tCenterX=0,
|
|
|
|
tCenterY=0,
|
|
|
|
),
|
|
|
|
{},
|
2023-02-02 14:59:32 -07:00
|
|
|
),
|
|
|
|
),
|
|
|
|
]
|
|
|
|
|
|
|
|
assert actual == expected, (actual, expected)
|
|
|
|
|
2024-03-22 10:46:22 -06:00
|
|
|
def test_glyphset_varComposite_conditional(self):
|
|
|
|
font = TTFont(self.getpath("varc-ac01-conditional.ttf"))
|
|
|
|
|
|
|
|
glyphset = font.getGlyphSet()
|
|
|
|
pen = RecordingPen()
|
|
|
|
glyph = glyphset["uniAC01"]
|
|
|
|
glyph.draw(pen)
|
|
|
|
assert len(pen.value) == 2
|
|
|
|
|
|
|
|
glyphset = font.getGlyphSet(location={"wght": 800})
|
|
|
|
pen = RecordingPen()
|
|
|
|
glyph = glyphset["uniAC01"]
|
|
|
|
glyph.draw(pen)
|
|
|
|
assert len(pen.value) == 3
|
|
|
|
|
2023-02-01 18:55:48 -07:00
|
|
|
def test_glyphset_varComposite1(self):
|
2023-01-18 16:06:57 -07:00
|
|
|
font = TTFont(self.getpath("varc-ac00-ac01.ttf"))
|
2023-02-01 18:31:54 -07:00
|
|
|
glyphset = font.getGlyphSet(location={"wght": 600})
|
2023-01-18 16:06:57 -07:00
|
|
|
|
2023-02-02 14:59:32 -07:00
|
|
|
pen = DecomposingRecordingPen(glyphset)
|
2023-01-18 16:06:57 -07:00
|
|
|
glyph = glyphset["uniAC00"]
|
|
|
|
|
|
|
|
glyph.draw(pen)
|
|
|
|
actual = pen.value
|
|
|
|
|
|
|
|
expected = [
|
2023-12-17 13:08:12 -07:00
|
|
|
("moveTo", ((82, 108),)),
|
|
|
|
("qCurveTo", ((188, 138), (350, 240), (461, 384), (518, 567), (518, 678))),
|
|
|
|
("lineTo", ((518, 732),)),
|
|
|
|
("lineTo", ((74, 732),)),
|
|
|
|
("lineTo", ((74, 630),)),
|
|
|
|
("lineTo", ((456, 630),)),
|
|
|
|
("lineTo", ((403, 660),)),
|
|
|
|
("qCurveTo", ((403, 575), (358, 431), (267, 314), (128, 225), (34, 194))),
|
2023-01-18 16:06:57 -07:00
|
|
|
("closePath", ()),
|
2023-12-17 13:08:12 -07:00
|
|
|
("moveTo", ((702, 385),)),
|
|
|
|
("lineTo", ((897, 385),)),
|
|
|
|
("lineTo", ((897, 485),)),
|
|
|
|
("lineTo", ((702, 485),)),
|
2023-01-18 16:06:57 -07:00
|
|
|
("closePath", ()),
|
2023-12-17 13:08:12 -07:00
|
|
|
("moveTo", ((641, -92),)),
|
|
|
|
("lineTo", ((752, -92),)),
|
|
|
|
("lineTo", ((752, 813),)),
|
|
|
|
("lineTo", ((641, 813),)),
|
2023-01-18 16:06:57 -07:00
|
|
|
("closePath", ()),
|
|
|
|
]
|
|
|
|
|
|
|
|
actual = [
|
|
|
|
(op, tuple((otRound(pt[0]), otRound(pt[1])) for pt in args))
|
|
|
|
for op, args in actual
|
|
|
|
]
|
|
|
|
|
|
|
|
assert actual == expected, (actual, expected)
|
2023-02-01 18:55:48 -07:00
|
|
|
|
2023-02-03 15:27:59 -07:00
|
|
|
# Test that drawing twice works, we accidentally don't change the component
|
|
|
|
pen = DecomposingRecordingPen(glyphset)
|
|
|
|
glyph.draw(pen)
|
|
|
|
actual = pen.value
|
|
|
|
actual = [
|
|
|
|
(op, tuple((otRound(pt[0]), otRound(pt[1])) for pt in args))
|
|
|
|
for op, args in actual
|
|
|
|
]
|
|
|
|
assert actual == expected, (actual, expected)
|
|
|
|
|
2023-02-03 10:58:02 -07:00
|
|
|
pen = RecordingPointPen()
|
|
|
|
glyph.drawPoints(pen)
|
|
|
|
assert pen.value
|
|
|
|
|
2023-02-01 18:55:48 -07:00
|
|
|
def test_glyphset_varComposite2(self):
|
|
|
|
# This test font has axis variations
|
|
|
|
|
|
|
|
font = TTFont(self.getpath("varc-6868.ttf"))
|
|
|
|
glyphset = font.getGlyphSet(location={"wght": 600})
|
|
|
|
|
2023-02-02 14:59:32 -07:00
|
|
|
pen = DecomposingRecordingPen(glyphset)
|
2023-02-01 18:55:48 -07:00
|
|
|
glyph = glyphset["uni6868"]
|
|
|
|
|
|
|
|
glyph.draw(pen)
|
|
|
|
actual = pen.value
|
|
|
|
|
|
|
|
expected = [
|
|
|
|
("moveTo", ((460, 565),)),
|
|
|
|
(
|
|
|
|
"qCurveTo",
|
|
|
|
(
|
|
|
|
(482, 577),
|
|
|
|
(526, 603),
|
|
|
|
(568, 632),
|
|
|
|
(607, 663),
|
|
|
|
(644, 698),
|
|
|
|
(678, 735),
|
|
|
|
(708, 775),
|
|
|
|
(721, 796),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
("lineTo", ((632, 835),)),
|
|
|
|
(
|
|
|
|
"qCurveTo",
|
|
|
|
(
|
|
|
|
(621, 817),
|
|
|
|
(595, 784),
|
|
|
|
(566, 753),
|
|
|
|
(534, 724),
|
|
|
|
(499, 698),
|
|
|
|
(462, 675),
|
|
|
|
(423, 653),
|
|
|
|
(403, 644),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
("closePath", ()),
|
|
|
|
("moveTo", ((616, 765),)),
|
|
|
|
("lineTo", ((590, 682),)),
|
|
|
|
("lineTo", ((830, 682),)),
|
|
|
|
("lineTo", ((833, 682),)),
|
|
|
|
("lineTo", ((828, 693),)),
|
|
|
|
(
|
|
|
|
"qCurveTo",
|
|
|
|
(
|
|
|
|
(817, 671),
|
|
|
|
(775, 620),
|
|
|
|
(709, 571),
|
|
|
|
(615, 525),
|
|
|
|
(492, 490),
|
|
|
|
(413, 480),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
("lineTo", ((454, 386),)),
|
|
|
|
(
|
|
|
|
"qCurveTo",
|
|
|
|
(
|
|
|
|
(544, 403),
|
|
|
|
(687, 455),
|
|
|
|
(798, 519),
|
|
|
|
(877, 590),
|
|
|
|
(926, 655),
|
|
|
|
(937, 684),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
("lineTo", ((937, 765),)),
|
|
|
|
("closePath", ()),
|
|
|
|
("moveTo", ((723, 555),)),
|
|
|
|
(
|
|
|
|
"qCurveTo",
|
|
|
|
(
|
|
|
|
(713, 563),
|
|
|
|
(693, 579),
|
|
|
|
(672, 595),
|
|
|
|
(651, 610),
|
|
|
|
(629, 625),
|
|
|
|
(606, 638),
|
|
|
|
(583, 651),
|
|
|
|
(572, 657),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
("lineTo", ((514, 590),)),
|
|
|
|
(
|
|
|
|
"qCurveTo",
|
|
|
|
(
|
|
|
|
(525, 584),
|
|
|
|
(547, 572),
|
|
|
|
(568, 559),
|
|
|
|
(589, 545),
|
|
|
|
(609, 531),
|
|
|
|
(629, 516),
|
|
|
|
(648, 500),
|
|
|
|
(657, 492),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
("closePath", ()),
|
|
|
|
("moveTo", ((387, 375),)),
|
|
|
|
("lineTo", ((387, 830),)),
|
|
|
|
("lineTo", ((289, 830),)),
|
|
|
|
("lineTo", ((289, 375),)),
|
|
|
|
("closePath", ()),
|
|
|
|
("moveTo", ((96, 383),)),
|
|
|
|
(
|
|
|
|
"qCurveTo",
|
|
|
|
(
|
|
|
|
(116, 390),
|
|
|
|
(156, 408),
|
|
|
|
(194, 427),
|
|
|
|
(231, 449),
|
|
|
|
(268, 472),
|
|
|
|
(302, 497),
|
|
|
|
(335, 525),
|
|
|
|
(351, 539),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
("lineTo", ((307, 610),)),
|
|
|
|
(
|
|
|
|
"qCurveTo",
|
|
|
|
(
|
|
|
|
(291, 597),
|
|
|
|
(257, 572),
|
|
|
|
(221, 549),
|
|
|
|
(185, 528),
|
|
|
|
(147, 509),
|
|
|
|
(108, 492),
|
|
|
|
(69, 476),
|
|
|
|
(48, 469),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
("closePath", ()),
|
|
|
|
("moveTo", ((290, 653),)),
|
|
|
|
(
|
|
|
|
"qCurveTo",
|
|
|
|
(
|
|
|
|
(281, 664),
|
|
|
|
(261, 687),
|
|
|
|
(240, 708),
|
|
|
|
(219, 729),
|
|
|
|
(196, 749),
|
|
|
|
(173, 768),
|
|
|
|
(148, 786),
|
|
|
|
(136, 794),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
("lineTo", ((69, 727),)),
|
|
|
|
(
|
|
|
|
"qCurveTo",
|
|
|
|
(
|
|
|
|
(81, 719),
|
|
|
|
(105, 702),
|
|
|
|
(129, 684),
|
|
|
|
(151, 665),
|
|
|
|
(173, 645),
|
|
|
|
(193, 625),
|
|
|
|
(213, 604),
|
|
|
|
(222, 593),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
("closePath", ()),
|
|
|
|
("moveTo", ((913, -57),)),
|
|
|
|
("lineTo", ((953, 30),)),
|
|
|
|
(
|
|
|
|
"qCurveTo",
|
|
|
|
(
|
|
|
|
(919, 41),
|
2023-12-17 13:08:12 -07:00
|
|
|
(854, 68),
|
2023-02-01 18:55:48 -07:00
|
|
|
(790, 98),
|
|
|
|
(729, 134),
|
|
|
|
(671, 173),
|
|
|
|
(616, 217),
|
|
|
|
(564, 264),
|
|
|
|
(540, 290),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
("lineTo", ((522, 286),)),
|
|
|
|
("qCurveTo", ((511, 267), (498, 235), (493, 213), (492, 206))),
|
|
|
|
("lineTo", ((515, 209),)),
|
2023-12-17 13:08:12 -07:00
|
|
|
("qCurveTo", ((569, 146), (695, 45), (835, -32), (913, -57))),
|
2023-02-01 18:55:48 -07:00
|
|
|
("closePath", ()),
|
|
|
|
("moveTo", ((474, 274),)),
|
|
|
|
("lineTo", ((452, 284),)),
|
|
|
|
(
|
|
|
|
"qCurveTo",
|
|
|
|
(
|
|
|
|
(428, 260),
|
|
|
|
(377, 214),
|
|
|
|
(323, 172),
|
|
|
|
(266, 135),
|
|
|
|
(206, 101),
|
|
|
|
(144, 71),
|
|
|
|
(80, 46),
|
|
|
|
(47, 36),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
("lineTo", ((89, -53),)),
|
|
|
|
("qCurveTo", ((163, -29), (299, 46), (423, 142), (476, 201))),
|
|
|
|
("lineTo", ((498, 196),)),
|
|
|
|
("qCurveTo", ((498, 203), (494, 225), (482, 255), (474, 274))),
|
|
|
|
("closePath", ()),
|
|
|
|
("moveTo", ((450, 250),)),
|
|
|
|
("lineTo", ((550, 250),)),
|
|
|
|
("lineTo", ((550, 379),)),
|
|
|
|
("lineTo", ((450, 379),)),
|
|
|
|
("closePath", ()),
|
|
|
|
("moveTo", ((68, 215),)),
|
|
|
|
("lineTo", ((932, 215),)),
|
|
|
|
("lineTo", ((932, 305),)),
|
|
|
|
("lineTo", ((68, 305),)),
|
|
|
|
("closePath", ()),
|
|
|
|
("moveTo", ((450, -71),)),
|
|
|
|
("lineTo", ((550, -71),)),
|
|
|
|
("lineTo", ((550, -71),)),
|
|
|
|
("lineTo", ((550, 267),)),
|
|
|
|
("lineTo", ((450, 267),)),
|
|
|
|
("lineTo", ((450, -71),)),
|
|
|
|
("closePath", ()),
|
|
|
|
]
|
|
|
|
|
|
|
|
actual = [
|
|
|
|
(op, tuple((otRound(pt[0]), otRound(pt[1])) for pt in args))
|
|
|
|
for op, args in actual
|
|
|
|
]
|
|
|
|
|
|
|
|
assert actual == expected, (actual, expected)
|
2023-02-03 10:58:02 -07:00
|
|
|
|
|
|
|
pen = RecordingPointPen()
|
|
|
|
glyph.drawPoints(pen)
|
|
|
|
assert pen.value
|
2023-02-21 16:52:36 -07:00
|
|
|
|
|
|
|
def test_cubic_glyf(self):
|
|
|
|
font = TTFont(self.getpath("dot-cubic.ttf"))
|
|
|
|
glyphset = font.getGlyphSet()
|
|
|
|
|
|
|
|
expected = [
|
|
|
|
("moveTo", ((76, 181),)),
|
|
|
|
("curveTo", ((103, 181), (125, 158), (125, 131))),
|
|
|
|
("curveTo", ((125, 104), (103, 82), (76, 82))),
|
|
|
|
("curveTo", ((48, 82), (26, 104), (26, 131))),
|
|
|
|
("curveTo", ((26, 158), (48, 181), (76, 181))),
|
|
|
|
("closePath", ()),
|
|
|
|
]
|
|
|
|
|
|
|
|
pen = RecordingPen()
|
2023-06-27 08:53:02 -06:00
|
|
|
glyphset["one"].draw(pen)
|
2023-02-21 16:52:36 -07:00
|
|
|
assert pen.value == expected
|
|
|
|
|
2023-06-27 09:23:46 -06:00
|
|
|
expectedPoints = [
|
|
|
|
("beginPath", (), {}),
|
|
|
|
("addPoint", ((76, 181), "curve", False, None), {}),
|
|
|
|
("addPoint", ((103, 181), None, False, None), {}),
|
|
|
|
("addPoint", ((125, 158), None, False, None), {}),
|
|
|
|
("addPoint", ((125, 104), None, False, None), {}),
|
|
|
|
("addPoint", ((103, 82), None, False, None), {}),
|
|
|
|
("addPoint", ((76, 82), "curve", False, None), {}),
|
|
|
|
("addPoint", ((48, 82), None, False, None), {}),
|
|
|
|
("addPoint", ((26, 104), None, False, None), {}),
|
|
|
|
("addPoint", ((26, 158), None, False, None), {}),
|
|
|
|
("addPoint", ((48, 181), None, False, None), {}),
|
|
|
|
("endPath", (), {}),
|
|
|
|
]
|
|
|
|
pen = RecordingPointPen()
|
|
|
|
glyphset["one"].drawPoints(pen)
|
|
|
|
assert pen.value == expectedPoints
|
|
|
|
|
2023-02-21 16:52:36 -07:00
|
|
|
pen = RecordingPen()
|
2023-06-27 08:53:02 -06:00
|
|
|
glyphset["two"].draw(pen)
|
2023-02-21 16:52:36 -07:00
|
|
|
assert pen.value == expected
|
|
|
|
|
2023-06-27 09:23:46 -06:00
|
|
|
expectedPoints = [
|
|
|
|
("beginPath", (), {}),
|
|
|
|
("addPoint", ((26, 158), None, False, None), {}),
|
|
|
|
("addPoint", ((48, 181), None, False, None), {}),
|
|
|
|
("addPoint", ((76, 181), "curve", False, None), {}),
|
|
|
|
("addPoint", ((103, 181), None, False, None), {}),
|
|
|
|
("addPoint", ((125, 158), None, False, None), {}),
|
|
|
|
("addPoint", ((125, 104), None, False, None), {}),
|
|
|
|
("addPoint", ((103, 82), None, False, None), {}),
|
|
|
|
("addPoint", ((76, 82), "curve", False, None), {}),
|
|
|
|
("addPoint", ((48, 82), None, False, None), {}),
|
|
|
|
("addPoint", ((26, 104), None, False, None), {}),
|
|
|
|
("endPath", (), {}),
|
|
|
|
]
|
|
|
|
pen = RecordingPointPen()
|
|
|
|
glyphset["two"].drawPoints(pen)
|
|
|
|
assert pen.value == expectedPoints
|
|
|
|
|
2023-02-21 16:52:36 -07:00
|
|
|
pen = RecordingPen()
|
2023-06-27 08:53:02 -06:00
|
|
|
glyphset["three"].draw(pen)
|
2023-02-21 16:52:36 -07:00
|
|
|
assert pen.value == expected
|
|
|
|
|
2023-06-27 09:23:46 -06:00
|
|
|
expectedPoints = [
|
|
|
|
("beginPath", (), {}),
|
|
|
|
("addPoint", ((48, 82), None, False, None), {}),
|
|
|
|
("addPoint", ((26, 104), None, False, None), {}),
|
|
|
|
("addPoint", ((26, 158), None, False, None), {}),
|
|
|
|
("addPoint", ((48, 181), None, False, None), {}),
|
|
|
|
("addPoint", ((76, 181), "curve", False, None), {}),
|
|
|
|
("addPoint", ((103, 181), None, False, None), {}),
|
|
|
|
("addPoint", ((125, 158), None, False, None), {}),
|
|
|
|
("addPoint", ((125, 104), None, False, None), {}),
|
|
|
|
("addPoint", ((103, 82), None, False, None), {}),
|
|
|
|
("addPoint", ((76, 82), "curve", False, None), {}),
|
|
|
|
("endPath", (), {}),
|
|
|
|
]
|
|
|
|
pen = RecordingPointPen()
|
|
|
|
glyphset["three"].drawPoints(pen)
|
|
|
|
assert pen.value == expectedPoints
|
|
|
|
|
2023-02-21 16:52:36 -07:00
|
|
|
pen = RecordingPen()
|
2023-06-27 08:53:02 -06:00
|
|
|
glyphset["four"].draw(pen)
|
2023-02-21 16:52:36 -07:00
|
|
|
assert pen.value == [
|
2023-06-27 08:47:56 -06:00
|
|
|
("moveTo", ((75.5, 181),)),
|
2023-02-21 16:52:36 -07:00
|
|
|
("curveTo", ((103, 181), (125, 158), (125, 131))),
|
|
|
|
("curveTo", ((125, 104), (103, 82), (75.5, 82))),
|
|
|
|
("curveTo", ((48, 82), (26, 104), (26, 131))),
|
|
|
|
("curveTo", ((26, 158), (48, 181), (75.5, 181))),
|
|
|
|
("closePath", ()),
|
|
|
|
]
|
2023-06-27 09:23:46 -06:00
|
|
|
|
|
|
|
# Ouch! We can't represent all-cubic-offcurves in pointPen!
|
2023-06-27 09:53:37 -06:00
|
|
|
# https://github.com/fonttools/fonttools/issues/3191
|
2023-06-27 09:23:46 -06:00
|
|
|
expectedPoints = [
|
|
|
|
("beginPath", (), {}),
|
|
|
|
("addPoint", ((103, 181), None, False, None), {}),
|
|
|
|
("addPoint", ((125, 158), None, False, None), {}),
|
|
|
|
("addPoint", ((125, 104), None, False, None), {}),
|
|
|
|
("addPoint", ((103, 82), None, False, None), {}),
|
|
|
|
("addPoint", ((48, 82), None, False, None), {}),
|
|
|
|
("addPoint", ((26, 104), None, False, None), {}),
|
|
|
|
("addPoint", ((26, 158), None, False, None), {}),
|
|
|
|
("addPoint", ((48, 181), None, False, None), {}),
|
|
|
|
("endPath", (), {}),
|
|
|
|
]
|
|
|
|
pen = RecordingPointPen()
|
|
|
|
glyphset["four"].drawPoints(pen)
|
|
|
|
print(pen.value)
|
|
|
|
assert pen.value == expectedPoints
|