From dbe1264b34969cbcb027937a6e26499732839e2e Mon Sep 17 00:00:00 2001 From: Khaled Hosny Date: Fri, 17 May 2024 18:06:34 +0300 Subject: [PATCH] [subset] Prune unused user name IDs even with --name-IDs='*' This option should affect only pre-defined name IDs, user name IDs should be pruned when nit used, as usual. Fixes https://github.com/fonttools/fonttools/issues/3508 --- Lib/fontTools/subset/__init__.py | 5 +-- Tests/subset/subset_test.py | 58 +++++++++++++++++++++++++++++--- 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/Lib/fontTools/subset/__init__.py b/Lib/fontTools/subset/__init__.py index 250a07ef1..7e6985db2 100644 --- a/Lib/fontTools/subset/__init__.py +++ b/Lib/fontTools/subset/__init__.py @@ -2913,8 +2913,9 @@ def prune_post_subset(self, font, options): visitor = NameRecordVisitor() visitor.visit(font) nameIDs = set(options.name_IDs) | visitor.seen - if "*" not in options.name_IDs: - self.names = [n for n in self.names if n.nameID in nameIDs] + if "*" in options.name_IDs: + nameIDs |= {n.nameID for n in self.names if n.nameID < 256} + self.names = [n for n in self.names if n.nameID in nameIDs] if not options.name_legacy: # TODO(behdad) Sometimes (eg Apple Color Emoji) there's only a macroman # entry for Latin and no Unicode names. diff --git a/Tests/subset/subset_test.py b/Tests/subset/subset_test.py index 2b57633c2..5c6dfbb2f 100644 --- a/Tests/subset/subset_test.py +++ b/Tests/subset/subset_test.py @@ -1915,10 +1915,6 @@ def test_subset_recalc_xAvgCharWidth(ttf_path): assert xAvgCharWidth_after == subset_font["OS/2"].xAvgCharWidth -if __name__ == "__main__": - sys.exit(unittest.main()) - - def test_subset_prune_gdef_markglyphsetsdef(): # GDEF_MarkGlyphSetsDef fb = FontBuilder(unitsPerEm=1000, isTTF=True) @@ -2023,3 +2019,57 @@ def test_subset_prune_gdef_markglyphsetsdef(): assert lookups[1].MarkFilteringSet == None marksets = font["GDEF"].table.MarkGlyphSetsDef.Coverage assert marksets[0].glyphs == ["acutecomb"] + + +def test_prune_user_name_IDs_with_keep_all(ttf_path): + font = TTFont(ttf_path) + + keepNameIDs = {n.nameID for n in font["name"].names} + + for i in range(10): + font["name"].addName(f"Test{i}") + + options = subset.Options() + options.name_IDs = ["*"] + options.name_legacy = True + options.name_languages = ["*"] + + subsetter = subset.Subsetter(options) + subsetter.populate(unicodes=font.getBestCmap().keys()) + subsetter.subset(font) + + nameIDs = {n.nameID for n in font["name"].names} + assert not any(n > 255 for n in nameIDs) + assert nameIDs == keepNameIDs + + +def test_prune_unused_user_name_IDs_with_keep_all(ttf_path): + font = TTFont(ttf_path) + + keepNameIDs = {n.nameID for n in font["name"].names} + + for i in range(10): + font["name"].addName(f"Test{i}") + + nameID = font["name"].addName("Test STAT") + keepNameIDs.add(nameID) + + font["STAT"] = newTable("STAT") + font["STAT"].table = ot.STAT() + font["STAT"].table.ElidedFallbackNameID = nameID + + options = subset.Options() + options.name_IDs = ["*"] + options.name_legacy = True + options.name_languages = ["*"] + + subsetter = subset.Subsetter(options) + subsetter.populate(unicodes=font.getBestCmap().keys()) + subsetter.subset(font) + + nameIDs = {n.nameID for n in font["name"].names} + assert nameIDs == keepNameIDs + + +if __name__ == "__main__": + sys.exit(unittest.main())