From a79106d09ab8ad29cbff1ed93058e5ac755cc1f5 Mon Sep 17 00:00:00 2001 From: Cosimo Lupo Date: Fri, 12 Nov 2021 18:59:09 +0000 Subject: [PATCH] add simple subset/svg_test.py --- Tests/subset/subset_test.py | 13 +++++ Tests/subset/svg_test.py | 113 ++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 Tests/subset/svg_test.py diff --git a/Tests/subset/subset_test.py b/Tests/subset/subset_test.py index aeb4ce1d9..d8f4dac0c 100644 --- a/Tests/subset/subset_test.py +++ b/Tests/subset/subset_test.py @@ -7,6 +7,7 @@ from fontTools.pens.ttGlyphPen import TTGlyphPen from fontTools.ttLib import TTFont, newTable from fontTools.ttLib.tables import otTables as ot from fontTools.misc.loggingTools import CapturingLogHandler +from fontTools.subset.svg import etree import difflib import logging import os @@ -1339,5 +1340,17 @@ def test_subset_keep_size_drop_empty_stylistic_set(): assert font["GSUB"].table.FeatureList.FeatureCount == 0 +@pytest.mark.skipif(etree is not None, reason="lxml is installed") +def test_subset_svg_missing_lxml(ttf_path): + # add dummy SVG table and confirm we raise ImportError upon trying to subset it + font = TTFont(ttf_path) + font["SVG "] = newTable("SVG ") + font["SVG "].docList = [('', 1, 1)] + font.save(ttf_path) + + with pytest.raises(ModuleNotFoundError): + subset.main([str(ttf_path), "--gids=0,1"]) + + if __name__ == "__main__": sys.exit(unittest.main()) diff --git a/Tests/subset/svg_test.py b/Tests/subset/svg_test.py new file mode 100644 index 000000000..acaeb57db --- /dev/null +++ b/Tests/subset/svg_test.py @@ -0,0 +1,113 @@ +from string import ascii_letters + +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 + +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 + + +def new_svg(**attrs): + return etree.Element("svg", {"xmlns": NAMESPACES["svg"], **attrs}) + + +def test_subset_svg_simple(empty_svg_font, tmp_path): + # 'simple' as in one glyph per svg doc + font = empty_svg_font + + svg_docs = font["SVG "].docList + for i in range(1, 11): + svg = new_svg() + etree.SubElement(svg, "path", {"id": f"glyph{i}", "d": f"M{i},{i}"}) + svg_docs.append((etree.tostring(svg).decode(), i, i)) + + svg_font_path = tmp_path / "TestSVG.ttf" + font.save(svg_font_path) + + subset_path = svg_font_path.with_suffix(".subset.ttf") + + # keep four glyphs in total, don't retain gids, which thus get remapped + subset.main( + [ + str(svg_font_path), + f"--output-file={subset_path}", + "--gids=2,4-6", + ] + ) + subset_font = TTFont(subset_path) + + assert getXML(subset_font["SVG "].toXML, subset_font) == [ + '', + ' ]]>', + "", + '', + ' ]]>', + "", + '', + ' ]]>', + "", + '', + ' ]]>', + "", + ] + + # same four glyphs, now retain gids + subset.main( + [ + str(svg_font_path), + f"--output-file={subset_path}", + "--gids=2,4-6", + "--retain-gids", + ] + ) + subset_font = TTFont(subset_path) + + assert getXML(subset_font["SVG "].toXML, subset_font) == [ + '', + ' ]]>', + "", + '', + ' ]]>', + "", + '', + ' ]]>', + "", + '', + ' ]]>', + "", + ]