diff --git a/Lib/ufo2ft/__init__.py b/Lib/ufo2ft/__init__.py
index aad7e05c9..72102292c 100644
--- a/Lib/ufo2ft/__init__.py
+++ b/Lib/ufo2ft/__init__.py
@@ -24,7 +24,7 @@
TTFPreProcessor,
)
from ufo2ft.util import (
- _getDefaultNotdefGlyph,
+ _notdefGlyphFallback,
colrClipBoxQuantization,
ensure_all_sources_have_names,
init_kwargs,
@@ -408,7 +408,7 @@ def compileInterpolatableTTFsFromDS(designSpaceDoc, **kwargs):
kwargs["skipExportGlyphs"] = designSpaceDoc.lib.get("public.skipExportGlyphs", [])
if kwargs["notdefGlyph"] is None:
- kwargs["notdefGlyph"] = _getDefaultNotdefGlyph(designSpaceDoc, empty=True)
+ kwargs["notdefGlyph"] = _notdefGlyphFallback(designSpaceDoc)
kwargs["extraSubstitutions"] = defaultdict(set)
for rule in designSpaceDoc.rules:
@@ -479,7 +479,7 @@ def compileInterpolatableOTFsFromDS(designSpaceDoc, **kwargs):
kwargs["skipExportGlyphs"] = designSpaceDoc.lib.get("public.skipExportGlyphs", [])
if kwargs["notdefGlyph"] is None:
- kwargs["notdefGlyph"] = _getDefaultNotdefGlyph(designSpaceDoc)
+ kwargs["notdefGlyph"] = _notdefGlyphFallback(designSpaceDoc)
kwargs["extraSubstitutions"] = defaultdict(set)
for rule in designSpaceDoc.rules:
diff --git a/Lib/ufo2ft/util.py b/Lib/ufo2ft/util.py
index 08aacc7a4..48d56a79c 100644
--- a/Lib/ufo2ft/util.py
+++ b/Lib/ufo2ft/util.py
@@ -475,7 +475,17 @@ def getDefaultMasterFont(designSpaceDoc):
return defaultSource.font
-def _getDefaultNotdefGlyph(designSpaceDoc, empty=False):
+def _notdefGlyphFallback(designSpaceDoc):
+ """Return an empty glyph to be used as .notdef for sparse layer masters.
+
+ Sparse layers usually do not contain a .notdef glyph, however in order to
+ compile valid TTFs to be used as master in varLib.build, a .notdef at index 0 is
+ required. We can't use the auto-generated .notdef glyph because it may be
+ incompatible with the one already present in the other masters. So we make
+ an empty glyph which will be ignored when building gvar or HVAR.
+ If the default master does not contain a .notdef either, return None since
+ the auto-generated .notdef can be used.
+ """
from ufo2ft.errors import InvalidDesignSpaceData
try:
@@ -489,17 +499,11 @@ def _getDefaultNotdefGlyph(designSpaceDoc, empty=False):
except KeyError:
notdefGlyph = None
else:
- if empty:
- # create a new empty .notdef glyph with the same width/height
- # as the default master's .notdef glyph to be use for sparse layer
- # master TTFs, so that it won't participate in gvar interpolation
- # TODO(anthrotype): Use sentinel values for width/height to
- # mark the glyph as non-participating for HVAR if/when fonttools
- # supports that, https://github.com/googlefonts/ufo2ft/issues/501
- emptyGlyph = _getNewGlyphFactory(notdefGlyph)(".notdef")
- emptyGlyph.width = notdefGlyph.width
- emptyGlyph.height = notdefGlyph.height
- notdefGlyph = emptyGlyph
+ notdefGlyph = _getNewGlyphFactory(notdefGlyph)(".notdef")
+ # sentinel value for varLib that means this advance does not participate
+ # https://github.com/fonttools/fonttools/pull/3235
+ notdefGlyph.width = 0xFFFF
+ notdefGlyph.height = 0xFFFF
return notdefGlyph
diff --git a/requirements.txt b/requirements.txt
index 03761ea5c..f905028bf 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,4 @@
-fonttools[lxml,ufo]==4.40.0
+fonttools[lxml,ufo]==4.42.0
defcon==0.10.2
compreffor==0.5.3
booleanOperations==0.9.0
diff --git a/setup.py b/setup.py
index 494f7ac48..6376893a7 100644
--- a/setup.py
+++ b/setup.py
@@ -29,7 +29,7 @@
setup_requires=pytest_runner + wheel + ["setuptools_scm"],
tests_require=["pytest>=2.8"],
install_requires=[
- "fonttools[ufo]>=4.40.0",
+ "fonttools[ufo]>=4.42.0",
"cffsubr>=0.2.8",
"booleanOperations>=0.9.0",
],
diff --git a/tests/data/TestVariableFont-CFF2-cffsubr.ttx b/tests/data/TestVariableFont-CFF2-cffsubr.ttx
index b55692286..229119048 100644
--- a/tests/data/TestVariableFont-CFF2-cffsubr.ttx
+++ b/tests/data/TestVariableFont-CFF2-cffsubr.ttx
@@ -471,20 +471,20 @@
-
+
-
-
+
+
-
+
diff --git a/tests/data/TestVariableFont-CFF2-post3.ttx b/tests/data/TestVariableFont-CFF2-post3.ttx
index f80c8a030..c34b0e365 100644
--- a/tests/data/TestVariableFont-CFF2-post3.ttx
+++ b/tests/data/TestVariableFont-CFF2-post3.ttx
@@ -448,20 +448,20 @@
-
+
-
-
+
+
-
+
diff --git a/tests/data/TestVariableFont-CFF2-sparse-notdefGlyph.ttx b/tests/data/TestVariableFont-CFF2-sparse-notdefGlyph.ttx
new file mode 100644
index 000000000..5cfd91194
--- /dev/null
+++ b/tests/data/TestVariableFont-CFF2-sparse-notdefGlyph.ttx
@@ -0,0 +1,182 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 50 -250 rmoveto
+ 400 1000 -400 hlineto
+ 50 -950 rmoveto
+ 900 300 -900 vlineto
+ 100 500 1 blend
+ 200 rmoveto
+ 278 -112 222 -138 -138 -112 -222 -278 277 -112 223 -138 -138 -112 -223 -277 8 blend
+ vhcurveto
+
+
+ 468 -1 rmoveto
+ -21 435 -233 70 -205 -76 27 -91 -56 1 blend
+ 172 60 155 -40 -59 2 2 blend
+ 3 -360 56 1 blend
+ rlineto
+ 12 266 59 -2 2 blend
+ rmoveto
+ -352 -23 3 -218 139 -34 221 83 -6 63 -222 -60 -75 52 15 40 13 37 -21 5 blend
+ 2 46 294 35 -78 -30 2 blend
+ rlineto
+
+
+ -21 597 -8 28 2 blend
+ rmoveto
+ -16 -94 78 -2 9 88 -19 -48 44 7 -4 29 6 blend
+ rlineto
+
+
+ 1 vsindex
+ 127 228 -1 70 -25 1 2 blend
+ rmoveto
+ 449 -2 1 -45 -2 -2 2 blend
+ -5 79 -255 208 -276 -252 148 -279 338 63 -17 84 -280 -54 -82 188 170 153 163 -124 -355 6 27 0 0 -27 0 36 0 -29 0 -34 0 31 0 -1 0 2 0 -45 -2 13 28 100 37 0 13 0 -2 55 -40 -54 -32 -86 -30 -57 -85 -60 34 57 84 146 -5 0 21 blend
+ rlineto
+
+
+ 127 228 70 1 2 blend
+ rmoveto
+ 449 -2 -45 -2 2 blend
+ -5 79 -255 208 -276 -252 148 -279 338 63 -17 84 -27 36 -29 -34 31 -1 2 -45 13 100 10 blend
+ -280 -54 -82 188 170 153 163 -124 -355 55 -54 -86 -57 -60 57 146 7 blend
+ 6 rlineto
+ 167 395 -84 118 2 blend
+ rmoveto
+ -16 -94 78 -2 9 88 -19 -48 44 7 -4 29 6 blend
+ rlineto
+
+
+ 559 459 rmoveto
+ -235 71 -286 -187 389 -188 -145 -79 -229 98 -28 -91 279 -96 278 187 -369 192 113 76 -22 55 -58 -61 19 49 34 9 9 -56 -2 -41 46 12 29 24 -57 -31 18 blend
+ 213 -66 rlineto
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/data/TestVariableFont-CFF2-useProductionNames.ttx b/tests/data/TestVariableFont-CFF2-useProductionNames.ttx
index e3d3b540f..5e6b95900 100644
--- a/tests/data/TestVariableFont-CFF2-useProductionNames.ttx
+++ b/tests/data/TestVariableFont-CFF2-useProductionNames.ttx
@@ -465,20 +465,20 @@
-
+
-
-
+
+
-
+
diff --git a/tests/data/TestVariableFont-CFF2.ttx b/tests/data/TestVariableFont-CFF2.ttx
index d82ba84f9..735005abd 100644
--- a/tests/data/TestVariableFont-CFF2.ttx
+++ b/tests/data/TestVariableFont-CFF2.ttx
@@ -462,20 +462,20 @@
-
+
-
-
+
+
-
+
diff --git a/tests/data/TestVariableFont-TTF-post3.ttx b/tests/data/TestVariableFont-TTF-post3.ttx
index 4f83e6bd1..eedec8ee2 100644
--- a/tests/data/TestVariableFont-TTF-post3.ttx
+++ b/tests/data/TestVariableFont-TTF-post3.ttx
@@ -451,20 +451,20 @@
-
+
-
-
+
+
-
+
diff --git a/tests/data/TestVariableFont-TTF-useProductionNames.ttx b/tests/data/TestVariableFont-TTF-useProductionNames.ttx
index 5adc73e7b..1042f99e9 100644
--- a/tests/data/TestVariableFont-TTF-useProductionNames.ttx
+++ b/tests/data/TestVariableFont-TTF-useProductionNames.ttx
@@ -468,20 +468,20 @@
-
+
-
-
+
+
-
+
diff --git a/tests/data/TestVariableFont-TTF.ttx b/tests/data/TestVariableFont-TTF.ttx
index e6fab0507..4749600e2 100644
--- a/tests/data/TestVariableFont-TTF.ttx
+++ b/tests/data/TestVariableFont-TTF.ttx
@@ -465,20 +465,20 @@
-
+
-
-
+
+
-
+
diff --git a/tests/integration_test.py b/tests/integration_test.py
index d8a71d6f3..05c2ba0dd 100644
--- a/tests/integration_test.py
+++ b/tests/integration_test.py
@@ -515,6 +515,23 @@ def test_compileVariableTTF_notdefGlyph_with_curves(self, designspace):
# varLib only warns: https://github.com/fonttools/fonttools/issues/2572
assert ".notdef" in vf["gvar"].variations
+ def test_compileVariableCFF2_sparse_notdefGlyph(self, designspace):
+ # test that sparse layer without .notdef does not participate in computation
+ # of CFF2 and HVAR deltas for the .notdef glypht
+ for src_idx, transform in ((0, (1, 0, 0, 1, 0, 0)), (2, (2, 0, 0, 2, 0, 0))):
+ notdef = designspace.sources[src_idx].font[".notdef"]
+ self.drawCurvedContour(notdef, transform)
+ designspace.sources[2].font[".notdef"].width *= 2
+ assert ".notdef" not in designspace.sources[1].font.layers["Medium"]
+
+ vf = compileVariableCFF2(designspace)
+
+ expectTTX(
+ vf,
+ "TestVariableFont-CFF2-sparse-notdefGlyph.ttx",
+ tables=["CFF2", "hmtx", "HVAR"],
+ )
+
if __name__ == "__main__":
sys.exit(pytest.main(sys.argv))