diff --git a/Lib/fontTools/subset/__init__.py b/Lib/fontTools/subset/__init__.py index 56d9c0ef5..b9d358564 100644 --- a/Lib/fontTools/subset/__init__.py +++ b/Lib/fontTools/subset/__init__.py @@ -636,10 +636,16 @@ def prune_post_subset(self, font, options): self.Value.prune_hints() self.ValueFormat = self.Value.getEffectiveFormat() elif self.Format == 2: - if not options.hinting: - for v in self.Value: - v.prune_hints() - self.ValueFormat = reduce(int.__or__, [v.getEffectiveFormat() for v in self.Value], 0) + if None in self.Value: + assert self.ValueFormat == 0 + assert all(v is None for v in self.Value) + else: + if not options.hinting: + for v in self.Value: + v.prune_hints() + self.ValueFormat = reduce( + int.__or__, [v.getEffectiveFormat() for v in self.Value], 0 + ) # Downgrade to Format 1 if all ValueRecords are the same if self.Format == 2 and all(v == self.Value[0] for v in self.Value): diff --git a/Tests/subset/subset_test.py b/Tests/subset/subset_test.py index facafb2a7..2c51a5a9e 100644 --- a/Tests/subset/subset_test.py +++ b/Tests/subset/subset_test.py @@ -953,7 +953,8 @@ def test_subset_feature_variations_drop_all(featureVarsTestFont): # https://github.com/fonttools/fonttools/issues/1881#issuecomment-619415044 -def test_subset_single_pos_format(): +@pytest.fixture +def singlepos2_font(): fb = FontBuilder(unitsPerEm=1000) fb.setupGlyphOrder([".notdef", "a", "b", "c"]) fb.setupCharacterMap({ord("a"): "a", ord("b"): "b", ord("c"): "c"}) @@ -971,8 +972,11 @@ def test_subset_single_pos_format(): fb.save(buf) buf.seek(0) - font = TTFont(buf) + return TTFont(buf) + +def test_subset_single_pos_format(singlepos2_font): + font = singlepos2_font # The input font has a SinglePos Format 2 subtable where each glyph has # different ValueRecords assert getXML(font["GPOS"].table.LookupList.Lookup[0].toXML, font) == [ @@ -1018,6 +1022,46 @@ def test_subset_single_pos_format(): '', ] +def test_subset_single_pos_format2_all_None(singlepos2_font): + # https://github.com/fonttools/fonttools/issues/2602 + font = singlepos2_font + gpos = font["GPOS"].table + subtable = gpos.LookupList.Lookup[0].SubTable[0] + assert subtable.Format == 2 + # Hack a SinglePosFormat2 with ValueFormat = 0; our own buildSinglePos + # never makes these as a SinglePosFormat1 is more compact, but they can + # be found in the wild. + subtable.Value = [None] * subtable.ValueCount + subtable.ValueFormat = 0 + + assert getXML(subtable.toXML, font) == [ + '', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + '', + ] + + options = subset.Options() + subsetter = subset.Subsetter(options) + subsetter.populate(unicodes=[ord("a"), ord("c")]) + subsetter.subset(font) + + # Check it was downgraded to Format1 after subsetting + assert getXML(font["GPOS"].table.LookupList.Lookup[0].SubTable[0].toXML, font) == [ + '', + ' ', + ' ', + ' ', + ' ', + ' ', + '', + ] + @pytest.fixture def ttf_path(tmp_path):