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) == [
+ '',
+ ' ]]>',
+ "",
+ '',
+ ' ]]>',
+ "",
+ '',
+ ' ]]>',
+ "",
+ '',
+ ' ]]>',
+ "",
+ ]