1*e1fe3e4aSElliott Hughesimport io 2*e1fe3e4aSElliott Hughesimport fontTools.ttLib.tables.otBase 3*e1fe3e4aSElliott Hughesfrom fontTools.misc.testTools import getXML, stripVariableItemsFromTTX 4*e1fe3e4aSElliott Hughesfrom fontTools.misc.textTools import tobytes, tostr 5*e1fe3e4aSElliott Hughesfrom fontTools import subset 6*e1fe3e4aSElliott Hughesfrom fontTools.fontBuilder import FontBuilder 7*e1fe3e4aSElliott Hughesfrom fontTools.pens.ttGlyphPen import TTGlyphPen 8*e1fe3e4aSElliott Hughesfrom fontTools.ttLib import TTFont, newTable 9*e1fe3e4aSElliott Hughesfrom fontTools.ttLib.tables import otTables as ot 10*e1fe3e4aSElliott Hughesfrom fontTools.misc.loggingTools import CapturingLogHandler 11*e1fe3e4aSElliott Hughesfrom fontTools.subset.svg import etree 12*e1fe3e4aSElliott Hughesimport difflib 13*e1fe3e4aSElliott Hughesimport logging 14*e1fe3e4aSElliott Hughesimport os 15*e1fe3e4aSElliott Hughesimport shutil 16*e1fe3e4aSElliott Hughesimport sys 17*e1fe3e4aSElliott Hughesimport tempfile 18*e1fe3e4aSElliott Hughesimport unittest 19*e1fe3e4aSElliott Hughesimport pathlib 20*e1fe3e4aSElliott Hughesimport pytest 21*e1fe3e4aSElliott Hughes 22*e1fe3e4aSElliott Hughes 23*e1fe3e4aSElliott Hughesclass SubsetTest: 24*e1fe3e4aSElliott Hughes @classmethod 25*e1fe3e4aSElliott Hughes def setup_class(cls): 26*e1fe3e4aSElliott Hughes cls.tempdir = None 27*e1fe3e4aSElliott Hughes cls.num_tempfiles = 0 28*e1fe3e4aSElliott Hughes 29*e1fe3e4aSElliott Hughes @classmethod 30*e1fe3e4aSElliott Hughes def teardown_class(cls): 31*e1fe3e4aSElliott Hughes if cls.tempdir: 32*e1fe3e4aSElliott Hughes shutil.rmtree(cls.tempdir, ignore_errors=True) 33*e1fe3e4aSElliott Hughes 34*e1fe3e4aSElliott Hughes @staticmethod 35*e1fe3e4aSElliott Hughes def getpath(*testfile): 36*e1fe3e4aSElliott Hughes path, _ = os.path.split(__file__) 37*e1fe3e4aSElliott Hughes return os.path.join(path, "data", *testfile) 38*e1fe3e4aSElliott Hughes 39*e1fe3e4aSElliott Hughes @classmethod 40*e1fe3e4aSElliott Hughes def temp_path(cls, suffix): 41*e1fe3e4aSElliott Hughes if not cls.tempdir: 42*e1fe3e4aSElliott Hughes cls.tempdir = tempfile.mkdtemp() 43*e1fe3e4aSElliott Hughes cls.num_tempfiles += 1 44*e1fe3e4aSElliott Hughes return os.path.join(cls.tempdir, "tmp%d%s" % (cls.num_tempfiles, suffix)) 45*e1fe3e4aSElliott Hughes 46*e1fe3e4aSElliott Hughes @staticmethod 47*e1fe3e4aSElliott Hughes def read_ttx(path): 48*e1fe3e4aSElliott Hughes with open(path, "r", encoding="utf-8") as f: 49*e1fe3e4aSElliott Hughes ttx = f.read() 50*e1fe3e4aSElliott Hughes # don't care whether TTF or OTF, thus strip sfntVersion as well 51*e1fe3e4aSElliott Hughes return stripVariableItemsFromTTX(ttx, sfntVersion=True).splitlines(True) 52*e1fe3e4aSElliott Hughes 53*e1fe3e4aSElliott Hughes def expect_ttx(self, font, expected_ttx, tables=None): 54*e1fe3e4aSElliott Hughes path = self.temp_path(suffix=".ttx") 55*e1fe3e4aSElliott Hughes font.saveXML(path, tables=tables) 56*e1fe3e4aSElliott Hughes actual = self.read_ttx(path) 57*e1fe3e4aSElliott Hughes expected = self.read_ttx(expected_ttx) 58*e1fe3e4aSElliott Hughes if actual != expected: 59*e1fe3e4aSElliott Hughes for line in difflib.unified_diff( 60*e1fe3e4aSElliott Hughes expected, actual, fromfile=expected_ttx, tofile=path 61*e1fe3e4aSElliott Hughes ): 62*e1fe3e4aSElliott Hughes sys.stdout.write(line) 63*e1fe3e4aSElliott Hughes pytest.fail("TTX output is different from expected") 64*e1fe3e4aSElliott Hughes 65*e1fe3e4aSElliott Hughes def compile_font(self, path, suffix): 66*e1fe3e4aSElliott Hughes savepath = self.temp_path(suffix=suffix) 67*e1fe3e4aSElliott Hughes font = TTFont(recalcBBoxes=False, recalcTimestamp=False) 68*e1fe3e4aSElliott Hughes font.importXML(path) 69*e1fe3e4aSElliott Hughes font.save(savepath, reorderTables=None) 70*e1fe3e4aSElliott Hughes return savepath 71*e1fe3e4aSElliott Hughes 72*e1fe3e4aSElliott Hughes # ----- 73*e1fe3e4aSElliott Hughes # Tests 74*e1fe3e4aSElliott Hughes # ----- 75*e1fe3e4aSElliott Hughes 76*e1fe3e4aSElliott Hughes def test_layout_scripts(self): 77*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("layout_scripts.ttx"), ".otf") 78*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".otf") 79*e1fe3e4aSElliott Hughes subset.main( 80*e1fe3e4aSElliott Hughes [ 81*e1fe3e4aSElliott Hughes fontpath, 82*e1fe3e4aSElliott Hughes "--glyphs=*", 83*e1fe3e4aSElliott Hughes "--layout-features=*", 84*e1fe3e4aSElliott Hughes "--layout-scripts=latn,arab.URD,arab.dflt", 85*e1fe3e4aSElliott Hughes "--output-file=%s" % subsetpath, 86*e1fe3e4aSElliott Hughes ] 87*e1fe3e4aSElliott Hughes ) 88*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 89*e1fe3e4aSElliott Hughes self.expect_ttx( 90*e1fe3e4aSElliott Hughes subsetfont, self.getpath("expect_layout_scripts.ttx"), ["GPOS", "GSUB"] 91*e1fe3e4aSElliott Hughes ) 92*e1fe3e4aSElliott Hughes 93*e1fe3e4aSElliott Hughes def test_no_notdef_outline_otf(self): 94*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestOTF-Regular.ttx"), ".otf") 95*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".otf") 96*e1fe3e4aSElliott Hughes subset.main( 97*e1fe3e4aSElliott Hughes [ 98*e1fe3e4aSElliott Hughes fontpath, 99*e1fe3e4aSElliott Hughes "--no-notdef-outline", 100*e1fe3e4aSElliott Hughes "--gids=0", 101*e1fe3e4aSElliott Hughes "--output-file=%s" % subsetpath, 102*e1fe3e4aSElliott Hughes ] 103*e1fe3e4aSElliott Hughes ) 104*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 105*e1fe3e4aSElliott Hughes self.expect_ttx( 106*e1fe3e4aSElliott Hughes subsetfont, self.getpath("expect_no_notdef_outline_otf.ttx"), ["CFF "] 107*e1fe3e4aSElliott Hughes ) 108*e1fe3e4aSElliott Hughes 109*e1fe3e4aSElliott Hughes def test_no_notdef_outline_cid(self): 110*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestCID-Regular.ttx"), ".otf") 111*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".otf") 112*e1fe3e4aSElliott Hughes subset.main( 113*e1fe3e4aSElliott Hughes [ 114*e1fe3e4aSElliott Hughes fontpath, 115*e1fe3e4aSElliott Hughes "--no-notdef-outline", 116*e1fe3e4aSElliott Hughes "--gids=0", 117*e1fe3e4aSElliott Hughes "--output-file=%s" % subsetpath, 118*e1fe3e4aSElliott Hughes ] 119*e1fe3e4aSElliott Hughes ) 120*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 121*e1fe3e4aSElliott Hughes self.expect_ttx( 122*e1fe3e4aSElliott Hughes subsetfont, self.getpath("expect_no_notdef_outline_cid.ttx"), ["CFF "] 123*e1fe3e4aSElliott Hughes ) 124*e1fe3e4aSElliott Hughes 125*e1fe3e4aSElliott Hughes def test_no_notdef_outline_ttf(self): 126*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestTTF-Regular.ttx"), ".ttf") 127*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 128*e1fe3e4aSElliott Hughes subset.main( 129*e1fe3e4aSElliott Hughes [ 130*e1fe3e4aSElliott Hughes fontpath, 131*e1fe3e4aSElliott Hughes "--no-notdef-outline", 132*e1fe3e4aSElliott Hughes "--gids=0", 133*e1fe3e4aSElliott Hughes "--output-file=%s" % subsetpath, 134*e1fe3e4aSElliott Hughes ] 135*e1fe3e4aSElliott Hughes ) 136*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 137*e1fe3e4aSElliott Hughes self.expect_ttx( 138*e1fe3e4aSElliott Hughes subsetfont, 139*e1fe3e4aSElliott Hughes self.getpath("expect_no_notdef_outline_ttf.ttx"), 140*e1fe3e4aSElliott Hughes ["glyf", "hmtx"], 141*e1fe3e4aSElliott Hughes ) 142*e1fe3e4aSElliott Hughes 143*e1fe3e4aSElliott Hughes def test_subset_ankr(self): 144*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestANKR.ttx"), ".ttf") 145*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 146*e1fe3e4aSElliott Hughes subset.main([fontpath, "--glyphs=one", "--output-file=%s" % subsetpath]) 147*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 148*e1fe3e4aSElliott Hughes self.expect_ttx(subsetfont, self.getpath("expect_ankr.ttx"), ["ankr"]) 149*e1fe3e4aSElliott Hughes 150*e1fe3e4aSElliott Hughes def test_subset_ankr_remove(self): 151*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestANKR.ttx"), ".ttf") 152*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 153*e1fe3e4aSElliott Hughes subset.main([fontpath, "--glyphs=two", "--output-file=%s" % subsetpath]) 154*e1fe3e4aSElliott Hughes assert "ankr" not in TTFont(subsetpath) 155*e1fe3e4aSElliott Hughes 156*e1fe3e4aSElliott Hughes def test_subset_bsln_format_0(self): 157*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestBSLN-0.ttx"), ".ttf") 158*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 159*e1fe3e4aSElliott Hughes subset.main([fontpath, "--glyphs=one", "--output-file=%s" % subsetpath]) 160*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 161*e1fe3e4aSElliott Hughes self.expect_ttx(subsetfont, self.getpath("expect_bsln_0.ttx"), ["bsln"]) 162*e1fe3e4aSElliott Hughes 163*e1fe3e4aSElliott Hughes def test_subset_bsln_format_0_from_format_1(self): 164*e1fe3e4aSElliott Hughes # TestBSLN-1 defines the ideographic baseline to be the font's default, 165*e1fe3e4aSElliott Hughes # and specifies that glyphs {.notdef, zero, one, two} use the roman 166*e1fe3e4aSElliott Hughes # baseline instead of the default ideographic baseline. As we request 167*e1fe3e4aSElliott Hughes # a subsetted font with {zero, one} and the implicit .notdef, all 168*e1fe3e4aSElliott Hughes # glyphs in the resulting font use the Roman baseline. In this case, 169*e1fe3e4aSElliott Hughes # we expect a format 0 'bsln' table because it is the most compact. 170*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestBSLN-1.ttx"), ".ttf") 171*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 172*e1fe3e4aSElliott Hughes subset.main( 173*e1fe3e4aSElliott Hughes [fontpath, "--unicodes=U+0030-0031", "--output-file=%s" % subsetpath] 174*e1fe3e4aSElliott Hughes ) 175*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 176*e1fe3e4aSElliott Hughes self.expect_ttx(subsetfont, self.getpath("expect_bsln_0.ttx"), ["bsln"]) 177*e1fe3e4aSElliott Hughes 178*e1fe3e4aSElliott Hughes def test_subset_bsln_format_1(self): 179*e1fe3e4aSElliott Hughes # TestBSLN-1 defines the ideographic baseline to be the font's default, 180*e1fe3e4aSElliott Hughes # and specifies that glyphs {.notdef, zero, one, two} use the roman 181*e1fe3e4aSElliott Hughes # baseline instead of the default ideographic baseline. We request 182*e1fe3e4aSElliott Hughes # a subset where the majority of glyphs use the roman baseline, 183*e1fe3e4aSElliott Hughes # but one single glyph (uni2EA2) is ideographic. In the resulting 184*e1fe3e4aSElliott Hughes # subsetted font, we expect a format 1 'bsln' table whose default 185*e1fe3e4aSElliott Hughes # is Roman, but with an override that uses the ideographic baseline 186*e1fe3e4aSElliott Hughes # for uni2EA2. 187*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestBSLN-1.ttx"), ".ttf") 188*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 189*e1fe3e4aSElliott Hughes subset.main( 190*e1fe3e4aSElliott Hughes [fontpath, "--unicodes=U+0030-0031,U+2EA2", "--output-file=%s" % subsetpath] 191*e1fe3e4aSElliott Hughes ) 192*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 193*e1fe3e4aSElliott Hughes self.expect_ttx(subsetfont, self.getpath("expect_bsln_1.ttx"), ["bsln"]) 194*e1fe3e4aSElliott Hughes 195*e1fe3e4aSElliott Hughes def test_subset_bsln_format_2(self): 196*e1fe3e4aSElliott Hughes # The 'bsln' table in TestBSLN-2 refers to control points in glyph 'P' 197*e1fe3e4aSElliott Hughes # for defining its baselines. Therefore, the subsetted font should 198*e1fe3e4aSElliott Hughes # include this glyph even though it is not requested explicitly. 199*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestBSLN-2.ttx"), ".ttf") 200*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 201*e1fe3e4aSElliott Hughes subset.main([fontpath, "--glyphs=one", "--output-file=%s" % subsetpath]) 202*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 203*e1fe3e4aSElliott Hughes self.expect_ttx(subsetfont, self.getpath("expect_bsln_2.ttx"), ["bsln"]) 204*e1fe3e4aSElliott Hughes 205*e1fe3e4aSElliott Hughes def test_subset_bsln_format_2_from_format_3(self): 206*e1fe3e4aSElliott Hughes # TestBSLN-3 defines the ideographic baseline to be the font's default, 207*e1fe3e4aSElliott Hughes # and specifies that glyphs {.notdef, zero, one, two, P} use the roman 208*e1fe3e4aSElliott Hughes # baseline instead of the default ideographic baseline. As we request 209*e1fe3e4aSElliott Hughes # a subsetted font with zero and the implicit .notdef and P for 210*e1fe3e4aSElliott Hughes # baseline measurement, all glyphs in the resulting font use the Roman 211*e1fe3e4aSElliott Hughes # baseline. In this case, we expect a format 2 'bsln' table because it 212*e1fe3e4aSElliott Hughes # is the most compact encoding. 213*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestBSLN-3.ttx"), ".ttf") 214*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 215*e1fe3e4aSElliott Hughes subset.main([fontpath, "--unicodes=U+0030", "--output-file=%s" % subsetpath]) 216*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 217*e1fe3e4aSElliott Hughes self.expect_ttx(subsetfont, self.getpath("expect_bsln_2.ttx"), ["bsln"]) 218*e1fe3e4aSElliott Hughes 219*e1fe3e4aSElliott Hughes def test_subset_bsln_format_3(self): 220*e1fe3e4aSElliott Hughes # TestBSLN-3 defines the ideographic baseline to be the font's default, 221*e1fe3e4aSElliott Hughes # and specifies that glyphs {.notdef, zero, one, two} use the roman 222*e1fe3e4aSElliott Hughes # baseline instead of the default ideographic baseline. We request 223*e1fe3e4aSElliott Hughes # a subset where the majority of glyphs use the roman baseline, 224*e1fe3e4aSElliott Hughes # but one single glyph (uni2EA2) is ideographic. In the resulting 225*e1fe3e4aSElliott Hughes # subsetted font, we expect a format 1 'bsln' table whose default 226*e1fe3e4aSElliott Hughes # is Roman, but with an override that uses the ideographic baseline 227*e1fe3e4aSElliott Hughes # for uni2EA2. 228*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestBSLN-3.ttx"), ".ttf") 229*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 230*e1fe3e4aSElliott Hughes subset.main( 231*e1fe3e4aSElliott Hughes [fontpath, "--unicodes=U+0030-0031,U+2EA2", "--output-file=%s" % subsetpath] 232*e1fe3e4aSElliott Hughes ) 233*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 234*e1fe3e4aSElliott Hughes self.expect_ttx(subsetfont, self.getpath("expect_bsln_3.ttx"), ["bsln"]) 235*e1fe3e4aSElliott Hughes 236*e1fe3e4aSElliott Hughes def test_subset_clr(self): 237*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestCLR-Regular.ttx"), ".ttf") 238*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 239*e1fe3e4aSElliott Hughes subset.main([fontpath, "--glyphs=smileface", "--output-file=%s" % subsetpath]) 240*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 241*e1fe3e4aSElliott Hughes self.expect_ttx( 242*e1fe3e4aSElliott Hughes subsetfont, 243*e1fe3e4aSElliott Hughes self.getpath("expect_keep_colr.ttx"), 244*e1fe3e4aSElliott Hughes ["GlyphOrder", "hmtx", "glyf", "COLR", "CPAL"], 245*e1fe3e4aSElliott Hughes ) 246*e1fe3e4aSElliott Hughes 247*e1fe3e4aSElliott Hughes def test_subset_gvar(self): 248*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestGVAR.ttx"), ".ttf") 249*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 250*e1fe3e4aSElliott Hughes subset.main( 251*e1fe3e4aSElliott Hughes [fontpath, "--unicodes=U+002B,U+2212", "--output-file=%s" % subsetpath] 252*e1fe3e4aSElliott Hughes ) 253*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 254*e1fe3e4aSElliott Hughes self.expect_ttx( 255*e1fe3e4aSElliott Hughes subsetfont, 256*e1fe3e4aSElliott Hughes self.getpath("expect_keep_gvar.ttx"), 257*e1fe3e4aSElliott Hughes ["GlyphOrder", "avar", "fvar", "gvar", "name"], 258*e1fe3e4aSElliott Hughes ) 259*e1fe3e4aSElliott Hughes 260*e1fe3e4aSElliott Hughes def test_subset_gvar_notdef_outline(self): 261*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestGVAR.ttx"), ".ttf") 262*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 263*e1fe3e4aSElliott Hughes subset.main( 264*e1fe3e4aSElliott Hughes [ 265*e1fe3e4aSElliott Hughes fontpath, 266*e1fe3e4aSElliott Hughes "--unicodes=U+0030", 267*e1fe3e4aSElliott Hughes "--notdef_outline", 268*e1fe3e4aSElliott Hughes "--output-file=%s" % subsetpath, 269*e1fe3e4aSElliott Hughes ] 270*e1fe3e4aSElliott Hughes ) 271*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 272*e1fe3e4aSElliott Hughes self.expect_ttx( 273*e1fe3e4aSElliott Hughes subsetfont, 274*e1fe3e4aSElliott Hughes self.getpath("expect_keep_gvar_notdef_outline.ttx"), 275*e1fe3e4aSElliott Hughes ["GlyphOrder", "avar", "fvar", "gvar", "name"], 276*e1fe3e4aSElliott Hughes ) 277*e1fe3e4aSElliott Hughes 278*e1fe3e4aSElliott Hughes def test_subset_lcar_remove(self): 279*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestLCAR-0.ttx"), ".ttf") 280*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 281*e1fe3e4aSElliott Hughes subset.main([fontpath, "--glyphs=one", "--output-file=%s" % subsetpath]) 282*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 283*e1fe3e4aSElliott Hughes assert "lcar" not in subsetfont 284*e1fe3e4aSElliott Hughes 285*e1fe3e4aSElliott Hughes def test_subset_lcar_format_0(self): 286*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestLCAR-0.ttx"), ".ttf") 287*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 288*e1fe3e4aSElliott Hughes subset.main([fontpath, "--unicodes=U+FB01", "--output-file=%s" % subsetpath]) 289*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 290*e1fe3e4aSElliott Hughes self.expect_ttx(subsetfont, self.getpath("expect_lcar_0.ttx"), ["lcar"]) 291*e1fe3e4aSElliott Hughes 292*e1fe3e4aSElliott Hughes def test_subset_lcar_format_1(self): 293*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestLCAR-1.ttx"), ".ttf") 294*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 295*e1fe3e4aSElliott Hughes subset.main([fontpath, "--unicodes=U+FB01", "--output-file=%s" % subsetpath]) 296*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 297*e1fe3e4aSElliott Hughes self.expect_ttx(subsetfont, self.getpath("expect_lcar_1.ttx"), ["lcar"]) 298*e1fe3e4aSElliott Hughes 299*e1fe3e4aSElliott Hughes def test_subset_math(self): 300*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestMATH-Regular.ttx"), ".ttf") 301*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 302*e1fe3e4aSElliott Hughes subset.main( 303*e1fe3e4aSElliott Hughes [ 304*e1fe3e4aSElliott Hughes fontpath, 305*e1fe3e4aSElliott Hughes "--unicodes=U+0041,U+0028,U+0302,U+1D400,U+1D435", 306*e1fe3e4aSElliott Hughes "--output-file=%s" % subsetpath, 307*e1fe3e4aSElliott Hughes ] 308*e1fe3e4aSElliott Hughes ) 309*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 310*e1fe3e4aSElliott Hughes self.expect_ttx( 311*e1fe3e4aSElliott Hughes subsetfont, 312*e1fe3e4aSElliott Hughes self.getpath("expect_keep_math.ttx"), 313*e1fe3e4aSElliott Hughes ["GlyphOrder", "CFF ", "MATH", "hmtx"], 314*e1fe3e4aSElliott Hughes ) 315*e1fe3e4aSElliott Hughes 316*e1fe3e4aSElliott Hughes def test_subset_math_partial(self): 317*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("test_math_partial.ttx"), ".ttf") 318*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 319*e1fe3e4aSElliott Hughes subset.main([fontpath, "--text=A", "--output-file=%s" % subsetpath]) 320*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 321*e1fe3e4aSElliott Hughes self.expect_ttx(subsetfont, self.getpath("expect_math_partial.ttx"), ["MATH"]) 322*e1fe3e4aSElliott Hughes 323*e1fe3e4aSElliott Hughes def test_subset_opbd_remove(self): 324*e1fe3e4aSElliott Hughes # In the test font, only the glyphs 'A' and 'zero' have an entry in 325*e1fe3e4aSElliott Hughes # the Optical Bounds table. When subsetting, we do not request any 326*e1fe3e4aSElliott Hughes # of those glyphs. Therefore, the produced subsetted font should 327*e1fe3e4aSElliott Hughes # not contain an 'opbd' table. 328*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestOPBD-0.ttx"), ".ttf") 329*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 330*e1fe3e4aSElliott Hughes subset.main([fontpath, "--glyphs=one", "--output-file=%s" % subsetpath]) 331*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 332*e1fe3e4aSElliott Hughes assert "opbd" not in subsetfont 333*e1fe3e4aSElliott Hughes 334*e1fe3e4aSElliott Hughes def test_subset_opbd_format_0(self): 335*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestOPBD-0.ttx"), ".ttf") 336*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 337*e1fe3e4aSElliott Hughes subset.main([fontpath, "--glyphs=A", "--output-file=%s" % subsetpath]) 338*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 339*e1fe3e4aSElliott Hughes self.expect_ttx(subsetfont, self.getpath("expect_opbd_0.ttx"), ["opbd"]) 340*e1fe3e4aSElliott Hughes 341*e1fe3e4aSElliott Hughes def test_subset_opbd_format_1(self): 342*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestOPBD-1.ttx"), ".ttf") 343*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 344*e1fe3e4aSElliott Hughes subset.main([fontpath, "--glyphs=A", "--output-file=%s" % subsetpath]) 345*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 346*e1fe3e4aSElliott Hughes self.expect_ttx(subsetfont, self.getpath("expect_opbd_1.ttx"), ["opbd"]) 347*e1fe3e4aSElliott Hughes 348*e1fe3e4aSElliott Hughes def test_subset_prop_remove_default_zero(self): 349*e1fe3e4aSElliott Hughes # If all glyphs have an AAT glyph property with value 0, 350*e1fe3e4aSElliott Hughes # the "prop" table should be removed from the subsetted font. 351*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestPROP.ttx"), ".ttf") 352*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 353*e1fe3e4aSElliott Hughes subset.main([fontpath, "--unicodes=U+0041", "--output-file=%s" % subsetpath]) 354*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 355*e1fe3e4aSElliott Hughes assert "prop" not in subsetfont 356*e1fe3e4aSElliott Hughes 357*e1fe3e4aSElliott Hughes def test_subset_prop_0(self): 358*e1fe3e4aSElliott Hughes # If all glyphs share the same AAT glyph properties, the "prop" table 359*e1fe3e4aSElliott Hughes # in the subsetted font should use format 0. 360*e1fe3e4aSElliott Hughes # 361*e1fe3e4aSElliott Hughes # Unless the shared value is zero, in which case the subsetted font 362*e1fe3e4aSElliott Hughes # should have no "prop" table at all. But that case has already been 363*e1fe3e4aSElliott Hughes # tested above in test_subset_prop_remove_default_zero(). 364*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestPROP.ttx"), ".ttf") 365*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 366*e1fe3e4aSElliott Hughes subset.main( 367*e1fe3e4aSElliott Hughes [ 368*e1fe3e4aSElliott Hughes fontpath, 369*e1fe3e4aSElliott Hughes "--unicodes=U+0030-0032", 370*e1fe3e4aSElliott Hughes "--no-notdef-glyph", 371*e1fe3e4aSElliott Hughes "--output-file=%s" % subsetpath, 372*e1fe3e4aSElliott Hughes ] 373*e1fe3e4aSElliott Hughes ) 374*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 375*e1fe3e4aSElliott Hughes self.expect_ttx(subsetfont, self.getpath("expect_prop_0.ttx"), ["prop"]) 376*e1fe3e4aSElliott Hughes 377*e1fe3e4aSElliott Hughes def test_subset_prop_1(self): 378*e1fe3e4aSElliott Hughes # If not all glyphs share the same AAT glyph properties, the subsetted 379*e1fe3e4aSElliott Hughes # font should contain a "prop" table in format 1. To save space, the 380*e1fe3e4aSElliott Hughes # DefaultProperties should be set to the most frequent value. 381*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestPROP.ttx"), ".ttf") 382*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 383*e1fe3e4aSElliott Hughes subset.main( 384*e1fe3e4aSElliott Hughes [ 385*e1fe3e4aSElliott Hughes fontpath, 386*e1fe3e4aSElliott Hughes "--unicodes=U+0030-0032", 387*e1fe3e4aSElliott Hughes "--notdef-outline", 388*e1fe3e4aSElliott Hughes "--output-file=%s" % subsetpath, 389*e1fe3e4aSElliott Hughes ] 390*e1fe3e4aSElliott Hughes ) 391*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 392*e1fe3e4aSElliott Hughes self.expect_ttx(subsetfont, self.getpath("expect_prop_1.ttx"), ["prop"]) 393*e1fe3e4aSElliott Hughes 394*e1fe3e4aSElliott Hughes def test_options(self): 395*e1fe3e4aSElliott Hughes # https://github.com/fonttools/fonttools/issues/413 396*e1fe3e4aSElliott Hughes opt1 = subset.Options() 397*e1fe3e4aSElliott Hughes assert "Xyz-" not in opt1.layout_features 398*e1fe3e4aSElliott Hughes opt2 = subset.Options() 399*e1fe3e4aSElliott Hughes opt2.layout_features.append("Xyz-") 400*e1fe3e4aSElliott Hughes assert "Xyz-" in opt2.layout_features 401*e1fe3e4aSElliott Hughes assert "Xyz-" not in opt1.layout_features 402*e1fe3e4aSElliott Hughes 403*e1fe3e4aSElliott Hughes def test_google_color(self): 404*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("google_color.ttx"), ".ttf") 405*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 406*e1fe3e4aSElliott Hughes subset.main([fontpath, "--gids=0,1", "--output-file=%s" % subsetpath]) 407*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 408*e1fe3e4aSElliott Hughes assert "CBDT" in subsetfont 409*e1fe3e4aSElliott Hughes assert "CBLC" in subsetfont 410*e1fe3e4aSElliott Hughes assert "x" in subsetfont["CBDT"].strikeData[0] 411*e1fe3e4aSElliott Hughes assert "y" not in subsetfont["CBDT"].strikeData[0] 412*e1fe3e4aSElliott Hughes 413*e1fe3e4aSElliott Hughes def test_google_color_all(self): 414*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("google_color.ttx"), ".ttf") 415*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 416*e1fe3e4aSElliott Hughes subset.main([fontpath, "--unicodes=*", "--output-file=%s" % subsetpath]) 417*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 418*e1fe3e4aSElliott Hughes assert "x" in subsetfont["CBDT"].strikeData[0] 419*e1fe3e4aSElliott Hughes assert "y" in subsetfont["CBDT"].strikeData[0] 420*e1fe3e4aSElliott Hughes 421*e1fe3e4aSElliott Hughes def test_sbix(self): 422*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("sbix.ttx"), ".ttf") 423*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 424*e1fe3e4aSElliott Hughes subset.main([fontpath, "--gids=0,1", "--output-file=%s" % subsetpath]) 425*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 426*e1fe3e4aSElliott Hughes self.expect_ttx(subsetfont, self.getpath("expect_sbix.ttx"), ["sbix"]) 427*e1fe3e4aSElliott Hughes 428*e1fe3e4aSElliott Hughes def test_varComposite(self): 429*e1fe3e4aSElliott Hughes fontpath = self.getpath("..", "..", "ttLib", "data", "varc-ac00-ac01.ttf") 430*e1fe3e4aSElliott Hughes origfont = TTFont(fontpath) 431*e1fe3e4aSElliott Hughes assert len(origfont.getGlyphOrder()) == 6 432*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 433*e1fe3e4aSElliott Hughes subset.main([fontpath, "--unicodes=ac00", "--output-file=%s" % subsetpath]) 434*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 435*e1fe3e4aSElliott Hughes assert len(subsetfont.getGlyphOrder()) == 4 436*e1fe3e4aSElliott Hughes subset.main([fontpath, "--unicodes=ac01", "--output-file=%s" % subsetpath]) 437*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 438*e1fe3e4aSElliott Hughes assert len(subsetfont.getGlyphOrder()) == 5 439*e1fe3e4aSElliott Hughes 440*e1fe3e4aSElliott Hughes def test_timing_publishes_parts(self): 441*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestTTF-Regular.ttx"), ".ttf") 442*e1fe3e4aSElliott Hughes 443*e1fe3e4aSElliott Hughes options = subset.Options() 444*e1fe3e4aSElliott Hughes options.timing = True 445*e1fe3e4aSElliott Hughes subsetter = subset.Subsetter(options) 446*e1fe3e4aSElliott Hughes subsetter.populate(text="ABC") 447*e1fe3e4aSElliott Hughes font = TTFont(fontpath) 448*e1fe3e4aSElliott Hughes with CapturingLogHandler("fontTools.subset.timer", logging.DEBUG) as captor: 449*e1fe3e4aSElliott Hughes subsetter.subset(font) 450*e1fe3e4aSElliott Hughes logs = captor.records 451*e1fe3e4aSElliott Hughes 452*e1fe3e4aSElliott Hughes assert len(logs) > 5 453*e1fe3e4aSElliott Hughes assert len(logs) == len( 454*e1fe3e4aSElliott Hughes [l for l in logs if "msg" in l.args and "time" in l.args] 455*e1fe3e4aSElliott Hughes ) 456*e1fe3e4aSElliott Hughes # Look for a few things we know should happen 457*e1fe3e4aSElliott Hughes assert filter(lambda l: l.args["msg"] == "load 'cmap'", logs) 458*e1fe3e4aSElliott Hughes assert filter(lambda l: l.args["msg"] == "subset 'cmap'", logs) 459*e1fe3e4aSElliott Hughes assert filter(lambda l: l.args["msg"] == "subset 'glyf'", logs) 460*e1fe3e4aSElliott Hughes 461*e1fe3e4aSElliott Hughes def test_passthrough_tables(self): 462*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestTTF-Regular.ttx"), ".ttf") 463*e1fe3e4aSElliott Hughes font = TTFont(fontpath) 464*e1fe3e4aSElliott Hughes unknown_tag = "ZZZZ" 465*e1fe3e4aSElliott Hughes unknown_table = newTable(unknown_tag) 466*e1fe3e4aSElliott Hughes unknown_table.data = b"\0" * 10 467*e1fe3e4aSElliott Hughes font[unknown_tag] = unknown_table 468*e1fe3e4aSElliott Hughes font.save(fontpath) 469*e1fe3e4aSElliott Hughes 470*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 471*e1fe3e4aSElliott Hughes subset.main([fontpath, "--output-file=%s" % subsetpath]) 472*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 473*e1fe3e4aSElliott Hughes 474*e1fe3e4aSElliott Hughes # tables we can't subset are dropped by default 475*e1fe3e4aSElliott Hughes assert unknown_tag not in subsetfont 476*e1fe3e4aSElliott Hughes 477*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 478*e1fe3e4aSElliott Hughes subset.main([fontpath, "--passthrough-tables", "--output-file=%s" % subsetpath]) 479*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 480*e1fe3e4aSElliott Hughes 481*e1fe3e4aSElliott Hughes # unknown tables are kept if --passthrough-tables option is passed 482*e1fe3e4aSElliott Hughes assert unknown_tag in subsetfont 483*e1fe3e4aSElliott Hughes 484*e1fe3e4aSElliott Hughes def test_non_BMP_text_arg_input(self): 485*e1fe3e4aSElliott Hughes fontpath = self.compile_font( 486*e1fe3e4aSElliott Hughes self.getpath("TestTTF-Regular_non_BMP_char.ttx"), ".ttf" 487*e1fe3e4aSElliott Hughes ) 488*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 489*e1fe3e4aSElliott Hughes text = tostr("A\U0001F6D2", encoding="utf-8") 490*e1fe3e4aSElliott Hughes 491*e1fe3e4aSElliott Hughes subset.main([fontpath, "--text=%s" % text, "--output-file=%s" % subsetpath]) 492*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 493*e1fe3e4aSElliott Hughes 494*e1fe3e4aSElliott Hughes assert subsetfont["maxp"].numGlyphs == 3 495*e1fe3e4aSElliott Hughes assert subsetfont.getGlyphOrder() == [".notdef", "A", "u1F6D2"] 496*e1fe3e4aSElliott Hughes 497*e1fe3e4aSElliott Hughes def test_non_BMP_text_file_input(self): 498*e1fe3e4aSElliott Hughes fontpath = self.compile_font( 499*e1fe3e4aSElliott Hughes self.getpath("TestTTF-Regular_non_BMP_char.ttx"), ".ttf" 500*e1fe3e4aSElliott Hughes ) 501*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 502*e1fe3e4aSElliott Hughes text = tobytes("A\U0001F6D2", encoding="utf-8") 503*e1fe3e4aSElliott Hughes with tempfile.NamedTemporaryFile(delete=False) as tmp: 504*e1fe3e4aSElliott Hughes tmp.write(text) 505*e1fe3e4aSElliott Hughes 506*e1fe3e4aSElliott Hughes try: 507*e1fe3e4aSElliott Hughes subset.main( 508*e1fe3e4aSElliott Hughes [fontpath, "--text-file=%s" % tmp.name, "--output-file=%s" % subsetpath] 509*e1fe3e4aSElliott Hughes ) 510*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 511*e1fe3e4aSElliott Hughes finally: 512*e1fe3e4aSElliott Hughes os.remove(tmp.name) 513*e1fe3e4aSElliott Hughes 514*e1fe3e4aSElliott Hughes assert subsetfont["maxp"].numGlyphs == 3 515*e1fe3e4aSElliott Hughes assert subsetfont.getGlyphOrder() == [".notdef", "A", "u1F6D2"] 516*e1fe3e4aSElliott Hughes 517*e1fe3e4aSElliott Hughes def test_no_hinting_CFF(self): 518*e1fe3e4aSElliott Hughes ttxpath = self.getpath("Lobster.subset.ttx") 519*e1fe3e4aSElliott Hughes fontpath = self.compile_font(ttxpath, ".otf") 520*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".otf") 521*e1fe3e4aSElliott Hughes subset.main( 522*e1fe3e4aSElliott Hughes [ 523*e1fe3e4aSElliott Hughes fontpath, 524*e1fe3e4aSElliott Hughes "--no-hinting", 525*e1fe3e4aSElliott Hughes "--notdef-outline", 526*e1fe3e4aSElliott Hughes "--output-file=%s" % subsetpath, 527*e1fe3e4aSElliott Hughes "*", 528*e1fe3e4aSElliott Hughes ] 529*e1fe3e4aSElliott Hughes ) 530*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 531*e1fe3e4aSElliott Hughes self.expect_ttx(subsetfont, self.getpath("expect_no_hinting_CFF.ttx"), ["CFF "]) 532*e1fe3e4aSElliott Hughes 533*e1fe3e4aSElliott Hughes def test_desubroutinize_CFF(self): 534*e1fe3e4aSElliott Hughes ttxpath = self.getpath("Lobster.subset.ttx") 535*e1fe3e4aSElliott Hughes fontpath = self.compile_font(ttxpath, ".otf") 536*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".otf") 537*e1fe3e4aSElliott Hughes subset.main( 538*e1fe3e4aSElliott Hughes [ 539*e1fe3e4aSElliott Hughes fontpath, 540*e1fe3e4aSElliott Hughes "--desubroutinize", 541*e1fe3e4aSElliott Hughes "--notdef-outline", 542*e1fe3e4aSElliott Hughes "--output-file=%s" % subsetpath, 543*e1fe3e4aSElliott Hughes "*", 544*e1fe3e4aSElliott Hughes ] 545*e1fe3e4aSElliott Hughes ) 546*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 547*e1fe3e4aSElliott Hughes self.expect_ttx( 548*e1fe3e4aSElliott Hughes subsetfont, self.getpath("expect_desubroutinize_CFF.ttx"), ["CFF "] 549*e1fe3e4aSElliott Hughes ) 550*e1fe3e4aSElliott Hughes 551*e1fe3e4aSElliott Hughes def test_desubroutinize_hinted_subrs_CFF(self): 552*e1fe3e4aSElliott Hughes ttxpath = self.getpath("test_hinted_subrs_CFF.ttx") 553*e1fe3e4aSElliott Hughes fontpath = self.compile_font(ttxpath, ".otf") 554*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".otf") 555*e1fe3e4aSElliott Hughes subset.main( 556*e1fe3e4aSElliott Hughes [ 557*e1fe3e4aSElliott Hughes fontpath, 558*e1fe3e4aSElliott Hughes "--desubroutinize", 559*e1fe3e4aSElliott Hughes "--notdef-outline", 560*e1fe3e4aSElliott Hughes "--output-file=%s" % subsetpath, 561*e1fe3e4aSElliott Hughes "*", 562*e1fe3e4aSElliott Hughes ] 563*e1fe3e4aSElliott Hughes ) 564*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 565*e1fe3e4aSElliott Hughes self.expect_ttx( 566*e1fe3e4aSElliott Hughes subsetfont, self.getpath("test_hinted_subrs_CFF.desub.ttx"), ["CFF "] 567*e1fe3e4aSElliott Hughes ) 568*e1fe3e4aSElliott Hughes 569*e1fe3e4aSElliott Hughes def test_desubroutinize_cntrmask_CFF(self): 570*e1fe3e4aSElliott Hughes ttxpath = self.getpath("test_cntrmask_CFF.ttx") 571*e1fe3e4aSElliott Hughes fontpath = self.compile_font(ttxpath, ".otf") 572*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".otf") 573*e1fe3e4aSElliott Hughes subset.main( 574*e1fe3e4aSElliott Hughes [ 575*e1fe3e4aSElliott Hughes fontpath, 576*e1fe3e4aSElliott Hughes "--desubroutinize", 577*e1fe3e4aSElliott Hughes "--notdef-outline", 578*e1fe3e4aSElliott Hughes "--output-file=%s" % subsetpath, 579*e1fe3e4aSElliott Hughes "*", 580*e1fe3e4aSElliott Hughes ] 581*e1fe3e4aSElliott Hughes ) 582*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 583*e1fe3e4aSElliott Hughes self.expect_ttx( 584*e1fe3e4aSElliott Hughes subsetfont, self.getpath("test_cntrmask_CFF.desub.ttx"), ["CFF "] 585*e1fe3e4aSElliott Hughes ) 586*e1fe3e4aSElliott Hughes 587*e1fe3e4aSElliott Hughes def test_no_hinting_desubroutinize_CFF(self): 588*e1fe3e4aSElliott Hughes ttxpath = self.getpath("test_hinted_subrs_CFF.ttx") 589*e1fe3e4aSElliott Hughes fontpath = self.compile_font(ttxpath, ".otf") 590*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".otf") 591*e1fe3e4aSElliott Hughes subset.main( 592*e1fe3e4aSElliott Hughes [ 593*e1fe3e4aSElliott Hughes fontpath, 594*e1fe3e4aSElliott Hughes "--no-hinting", 595*e1fe3e4aSElliott Hughes "--desubroutinize", 596*e1fe3e4aSElliott Hughes "--notdef-outline", 597*e1fe3e4aSElliott Hughes "--output-file=%s" % subsetpath, 598*e1fe3e4aSElliott Hughes "*", 599*e1fe3e4aSElliott Hughes ] 600*e1fe3e4aSElliott Hughes ) 601*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 602*e1fe3e4aSElliott Hughes self.expect_ttx( 603*e1fe3e4aSElliott Hughes subsetfont, 604*e1fe3e4aSElliott Hughes self.getpath("expect_no_hinting_desubroutinize_CFF.ttx"), 605*e1fe3e4aSElliott Hughes ["CFF "], 606*e1fe3e4aSElliott Hughes ) 607*e1fe3e4aSElliott Hughes 608*e1fe3e4aSElliott Hughes def test_no_hinting_TTF(self): 609*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestTTF-Regular.ttx"), ".ttf") 610*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 611*e1fe3e4aSElliott Hughes subset.main( 612*e1fe3e4aSElliott Hughes [ 613*e1fe3e4aSElliott Hughes fontpath, 614*e1fe3e4aSElliott Hughes "--no-hinting", 615*e1fe3e4aSElliott Hughes "--notdef-outline", 616*e1fe3e4aSElliott Hughes "--output-file=%s" % subsetpath, 617*e1fe3e4aSElliott Hughes "*", 618*e1fe3e4aSElliott Hughes ] 619*e1fe3e4aSElliott Hughes ) 620*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 621*e1fe3e4aSElliott Hughes self.expect_ttx( 622*e1fe3e4aSElliott Hughes subsetfont, self.getpath("expect_no_hinting_TTF.ttx"), ["glyf", "maxp"] 623*e1fe3e4aSElliott Hughes ) 624*e1fe3e4aSElliott Hughes for tag in subset.Options().hinting_tables: 625*e1fe3e4aSElliott Hughes assert tag not in subsetfont 626*e1fe3e4aSElliott Hughes 627*e1fe3e4aSElliott Hughes def test_notdef_width_cid(self): 628*e1fe3e4aSElliott Hughes # https://github.com/fonttools/fonttools/pull/845 629*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("NotdefWidthCID-Regular.ttx"), ".otf") 630*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".otf") 631*e1fe3e4aSElliott Hughes subset.main( 632*e1fe3e4aSElliott Hughes [ 633*e1fe3e4aSElliott Hughes fontpath, 634*e1fe3e4aSElliott Hughes "--no-notdef-outline", 635*e1fe3e4aSElliott Hughes "--gids=0,1", 636*e1fe3e4aSElliott Hughes "--output-file=%s" % subsetpath, 637*e1fe3e4aSElliott Hughes ] 638*e1fe3e4aSElliott Hughes ) 639*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 640*e1fe3e4aSElliott Hughes self.expect_ttx( 641*e1fe3e4aSElliott Hughes subsetfont, self.getpath("expect_notdef_width_cid.ttx"), ["CFF "] 642*e1fe3e4aSElliott Hughes ) 643*e1fe3e4aSElliott Hughes 644*e1fe3e4aSElliott Hughes def test_recalc_bounds_ttf(self): 645*e1fe3e4aSElliott Hughes ttxpath = self.getpath("TestTTF-Regular.ttx") 646*e1fe3e4aSElliott Hughes font = TTFont() 647*e1fe3e4aSElliott Hughes font.importXML(ttxpath) 648*e1fe3e4aSElliott Hughes head = font["head"] 649*e1fe3e4aSElliott Hughes bounds = [head.xMin, head.yMin, head.xMax, head.yMax] 650*e1fe3e4aSElliott Hughes 651*e1fe3e4aSElliott Hughes fontpath = self.compile_font(ttxpath, ".ttf") 652*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 653*e1fe3e4aSElliott Hughes 654*e1fe3e4aSElliott Hughes # by default, the subsetter does not recalculate the bounding box 655*e1fe3e4aSElliott Hughes subset.main([fontpath, "--output-file=%s" % subsetpath, "*"]) 656*e1fe3e4aSElliott Hughes head = TTFont(subsetpath)["head"] 657*e1fe3e4aSElliott Hughes assert bounds == [head.xMin, head.yMin, head.xMax, head.yMax] 658*e1fe3e4aSElliott Hughes 659*e1fe3e4aSElliott Hughes subset.main([fontpath, "--recalc-bounds", "--output-file=%s" % subsetpath, "*"]) 660*e1fe3e4aSElliott Hughes head = TTFont(subsetpath)["head"] 661*e1fe3e4aSElliott Hughes bounds = [132, 304, 365, 567] 662*e1fe3e4aSElliott Hughes assert bounds == [head.xMin, head.yMin, head.xMax, head.yMax] 663*e1fe3e4aSElliott Hughes 664*e1fe3e4aSElliott Hughes def test_recalc_bounds_otf(self): 665*e1fe3e4aSElliott Hughes ttxpath = self.getpath("TestOTF-Regular.ttx") 666*e1fe3e4aSElliott Hughes font = TTFont() 667*e1fe3e4aSElliott Hughes font.importXML(ttxpath) 668*e1fe3e4aSElliott Hughes head = font["head"] 669*e1fe3e4aSElliott Hughes bounds = [head.xMin, head.yMin, head.xMax, head.yMax] 670*e1fe3e4aSElliott Hughes 671*e1fe3e4aSElliott Hughes fontpath = self.compile_font(ttxpath, ".otf") 672*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".otf") 673*e1fe3e4aSElliott Hughes 674*e1fe3e4aSElliott Hughes # by default, the subsetter does not recalculate the bounding box 675*e1fe3e4aSElliott Hughes subset.main([fontpath, "--output-file=%s" % subsetpath, "*"]) 676*e1fe3e4aSElliott Hughes head = TTFont(subsetpath)["head"] 677*e1fe3e4aSElliott Hughes assert bounds == [head.xMin, head.yMin, head.xMax, head.yMax] 678*e1fe3e4aSElliott Hughes 679*e1fe3e4aSElliott Hughes subset.main([fontpath, "--recalc-bounds", "--output-file=%s" % subsetpath, "*"]) 680*e1fe3e4aSElliott Hughes head = TTFont(subsetpath)["head"] 681*e1fe3e4aSElliott Hughes bounds = [132, 304, 365, 567] 682*e1fe3e4aSElliott Hughes assert bounds == [head.xMin, head.yMin, head.xMax, head.yMax] 683*e1fe3e4aSElliott Hughes 684*e1fe3e4aSElliott Hughes def test_recalc_timestamp_ttf(self): 685*e1fe3e4aSElliott Hughes ttxpath = self.getpath("TestTTF-Regular.ttx") 686*e1fe3e4aSElliott Hughes font = TTFont() 687*e1fe3e4aSElliott Hughes font.importXML(ttxpath) 688*e1fe3e4aSElliott Hughes modified = font["head"].modified 689*e1fe3e4aSElliott Hughes fontpath = self.compile_font(ttxpath, ".ttf") 690*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 691*e1fe3e4aSElliott Hughes 692*e1fe3e4aSElliott Hughes # by default, the subsetter does not recalculate the modified timestamp 693*e1fe3e4aSElliott Hughes subset.main([fontpath, "--output-file=%s" % subsetpath, "*"]) 694*e1fe3e4aSElliott Hughes assert modified == TTFont(subsetpath)["head"].modified 695*e1fe3e4aSElliott Hughes 696*e1fe3e4aSElliott Hughes subset.main( 697*e1fe3e4aSElliott Hughes [fontpath, "--recalc-timestamp", "--output-file=%s" % subsetpath, "*"] 698*e1fe3e4aSElliott Hughes ) 699*e1fe3e4aSElliott Hughes assert modified < TTFont(subsetpath)["head"].modified 700*e1fe3e4aSElliott Hughes 701*e1fe3e4aSElliott Hughes def test_recalc_timestamp_otf(self): 702*e1fe3e4aSElliott Hughes ttxpath = self.getpath("TestOTF-Regular.ttx") 703*e1fe3e4aSElliott Hughes font = TTFont() 704*e1fe3e4aSElliott Hughes font.importXML(ttxpath) 705*e1fe3e4aSElliott Hughes modified = font["head"].modified 706*e1fe3e4aSElliott Hughes fontpath = self.compile_font(ttxpath, ".otf") 707*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".otf") 708*e1fe3e4aSElliott Hughes 709*e1fe3e4aSElliott Hughes # by default, the subsetter does not recalculate the modified timestamp 710*e1fe3e4aSElliott Hughes subset.main([fontpath, "--output-file=%s" % subsetpath, "*"]) 711*e1fe3e4aSElliott Hughes assert modified == TTFont(subsetpath)["head"].modified 712*e1fe3e4aSElliott Hughes 713*e1fe3e4aSElliott Hughes subset.main( 714*e1fe3e4aSElliott Hughes [fontpath, "--recalc-timestamp", "--output-file=%s" % subsetpath, "*"] 715*e1fe3e4aSElliott Hughes ) 716*e1fe3e4aSElliott Hughes assert modified < TTFont(subsetpath)["head"].modified 717*e1fe3e4aSElliott Hughes 718*e1fe3e4aSElliott Hughes def test_recalc_max_context(self): 719*e1fe3e4aSElliott Hughes ttxpath = self.getpath("Lobster.subset.ttx") 720*e1fe3e4aSElliott Hughes font = TTFont() 721*e1fe3e4aSElliott Hughes font.importXML(ttxpath) 722*e1fe3e4aSElliott Hughes max_context = font["OS/2"].usMaxContext 723*e1fe3e4aSElliott Hughes fontpath = self.compile_font(ttxpath, ".otf") 724*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".otf") 725*e1fe3e4aSElliott Hughes 726*e1fe3e4aSElliott Hughes # by default, the subsetter does not recalculate the usMaxContext 727*e1fe3e4aSElliott Hughes subset.main( 728*e1fe3e4aSElliott Hughes [fontpath, "--drop-tables+=GSUB,GPOS", "--output-file=%s" % subsetpath] 729*e1fe3e4aSElliott Hughes ) 730*e1fe3e4aSElliott Hughes assert max_context == TTFont(subsetpath)["OS/2"].usMaxContext 731*e1fe3e4aSElliott Hughes 732*e1fe3e4aSElliott Hughes subset.main( 733*e1fe3e4aSElliott Hughes [ 734*e1fe3e4aSElliott Hughes fontpath, 735*e1fe3e4aSElliott Hughes "--recalc-max-context", 736*e1fe3e4aSElliott Hughes "--drop-tables+=GSUB,GPOS", 737*e1fe3e4aSElliott Hughes "--output-file=%s" % subsetpath, 738*e1fe3e4aSElliott Hughes ] 739*e1fe3e4aSElliott Hughes ) 740*e1fe3e4aSElliott Hughes assert 0 == TTFont(subsetpath)["OS/2"].usMaxContext 741*e1fe3e4aSElliott Hughes 742*e1fe3e4aSElliott Hughes def test_retain_gids_ttf(self): 743*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestTTF-Regular.ttx"), ".ttf") 744*e1fe3e4aSElliott Hughes font = TTFont(fontpath) 745*e1fe3e4aSElliott Hughes 746*e1fe3e4aSElliott Hughes assert font["hmtx"]["A"] == (500, 132) 747*e1fe3e4aSElliott Hughes assert font["hmtx"]["B"] == (400, 132) 748*e1fe3e4aSElliott Hughes 749*e1fe3e4aSElliott Hughes assert font["glyf"]["A"].numberOfContours > 0 750*e1fe3e4aSElliott Hughes assert font["glyf"]["B"].numberOfContours > 0 751*e1fe3e4aSElliott Hughes 752*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 753*e1fe3e4aSElliott Hughes subset.main( 754*e1fe3e4aSElliott Hughes [ 755*e1fe3e4aSElliott Hughes fontpath, 756*e1fe3e4aSElliott Hughes "--retain-gids", 757*e1fe3e4aSElliott Hughes "--output-file=%s" % subsetpath, 758*e1fe3e4aSElliott Hughes "--glyph-names", 759*e1fe3e4aSElliott Hughes "B", 760*e1fe3e4aSElliott Hughes ] 761*e1fe3e4aSElliott Hughes ) 762*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 763*e1fe3e4aSElliott Hughes 764*e1fe3e4aSElliott Hughes assert subsetfont.getGlyphOrder() == font.getGlyphOrder()[0:3] 765*e1fe3e4aSElliott Hughes 766*e1fe3e4aSElliott Hughes hmtx = subsetfont["hmtx"] 767*e1fe3e4aSElliott Hughes assert hmtx["A"] == (0, 0) 768*e1fe3e4aSElliott Hughes assert hmtx["B"] == (400, 132) 769*e1fe3e4aSElliott Hughes 770*e1fe3e4aSElliott Hughes glyf = subsetfont["glyf"] 771*e1fe3e4aSElliott Hughes assert glyf["A"].numberOfContours == 0 772*e1fe3e4aSElliott Hughes assert glyf["B"].numberOfContours > 0 773*e1fe3e4aSElliott Hughes 774*e1fe3e4aSElliott Hughes def test_retain_gids_cff(self): 775*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestOTF-Regular.ttx"), ".otf") 776*e1fe3e4aSElliott Hughes font = TTFont(fontpath) 777*e1fe3e4aSElliott Hughes 778*e1fe3e4aSElliott Hughes assert font["hmtx"]["A"] == (500, 132) 779*e1fe3e4aSElliott Hughes assert font["hmtx"]["B"] == (400, 132) 780*e1fe3e4aSElliott Hughes assert font["hmtx"]["C"] == (500, 0) 781*e1fe3e4aSElliott Hughes 782*e1fe3e4aSElliott Hughes font["CFF "].cff[0].decompileAllCharStrings() 783*e1fe3e4aSElliott Hughes cs = font["CFF "].cff[0].CharStrings 784*e1fe3e4aSElliott Hughes assert len(cs["A"].program) > 0 785*e1fe3e4aSElliott Hughes assert len(cs["B"].program) > 0 786*e1fe3e4aSElliott Hughes assert len(cs["C"].program) > 0 787*e1fe3e4aSElliott Hughes 788*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".otf") 789*e1fe3e4aSElliott Hughes subset.main( 790*e1fe3e4aSElliott Hughes [ 791*e1fe3e4aSElliott Hughes fontpath, 792*e1fe3e4aSElliott Hughes "--retain-gids", 793*e1fe3e4aSElliott Hughes "--output-file=%s" % subsetpath, 794*e1fe3e4aSElliott Hughes "--glyph-names", 795*e1fe3e4aSElliott Hughes "B", 796*e1fe3e4aSElliott Hughes ] 797*e1fe3e4aSElliott Hughes ) 798*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 799*e1fe3e4aSElliott Hughes 800*e1fe3e4aSElliott Hughes assert subsetfont.getGlyphOrder() == font.getGlyphOrder()[0:3] 801*e1fe3e4aSElliott Hughes 802*e1fe3e4aSElliott Hughes hmtx = subsetfont["hmtx"] 803*e1fe3e4aSElliott Hughes assert hmtx["A"] == (0, 0) 804*e1fe3e4aSElliott Hughes assert hmtx["B"] == (400, 132) 805*e1fe3e4aSElliott Hughes 806*e1fe3e4aSElliott Hughes subsetfont["CFF "].cff[0].decompileAllCharStrings() 807*e1fe3e4aSElliott Hughes cs = subsetfont["CFF "].cff[0].CharStrings 808*e1fe3e4aSElliott Hughes 809*e1fe3e4aSElliott Hughes assert cs["A"].program == ["endchar"] 810*e1fe3e4aSElliott Hughes assert len(cs["B"].program) > 0 811*e1fe3e4aSElliott Hughes 812*e1fe3e4aSElliott Hughes def test_retain_gids_cff2(self): 813*e1fe3e4aSElliott Hughes ttx_path = self.getpath( 814*e1fe3e4aSElliott Hughes "../../varLib/data/master_ttx_varfont_otf/TestCFF2VF.ttx" 815*e1fe3e4aSElliott Hughes ) 816*e1fe3e4aSElliott Hughes fontpath = self.compile_font(ttx_path, ".otf") 817*e1fe3e4aSElliott Hughes font = TTFont(fontpath) 818*e1fe3e4aSElliott Hughes 819*e1fe3e4aSElliott Hughes assert font["hmtx"]["A"] == (600, 31) 820*e1fe3e4aSElliott Hughes assert font["hmtx"]["T"] == (600, 41) 821*e1fe3e4aSElliott Hughes 822*e1fe3e4aSElliott Hughes font["CFF2"].cff[0].decompileAllCharStrings() 823*e1fe3e4aSElliott Hughes cs = font["CFF2"].cff[0].CharStrings 824*e1fe3e4aSElliott Hughes assert len(cs["A"].program) > 0 825*e1fe3e4aSElliott Hughes assert len(cs["T"].program) > 0 826*e1fe3e4aSElliott Hughes 827*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".otf") 828*e1fe3e4aSElliott Hughes subset.main( 829*e1fe3e4aSElliott Hughes [ 830*e1fe3e4aSElliott Hughes fontpath, 831*e1fe3e4aSElliott Hughes "--retain-gids", 832*e1fe3e4aSElliott Hughes "--output-file=%s" % subsetpath, 833*e1fe3e4aSElliott Hughes "T", 834*e1fe3e4aSElliott Hughes ] 835*e1fe3e4aSElliott Hughes ) 836*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 837*e1fe3e4aSElliott Hughes 838*e1fe3e4aSElliott Hughes assert len(subsetfont.getGlyphOrder()) == len(font.getGlyphOrder()[0:3]) 839*e1fe3e4aSElliott Hughes 840*e1fe3e4aSElliott Hughes hmtx = subsetfont["hmtx"] 841*e1fe3e4aSElliott Hughes assert hmtx["glyph00001"] == (0, 0) 842*e1fe3e4aSElliott Hughes assert hmtx["T"] == (600, 41) 843*e1fe3e4aSElliott Hughes 844*e1fe3e4aSElliott Hughes subsetfont["CFF2"].cff[0].decompileAllCharStrings() 845*e1fe3e4aSElliott Hughes cs = subsetfont["CFF2"].cff[0].CharStrings 846*e1fe3e4aSElliott Hughes assert cs["glyph00001"].program == [] 847*e1fe3e4aSElliott Hughes assert len(cs["T"].program) > 0 848*e1fe3e4aSElliott Hughes 849*e1fe3e4aSElliott Hughes def test_HVAR_VVAR(self): 850*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestHVVAR.ttx"), ".ttf") 851*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 852*e1fe3e4aSElliott Hughes subset.main([fontpath, "--text=BD", "--output-file=%s" % subsetpath]) 853*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 854*e1fe3e4aSElliott Hughes self.expect_ttx( 855*e1fe3e4aSElliott Hughes subsetfont, 856*e1fe3e4aSElliott Hughes self.getpath("expect_HVVAR.ttx"), 857*e1fe3e4aSElliott Hughes ["GlyphOrder", "HVAR", "VVAR", "avar", "fvar"], 858*e1fe3e4aSElliott Hughes ) 859*e1fe3e4aSElliott Hughes 860*e1fe3e4aSElliott Hughes def test_HVAR_VVAR_retain_gids(self): 861*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestHVVAR.ttx"), ".ttf") 862*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 863*e1fe3e4aSElliott Hughes subset.main( 864*e1fe3e4aSElliott Hughes [fontpath, "--text=BD", "--retain-gids", "--output-file=%s" % subsetpath] 865*e1fe3e4aSElliott Hughes ) 866*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 867*e1fe3e4aSElliott Hughes self.expect_ttx( 868*e1fe3e4aSElliott Hughes subsetfont, 869*e1fe3e4aSElliott Hughes self.getpath("expect_HVVAR_retain_gids.ttx"), 870*e1fe3e4aSElliott Hughes ["GlyphOrder", "HVAR", "VVAR", "avar", "fvar"], 871*e1fe3e4aSElliott Hughes ) 872*e1fe3e4aSElliott Hughes 873*e1fe3e4aSElliott Hughes def test_subset_flavor_woff(self): 874*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestTTF-Regular.ttx"), ".ttf") 875*e1fe3e4aSElliott Hughes woff_path = self.temp_path(".woff") 876*e1fe3e4aSElliott Hughes 877*e1fe3e4aSElliott Hughes subset.main( 878*e1fe3e4aSElliott Hughes [ 879*e1fe3e4aSElliott Hughes fontpath, 880*e1fe3e4aSElliott Hughes "*", 881*e1fe3e4aSElliott Hughes "--flavor=woff", 882*e1fe3e4aSElliott Hughes "--output-file=%s" % woff_path, 883*e1fe3e4aSElliott Hughes ] 884*e1fe3e4aSElliott Hughes ) 885*e1fe3e4aSElliott Hughes woff = TTFont(woff_path) 886*e1fe3e4aSElliott Hughes 887*e1fe3e4aSElliott Hughes assert woff.flavor == "woff" 888*e1fe3e4aSElliott Hughes 889*e1fe3e4aSElliott Hughes def test_subset_flavor_woff2(self): 890*e1fe3e4aSElliott Hughes # skip if brotli is not importable, required for woff2 891*e1fe3e4aSElliott Hughes pytest.importorskip("brotli") 892*e1fe3e4aSElliott Hughes 893*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestTTF-Regular.ttx"), ".ttf") 894*e1fe3e4aSElliott Hughes woff2_path = self.temp_path(".woff2") 895*e1fe3e4aSElliott Hughes 896*e1fe3e4aSElliott Hughes subset.main( 897*e1fe3e4aSElliott Hughes [ 898*e1fe3e4aSElliott Hughes fontpath, 899*e1fe3e4aSElliott Hughes "*", 900*e1fe3e4aSElliott Hughes "--flavor=woff2", 901*e1fe3e4aSElliott Hughes "--output-file=%s" % woff2_path, 902*e1fe3e4aSElliott Hughes ] 903*e1fe3e4aSElliott Hughes ) 904*e1fe3e4aSElliott Hughes woff2 = TTFont(woff2_path) 905*e1fe3e4aSElliott Hughes 906*e1fe3e4aSElliott Hughes assert woff2.flavor == "woff2" 907*e1fe3e4aSElliott Hughes 908*e1fe3e4aSElliott Hughes def test_subset_flavor_none(self): 909*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("TestTTF-Regular.ttx"), ".ttf") 910*e1fe3e4aSElliott Hughes ttf_path = self.temp_path(".ttf") 911*e1fe3e4aSElliott Hughes 912*e1fe3e4aSElliott Hughes subset.main( 913*e1fe3e4aSElliott Hughes [ 914*e1fe3e4aSElliott Hughes fontpath, 915*e1fe3e4aSElliott Hughes "*", 916*e1fe3e4aSElliott Hughes "--output-file=%s" % ttf_path, 917*e1fe3e4aSElliott Hughes ] 918*e1fe3e4aSElliott Hughes ) 919*e1fe3e4aSElliott Hughes ttf = TTFont(ttf_path) 920*e1fe3e4aSElliott Hughes 921*e1fe3e4aSElliott Hughes assert ttf.flavor is None 922*e1fe3e4aSElliott Hughes 923*e1fe3e4aSElliott Hughes def test_subset_context_subst_format_3(self): 924*e1fe3e4aSElliott Hughes # https://github.com/fonttools/fonttools/issues/1879 925*e1fe3e4aSElliott Hughes # Test font contains 'calt' feature with Format 3 ContextSubst lookup subtables 926*e1fe3e4aSElliott Hughes ttx = self.getpath("TestContextSubstFormat3.ttx") 927*e1fe3e4aSElliott Hughes fontpath = self.compile_font(ttx, ".ttf") 928*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 929*e1fe3e4aSElliott Hughes subset.main([fontpath, "--unicodes=*", "--output-file=%s" % subsetpath]) 930*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 931*e1fe3e4aSElliott Hughes # check all glyphs are kept via GSUB closure, no changes expected 932*e1fe3e4aSElliott Hughes self.expect_ttx(subsetfont, ttx) 933*e1fe3e4aSElliott Hughes 934*e1fe3e4aSElliott Hughes def test_cmap_prune_format12(self): 935*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("CmapSubsetTest.ttx"), ".ttf") 936*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 937*e1fe3e4aSElliott Hughes subset.main([fontpath, "--glyphs=a", "--output-file=%s" % subsetpath]) 938*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 939*e1fe3e4aSElliott Hughes self.expect_ttx(subsetfont, self.getpath("CmapSubsetTest.subset.ttx"), ["cmap"]) 940*e1fe3e4aSElliott Hughes 941*e1fe3e4aSElliott Hughes @pytest.mark.parametrize("text, n", [("!", 1), ("#", 2)]) 942*e1fe3e4aSElliott Hughes def test_GPOS_PairPos_Format2_useClass0(self, text, n): 943*e1fe3e4aSElliott Hughes # Check two things related to class 0 ('every other glyph'): 944*e1fe3e4aSElliott Hughes # 1) that it's reused for ClassDef1 when it becomes empty as the subset glyphset 945*e1fe3e4aSElliott Hughes # is intersected with the table's Coverage 946*e1fe3e4aSElliott Hughes # 2) that it is never reused for ClassDef2 even when it happens to become empty 947*e1fe3e4aSElliott Hughes # because of the subset glyphset. In this case, we don't keep a PairPosClass2 948*e1fe3e4aSElliott Hughes # subtable if only ClassDef2's class0 survived subsetting. 949*e1fe3e4aSElliott Hughes # The test font (from Harfbuzz test suite) is constructed to trigger these two 950*e1fe3e4aSElliott Hughes # situations depending on the input subset --text. 951*e1fe3e4aSElliott Hughes # https://github.com/fonttools/fonttools/pull/2221 952*e1fe3e4aSElliott Hughes fontpath = self.compile_font( 953*e1fe3e4aSElliott Hughes self.getpath("GPOS_PairPos_Format2_PR_2221.ttx"), ".ttf" 954*e1fe3e4aSElliott Hughes ) 955*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 956*e1fe3e4aSElliott Hughes 957*e1fe3e4aSElliott Hughes expected_ttx = self.getpath( 958*e1fe3e4aSElliott Hughes f"GPOS_PairPos_Format2_ClassDef{n}_useClass0.subset.ttx" 959*e1fe3e4aSElliott Hughes ) 960*e1fe3e4aSElliott Hughes subset.main( 961*e1fe3e4aSElliott Hughes [ 962*e1fe3e4aSElliott Hughes fontpath, 963*e1fe3e4aSElliott Hughes f"--text='{text}'", 964*e1fe3e4aSElliott Hughes "--layout-features+=test", 965*e1fe3e4aSElliott Hughes "--output-file=%s" % subsetpath, 966*e1fe3e4aSElliott Hughes ] 967*e1fe3e4aSElliott Hughes ) 968*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 969*e1fe3e4aSElliott Hughes self.expect_ttx(subsetfont, expected_ttx, ["GPOS"]) 970*e1fe3e4aSElliott Hughes 971*e1fe3e4aSElliott Hughes def test_GPOS_SinglePos_prune_post_subset_no_value(self): 972*e1fe3e4aSElliott Hughes fontpath = self.compile_font( 973*e1fe3e4aSElliott Hughes self.getpath("GPOS_SinglePos_no_value_issue_2312.ttx"), ".ttf" 974*e1fe3e4aSElliott Hughes ) 975*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".ttf") 976*e1fe3e4aSElliott Hughes subset.main([fontpath, "*", "--glyph-names", "--output-file=%s" % subsetpath]) 977*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 978*e1fe3e4aSElliott Hughes self.expect_ttx( 979*e1fe3e4aSElliott Hughes subsetfont, 980*e1fe3e4aSElliott Hughes self.getpath("GPOS_SinglePos_no_value_issue_2312.subset.ttx"), 981*e1fe3e4aSElliott Hughes ["GlyphOrder", "GPOS"], 982*e1fe3e4aSElliott Hughes ) 983*e1fe3e4aSElliott Hughes 984*e1fe3e4aSElliott Hughes @pytest.mark.parametrize( 985*e1fe3e4aSElliott Hughes "installed, enabled, ok", 986*e1fe3e4aSElliott Hughes [ 987*e1fe3e4aSElliott Hughes pytest.param(True, None, True, id="installed-auto-ok"), 988*e1fe3e4aSElliott Hughes pytest.param(True, None, False, id="installed-auto-fail"), 989*e1fe3e4aSElliott Hughes pytest.param(True, True, True, id="installed-enabled-ok"), 990*e1fe3e4aSElliott Hughes pytest.param(True, True, False, id="installed-enabled-fail"), 991*e1fe3e4aSElliott Hughes pytest.param(True, False, True, id="installed-disabled"), 992*e1fe3e4aSElliott Hughes pytest.param(False, True, True, id="not_installed-enabled"), 993*e1fe3e4aSElliott Hughes pytest.param(False, False, True, id="not_installed-disabled"), 994*e1fe3e4aSElliott Hughes ], 995*e1fe3e4aSElliott Hughes ) 996*e1fe3e4aSElliott Hughes def test_harfbuzz_repacker(self, caplog, monkeypatch, installed, enabled, ok): 997*e1fe3e4aSElliott Hughes # Use a mock to test the pure-python serializer is used when uharfbuzz 998*e1fe3e4aSElliott Hughes # returns an error or is not installed 999*e1fe3e4aSElliott Hughes have_uharfbuzz = fontTools.ttLib.tables.otBase.have_uharfbuzz 1000*e1fe3e4aSElliott Hughes if installed: 1001*e1fe3e4aSElliott Hughes if not have_uharfbuzz: 1002*e1fe3e4aSElliott Hughes pytest.skip("uharfbuzz is not installed") 1003*e1fe3e4aSElliott Hughes if not ok: 1004*e1fe3e4aSElliott Hughes # pretend hb.repack/repack_with_tag return an error 1005*e1fe3e4aSElliott Hughes import uharfbuzz as hb 1006*e1fe3e4aSElliott Hughes 1007*e1fe3e4aSElliott Hughes def mock_repack(data, obj_list): 1008*e1fe3e4aSElliott Hughes raise hb.RepackerError("mocking") 1009*e1fe3e4aSElliott Hughes 1010*e1fe3e4aSElliott Hughes monkeypatch.setattr(hb, "repack", mock_repack) 1011*e1fe3e4aSElliott Hughes 1012*e1fe3e4aSElliott Hughes if hasattr(hb, "repack_with_tag"): # uharfbuzz >= 0.30.0 1013*e1fe3e4aSElliott Hughes 1014*e1fe3e4aSElliott Hughes def mock_repack_with_tag(tag, data, obj_list): 1015*e1fe3e4aSElliott Hughes raise hb.RepackerError("mocking") 1016*e1fe3e4aSElliott Hughes 1017*e1fe3e4aSElliott Hughes monkeypatch.setattr(hb, "repack_with_tag", mock_repack_with_tag) 1018*e1fe3e4aSElliott Hughes else: 1019*e1fe3e4aSElliott Hughes if have_uharfbuzz: 1020*e1fe3e4aSElliott Hughes # pretend uharfbuzz is not installed 1021*e1fe3e4aSElliott Hughes monkeypatch.setattr( 1022*e1fe3e4aSElliott Hughes fontTools.ttLib.tables.otBase, "have_uharfbuzz", False 1023*e1fe3e4aSElliott Hughes ) 1024*e1fe3e4aSElliott Hughes 1025*e1fe3e4aSElliott Hughes fontpath = self.compile_font(self.getpath("harfbuzz_repacker.ttx"), ".otf") 1026*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".otf") 1027*e1fe3e4aSElliott Hughes args = [ 1028*e1fe3e4aSElliott Hughes fontpath, 1029*e1fe3e4aSElliott Hughes "--unicodes=0x53a9", 1030*e1fe3e4aSElliott Hughes "--layout-features=*", 1031*e1fe3e4aSElliott Hughes f"--output-file={subsetpath}", 1032*e1fe3e4aSElliott Hughes ] 1033*e1fe3e4aSElliott Hughes if enabled is True: 1034*e1fe3e4aSElliott Hughes args.append("--harfbuzz-repacker") 1035*e1fe3e4aSElliott Hughes elif enabled is False: 1036*e1fe3e4aSElliott Hughes args.append("--no-harfbuzz-repacker") 1037*e1fe3e4aSElliott Hughes # elif enabled is None: ... is the default 1038*e1fe3e4aSElliott Hughes 1039*e1fe3e4aSElliott Hughes if enabled is True and not installed: 1040*e1fe3e4aSElliott Hughes # raise if enabled but not installed 1041*e1fe3e4aSElliott Hughes with pytest.raises(ImportError, match="uharfbuzz"): 1042*e1fe3e4aSElliott Hughes subset.main(args) 1043*e1fe3e4aSElliott Hughes return 1044*e1fe3e4aSElliott Hughes 1045*e1fe3e4aSElliott Hughes with caplog.at_level(logging.DEBUG, "fontTools.ttLib.tables.otBase"): 1046*e1fe3e4aSElliott Hughes subset.main(args) 1047*e1fe3e4aSElliott Hughes 1048*e1fe3e4aSElliott Hughes subsetfont = TTFont(subsetpath) 1049*e1fe3e4aSElliott Hughes # both hb.repack and pure-python serializer compile to the same ttx 1050*e1fe3e4aSElliott Hughes self.expect_ttx( 1051*e1fe3e4aSElliott Hughes subsetfont, self.getpath("expect_harfbuzz_repacker.ttx"), ["GSUB"] 1052*e1fe3e4aSElliott Hughes ) 1053*e1fe3e4aSElliott Hughes 1054*e1fe3e4aSElliott Hughes if enabled or enabled is None: 1055*e1fe3e4aSElliott Hughes if installed: 1056*e1fe3e4aSElliott Hughes assert "serializing 'GSUB' with hb.repack" in caplog.text 1057*e1fe3e4aSElliott Hughes 1058*e1fe3e4aSElliott Hughes if enabled is None and not installed: 1059*e1fe3e4aSElliott Hughes assert ( 1060*e1fe3e4aSElliott Hughes "uharfbuzz not found, compiling 'GSUB' with pure-python serializer" 1061*e1fe3e4aSElliott Hughes ) in caplog.text 1062*e1fe3e4aSElliott Hughes 1063*e1fe3e4aSElliott Hughes if enabled is False: 1064*e1fe3e4aSElliott Hughes assert ( 1065*e1fe3e4aSElliott Hughes "hb.repack disabled, compiling 'GSUB' with pure-python serializer" 1066*e1fe3e4aSElliott Hughes ) in caplog.text 1067*e1fe3e4aSElliott Hughes 1068*e1fe3e4aSElliott Hughes # test we emit a log.error if hb.repack fails (and we don't if successful) 1069*e1fe3e4aSElliott Hughes assert ( 1070*e1fe3e4aSElliott Hughes ( 1071*e1fe3e4aSElliott Hughes "hb.repack failed to serialize 'GSUB', attempting fonttools resolutions " 1072*e1fe3e4aSElliott Hughes "; the error message was: RepackerError: mocking" 1073*e1fe3e4aSElliott Hughes ) 1074*e1fe3e4aSElliott Hughes in caplog.text 1075*e1fe3e4aSElliott Hughes ) ^ ok 1076*e1fe3e4aSElliott Hughes 1077*e1fe3e4aSElliott Hughes def test_retain_east_asian_spacing_features(self): 1078*e1fe3e4aSElliott Hughes # This test font contains halt and vhal features, check that 1079*e1fe3e4aSElliott Hughes # they are retained by default after subsetting. 1080*e1fe3e4aSElliott Hughes ttx_path = self.getpath("NotoSansCJKjp-Regular.subset.ttx") 1081*e1fe3e4aSElliott Hughes ttx = pathlib.Path(ttx_path).read_text() 1082*e1fe3e4aSElliott Hughes assert 'FeatureTag value="halt"' in ttx 1083*e1fe3e4aSElliott Hughes assert 'FeatureTag value="vhal"' in ttx 1084*e1fe3e4aSElliott Hughes 1085*e1fe3e4aSElliott Hughes fontpath = self.compile_font(ttx_path, ".otf") 1086*e1fe3e4aSElliott Hughes subsetpath = self.temp_path(".otf") 1087*e1fe3e4aSElliott Hughes subset.main( 1088*e1fe3e4aSElliott Hughes [ 1089*e1fe3e4aSElliott Hughes fontpath, 1090*e1fe3e4aSElliott Hughes "--unicodes=*", 1091*e1fe3e4aSElliott Hughes "--output-file=%s" % subsetpath, 1092*e1fe3e4aSElliott Hughes ] 1093*e1fe3e4aSElliott Hughes ) 1094*e1fe3e4aSElliott Hughes # subset output is the same as the input 1095*e1fe3e4aSElliott Hughes self.expect_ttx(TTFont(subsetpath), ttx_path) 1096*e1fe3e4aSElliott Hughes 1097*e1fe3e4aSElliott Hughes 1098*e1fe3e4aSElliott Hughes@pytest.fixture 1099*e1fe3e4aSElliott Hughesdef featureVarsTestFont(): 1100*e1fe3e4aSElliott Hughes fb = FontBuilder(unitsPerEm=100) 1101*e1fe3e4aSElliott Hughes fb.setupGlyphOrder([".notdef", "f", "f_f", "dollar", "dollar.rvrn"]) 1102*e1fe3e4aSElliott Hughes fb.setupCharacterMap({ord("f"): "f", ord("$"): "dollar"}) 1103*e1fe3e4aSElliott Hughes fb.setupNameTable({"familyName": "TestFeatureVars", "styleName": "Regular"}) 1104*e1fe3e4aSElliott Hughes fb.setupPost() 1105*e1fe3e4aSElliott Hughes fb.setupFvar(axes=[("wght", 100, 400, 900, "Weight")], instances=[]) 1106*e1fe3e4aSElliott Hughes fb.addOpenTypeFeatures( 1107*e1fe3e4aSElliott Hughes """\ 1108*e1fe3e4aSElliott Hughes feature dlig { 1109*e1fe3e4aSElliott Hughes sub f f by f_f; 1110*e1fe3e4aSElliott Hughes } dlig; 1111*e1fe3e4aSElliott Hughes """ 1112*e1fe3e4aSElliott Hughes ) 1113*e1fe3e4aSElliott Hughes fb.addFeatureVariations( 1114*e1fe3e4aSElliott Hughes [([{"wght": (0.20886, 1.0)}], {"dollar": "dollar.rvrn"})], featureTag="rvrn" 1115*e1fe3e4aSElliott Hughes ) 1116*e1fe3e4aSElliott Hughes buf = io.BytesIO() 1117*e1fe3e4aSElliott Hughes fb.save(buf) 1118*e1fe3e4aSElliott Hughes buf.seek(0) 1119*e1fe3e4aSElliott Hughes 1120*e1fe3e4aSElliott Hughes return TTFont(buf) 1121*e1fe3e4aSElliott Hughes 1122*e1fe3e4aSElliott Hughes 1123*e1fe3e4aSElliott Hughesdef test_subset_feature_variations_keep_all(featureVarsTestFont): 1124*e1fe3e4aSElliott Hughes font = featureVarsTestFont 1125*e1fe3e4aSElliott Hughes 1126*e1fe3e4aSElliott Hughes options = subset.Options() 1127*e1fe3e4aSElliott Hughes subsetter = subset.Subsetter(options) 1128*e1fe3e4aSElliott Hughes subsetter.populate(unicodes=[ord("f"), ord("$")]) 1129*e1fe3e4aSElliott Hughes subsetter.subset(font) 1130*e1fe3e4aSElliott Hughes 1131*e1fe3e4aSElliott Hughes featureTags = {r.FeatureTag for r in font["GSUB"].table.FeatureList.FeatureRecord} 1132*e1fe3e4aSElliott Hughes # 'dlig' is discretionary so it is dropped by default 1133*e1fe3e4aSElliott Hughes assert "dlig" not in featureTags 1134*e1fe3e4aSElliott Hughes assert "f_f" not in font.getGlyphOrder() 1135*e1fe3e4aSElliott Hughes # 'rvrn' is required so it is kept by default 1136*e1fe3e4aSElliott Hughes assert "rvrn" in featureTags 1137*e1fe3e4aSElliott Hughes assert "dollar.rvrn" in font.getGlyphOrder() 1138*e1fe3e4aSElliott Hughes 1139*e1fe3e4aSElliott Hughes 1140*e1fe3e4aSElliott Hughesdef test_subset_feature_variations_drop_all(featureVarsTestFont): 1141*e1fe3e4aSElliott Hughes font = featureVarsTestFont 1142*e1fe3e4aSElliott Hughes 1143*e1fe3e4aSElliott Hughes options = subset.Options() 1144*e1fe3e4aSElliott Hughes options.layout_features.remove("rvrn") # drop 'rvrn' 1145*e1fe3e4aSElliott Hughes subsetter = subset.Subsetter(options) 1146*e1fe3e4aSElliott Hughes subsetter.populate(unicodes=[ord("f"), ord("$")]) 1147*e1fe3e4aSElliott Hughes subsetter.subset(font) 1148*e1fe3e4aSElliott Hughes 1149*e1fe3e4aSElliott Hughes featureTags = {r.FeatureTag for r in font["GSUB"].table.FeatureList.FeatureRecord} 1150*e1fe3e4aSElliott Hughes glyphs = set(font.getGlyphOrder()) 1151*e1fe3e4aSElliott Hughes 1152*e1fe3e4aSElliott Hughes assert "rvrn" not in featureTags 1153*e1fe3e4aSElliott Hughes assert glyphs == {".notdef", "f", "dollar"} 1154*e1fe3e4aSElliott Hughes # all FeatureVariationRecords were dropped 1155*e1fe3e4aSElliott Hughes assert font["GSUB"].table.FeatureVariations is None 1156*e1fe3e4aSElliott Hughes assert font["GSUB"].table.Version == 0x00010000 1157*e1fe3e4aSElliott Hughes 1158*e1fe3e4aSElliott Hughes 1159*e1fe3e4aSElliott Hughes# TODO test_subset_feature_variations_drop_from_end_empty_records 1160*e1fe3e4aSElliott Hughes# https://github.com/fonttools/fonttools/issues/1881#issuecomment-619415044 1161*e1fe3e4aSElliott Hughes 1162*e1fe3e4aSElliott Hughes 1163*e1fe3e4aSElliott Hughes@pytest.fixture 1164*e1fe3e4aSElliott Hughesdef singlepos2_font(): 1165*e1fe3e4aSElliott Hughes fb = FontBuilder(unitsPerEm=1000) 1166*e1fe3e4aSElliott Hughes fb.setupGlyphOrder([".notdef", "a", "b", "c"]) 1167*e1fe3e4aSElliott Hughes fb.setupCharacterMap({ord("a"): "a", ord("b"): "b", ord("c"): "c"}) 1168*e1fe3e4aSElliott Hughes fb.setupNameTable({"familyName": "TestSingePosFormat", "styleName": "Regular"}) 1169*e1fe3e4aSElliott Hughes fb.setupPost() 1170*e1fe3e4aSElliott Hughes fb.addOpenTypeFeatures( 1171*e1fe3e4aSElliott Hughes """ 1172*e1fe3e4aSElliott Hughes feature kern { 1173*e1fe3e4aSElliott Hughes pos a -50; 1174*e1fe3e4aSElliott Hughes pos b -40; 1175*e1fe3e4aSElliott Hughes pos c -50; 1176*e1fe3e4aSElliott Hughes } kern; 1177*e1fe3e4aSElliott Hughes """ 1178*e1fe3e4aSElliott Hughes ) 1179*e1fe3e4aSElliott Hughes 1180*e1fe3e4aSElliott Hughes buf = io.BytesIO() 1181*e1fe3e4aSElliott Hughes fb.save(buf) 1182*e1fe3e4aSElliott Hughes buf.seek(0) 1183*e1fe3e4aSElliott Hughes 1184*e1fe3e4aSElliott Hughes return TTFont(buf) 1185*e1fe3e4aSElliott Hughes 1186*e1fe3e4aSElliott Hughes 1187*e1fe3e4aSElliott Hughesdef test_subset_single_pos_format(singlepos2_font): 1188*e1fe3e4aSElliott Hughes font = singlepos2_font 1189*e1fe3e4aSElliott Hughes # The input font has a SinglePos Format 2 subtable where each glyph has 1190*e1fe3e4aSElliott Hughes # different ValueRecords 1191*e1fe3e4aSElliott Hughes assert getXML(font["GPOS"].table.LookupList.Lookup[0].toXML, font) == [ 1192*e1fe3e4aSElliott Hughes "<Lookup>", 1193*e1fe3e4aSElliott Hughes ' <LookupType value="1"/>', 1194*e1fe3e4aSElliott Hughes ' <LookupFlag value="0"/>', 1195*e1fe3e4aSElliott Hughes " <!-- SubTableCount=1 -->", 1196*e1fe3e4aSElliott Hughes ' <SinglePos index="0" Format="2">', 1197*e1fe3e4aSElliott Hughes " <Coverage>", 1198*e1fe3e4aSElliott Hughes ' <Glyph value="a"/>', 1199*e1fe3e4aSElliott Hughes ' <Glyph value="b"/>', 1200*e1fe3e4aSElliott Hughes ' <Glyph value="c"/>', 1201*e1fe3e4aSElliott Hughes " </Coverage>", 1202*e1fe3e4aSElliott Hughes ' <ValueFormat value="4"/>', 1203*e1fe3e4aSElliott Hughes " <!-- ValueCount=3 -->", 1204*e1fe3e4aSElliott Hughes ' <Value index="0" XAdvance="-50"/>', 1205*e1fe3e4aSElliott Hughes ' <Value index="1" XAdvance="-40"/>', 1206*e1fe3e4aSElliott Hughes ' <Value index="2" XAdvance="-50"/>', 1207*e1fe3e4aSElliott Hughes " </SinglePos>", 1208*e1fe3e4aSElliott Hughes "</Lookup>", 1209*e1fe3e4aSElliott Hughes ] 1210*e1fe3e4aSElliott Hughes 1211*e1fe3e4aSElliott Hughes options = subset.Options() 1212*e1fe3e4aSElliott Hughes subsetter = subset.Subsetter(options) 1213*e1fe3e4aSElliott Hughes subsetter.populate(unicodes=[ord("a"), ord("c")]) 1214*e1fe3e4aSElliott Hughes subsetter.subset(font) 1215*e1fe3e4aSElliott Hughes 1216*e1fe3e4aSElliott Hughes # All the subsetted glyphs from the original SinglePos Format2 subtable 1217*e1fe3e4aSElliott Hughes # now have the same ValueRecord, so we use a more compact Format 1 subtable. 1218*e1fe3e4aSElliott Hughes assert getXML(font["GPOS"].table.LookupList.Lookup[0].toXML, font) == [ 1219*e1fe3e4aSElliott Hughes "<Lookup>", 1220*e1fe3e4aSElliott Hughes ' <LookupType value="1"/>', 1221*e1fe3e4aSElliott Hughes ' <LookupFlag value="0"/>', 1222*e1fe3e4aSElliott Hughes " <!-- SubTableCount=1 -->", 1223*e1fe3e4aSElliott Hughes ' <SinglePos index="0" Format="1">', 1224*e1fe3e4aSElliott Hughes " <Coverage>", 1225*e1fe3e4aSElliott Hughes ' <Glyph value="a"/>', 1226*e1fe3e4aSElliott Hughes ' <Glyph value="c"/>', 1227*e1fe3e4aSElliott Hughes " </Coverage>", 1228*e1fe3e4aSElliott Hughes ' <ValueFormat value="4"/>', 1229*e1fe3e4aSElliott Hughes ' <Value XAdvance="-50"/>', 1230*e1fe3e4aSElliott Hughes " </SinglePos>", 1231*e1fe3e4aSElliott Hughes "</Lookup>", 1232*e1fe3e4aSElliott Hughes ] 1233*e1fe3e4aSElliott Hughes 1234*e1fe3e4aSElliott Hughes 1235*e1fe3e4aSElliott Hughesdef test_subset_single_pos_format2_all_None(singlepos2_font): 1236*e1fe3e4aSElliott Hughes # https://github.com/fonttools/fonttools/issues/2602 1237*e1fe3e4aSElliott Hughes font = singlepos2_font 1238*e1fe3e4aSElliott Hughes gpos = font["GPOS"].table 1239*e1fe3e4aSElliott Hughes subtable = gpos.LookupList.Lookup[0].SubTable[0] 1240*e1fe3e4aSElliott Hughes assert subtable.Format == 2 1241*e1fe3e4aSElliott Hughes # Hack a SinglePosFormat2 with ValueFormat = 0; our own buildSinglePos 1242*e1fe3e4aSElliott Hughes # never makes these as a SinglePosFormat1 is more compact, but they can 1243*e1fe3e4aSElliott Hughes # be found in the wild. 1244*e1fe3e4aSElliott Hughes subtable.Value = [None] * subtable.ValueCount 1245*e1fe3e4aSElliott Hughes subtable.ValueFormat = 0 1246*e1fe3e4aSElliott Hughes 1247*e1fe3e4aSElliott Hughes assert getXML(subtable.toXML, font) == [ 1248*e1fe3e4aSElliott Hughes '<SinglePos Format="2">', 1249*e1fe3e4aSElliott Hughes " <Coverage>", 1250*e1fe3e4aSElliott Hughes ' <Glyph value="a"/>', 1251*e1fe3e4aSElliott Hughes ' <Glyph value="b"/>', 1252*e1fe3e4aSElliott Hughes ' <Glyph value="c"/>', 1253*e1fe3e4aSElliott Hughes " </Coverage>", 1254*e1fe3e4aSElliott Hughes ' <ValueFormat value="0"/>', 1255*e1fe3e4aSElliott Hughes " <!-- ValueCount=3 -->", 1256*e1fe3e4aSElliott Hughes "</SinglePos>", 1257*e1fe3e4aSElliott Hughes ] 1258*e1fe3e4aSElliott Hughes 1259*e1fe3e4aSElliott Hughes options = subset.Options() 1260*e1fe3e4aSElliott Hughes subsetter = subset.Subsetter(options) 1261*e1fe3e4aSElliott Hughes subsetter.populate(unicodes=[ord("a"), ord("c")]) 1262*e1fe3e4aSElliott Hughes subsetter.subset(font) 1263*e1fe3e4aSElliott Hughes 1264*e1fe3e4aSElliott Hughes # Check it was downgraded to Format1 after subsetting 1265*e1fe3e4aSElliott Hughes assert getXML(font["GPOS"].table.LookupList.Lookup[0].SubTable[0].toXML, font) == [ 1266*e1fe3e4aSElliott Hughes '<SinglePos Format="1">', 1267*e1fe3e4aSElliott Hughes " <Coverage>", 1268*e1fe3e4aSElliott Hughes ' <Glyph value="a"/>', 1269*e1fe3e4aSElliott Hughes ' <Glyph value="c"/>', 1270*e1fe3e4aSElliott Hughes " </Coverage>", 1271*e1fe3e4aSElliott Hughes ' <ValueFormat value="0"/>', 1272*e1fe3e4aSElliott Hughes "</SinglePos>", 1273*e1fe3e4aSElliott Hughes ] 1274*e1fe3e4aSElliott Hughes 1275*e1fe3e4aSElliott Hughes 1276*e1fe3e4aSElliott Hughes@pytest.fixture 1277*e1fe3e4aSElliott Hughesdef ttf_path(tmp_path): 1278*e1fe3e4aSElliott Hughes # $(dirname $0)/../ttLib/data 1279*e1fe3e4aSElliott Hughes ttLib_data = pathlib.Path(__file__).parent.parent / "ttLib" / "data" 1280*e1fe3e4aSElliott Hughes font = TTFont() 1281*e1fe3e4aSElliott Hughes font.importXML(ttLib_data / "TestTTF-Regular.ttx") 1282*e1fe3e4aSElliott Hughes font_path = tmp_path / "TestTTF-Regular.ttf" 1283*e1fe3e4aSElliott Hughes font.save(font_path) 1284*e1fe3e4aSElliott Hughes return font_path 1285*e1fe3e4aSElliott Hughes 1286*e1fe3e4aSElliott Hughes 1287*e1fe3e4aSElliott Hughesdef test_subset_empty_glyf(tmp_path, ttf_path): 1288*e1fe3e4aSElliott Hughes subset_path = tmp_path / (ttf_path.name + ".subset") 1289*e1fe3e4aSElliott Hughes # only keep empty .notdef and space glyph, resulting in an empty glyf table 1290*e1fe3e4aSElliott Hughes subset.main( 1291*e1fe3e4aSElliott Hughes [ 1292*e1fe3e4aSElliott Hughes str(ttf_path), 1293*e1fe3e4aSElliott Hughes "--no-notdef-outline", 1294*e1fe3e4aSElliott Hughes "--glyph-names", 1295*e1fe3e4aSElliott Hughes f"--output-file={subset_path}", 1296*e1fe3e4aSElliott Hughes "--glyphs=.notdef space", 1297*e1fe3e4aSElliott Hughes ] 1298*e1fe3e4aSElliott Hughes ) 1299*e1fe3e4aSElliott Hughes subset_font = TTFont(subset_path) 1300*e1fe3e4aSElliott Hughes 1301*e1fe3e4aSElliott Hughes assert subset_font.getGlyphOrder() == [".notdef", "space"] 1302*e1fe3e4aSElliott Hughes assert subset_font.reader["glyf"] == b"\x00" 1303*e1fe3e4aSElliott Hughes 1304*e1fe3e4aSElliott Hughes glyf = subset_font["glyf"] 1305*e1fe3e4aSElliott Hughes assert all(glyf[g].numberOfContours == 0 for g in subset_font.getGlyphOrder()) 1306*e1fe3e4aSElliott Hughes 1307*e1fe3e4aSElliott Hughes loca = subset_font["loca"] 1308*e1fe3e4aSElliott Hughes assert all(loc == 0 for loc in loca) 1309*e1fe3e4aSElliott Hughes 1310*e1fe3e4aSElliott Hughes 1311*e1fe3e4aSElliott Hughes@pytest.fixture 1312*e1fe3e4aSElliott Hughesdef colrv1_path(tmp_path): 1313*e1fe3e4aSElliott Hughes base_glyph_names = ["uni%04X" % i for i in range(0xE000, 0xE000 + 10)] 1314*e1fe3e4aSElliott Hughes layer_glyph_names = ["glyph%05d" % i for i in range(10, 20)] 1315*e1fe3e4aSElliott Hughes glyph_order = [".notdef"] + base_glyph_names + layer_glyph_names 1316*e1fe3e4aSElliott Hughes 1317*e1fe3e4aSElliott Hughes pen = TTGlyphPen(glyphSet=None) 1318*e1fe3e4aSElliott Hughes pen.moveTo((0, 0)) 1319*e1fe3e4aSElliott Hughes pen.lineTo((0, 500)) 1320*e1fe3e4aSElliott Hughes pen.lineTo((500, 500)) 1321*e1fe3e4aSElliott Hughes pen.lineTo((500, 0)) 1322*e1fe3e4aSElliott Hughes pen.closePath() 1323*e1fe3e4aSElliott Hughes glyph = pen.glyph() 1324*e1fe3e4aSElliott Hughes glyphs = {g: glyph for g in glyph_order} 1325*e1fe3e4aSElliott Hughes 1326*e1fe3e4aSElliott Hughes fb = FontBuilder(unitsPerEm=1024, isTTF=True) 1327*e1fe3e4aSElliott Hughes fb.setupGlyphOrder(glyph_order) 1328*e1fe3e4aSElliott Hughes fb.setupCharacterMap({int(name[3:], 16): name for name in base_glyph_names}) 1329*e1fe3e4aSElliott Hughes fb.setupGlyf(glyphs) 1330*e1fe3e4aSElliott Hughes fb.setupHorizontalMetrics({g: (500, 0) for g in glyph_order}) 1331*e1fe3e4aSElliott Hughes fb.setupHorizontalHeader() 1332*e1fe3e4aSElliott Hughes fb.setupOS2() 1333*e1fe3e4aSElliott Hughes fb.setupPost() 1334*e1fe3e4aSElliott Hughes fb.setupNameTable({"familyName": "TestCOLRv1", "styleName": "Regular"}) 1335*e1fe3e4aSElliott Hughes 1336*e1fe3e4aSElliott Hughes fb.setupCOLR( 1337*e1fe3e4aSElliott Hughes { 1338*e1fe3e4aSElliott Hughes "uniE000": ( 1339*e1fe3e4aSElliott Hughes ot.PaintFormat.PaintColrLayers, 1340*e1fe3e4aSElliott Hughes [ 1341*e1fe3e4aSElliott Hughes { 1342*e1fe3e4aSElliott Hughes "Format": ot.PaintFormat.PaintGlyph, 1343*e1fe3e4aSElliott Hughes "Paint": (ot.PaintFormat.PaintSolid, 0), 1344*e1fe3e4aSElliott Hughes "Glyph": "glyph00010", 1345*e1fe3e4aSElliott Hughes }, 1346*e1fe3e4aSElliott Hughes { 1347*e1fe3e4aSElliott Hughes "Format": ot.PaintFormat.PaintGlyph, 1348*e1fe3e4aSElliott Hughes "Paint": (ot.PaintFormat.PaintSolid, 2, 0.3), 1349*e1fe3e4aSElliott Hughes "Glyph": "glyph00011", 1350*e1fe3e4aSElliott Hughes }, 1351*e1fe3e4aSElliott Hughes ], 1352*e1fe3e4aSElliott Hughes ), 1353*e1fe3e4aSElliott Hughes "uniE001": ( 1354*e1fe3e4aSElliott Hughes ot.PaintFormat.PaintColrLayers, 1355*e1fe3e4aSElliott Hughes [ 1356*e1fe3e4aSElliott Hughes { 1357*e1fe3e4aSElliott Hughes "Format": ot.PaintFormat.PaintTransform, 1358*e1fe3e4aSElliott Hughes "Paint": { 1359*e1fe3e4aSElliott Hughes "Format": ot.PaintFormat.PaintGlyph, 1360*e1fe3e4aSElliott Hughes "Paint": { 1361*e1fe3e4aSElliott Hughes "Format": ot.PaintFormat.PaintRadialGradient, 1362*e1fe3e4aSElliott Hughes "x0": 250, 1363*e1fe3e4aSElliott Hughes "y0": 250, 1364*e1fe3e4aSElliott Hughes "r0": 250, 1365*e1fe3e4aSElliott Hughes "x1": 200, 1366*e1fe3e4aSElliott Hughes "y1": 200, 1367*e1fe3e4aSElliott Hughes "r1": 0, 1368*e1fe3e4aSElliott Hughes "ColorLine": { 1369*e1fe3e4aSElliott Hughes "ColorStop": [(0.0, 1), (1.0, 2)], 1370*e1fe3e4aSElliott Hughes "Extend": "repeat", 1371*e1fe3e4aSElliott Hughes }, 1372*e1fe3e4aSElliott Hughes }, 1373*e1fe3e4aSElliott Hughes "Glyph": "glyph00012", 1374*e1fe3e4aSElliott Hughes }, 1375*e1fe3e4aSElliott Hughes "Transform": (0.7071, 0.7071, -0.7071, 0.7071, 0, 0), 1376*e1fe3e4aSElliott Hughes }, 1377*e1fe3e4aSElliott Hughes { 1378*e1fe3e4aSElliott Hughes "Format": ot.PaintFormat.PaintGlyph, 1379*e1fe3e4aSElliott Hughes "Paint": (ot.PaintFormat.PaintSolid, 1, 0.5), 1380*e1fe3e4aSElliott Hughes "Glyph": "glyph00013", 1381*e1fe3e4aSElliott Hughes }, 1382*e1fe3e4aSElliott Hughes ], 1383*e1fe3e4aSElliott Hughes ), 1384*e1fe3e4aSElliott Hughes "uniE002": ( 1385*e1fe3e4aSElliott Hughes ot.PaintFormat.PaintColrLayers, 1386*e1fe3e4aSElliott Hughes [ 1387*e1fe3e4aSElliott Hughes { 1388*e1fe3e4aSElliott Hughes "Format": ot.PaintFormat.PaintGlyph, 1389*e1fe3e4aSElliott Hughes "Paint": { 1390*e1fe3e4aSElliott Hughes "Format": ot.PaintFormat.PaintLinearGradient, 1391*e1fe3e4aSElliott Hughes "x0": 0, 1392*e1fe3e4aSElliott Hughes "y0": 0, 1393*e1fe3e4aSElliott Hughes "x1": 500, 1394*e1fe3e4aSElliott Hughes "y1": 500, 1395*e1fe3e4aSElliott Hughes "x2": -500, 1396*e1fe3e4aSElliott Hughes "y2": 500, 1397*e1fe3e4aSElliott Hughes "ColorLine": {"ColorStop": [(0.0, 1), (1.0, 2)]}, 1398*e1fe3e4aSElliott Hughes }, 1399*e1fe3e4aSElliott Hughes "Glyph": "glyph00014", 1400*e1fe3e4aSElliott Hughes }, 1401*e1fe3e4aSElliott Hughes { 1402*e1fe3e4aSElliott Hughes "Format": ot.PaintFormat.PaintTransform, 1403*e1fe3e4aSElliott Hughes "Paint": { 1404*e1fe3e4aSElliott Hughes "Format": ot.PaintFormat.PaintGlyph, 1405*e1fe3e4aSElliott Hughes "Paint": (ot.PaintFormat.PaintSolid, 1), 1406*e1fe3e4aSElliott Hughes "Glyph": "glyph00015", 1407*e1fe3e4aSElliott Hughes }, 1408*e1fe3e4aSElliott Hughes "Transform": (1, 0, 0, 1, 400, 400), 1409*e1fe3e4aSElliott Hughes }, 1410*e1fe3e4aSElliott Hughes ], 1411*e1fe3e4aSElliott Hughes ), 1412*e1fe3e4aSElliott Hughes "uniE003": { 1413*e1fe3e4aSElliott Hughes "Format": ot.PaintFormat.PaintRotateAroundCenter, 1414*e1fe3e4aSElliott Hughes "Paint": { 1415*e1fe3e4aSElliott Hughes "Format": ot.PaintFormat.PaintColrGlyph, 1416*e1fe3e4aSElliott Hughes "Glyph": "uniE001", 1417*e1fe3e4aSElliott Hughes }, 1418*e1fe3e4aSElliott Hughes "angle": 45, 1419*e1fe3e4aSElliott Hughes "centerX": 250, 1420*e1fe3e4aSElliott Hughes "centerY": 250, 1421*e1fe3e4aSElliott Hughes }, 1422*e1fe3e4aSElliott Hughes "uniE004": [ 1423*e1fe3e4aSElliott Hughes ("glyph00016", 1), 1424*e1fe3e4aSElliott Hughes ("glyph00017", 0xFFFF), # special palette index for foreground text 1425*e1fe3e4aSElliott Hughes ("glyph00018", 2), 1426*e1fe3e4aSElliott Hughes ], 1427*e1fe3e4aSElliott Hughes }, 1428*e1fe3e4aSElliott Hughes clipBoxes={ 1429*e1fe3e4aSElliott Hughes "uniE000": (0, 0, 200, 300), 1430*e1fe3e4aSElliott Hughes "uniE001": (0, 0, 500, 500), 1431*e1fe3e4aSElliott Hughes "uniE002": (-50, -50, 400, 400), 1432*e1fe3e4aSElliott Hughes "uniE003": (-50, -50, 400, 400), 1433*e1fe3e4aSElliott Hughes }, 1434*e1fe3e4aSElliott Hughes ) 1435*e1fe3e4aSElliott Hughes fb.setupCPAL( 1436*e1fe3e4aSElliott Hughes [ 1437*e1fe3e4aSElliott Hughes [ 1438*e1fe3e4aSElliott Hughes (1.0, 0.0, 0.0, 1.0), # red 1439*e1fe3e4aSElliott Hughes (0.0, 1.0, 0.0, 1.0), # green 1440*e1fe3e4aSElliott Hughes (0.0, 0.0, 1.0, 1.0), # blue 1441*e1fe3e4aSElliott Hughes ], 1442*e1fe3e4aSElliott Hughes ], 1443*e1fe3e4aSElliott Hughes ) 1444*e1fe3e4aSElliott Hughes 1445*e1fe3e4aSElliott Hughes output_path = tmp_path / "TestCOLRv1.ttf" 1446*e1fe3e4aSElliott Hughes fb.save(output_path) 1447*e1fe3e4aSElliott Hughes 1448*e1fe3e4aSElliott Hughes return output_path 1449*e1fe3e4aSElliott Hughes 1450*e1fe3e4aSElliott Hughes 1451*e1fe3e4aSElliott Hughes@pytest.fixture 1452*e1fe3e4aSElliott Hughesdef colrv1_cpalv1_path(colrv1_path): 1453*e1fe3e4aSElliott Hughes # upgrade CPAL from v0 to v1 by adding labels 1454*e1fe3e4aSElliott Hughes font = TTFont(colrv1_path) 1455*e1fe3e4aSElliott Hughes fb = FontBuilder(font=font) 1456*e1fe3e4aSElliott Hughes fb.setupCPAL( 1457*e1fe3e4aSElliott Hughes [ 1458*e1fe3e4aSElliott Hughes [ 1459*e1fe3e4aSElliott Hughes (1.0, 0.0, 0.0, 1.0), # red 1460*e1fe3e4aSElliott Hughes (0.0, 1.0, 0.0, 1.0), # green 1461*e1fe3e4aSElliott Hughes (0.0, 0.0, 1.0, 1.0), # blue 1462*e1fe3e4aSElliott Hughes ], 1463*e1fe3e4aSElliott Hughes ], 1464*e1fe3e4aSElliott Hughes paletteLabels=["test palette"], 1465*e1fe3e4aSElliott Hughes paletteEntryLabels=["first color", "second color", "third color"], 1466*e1fe3e4aSElliott Hughes ) 1467*e1fe3e4aSElliott Hughes 1468*e1fe3e4aSElliott Hughes output_path = colrv1_path.parent / "TestCOLRv1CPALv1.ttf" 1469*e1fe3e4aSElliott Hughes fb.save(output_path) 1470*e1fe3e4aSElliott Hughes 1471*e1fe3e4aSElliott Hughes return output_path 1472*e1fe3e4aSElliott Hughes 1473*e1fe3e4aSElliott Hughes 1474*e1fe3e4aSElliott Hughes@pytest.fixture 1475*e1fe3e4aSElliott Hughesdef colrv1_cpalv1_share_nameID_path(colrv1_path): 1476*e1fe3e4aSElliott Hughes font = TTFont(colrv1_path) 1477*e1fe3e4aSElliott Hughes fb = FontBuilder(font=font) 1478*e1fe3e4aSElliott Hughes fb.setupCPAL( 1479*e1fe3e4aSElliott Hughes [ 1480*e1fe3e4aSElliott Hughes [ 1481*e1fe3e4aSElliott Hughes (1.0, 0.0, 0.0, 1.0), # red 1482*e1fe3e4aSElliott Hughes (0.0, 1.0, 0.0, 1.0), # green 1483*e1fe3e4aSElliott Hughes (0.0, 0.0, 1.0, 1.0), # blue 1484*e1fe3e4aSElliott Hughes ], 1485*e1fe3e4aSElliott Hughes ], 1486*e1fe3e4aSElliott Hughes paletteLabels=["test palette"], 1487*e1fe3e4aSElliott Hughes paletteEntryLabels=["first color", "second color", "third color"], 1488*e1fe3e4aSElliott Hughes ) 1489*e1fe3e4aSElliott Hughes 1490*e1fe3e4aSElliott Hughes # Set the name ID of the first color to use nameID 1 = familyName = "TestCOLRv1" 1491*e1fe3e4aSElliott Hughes fb.font["CPAL"].paletteEntryLabels[0] = 1 1492*e1fe3e4aSElliott Hughes 1493*e1fe3e4aSElliott Hughes output_path = colrv1_path.parent / "TestCOLRv1CPALv1.ttf" 1494*e1fe3e4aSElliott Hughes fb.save(output_path) 1495*e1fe3e4aSElliott Hughes 1496*e1fe3e4aSElliott Hughes return output_path 1497*e1fe3e4aSElliott Hughes 1498*e1fe3e4aSElliott Hughes 1499*e1fe3e4aSElliott Hughesdef test_subset_COLRv1_and_CPAL(colrv1_path): 1500*e1fe3e4aSElliott Hughes subset_path = colrv1_path.parent / (colrv1_path.name + ".subset") 1501*e1fe3e4aSElliott Hughes 1502*e1fe3e4aSElliott Hughes subset.main( 1503*e1fe3e4aSElliott Hughes [ 1504*e1fe3e4aSElliott Hughes str(colrv1_path), 1505*e1fe3e4aSElliott Hughes "--glyph-names", 1506*e1fe3e4aSElliott Hughes f"--output-file={subset_path}", 1507*e1fe3e4aSElliott Hughes "--unicodes=E002,E003,E004", 1508*e1fe3e4aSElliott Hughes ] 1509*e1fe3e4aSElliott Hughes ) 1510*e1fe3e4aSElliott Hughes subset_font = TTFont(subset_path) 1511*e1fe3e4aSElliott Hughes 1512*e1fe3e4aSElliott Hughes glyph_set = set(subset_font.getGlyphOrder()) 1513*e1fe3e4aSElliott Hughes 1514*e1fe3e4aSElliott Hughes # uniE000 and its children are excluded from subset 1515*e1fe3e4aSElliott Hughes assert "uniE000" not in glyph_set 1516*e1fe3e4aSElliott Hughes assert "glyph00010" not in glyph_set 1517*e1fe3e4aSElliott Hughes assert "glyph00011" not in glyph_set 1518*e1fe3e4aSElliott Hughes 1519*e1fe3e4aSElliott Hughes # uniE001 and children are pulled in indirectly as PaintColrGlyph by uniE003 1520*e1fe3e4aSElliott Hughes assert "uniE001" in glyph_set 1521*e1fe3e4aSElliott Hughes assert "glyph00012" in glyph_set 1522*e1fe3e4aSElliott Hughes assert "glyph00013" in glyph_set 1523*e1fe3e4aSElliott Hughes 1524*e1fe3e4aSElliott Hughes assert "uniE002" in glyph_set 1525*e1fe3e4aSElliott Hughes assert "glyph00014" in glyph_set 1526*e1fe3e4aSElliott Hughes assert "glyph00015" in glyph_set 1527*e1fe3e4aSElliott Hughes 1528*e1fe3e4aSElliott Hughes assert "uniE003" in glyph_set 1529*e1fe3e4aSElliott Hughes 1530*e1fe3e4aSElliott Hughes assert "uniE004" in glyph_set 1531*e1fe3e4aSElliott Hughes assert "glyph00016" in glyph_set 1532*e1fe3e4aSElliott Hughes assert "glyph00017" in glyph_set 1533*e1fe3e4aSElliott Hughes assert "glyph00018" in glyph_set 1534*e1fe3e4aSElliott Hughes 1535*e1fe3e4aSElliott Hughes assert "COLR" in subset_font 1536*e1fe3e4aSElliott Hughes colr = subset_font["COLR"].table 1537*e1fe3e4aSElliott Hughes assert colr.Version == 1 1538*e1fe3e4aSElliott Hughes assert len(colr.BaseGlyphRecordArray.BaseGlyphRecord) == 1 1539*e1fe3e4aSElliott Hughes assert len(colr.BaseGlyphList.BaseGlyphPaintRecord) == 3 # was 4 1540*e1fe3e4aSElliott Hughes 1541*e1fe3e4aSElliott Hughes base = colr.BaseGlyphList.BaseGlyphPaintRecord[0] 1542*e1fe3e4aSElliott Hughes assert base.BaseGlyph == "uniE001" 1543*e1fe3e4aSElliott Hughes layers = colr.LayerList.Paint[ 1544*e1fe3e4aSElliott Hughes base.Paint.FirstLayerIndex : base.Paint.FirstLayerIndex + base.Paint.NumLayers 1545*e1fe3e4aSElliott Hughes ] 1546*e1fe3e4aSElliott Hughes assert len(layers) == 2 1547*e1fe3e4aSElliott Hughes # check v1 palette indices were remapped 1548*e1fe3e4aSElliott Hughes assert layers[0].Paint.Paint.ColorLine.ColorStop[0].PaletteIndex == 0 1549*e1fe3e4aSElliott Hughes assert layers[0].Paint.Paint.ColorLine.ColorStop[1].PaletteIndex == 1 1550*e1fe3e4aSElliott Hughes assert layers[1].Paint.PaletteIndex == 0 1551*e1fe3e4aSElliott Hughes 1552*e1fe3e4aSElliott Hughes baseRecV0 = colr.BaseGlyphRecordArray.BaseGlyphRecord[0] 1553*e1fe3e4aSElliott Hughes assert baseRecV0.BaseGlyph == "uniE004" 1554*e1fe3e4aSElliott Hughes layersV0 = colr.LayerRecordArray.LayerRecord 1555*e1fe3e4aSElliott Hughes assert len(layersV0) == 3 1556*e1fe3e4aSElliott Hughes # check v0 palette indices were remapped (except for 0xFFFF) 1557*e1fe3e4aSElliott Hughes assert layersV0[0].PaletteIndex == 0 1558*e1fe3e4aSElliott Hughes assert layersV0[1].PaletteIndex == 0xFFFF 1559*e1fe3e4aSElliott Hughes assert layersV0[2].PaletteIndex == 1 1560*e1fe3e4aSElliott Hughes 1561*e1fe3e4aSElliott Hughes clipBoxes = colr.ClipList.clips 1562*e1fe3e4aSElliott Hughes assert {"uniE001", "uniE002", "uniE003"} == set(clipBoxes) 1563*e1fe3e4aSElliott Hughes assert clipBoxes["uniE002"] == clipBoxes["uniE003"] 1564*e1fe3e4aSElliott Hughes 1565*e1fe3e4aSElliott Hughes assert "CPAL" in subset_font 1566*e1fe3e4aSElliott Hughes cpal = subset_font["CPAL"] 1567*e1fe3e4aSElliott Hughes assert [ 1568*e1fe3e4aSElliott Hughes tuple(v / 255 for v in (c.red, c.green, c.blue, c.alpha)) 1569*e1fe3e4aSElliott Hughes for c in cpal.palettes[0] 1570*e1fe3e4aSElliott Hughes ] == [ 1571*e1fe3e4aSElliott Hughes # the first color 'red' was pruned 1572*e1fe3e4aSElliott Hughes (0.0, 1.0, 0.0, 1.0), # green 1573*e1fe3e4aSElliott Hughes (0.0, 0.0, 1.0, 1.0), # blue 1574*e1fe3e4aSElliott Hughes ] 1575*e1fe3e4aSElliott Hughes 1576*e1fe3e4aSElliott Hughes 1577*e1fe3e4aSElliott Hughesdef test_subset_COLRv1_and_CPALv1(colrv1_cpalv1_path): 1578*e1fe3e4aSElliott Hughes subset_path = colrv1_cpalv1_path.parent / (colrv1_cpalv1_path.name + ".subset") 1579*e1fe3e4aSElliott Hughes 1580*e1fe3e4aSElliott Hughes subset.main( 1581*e1fe3e4aSElliott Hughes [ 1582*e1fe3e4aSElliott Hughes str(colrv1_cpalv1_path), 1583*e1fe3e4aSElliott Hughes "--glyph-names", 1584*e1fe3e4aSElliott Hughes f"--output-file={subset_path}", 1585*e1fe3e4aSElliott Hughes "--unicodes=E002,E003,E004", 1586*e1fe3e4aSElliott Hughes ] 1587*e1fe3e4aSElliott Hughes ) 1588*e1fe3e4aSElliott Hughes subset_font = TTFont(subset_path) 1589*e1fe3e4aSElliott Hughes 1590*e1fe3e4aSElliott Hughes assert "CPAL" in subset_font 1591*e1fe3e4aSElliott Hughes cpal = subset_font["CPAL"] 1592*e1fe3e4aSElliott Hughes name_table = subset_font["name"] 1593*e1fe3e4aSElliott Hughes assert [ 1594*e1fe3e4aSElliott Hughes name_table.getDebugName(name_id) for name_id in cpal.paletteEntryLabels 1595*e1fe3e4aSElliott Hughes ] == [ 1596*e1fe3e4aSElliott Hughes # "first color", # The first color was pruned 1597*e1fe3e4aSElliott Hughes "second color", 1598*e1fe3e4aSElliott Hughes "third color", 1599*e1fe3e4aSElliott Hughes ] 1600*e1fe3e4aSElliott Hughes # check that the "first color" name is dropped from name table 1601*e1fe3e4aSElliott Hughes font = TTFont(colrv1_cpalv1_path) 1602*e1fe3e4aSElliott Hughes 1603*e1fe3e4aSElliott Hughes first_color_nameID = None 1604*e1fe3e4aSElliott Hughes for n in font["name"].names: 1605*e1fe3e4aSElliott Hughes if n.toUnicode() == "first color": 1606*e1fe3e4aSElliott Hughes first_color_nameID = n.nameID 1607*e1fe3e4aSElliott Hughes break 1608*e1fe3e4aSElliott Hughes assert first_color_nameID is not None 1609*e1fe3e4aSElliott Hughes assert all(n.nameID != first_color_nameID for n in name_table.names) 1610*e1fe3e4aSElliott Hughes 1611*e1fe3e4aSElliott Hughes 1612*e1fe3e4aSElliott Hughesdef test_subset_COLRv1_and_CPALv1_keep_nameID(colrv1_cpalv1_path): 1613*e1fe3e4aSElliott Hughes subset_path = colrv1_cpalv1_path.parent / (colrv1_cpalv1_path.name + ".subset") 1614*e1fe3e4aSElliott Hughes 1615*e1fe3e4aSElliott Hughes # figure out the name ID of first color so we can keep it 1616*e1fe3e4aSElliott Hughes font = TTFont(colrv1_cpalv1_path) 1617*e1fe3e4aSElliott Hughes 1618*e1fe3e4aSElliott Hughes first_color_nameID = None 1619*e1fe3e4aSElliott Hughes for n in font["name"].names: 1620*e1fe3e4aSElliott Hughes if n.toUnicode() == "first color": 1621*e1fe3e4aSElliott Hughes first_color_nameID = n.nameID 1622*e1fe3e4aSElliott Hughes break 1623*e1fe3e4aSElliott Hughes assert first_color_nameID is not None 1624*e1fe3e4aSElliott Hughes 1625*e1fe3e4aSElliott Hughes subset.main( 1626*e1fe3e4aSElliott Hughes [ 1627*e1fe3e4aSElliott Hughes str(colrv1_cpalv1_path), 1628*e1fe3e4aSElliott Hughes "--glyph-names", 1629*e1fe3e4aSElliott Hughes f"--output-file={subset_path}", 1630*e1fe3e4aSElliott Hughes "--unicodes=E002,E003,E004", 1631*e1fe3e4aSElliott Hughes f"--name-IDs={first_color_nameID}", 1632*e1fe3e4aSElliott Hughes ] 1633*e1fe3e4aSElliott Hughes ) 1634*e1fe3e4aSElliott Hughes subset_font = TTFont(subset_path) 1635*e1fe3e4aSElliott Hughes 1636*e1fe3e4aSElliott Hughes assert "CPAL" in subset_font 1637*e1fe3e4aSElliott Hughes cpal = subset_font["CPAL"] 1638*e1fe3e4aSElliott Hughes name_table = subset_font["name"] 1639*e1fe3e4aSElliott Hughes assert [ 1640*e1fe3e4aSElliott Hughes name_table.getDebugName(name_id) for name_id in cpal.paletteEntryLabels 1641*e1fe3e4aSElliott Hughes ] == [ 1642*e1fe3e4aSElliott Hughes # "first color", # The first color was pruned 1643*e1fe3e4aSElliott Hughes "second color", 1644*e1fe3e4aSElliott Hughes "third color", 1645*e1fe3e4aSElliott Hughes ] 1646*e1fe3e4aSElliott Hughes 1647*e1fe3e4aSElliott Hughes # Check that the name ID is kept 1648*e1fe3e4aSElliott Hughes assert any(n.nameID == first_color_nameID for n in name_table.names) 1649*e1fe3e4aSElliott Hughes 1650*e1fe3e4aSElliott Hughes 1651*e1fe3e4aSElliott Hughesdef test_subset_COLRv1_and_CPALv1_share_nameID(colrv1_cpalv1_share_nameID_path): 1652*e1fe3e4aSElliott Hughes subset_path = colrv1_cpalv1_share_nameID_path.parent / ( 1653*e1fe3e4aSElliott Hughes colrv1_cpalv1_share_nameID_path.name + ".subset" 1654*e1fe3e4aSElliott Hughes ) 1655*e1fe3e4aSElliott Hughes 1656*e1fe3e4aSElliott Hughes subset.main( 1657*e1fe3e4aSElliott Hughes [ 1658*e1fe3e4aSElliott Hughes str(colrv1_cpalv1_share_nameID_path), 1659*e1fe3e4aSElliott Hughes "--glyph-names", 1660*e1fe3e4aSElliott Hughes f"--output-file={subset_path}", 1661*e1fe3e4aSElliott Hughes "--unicodes=E002,E003,E004", 1662*e1fe3e4aSElliott Hughes ] 1663*e1fe3e4aSElliott Hughes ) 1664*e1fe3e4aSElliott Hughes subset_font = TTFont(subset_path) 1665*e1fe3e4aSElliott Hughes 1666*e1fe3e4aSElliott Hughes assert "CPAL" in subset_font 1667*e1fe3e4aSElliott Hughes cpal = subset_font["CPAL"] 1668*e1fe3e4aSElliott Hughes name_table = subset_font["name"] 1669*e1fe3e4aSElliott Hughes assert [ 1670*e1fe3e4aSElliott Hughes name_table.getDebugName(name_id) for name_id in cpal.paletteEntryLabels 1671*e1fe3e4aSElliott Hughes ] == [ 1672*e1fe3e4aSElliott Hughes # "first color", # The first color was pruned 1673*e1fe3e4aSElliott Hughes "second color", 1674*e1fe3e4aSElliott Hughes "third color", 1675*e1fe3e4aSElliott Hughes ] 1676*e1fe3e4aSElliott Hughes 1677*e1fe3e4aSElliott Hughes # Check that the name ID 1 is kept 1678*e1fe3e4aSElliott Hughes assert any(n.nameID == 1 for n in name_table.names) 1679*e1fe3e4aSElliott Hughes 1680*e1fe3e4aSElliott Hughes 1681*e1fe3e4aSElliott Hughesdef test_subset_COLRv1_and_CPAL_drop_empty(colrv1_path): 1682*e1fe3e4aSElliott Hughes subset_path = colrv1_path.parent / (colrv1_path.name + ".subset") 1683*e1fe3e4aSElliott Hughes 1684*e1fe3e4aSElliott Hughes subset.main( 1685*e1fe3e4aSElliott Hughes [ 1686*e1fe3e4aSElliott Hughes str(colrv1_path), 1687*e1fe3e4aSElliott Hughes "--glyph-names", 1688*e1fe3e4aSElliott Hughes f"--output-file={subset_path}", 1689*e1fe3e4aSElliott Hughes "--glyphs=glyph00010", 1690*e1fe3e4aSElliott Hughes ] 1691*e1fe3e4aSElliott Hughes ) 1692*e1fe3e4aSElliott Hughes subset_font = TTFont(subset_path) 1693*e1fe3e4aSElliott Hughes 1694*e1fe3e4aSElliott Hughes glyph_set = set(subset_font.getGlyphOrder()) 1695*e1fe3e4aSElliott Hughes 1696*e1fe3e4aSElliott Hughes assert "glyph00010" in glyph_set 1697*e1fe3e4aSElliott Hughes assert "uniE000" not in glyph_set 1698*e1fe3e4aSElliott Hughes 1699*e1fe3e4aSElliott Hughes assert "COLR" not in subset_font 1700*e1fe3e4aSElliott Hughes assert "CPAL" not in subset_font 1701*e1fe3e4aSElliott Hughes 1702*e1fe3e4aSElliott Hughes 1703*e1fe3e4aSElliott Hughesdef test_subset_COLRv1_downgrade_version(colrv1_path): 1704*e1fe3e4aSElliott Hughes subset_path = colrv1_path.parent / (colrv1_path.name + ".subset") 1705*e1fe3e4aSElliott Hughes 1706*e1fe3e4aSElliott Hughes subset.main( 1707*e1fe3e4aSElliott Hughes [ 1708*e1fe3e4aSElliott Hughes str(colrv1_path), 1709*e1fe3e4aSElliott Hughes "--glyph-names", 1710*e1fe3e4aSElliott Hughes f"--output-file={subset_path}", 1711*e1fe3e4aSElliott Hughes "--unicodes=E004", 1712*e1fe3e4aSElliott Hughes ] 1713*e1fe3e4aSElliott Hughes ) 1714*e1fe3e4aSElliott Hughes subset_font = TTFont(subset_path) 1715*e1fe3e4aSElliott Hughes 1716*e1fe3e4aSElliott Hughes assert set(subset_font.getGlyphOrder()) == { 1717*e1fe3e4aSElliott Hughes ".notdef", 1718*e1fe3e4aSElliott Hughes "uniE004", 1719*e1fe3e4aSElliott Hughes "glyph00016", 1720*e1fe3e4aSElliott Hughes "glyph00017", 1721*e1fe3e4aSElliott Hughes "glyph00018", 1722*e1fe3e4aSElliott Hughes } 1723*e1fe3e4aSElliott Hughes 1724*e1fe3e4aSElliott Hughes assert "COLR" in subset_font 1725*e1fe3e4aSElliott Hughes assert subset_font["COLR"].version == 0 1726*e1fe3e4aSElliott Hughes 1727*e1fe3e4aSElliott Hughes 1728*e1fe3e4aSElliott Hughesdef test_subset_COLRv1_drop_all_v0_glyphs(colrv1_path): 1729*e1fe3e4aSElliott Hughes subset_path = colrv1_path.parent / (colrv1_path.name + ".subset") 1730*e1fe3e4aSElliott Hughes 1731*e1fe3e4aSElliott Hughes subset.main( 1732*e1fe3e4aSElliott Hughes [ 1733*e1fe3e4aSElliott Hughes str(colrv1_path), 1734*e1fe3e4aSElliott Hughes "--glyph-names", 1735*e1fe3e4aSElliott Hughes f"--output-file={subset_path}", 1736*e1fe3e4aSElliott Hughes "--unicodes=E003", 1737*e1fe3e4aSElliott Hughes ] 1738*e1fe3e4aSElliott Hughes ) 1739*e1fe3e4aSElliott Hughes subset_font = TTFont(subset_path) 1740*e1fe3e4aSElliott Hughes 1741*e1fe3e4aSElliott Hughes assert set(subset_font.getGlyphOrder()) == { 1742*e1fe3e4aSElliott Hughes ".notdef", 1743*e1fe3e4aSElliott Hughes "uniE001", 1744*e1fe3e4aSElliott Hughes "uniE003", 1745*e1fe3e4aSElliott Hughes "glyph00012", 1746*e1fe3e4aSElliott Hughes "glyph00013", 1747*e1fe3e4aSElliott Hughes } 1748*e1fe3e4aSElliott Hughes 1749*e1fe3e4aSElliott Hughes assert "COLR" in subset_font 1750*e1fe3e4aSElliott Hughes colr = subset_font["COLR"] 1751*e1fe3e4aSElliott Hughes assert colr.version == 1 1752*e1fe3e4aSElliott Hughes assert colr.table.BaseGlyphRecordCount == 0 1753*e1fe3e4aSElliott Hughes assert colr.table.BaseGlyphRecordArray is None 1754*e1fe3e4aSElliott Hughes assert colr.table.LayerRecordArray is None 1755*e1fe3e4aSElliott Hughes assert colr.table.LayerRecordCount is 0 1756*e1fe3e4aSElliott Hughes 1757*e1fe3e4aSElliott Hughes 1758*e1fe3e4aSElliott Hughesdef test_subset_COLRv1_no_ClipList(colrv1_path): 1759*e1fe3e4aSElliott Hughes font = TTFont(colrv1_path) 1760*e1fe3e4aSElliott Hughes font["COLR"].table.ClipList = None # empty ClipList 1761*e1fe3e4aSElliott Hughes font.save(colrv1_path) 1762*e1fe3e4aSElliott Hughes 1763*e1fe3e4aSElliott Hughes subset_path = colrv1_path.parent / (colrv1_path.name + ".subset") 1764*e1fe3e4aSElliott Hughes subset.main( 1765*e1fe3e4aSElliott Hughes [ 1766*e1fe3e4aSElliott Hughes str(colrv1_path), 1767*e1fe3e4aSElliott Hughes f"--output-file={subset_path}", 1768*e1fe3e4aSElliott Hughes "--unicodes=*", 1769*e1fe3e4aSElliott Hughes ] 1770*e1fe3e4aSElliott Hughes ) 1771*e1fe3e4aSElliott Hughes subset_font = TTFont(subset_path) 1772*e1fe3e4aSElliott Hughes assert subset_font["COLR"].table.ClipList is None 1773*e1fe3e4aSElliott Hughes 1774*e1fe3e4aSElliott Hughes 1775*e1fe3e4aSElliott Hughesdef test_subset_keep_size_drop_empty_stylistic_set(): 1776*e1fe3e4aSElliott Hughes fb = FontBuilder(unitsPerEm=1000, isTTF=True) 1777*e1fe3e4aSElliott Hughes glyph_order = [".notdef", "a", "b", "b.ss01"] 1778*e1fe3e4aSElliott Hughes fb.setupGlyphOrder(glyph_order) 1779*e1fe3e4aSElliott Hughes fb.setupGlyf({g: TTGlyphPen(None).glyph() for g in glyph_order}) 1780*e1fe3e4aSElliott Hughes fb.setupCharacterMap({ord("a"): "a", ord("b"): "b"}) 1781*e1fe3e4aSElliott Hughes fb.setupHorizontalMetrics({g: (500, 0) for g in glyph_order}) 1782*e1fe3e4aSElliott Hughes fb.setupHorizontalHeader() 1783*e1fe3e4aSElliott Hughes fb.setupOS2() 1784*e1fe3e4aSElliott Hughes fb.setupPost() 1785*e1fe3e4aSElliott Hughes fb.setupNameTable({"familyName": "TestKeepSizeFeature", "styleName": "Regular"}) 1786*e1fe3e4aSElliott Hughes fb.addOpenTypeFeatures( 1787*e1fe3e4aSElliott Hughes """ 1788*e1fe3e4aSElliott Hughes feature size { 1789*e1fe3e4aSElliott Hughes parameters 10.0 0; 1790*e1fe3e4aSElliott Hughes } size; 1791*e1fe3e4aSElliott Hughes feature ss01 { 1792*e1fe3e4aSElliott Hughes featureNames { 1793*e1fe3e4aSElliott Hughes name "Alternate b"; 1794*e1fe3e4aSElliott Hughes }; 1795*e1fe3e4aSElliott Hughes sub b by b.ss01; 1796*e1fe3e4aSElliott Hughes } ss01; 1797*e1fe3e4aSElliott Hughes """ 1798*e1fe3e4aSElliott Hughes ) 1799*e1fe3e4aSElliott Hughes 1800*e1fe3e4aSElliott Hughes buf = io.BytesIO() 1801*e1fe3e4aSElliott Hughes fb.save(buf) 1802*e1fe3e4aSElliott Hughes buf.seek(0) 1803*e1fe3e4aSElliott Hughes 1804*e1fe3e4aSElliott Hughes font = TTFont(buf) 1805*e1fe3e4aSElliott Hughes 1806*e1fe3e4aSElliott Hughes gpos_features = font["GPOS"].table.FeatureList.FeatureRecord 1807*e1fe3e4aSElliott Hughes assert gpos_features[0].FeatureTag == "size" 1808*e1fe3e4aSElliott Hughes assert isinstance(gpos_features[0].Feature.FeatureParams, ot.FeatureParamsSize) 1809*e1fe3e4aSElliott Hughes assert gpos_features[0].Feature.LookupCount == 0 1810*e1fe3e4aSElliott Hughes gsub_features = font["GSUB"].table.FeatureList.FeatureRecord 1811*e1fe3e4aSElliott Hughes assert gsub_features[0].FeatureTag == "ss01" 1812*e1fe3e4aSElliott Hughes assert isinstance( 1813*e1fe3e4aSElliott Hughes gsub_features[0].Feature.FeatureParams, ot.FeatureParamsStylisticSet 1814*e1fe3e4aSElliott Hughes ) 1815*e1fe3e4aSElliott Hughes 1816*e1fe3e4aSElliott Hughes options = subset.Options(layout_features=["*"]) 1817*e1fe3e4aSElliott Hughes subsetter = subset.Subsetter(options) 1818*e1fe3e4aSElliott Hughes subsetter.populate(unicodes=[ord("a")]) 1819*e1fe3e4aSElliott Hughes subsetter.subset(font) 1820*e1fe3e4aSElliott Hughes 1821*e1fe3e4aSElliott Hughes # empty size feature was kept 1822*e1fe3e4aSElliott Hughes gpos_features = font["GPOS"].table.FeatureList.FeatureRecord 1823*e1fe3e4aSElliott Hughes assert gpos_features[0].FeatureTag == "size" 1824*e1fe3e4aSElliott Hughes assert isinstance(gpos_features[0].Feature.FeatureParams, ot.FeatureParamsSize) 1825*e1fe3e4aSElliott Hughes assert gpos_features[0].Feature.LookupCount == 0 1826*e1fe3e4aSElliott Hughes # empty ss01 feature was dropped 1827*e1fe3e4aSElliott Hughes assert font["GSUB"].table.FeatureList.FeatureCount == 0 1828*e1fe3e4aSElliott Hughes 1829*e1fe3e4aSElliott Hughes 1830*e1fe3e4aSElliott Hughes@pytest.mark.skipif(etree is not None, reason="lxml is installed") 1831*e1fe3e4aSElliott Hughesdef test_subset_svg_missing_lxml(ttf_path): 1832*e1fe3e4aSElliott Hughes # add dummy SVG table and confirm we raise ImportError upon trying to subset it 1833*e1fe3e4aSElliott Hughes font = TTFont(ttf_path) 1834*e1fe3e4aSElliott Hughes font["SVG "] = newTable("SVG ") 1835*e1fe3e4aSElliott Hughes font["SVG "].docList = [('<svg><g id="glyph1"/></svg>', 1, 1)] 1836*e1fe3e4aSElliott Hughes font.save(ttf_path) 1837*e1fe3e4aSElliott Hughes 1838*e1fe3e4aSElliott Hughes with pytest.raises(ImportError): 1839*e1fe3e4aSElliott Hughes subset.main([str(ttf_path), "--gids=0,1"]) 1840*e1fe3e4aSElliott Hughes 1841*e1fe3e4aSElliott Hughes 1842*e1fe3e4aSElliott Hughesdef test_subset_COLR_glyph_closure(tmp_path): 1843*e1fe3e4aSElliott Hughes # https://github.com/fonttools/fonttools/issues/2461 1844*e1fe3e4aSElliott Hughes font = TTFont() 1845*e1fe3e4aSElliott Hughes ttx = pathlib.Path(__file__).parent / "data" / "BungeeColor-Regular.ttx" 1846*e1fe3e4aSElliott Hughes font.importXML(ttx) 1847*e1fe3e4aSElliott Hughes 1848*e1fe3e4aSElliott Hughes color_layers = font["COLR"].ColorLayers 1849*e1fe3e4aSElliott Hughes assert ".notdef" in color_layers 1850*e1fe3e4aSElliott Hughes assert "Agrave" in color_layers 1851*e1fe3e4aSElliott Hughes assert "grave" in color_layers 1852*e1fe3e4aSElliott Hughes 1853*e1fe3e4aSElliott Hughes font_path = tmp_path / "BungeeColor-Regular.ttf" 1854*e1fe3e4aSElliott Hughes subset_path = font_path.with_suffix(".subset.ttf)") 1855*e1fe3e4aSElliott Hughes font.save(font_path) 1856*e1fe3e4aSElliott Hughes 1857*e1fe3e4aSElliott Hughes subset.main( 1858*e1fe3e4aSElliott Hughes [ 1859*e1fe3e4aSElliott Hughes str(font_path), 1860*e1fe3e4aSElliott Hughes "--glyph-names", 1861*e1fe3e4aSElliott Hughes f"--output-file={subset_path}", 1862*e1fe3e4aSElliott Hughes "--glyphs=Agrave", 1863*e1fe3e4aSElliott Hughes ] 1864*e1fe3e4aSElliott Hughes ) 1865*e1fe3e4aSElliott Hughes subset_font = TTFont(subset_path) 1866*e1fe3e4aSElliott Hughes 1867*e1fe3e4aSElliott Hughes glyph_order = subset_font.getGlyphOrder() 1868*e1fe3e4aSElliott Hughes 1869*e1fe3e4aSElliott Hughes assert glyph_order == [ 1870*e1fe3e4aSElliott Hughes ".notdef", # '.notdef' is always included automatically 1871*e1fe3e4aSElliott Hughes "A", 1872*e1fe3e4aSElliott Hughes "grave", 1873*e1fe3e4aSElliott Hughes "Agrave", 1874*e1fe3e4aSElliott Hughes ".notdef.alt001", 1875*e1fe3e4aSElliott Hughes ".notdef.alt002", 1876*e1fe3e4aSElliott Hughes "A.alt002", 1877*e1fe3e4aSElliott Hughes "Agrave.alt001", 1878*e1fe3e4aSElliott Hughes "Agrave.alt002", 1879*e1fe3e4aSElliott Hughes "grave.alt002", 1880*e1fe3e4aSElliott Hughes ] 1881*e1fe3e4aSElliott Hughes 1882*e1fe3e4aSElliott Hughes color_layers = subset_font["COLR"].ColorLayers 1883*e1fe3e4aSElliott Hughes assert ".notdef" in color_layers 1884*e1fe3e4aSElliott Hughes assert "Agrave" in color_layers 1885*e1fe3e4aSElliott Hughes # Agrave 'glyf' uses grave. It should be retained in 'glyf' but NOT in 1886*e1fe3e4aSElliott Hughes # COLR when we subset down to Agrave. 1887*e1fe3e4aSElliott Hughes assert "grave" not in color_layers 1888*e1fe3e4aSElliott Hughes 1889*e1fe3e4aSElliott Hughes 1890*e1fe3e4aSElliott Hughesdef test_subset_recalc_xAvgCharWidth(ttf_path): 1891*e1fe3e4aSElliott Hughes # Note that the font in in the *ttLib*/data/TestTTF-Regular.ttx file, 1892*e1fe3e4aSElliott Hughes # not this subset/data folder. 1893*e1fe3e4aSElliott Hughes font = TTFont(ttf_path) 1894*e1fe3e4aSElliott Hughes xAvgCharWidth_before = font["OS/2"].xAvgCharWidth 1895*e1fe3e4aSElliott Hughes 1896*e1fe3e4aSElliott Hughes subset_path = ttf_path.with_suffix(".subset.ttf") 1897*e1fe3e4aSElliott Hughes subset.main( 1898*e1fe3e4aSElliott Hughes [ 1899*e1fe3e4aSElliott Hughes str(ttf_path), 1900*e1fe3e4aSElliott Hughes f"--output-file={subset_path}", 1901*e1fe3e4aSElliott Hughes # Keep only the ellipsis, which is very wide, that ought to bump up the average 1902*e1fe3e4aSElliott Hughes "--glyphs=ellipsis", 1903*e1fe3e4aSElliott Hughes "--recalc-average-width", 1904*e1fe3e4aSElliott Hughes "--no-prune-unicode-ranges", 1905*e1fe3e4aSElliott Hughes ] 1906*e1fe3e4aSElliott Hughes ) 1907*e1fe3e4aSElliott Hughes subset_font = TTFont(subset_path) 1908*e1fe3e4aSElliott Hughes xAvgCharWidth_after = subset_font["OS/2"].xAvgCharWidth 1909*e1fe3e4aSElliott Hughes 1910*e1fe3e4aSElliott Hughes # Check that the value gets updated 1911*e1fe3e4aSElliott Hughes assert xAvgCharWidth_after != xAvgCharWidth_before 1912*e1fe3e4aSElliott Hughes 1913*e1fe3e4aSElliott Hughes # Check that the value gets updated to the actual new value 1914*e1fe3e4aSElliott Hughes subset_font["OS/2"].recalcAvgCharWidth(subset_font) 1915*e1fe3e4aSElliott Hughes assert xAvgCharWidth_after == subset_font["OS/2"].xAvgCharWidth 1916*e1fe3e4aSElliott Hughes 1917*e1fe3e4aSElliott Hughes 1918*e1fe3e4aSElliott Hughesif __name__ == "__main__": 1919*e1fe3e4aSElliott Hughes sys.exit(unittest.main()) 1920*e1fe3e4aSElliott Hughes 1921*e1fe3e4aSElliott Hughes 1922*e1fe3e4aSElliott Hughesdef test_subset_prune_gdef_markglyphsetsdef(): 1923*e1fe3e4aSElliott Hughes # GDEF_MarkGlyphSetsDef 1924*e1fe3e4aSElliott Hughes fb = FontBuilder(unitsPerEm=1000, isTTF=True) 1925*e1fe3e4aSElliott Hughes glyph_order = [ 1926*e1fe3e4aSElliott Hughes ".notdef", 1927*e1fe3e4aSElliott Hughes "A", 1928*e1fe3e4aSElliott Hughes "Aacute", 1929*e1fe3e4aSElliott Hughes "Acircumflex", 1930*e1fe3e4aSElliott Hughes "Adieresis", 1931*e1fe3e4aSElliott Hughes "a", 1932*e1fe3e4aSElliott Hughes "aacute", 1933*e1fe3e4aSElliott Hughes "acircumflex", 1934*e1fe3e4aSElliott Hughes "adieresis", 1935*e1fe3e4aSElliott Hughes "dieresiscomb", 1936*e1fe3e4aSElliott Hughes "acutecomb", 1937*e1fe3e4aSElliott Hughes "circumflexcomb", 1938*e1fe3e4aSElliott Hughes ] 1939*e1fe3e4aSElliott Hughes fb.setupGlyphOrder(glyph_order) 1940*e1fe3e4aSElliott Hughes fb.setupGlyf({g: TTGlyphPen(None).glyph() for g in glyph_order}) 1941*e1fe3e4aSElliott Hughes fb.setupHorizontalMetrics({g: (500, 0) for g in glyph_order}) 1942*e1fe3e4aSElliott Hughes fb.setupHorizontalHeader() 1943*e1fe3e4aSElliott Hughes fb.setupPost() 1944*e1fe3e4aSElliott Hughes fb.setupNameTable( 1945*e1fe3e4aSElliott Hughes {"familyName": "TestGDEFMarkGlyphSetsDef", "styleName": "Regular"} 1946*e1fe3e4aSElliott Hughes ) 1947*e1fe3e4aSElliott Hughes fb.addOpenTypeFeatures( 1948*e1fe3e4aSElliott Hughes """ 1949*e1fe3e4aSElliott Hughes feature ccmp { 1950*e1fe3e4aSElliott Hughes lookup ccmp_1 { 1951*e1fe3e4aSElliott Hughes lookupflag UseMarkFilteringSet [acutecomb]; 1952*e1fe3e4aSElliott Hughes sub a acutecomb by aacute; 1953*e1fe3e4aSElliott Hughes sub A acutecomb by Aacute; 1954*e1fe3e4aSElliott Hughes } ccmp_1; 1955*e1fe3e4aSElliott Hughes lookup ccmp_2 { 1956*e1fe3e4aSElliott Hughes lookupflag UseMarkFilteringSet [circumflexcomb]; 1957*e1fe3e4aSElliott Hughes sub a circumflexcomb by acircumflex; 1958*e1fe3e4aSElliott Hughes sub A circumflexcomb by Acircumflex; 1959*e1fe3e4aSElliott Hughes } ccmp_2; 1960*e1fe3e4aSElliott Hughes lookup ccmp_3 { 1961*e1fe3e4aSElliott Hughes lookupflag UseMarkFilteringSet [dieresiscomb]; 1962*e1fe3e4aSElliott Hughes sub a dieresiscomb by adieresis; 1963*e1fe3e4aSElliott Hughes sub A dieresiscomb by Adieresis; 1964*e1fe3e4aSElliott Hughes sub A acutecomb by Aacute; 1965*e1fe3e4aSElliott Hughes } ccmp_3; 1966*e1fe3e4aSElliott Hughes } ccmp; 1967*e1fe3e4aSElliott Hughes """ 1968*e1fe3e4aSElliott Hughes ) 1969*e1fe3e4aSElliott Hughes 1970*e1fe3e4aSElliott Hughes buf = io.BytesIO() 1971*e1fe3e4aSElliott Hughes fb.save(buf) 1972*e1fe3e4aSElliott Hughes buf.seek(0) 1973*e1fe3e4aSElliott Hughes 1974*e1fe3e4aSElliott Hughes font = TTFont(buf) 1975*e1fe3e4aSElliott Hughes 1976*e1fe3e4aSElliott Hughes features = font["GSUB"].table.FeatureList.FeatureRecord 1977*e1fe3e4aSElliott Hughes assert features[0].FeatureTag == "ccmp" 1978*e1fe3e4aSElliott Hughes lookups = font["GSUB"].table.LookupList.Lookup 1979*e1fe3e4aSElliott Hughes assert lookups[0].LookupFlag == 16 1980*e1fe3e4aSElliott Hughes assert lookups[0].MarkFilteringSet == 0 1981*e1fe3e4aSElliott Hughes assert lookups[1].LookupFlag == 16 1982*e1fe3e4aSElliott Hughes assert lookups[1].MarkFilteringSet == 1 1983*e1fe3e4aSElliott Hughes assert lookups[2].LookupFlag == 16 1984*e1fe3e4aSElliott Hughes assert lookups[2].MarkFilteringSet == 2 1985*e1fe3e4aSElliott Hughes marksets = font["GDEF"].table.MarkGlyphSetsDef.Coverage 1986*e1fe3e4aSElliott Hughes assert marksets[0].glyphs == ["acutecomb"] 1987*e1fe3e4aSElliott Hughes assert marksets[1].glyphs == ["circumflexcomb"] 1988*e1fe3e4aSElliott Hughes assert marksets[2].glyphs == ["dieresiscomb"] 1989*e1fe3e4aSElliott Hughes 1990*e1fe3e4aSElliott Hughes options = subset.Options(layout_features=["*"]) 1991*e1fe3e4aSElliott Hughes subsetter = subset.Subsetter(options) 1992*e1fe3e4aSElliott Hughes subsetter.populate(glyphs=["A", "a", "acutecomb", "dieresiscomb"]) 1993*e1fe3e4aSElliott Hughes subsetter.subset(font) 1994*e1fe3e4aSElliott Hughes 1995*e1fe3e4aSElliott Hughes features = font["GSUB"].table.FeatureList.FeatureRecord 1996*e1fe3e4aSElliott Hughes assert features[0].FeatureTag == "ccmp" 1997*e1fe3e4aSElliott Hughes lookups = font["GSUB"].table.LookupList.Lookup 1998*e1fe3e4aSElliott Hughes assert lookups[0].LookupFlag == 16 1999*e1fe3e4aSElliott Hughes assert lookups[0].MarkFilteringSet == 0 2000*e1fe3e4aSElliott Hughes assert lookups[1].LookupFlag == 16 2001*e1fe3e4aSElliott Hughes assert lookups[1].MarkFilteringSet == 1 2002*e1fe3e4aSElliott Hughes marksets = font["GDEF"].table.MarkGlyphSetsDef.Coverage 2003*e1fe3e4aSElliott Hughes assert marksets[0].glyphs == ["acutecomb"] 2004*e1fe3e4aSElliott Hughes assert marksets[1].glyphs == ["dieresiscomb"] 2005*e1fe3e4aSElliott Hughes 2006*e1fe3e4aSElliott Hughes buf = io.BytesIO() 2007*e1fe3e4aSElliott Hughes fb.save(buf) 2008*e1fe3e4aSElliott Hughes buf.seek(0) 2009*e1fe3e4aSElliott Hughes 2010*e1fe3e4aSElliott Hughes font = TTFont(buf) 2011*e1fe3e4aSElliott Hughes 2012*e1fe3e4aSElliott Hughes options = subset.Options(layout_features=["*"], layout_closure=False) 2013*e1fe3e4aSElliott Hughes subsetter = subset.Subsetter(options) 2014*e1fe3e4aSElliott Hughes subsetter.populate(glyphs=["A", "acutecomb", "Aacute"]) 2015*e1fe3e4aSElliott Hughes subsetter.subset(font) 2016*e1fe3e4aSElliott Hughes 2017*e1fe3e4aSElliott Hughes features = font["GSUB"].table.FeatureList.FeatureRecord 2018*e1fe3e4aSElliott Hughes assert features[0].FeatureTag == "ccmp" 2019*e1fe3e4aSElliott Hughes lookups = font["GSUB"].table.LookupList.Lookup 2020*e1fe3e4aSElliott Hughes assert lookups[0].LookupFlag == 16 2021*e1fe3e4aSElliott Hughes assert lookups[0].MarkFilteringSet == 0 2022*e1fe3e4aSElliott Hughes assert lookups[1].LookupFlag == 0 2023*e1fe3e4aSElliott Hughes assert lookups[1].MarkFilteringSet == None 2024*e1fe3e4aSElliott Hughes marksets = font["GDEF"].table.MarkGlyphSetsDef.Coverage 2025*e1fe3e4aSElliott Hughes assert marksets[0].glyphs == ["acutecomb"] 2026