From af1a0d1fe524ffb2718f5068df75fcd0863f9e02 Mon Sep 17 00:00:00 2001 From: Cosimo Lupo Date: Tue, 15 Jan 2019 14:07:54 +0000 Subject: [PATCH] [subset] set emptied CFF charstrings to 'endchar' with --retain-gids Part of #1446 --- Lib/fontTools/subset/cff.py | 67 ++++++++++++++++++++----------------- Tests/subset/subset_test.py | 37 +++++++++++++++++++- 2 files changed, 73 insertions(+), 31 deletions(-) diff --git a/Lib/fontTools/subset/cff.py b/Lib/fontTools/subset/cff.py index 9a2b77e4d..71092c70c 100644 --- a/Lib/fontTools/subset/cff.py +++ b/Lib/fontTools/subset/cff.py @@ -104,37 +104,44 @@ def subset_glyphs(self, s): font = cff[fontname] cs = font.CharStrings - # Load all glyphs - for g in font.charset: - if g not in s.glyphs: continue - c, _ = cs.getItemAndSelector(g) - - if cs.charStringsAreIndexed: - indices = [i for i,g in enumerate(font.charset) if g in s.glyphs] - csi = cs.charStringsIndex - csi.items = [csi.items[i] for i in indices] - del csi.file, csi.offsets - if hasattr(font, "FDSelect"): - sel = font.FDSelect - # XXX We want to set sel.format to None, such that the - # most compact format is selected. However, OTS was - # broken and couldn't parse a FDSelect format 0 that - # happened before CharStrings. As such, always force - # format 3 until we fix cffLib to always generate - # FDSelect after CharStrings. - # https://github.com/khaledhosny/ots/pull/31 - #sel.format = None - sel.format = 3 - sel.gidArray = [sel.gidArray[i] for i in indices] - cs.charStrings = {g:indices.index(v) - for g,v in cs.charStrings.items() - if g in s.glyphs} + if s.options.retain_gids: + for g in cs.keys(): + if g in s.glyphs_emptied: + c = cs[g] + c.decompile() + c.program = ["endchar"] else: - cs.charStrings = {g:v - for g,v in cs.charStrings.items() - if g in s.glyphs} - font.charset = [g for g in font.charset if g in s.glyphs] - font.numGlyphs = len(font.charset) + # Load all glyphs + for g in font.charset: + if g not in s.glyphs: continue + c, _ = cs.getItemAndSelector(g) + + if cs.charStringsAreIndexed: + indices = [i for i,g in enumerate(font.charset) if g in s.glyphs] + csi = cs.charStringsIndex + csi.items = [csi.items[i] for i in indices] + del csi.file, csi.offsets + if hasattr(font, "FDSelect"): + sel = font.FDSelect + # XXX We want to set sel.format to None, such that the + # most compact format is selected. However, OTS was + # broken and couldn't parse a FDSelect format 0 that + # happened before CharStrings. As such, always force + # format 3 until we fix cffLib to always generate + # FDSelect after CharStrings. + # https://github.com/khaledhosny/ots/pull/31 + #sel.format = None + sel.format = 3 + sel.gidArray = [sel.gidArray[i] for i in indices] + cs.charStrings = {g:indices.index(v) + for g,v in cs.charStrings.items() + if g in s.glyphs} + else: + cs.charStrings = {g:v + for g,v in cs.charStrings.items() + if g in s.glyphs} + font.charset = [g for g in font.charset if g in s.glyphs] + font.numGlyphs = len(font.charset) return True # any(cff[fontname].numGlyphs for fontname in cff.keys()) diff --git a/Tests/subset/subset_test.py b/Tests/subset/subset_test.py index 030caa136..cd8787b2c 100644 --- a/Tests/subset/subset_test.py +++ b/Tests/subset/subset_test.py @@ -475,7 +475,7 @@ class SubsetTest(unittest.TestCase): subset.main([fontpath, "--recalc-timestamp", "--output-file=%s" % subsetpath, "*"]) self.assertLess(modified, TTFont(subsetpath)['head'].modified) - def test_retain_gids(self): + def test_retain_gids_ttf(self): _, fontpath = self.compile_font(self.getpath("TestTTF-Regular.ttx"), ".ttf") font = TTFont(fontpath) @@ -507,6 +507,41 @@ class SubsetTest(unittest.TestCase): self.assertGreater(glyf["A"].numberOfContours, 0) self.assertEqual(glyf["B"].numberOfContours, 0) + def test_retain_gids_otf(self): + _, fontpath = self.compile_font(self.getpath("TestOTF-Regular.ttx"), ".otf") + font = TTFont(fontpath) + + self.assertEqual(font["hmtx"]["A"], (500, 132)) + self.assertEqual(font["hmtx"]["B"], (400, 132)) + + font["CFF "].cff[0].decompileAllCharStrings() + cs = font["CFF "].cff[0].CharStrings + self.assertGreater(len(cs["A"].program), 0) + self.assertGreater(len(cs["B"].program), 0) + + subsetpath = self.temp_path(".ttf") + subset.main( + [ + fontpath, + "--retain-gids", + "--output-file=%s" % subsetpath, + "--glyph-names", + "A", + ] + ) + subsetfont = TTFont(subsetpath) + + self.assertEqual(subsetfont.getGlyphOrder(), font.getGlyphOrder()) + + hmtx = subsetfont["hmtx"] + self.assertEqual(hmtx["A"], (500, 132)) + self.assertEqual(hmtx["B"], (0, 0)) + + subsetfont["CFF "].cff[0].decompileAllCharStrings() + cs = subsetfont["CFF "].cff[0].CharStrings + self.assertGreater(len(cs["A"].program), 0) + self.assertEqual(cs["B"].program, ["endchar"]) + if __name__ == "__main__": sys.exit(unittest.main())