Merge pull request #2603 from fonttools/subset-singlepos2-all-none

[subset] Fix subsetting SinglePosFormat2 with ValueFormat=0
This commit is contained in:
Cosimo Lupo 2022-04-27 16:15:21 +01:00 committed by GitHub
commit 41bd3a143d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 6 deletions

View File

@ -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):

View File

@ -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():
'</Lookup>',
]
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) == [
'<SinglePos Format="2">',
' <Coverage>',
' <Glyph value="a"/>',
' <Glyph value="b"/>',
' <Glyph value="c"/>',
' </Coverage>',
' <ValueFormat value="0"/>',
' <!-- ValueCount=3 -->',
'</SinglePos>',
]
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) == [
'<SinglePos Format="1">',
' <Coverage>',
' <Glyph value="a"/>',
' <Glyph value="c"/>',
' </Coverage>',
' <ValueFormat value="0"/>',
'</SinglePos>',
]
@pytest.fixture
def ttf_path(tmp_path):