Skip to content

Commit 28acf88

Browse files
authored
Merge pull request #962 from googlefonts/fix-dangling-dist
Fix dangling lookups when feature block already exists
2 parents 3203897 + 567cabb commit 28acf88

File tree

3 files changed

+86
-4
lines changed

3 files changed

+86
-4
lines changed

Lib/ufo2ft/featureWriters/kernFeatureWriter.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,18 +297,32 @@ def _write(self):
297297
classDefs = self.context.kerning.classDefs
298298
newClassDefs = [c for _, c in sorted(classDefs.items())]
299299

300+
featureBlocks = [features[tag] for tag in ["kern", "dist"] if tag in features]
301+
302+
# Collect only the lookups that are referenced by the features we're
303+
# writing, to avoid inserting unreferenced/dangling lookups when a
304+
# feature block already exists in the feature file.
305+
referencedLookups = {
306+
statement.lookup
307+
for feature in featureBlocks
308+
for statement in feature.statements
309+
if isinstance(statement, ast.LookupReferenceStatement)
310+
}
311+
300312
lookupGroups = []
301313
for _, lookupGroup in sorted(lookups.items()):
302314
lookupGroups.extend(
303-
lkp for lkp in lookupGroup.values() if lkp not in lookupGroups
315+
lkp
316+
for lkp in lookupGroup.values()
317+
if lkp in referencedLookups and lkp not in lookupGroups
304318
)
305319

306320
# NOTE: We don't write classDefs because we literalise all classes.
307321
self._insert(
308322
feaFile=feaFile,
309323
classDefs=newClassDefs,
310324
lookups=lookupGroups,
311-
features=[features[tag] for tag in ["kern", "dist"] if tag in features],
325+
features=featureBlocks,
312326
)
313327
return True
314328

Lib/ufo2ft/featureWriters/kernFeatureWriter2.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -291,17 +291,31 @@ def _write(self):
291291
classDefs = self.context.kerning.classDefs
292292
newClassDefs = [c for _, c in sorted(classDefs.items())]
293293

294+
featureBlocks = [features[tag] for tag in ["kern", "dist"] if tag in features]
295+
296+
# Collect only the lookups that are referenced by the features we're
297+
# writing, to avoid inserting unreferenced/dangling lookups when a
298+
# feature block already exists in the feature file.
299+
referencedLookups = {
300+
statement.lookup
301+
for feature in featureBlocks
302+
for statement in feature.statements
303+
if isinstance(statement, ast.LookupReferenceStatement)
304+
}
305+
294306
lookupGroups = []
295307
for _, lookupGroup in sorted(lookups.items(), key=lambda x: x[0].value):
296308
lookupGroups.extend(
297-
lkp for lkp in lookupGroup.values() if lkp not in lookupGroups
309+
lkp
310+
for lkp in lookupGroup.values()
311+
if lkp in referencedLookups and lkp not in lookupGroups
298312
)
299313

300314
self._insert(
301315
feaFile=feaFile,
302316
classDefs=newClassDefs,
303317
lookups=lookupGroups,
304-
features=[features[tag] for tag in ["kern", "dist"] if tag in features],
318+
features=featureBlocks,
305319
)
306320
return True
307321

tests/featureWriters/kernFeatureWriter_test.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2279,6 +2279,60 @@ def test_dflt_language(FontClass):
22792279
)
22802280

22812281

2282+
def test_skip_existing_feature_no_dangling_lookups(FontClass):
2283+
"""Check that when a feature block already exists (e.g. dist), the lookups
2284+
that would have been generated for that feature are not written to the
2285+
feature file, thus ensuring no dangling/unreferenced lookups.
2286+
2287+
See: https://github.com/googlefonts/ufo2ft/issues/960
2288+
"""
2289+
# Create glyphs for both kern (Latin) and dist (Kannada)
2290+
glyphs = {
2291+
"a": ord("a"),
2292+
"b": ord("b"),
2293+
"aaMatra_kannada": 0x0CBE,
2294+
"ailength_kannada": 0xCD6,
2295+
}
2296+
groups = {
2297+
"public.kern1.KND_aaMatra_R": ["aaMatra_kannada"],
2298+
"public.kern2.KND_ailength_L": ["aaMatra_kannada"],
2299+
}
2300+
kerning = {
2301+
("a", "b"): 10, # This will go to kern feature
2302+
("public.kern1.KND_aaMatra_R", "public.kern2.KND_ailength_L"): 34, # dist
2303+
}
2304+
# Features with existing dist block: this should cause dist to be skipped
2305+
features = dedent(
2306+
"""\
2307+
languagesystem DFLT dflt;
2308+
languagesystem latn dflt;
2309+
languagesystem knda dflt;
2310+
languagesystem knd2 dflt;
2311+
2312+
feature dist {
2313+
# manual dist feature
2314+
pos aaMatra_kannada ailength_kannada 50;
2315+
} dist;
2316+
"""
2317+
)
2318+
2319+
ufo = makeUFO(FontClass, glyphs, groups, kerning, features)
2320+
2321+
writer = KernFeatureWriter()
2322+
feaFile = parseLayoutFeatures(ufo)
2323+
writer.write(ufo, feaFile)
2324+
2325+
# Get all lookups in the generated feature file
2326+
lookups = getLookups(feaFile)
2327+
lookup_names = [lkp.name for lkp in lookups]
2328+
2329+
# Expect kern lookup for Latin, but NOT dist lookup for Kannada
2330+
assert "kern_Latn" in lookup_names
2331+
assert (
2332+
"kern_Knda" not in lookup_names
2333+
), "kern_Knda lookup should not be generated when dist feature exists"
2334+
2335+
22822336
if __name__ == "__main__":
22832337
import sys
22842338

0 commit comments

Comments
 (0)