from string import ascii_letters
import textwrap
from fontTools.misc.testTools import getXML
from fontTools import subset
from fontTools.fontBuilder import FontBuilder
from fontTools.pens.ttGlyphPen import TTGlyphPen
from fontTools.ttLib import TTFont, newTable
from fontTools.subset.svg import NAMESPACES, ranges
import pytest
etree = pytest.importorskip("lxml.etree")
@pytest.fixture
def empty_svg_font():
glyph_order = [".notdef"] + list(ascii_letters)
pen = TTGlyphPen(glyphSet=None)
pen.moveTo((0, 0))
pen.lineTo((0, 500))
pen.lineTo((500, 500))
pen.lineTo((500, 0))
pen.closePath()
glyph = pen.glyph()
glyphs = {g: glyph for g in glyph_order}
fb = FontBuilder(unitsPerEm=1024, isTTF=True)
fb.setupGlyphOrder(glyph_order)
fb.setupCharacterMap({ord(c): c for c in ascii_letters})
fb.setupGlyf(glyphs)
fb.setupHorizontalMetrics({g: (500, 0) for g in glyph_order})
fb.setupHorizontalHeader()
fb.setupOS2()
fb.setupPost()
fb.setupNameTable({"familyName": "TestSVG", "styleName": "Regular"})
svg_table = newTable("SVG ")
svg_table.docList = []
fb.font["SVG "] = svg_table
return fb.font
# 'simple' here means one svg document per glyph. The required 'id' attribute
# containing the 'glyphXXX' indices can be either on a child of the root ]]>
]]>
]]>
"""
),
),
# same as above but with glyph id attribute in the root element itself
# https://github.com/fonttools/fonttools/issues/2548
(
simple_svg_table_glyph_ids_on_roots,
"2,4-6",
False,
_lines(
"""\
]]>
]]>
]]>
]]>
"""
),
),
# same four glyphs, but we now retain gids
(
simple_svg_table_glyph_ids_on_children,
"2,4-6",
True,
_lines(
"""\
]]>
]]>
]]>
]]>
"""
),
),
# retain gids like above but with glyph id attribute in the root element itself
# https://github.com/fonttools/fonttools/issues/2548
(
simple_svg_table_glyph_ids_on_roots,
"2,4-6",
True,
_lines(
"""\
]]>
]]>
]]>
]]>
"""
),
),
],
)
def test_subset_single_glyph_per_svg(
empty_svg_font, add_svg_table, tmp_path, gids, retain_gids, expected_xml
):
font = add_svg_table(empty_svg_font)
svg_font_path = tmp_path / "TestSVG.ttf"
font.save(svg_font_path)
subset_path = svg_font_path.with_suffix(".subset.ttf")
subset.main(
[
str(svg_font_path),
f"--output-file={subset_path}",
f"--gids={gids}",
"--retain_gids" if retain_gids else "--no-retain_gids",
]
)
subset_font = TTFont(subset_path)
assert getXML(subset_font["SVG "].toXML, subset_font) == expected_xml
# This contains a bunch of cross-references between glyphs, paths, gradients, etc.
# Note the path coordinates are completely made up and not meant to be rendered.
# We only care about the tree structure, not it's visual content.
COMPLEX_SVG = """\
"""
@pytest.mark.parametrize(
"subset_gids, expected_xml",
[
# we only keep gid=2, with 'glyph2' defined inside 'glyph1': 'glyph2'
# is renamed 'glyph1' to match the new subset indices, and the old 'glyph1'
# is kept (as it contains 'glyph2') but renamed '.glyph1' to avoid clash
(
"2",
_lines(
"""\
]]>
"""
),
),
# we keep both gid 1 and 2: the glyph elements' ids stay as they are (only the
# range endGlyphID change); a gradient is kept since it's referenced by glyph1
(
"1,2",
_lines(
"""\
]]>
"""
),
),
(
# both gid 3 and 6 refer (via