diff --git a/Lib/ufo2ft/__init__.py b/Lib/ufo2ft/__init__.py index 6825465a7..fb17a5db8 100644 --- a/Lib/ufo2ft/__init__.py +++ b/Lib/ufo2ft/__init__.py @@ -1,5 +1,6 @@ import logging from enum import IntEnum +from typing import Any, Optional from fontTools import varLib @@ -53,6 +54,7 @@ def compileOTF( cffVersion=1, subroutinizer=None, notdefGlyph=None, + postProcessorClass: Optional[Any] = PostProcessor, _tables=None, ): """Create FontTools CFF font from a UFO. @@ -153,13 +155,14 @@ def compileOTF( debugFeatureFile=debugFeatureFile, ) - postProcessor = PostProcessor(otf, ufo, glyphSet=glyphSet) - otf = postProcessor.process( - useProductionNames, - optimizeCFF=optimizeCFF >= CFFOptimization.SUBROUTINIZE, - subroutinizer=subroutinizer, - cffVersion=cffVersion, - ) + if postProcessorClass is not None: + postProcessor = postProcessorClass(otf, ufo, glyphSet=glyphSet) + otf = postProcessor.process( + useProductionNames, + optimizeCFF=optimizeCFF >= CFFOptimization.SUBROUTINIZE, + subroutinizer=subroutinizer, + cffVersion=cffVersion, + ) return otf @@ -185,6 +188,7 @@ def compileTTF( skipExportGlyphs=None, debugFeatureFile=None, notdefGlyph=None, + postProcessorClass: Optional[Any] = PostProcessor, ): """Create FontTools TrueType font from a UFO. @@ -244,8 +248,9 @@ def compileTTF( debugFeatureFile=debugFeatureFile, ) - postProcessor = PostProcessor(otf, ufo, glyphSet=glyphSet) - otf = postProcessor.process(useProductionNames) + if postProcessorClass is not None: + postProcessor = postProcessorClass(otf, ufo, glyphSet=glyphSet) + otf = postProcessor.process(useProductionNames) return otf @@ -267,6 +272,7 @@ def compileInterpolatableTTFs( skipExportGlyphs=None, debugFeatureFile=None, notdefGlyph=None, + postProcessorClass: Optional[Any] = PostProcessor, ): """Create FontTools TrueType fonts from a list of UFOs with interpolatable outlines. Cubic curves are converted compatibly to quadratic curves using @@ -343,8 +349,9 @@ def compileInterpolatableTTFs( debugFeatureFile=debugFeatureFile, ) - postProcessor = PostProcessor(ttf, ufo, glyphSet=glyphSet) - ttf = postProcessor.process(useProductionNames) + if postProcessorClass is not None: + postProcessor = postProcessorClass(ttf, ufo, glyphSet=glyphSet) + ttf = postProcessor.process(useProductionNames) if layerName is not None: # for sparse masters (i.e. containing only a subset of the glyphs), we @@ -375,6 +382,7 @@ def compileInterpolatableTTFsFromDS( inplace=False, debugFeatureFile=None, notdefGlyph=None, + postProcessorClass: Optional[Any] = PostProcessor, ): """Create FontTools TrueType fonts from the DesignSpaceDocument UFO sources with interpolatable outlines. Cubic curves are converted compatibly to @@ -433,6 +441,7 @@ def compileInterpolatableTTFsFromDS( skipExportGlyphs=skipExportGlyphs, debugFeatureFile=debugFeatureFile, notdefGlyph=notdefGlyph, + postProcessorClass=postProcessorClass, ) if inplace: @@ -458,6 +467,7 @@ def compileInterpolatableOTFsFromDS( inplace=False, debugFeatureFile=None, notdefGlyph=None, + postProcessorClass: Optional[Any] = PostProcessor, ): """Create FontTools CFF fonts from the DesignSpaceDocument UFO sources with interpolatable outlines. @@ -519,6 +529,7 @@ def compileInterpolatableOTFsFromDS( debugFeatureFile=debugFeatureFile, notdefGlyph=notdefGlyph, _tables=SPARSE_OTF_MASTER_TABLES if source.layerName else None, + postProcessorClass=postProcessorClass, ) ) @@ -596,6 +607,7 @@ def compileVariableTTF( inplace=False, debugFeatureFile=None, notdefGlyph=None, + postProcessorClass: Optional[Any] = PostProcessor, ): """Create FontTools TrueType variable font from the DesignSpaceDocument UFO sources with interpolatable outlines, using fontTools.varLib.build. @@ -627,6 +639,8 @@ def compileVariableTTF( inplace=inplace, debugFeatureFile=debugFeatureFile, notdefGlyph=notdefGlyph, + # No need to post-process intermediate fonts. + postProcessorClass=None, ) logger.info("Building variable TTF font") @@ -635,8 +649,9 @@ def compileVariableTTF( ttfDesignSpace, exclude=excludeVariationTables, optimize=optimizeGvar )[0] - postProcessor = PostProcessor(varfont, baseUfo) - varfont = postProcessor.process(useProductionNames) + if postProcessorClass is not None: + postProcessor = postProcessorClass(varfont, baseUfo) + varfont = postProcessor.process(useProductionNames) return varfont @@ -656,6 +671,7 @@ def compileVariableCFF2( debugFeatureFile=None, optimizeCFF=CFFOptimization.SPECIALIZE, notdefGlyph=None, + postProcessorClass: Optional[Any] = PostProcessor, ): """Create FontTools CFF2 variable font from the DesignSpaceDocument UFO sources with interpolatable outlines, using fontTools.varLib.build. @@ -690,6 +706,8 @@ def compileVariableCFF2( inplace=inplace, debugFeatureFile=debugFeatureFile, notdefGlyph=notdefGlyph, + # No need to post-process intermediate fonts. + postProcessorClass=None, ) logger.info("Building variable CFF2 font") @@ -704,10 +722,11 @@ def compileVariableCFF2( optimize=optimizeCFF >= CFFOptimization.SPECIALIZE, )[0] - postProcessor = PostProcessor(varfont, baseUfo) - varfont = postProcessor.process( - useProductionNames, - optimizeCFF=optimizeCFF >= CFFOptimization.SUBROUTINIZE, - ) + if postProcessorClass is not None: + postProcessor = postProcessorClass(varfont, baseUfo) + varfont = postProcessor.process( + useProductionNames, + optimizeCFF=optimizeCFF >= CFFOptimization.SUBROUTINIZE, + ) return varfont diff --git a/Lib/ufo2ft/outlineCompiler.py b/Lib/ufo2ft/outlineCompiler.py index c0054ff92..b1877503e 100644 --- a/Lib/ufo2ft/outlineCompiler.py +++ b/Lib/ufo2ft/outlineCompiler.py @@ -537,7 +537,7 @@ def setupTable_OS2(self): # subscript, superscript, strikeout values, taken from AFDKO: # FDK/Tools/Programs/makeotf/makeotf_lib/source/hotconv/hot.c unitsPerEm = getAttrWithFallback(font.info, "unitsPerEm") - italicAngle = getAttrWithFallback(font.info, "italicAngle") + italicAngle = float(getAttrWithFallback(font.info, "italicAngle")) xHeight = getAttrWithFallback(font.info, "xHeight") def adjustOffset(offset, angle): @@ -889,7 +889,7 @@ def setupTable_post(self): font = self.ufo post.formatType = 3.0 # italic angle - italicAngle = getAttrWithFallback(font.info, "italicAngle") + italicAngle = float(getAttrWithFallback(font.info, "italicAngle")) post.italicAngle = italicAngle # underline underlinePosition = getAttrWithFallback( @@ -900,7 +900,9 @@ def setupTable_post(self): font.info, "postscriptUnderlineThickness" ) post.underlineThickness = otRound(underlineThickness) - post.isFixedPitch = getAttrWithFallback(font.info, "postscriptIsFixedPitch") + post.isFixedPitch = int( + getAttrWithFallback(font.info, "postscriptIsFixedPitch") + ) # misc post.minMemType42 = 0 post.maxMemType42 = 0 @@ -1140,6 +1142,9 @@ def setupTable_CFF(self): self.otf["CFF "] = cff = newTable("CFF ") cff = cff.cff + # NOTE: Set up a back-reference to be used by some CFFFontSet methods + # down the line (as of fontTools 4.21.1). + cff.otFont = self.otf # set up the basics cff.major = 1 cff.minor = 0 @@ -1215,8 +1220,8 @@ def setupTable_CFF(self): ) topDict.Weight = getAttrWithFallback(info, "postscriptWeightName") # populate various numbers - topDict.isFixedPitch = getAttrWithFallback(info, "postscriptIsFixedPitch") - topDict.ItalicAngle = getAttrWithFallback(info, "italicAngle") + topDict.isFixedPitch = int(getAttrWithFallback(info, "postscriptIsFixedPitch")) + topDict.ItalicAngle = float(getAttrWithFallback(info, "italicAngle")) underlinePosition = getAttrWithFallback(info, "postscriptUnderlinePosition") topDict.UnderlinePosition = otRound(underlinePosition) underlineThickness = getAttrWithFallback(info, "postscriptUnderlineThickness") diff --git a/Lib/ufo2ft/postProcessor.py b/Lib/ufo2ft/postProcessor.py index 02d2d323c..2f8c1a797 100644 --- a/Lib/ufo2ft/postProcessor.py +++ b/Lib/ufo2ft/postProcessor.py @@ -40,10 +40,15 @@ class SubroutinizerBackend(enum.Enum): def __init__(self, otf, ufo, glyphSet=None): self.ufo = ufo self.glyphSet = glyphSet if glyphSet is not None else ufo - stream = BytesIO() - otf.save(stream) - stream.seek(0) - self.otf = TTFont(stream) + + # FIXME: Stop reloading all incoming fonts here. It ensures that 1) we + # get the final binary layout, which canonicalizes data for us and 2) + # can easily rename glyphs later. The former point should be fixed, as + # reloading is expensive and it is within reason for the compiler to + # spit out something that can be used without reloading. + # https://github.com/googlefonts/ufo2ft/issues/485 + self.otf = _reloadFont(otf) + self._postscriptNames = ufo.lib.get("public.postscriptNames") def process( @@ -379,3 +384,11 @@ def _stripCharStringWidth(program): if stack: result.extend(stack) return result + + +def _reloadFont(font: TTFont) -> TTFont: + """Recompile a font to arrive at the final internal layout.""" + stream = BytesIO() + font.save(stream) + stream.seek(0) + return TTFont(stream) diff --git a/requirements.txt b/requirements.txt index 0b4859587..cb3f750bd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -fonttools[lxml,ufo]==4.21.1 +fonttools[lxml,ufo]==4.22.0 defcon==0.8.1 cu2qu==1.6.7 compreffor==0.5.1 diff --git a/setup.py b/setup.py index 551fe4cab..4d34f5959 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.21.1", + "fonttools[ufo]>=4.22.0", "cu2qu>=1.6.7", "cffsubr>=0.2.8", "booleanOperations>=0.9.0", diff --git a/tests/data/Bug108.ttx b/tests/data/Bug108.ttx index 90d792fba..48adca775 100644 --- a/tests/data/Bug108.ttx +++ b/tests/data/Bug108.ttx @@ -34,7 +34,7 @@ - + diff --git a/tests/data/MTIFeatures.ttx b/tests/data/MTIFeatures.ttx index 1f146e42c..c0f57e6c8 100644 --- a/tests/data/MTIFeatures.ttx +++ b/tests/data/MTIFeatures.ttx @@ -33,7 +33,7 @@ - + diff --git a/tests/data/TestFont-CFF-compreffor.ttx b/tests/data/TestFont-CFF-compreffor.ttx index a5462adb9..9877c3e17 100644 --- a/tests/data/TestFont-CFF-compreffor.ttx +++ b/tests/data/TestFont-CFF-compreffor.ttx @@ -420,7 +420,7 @@ - + diff --git a/tests/data/TestFont-CFF.ttx b/tests/data/TestFont-CFF.ttx index 167e7a658..0a916f689 100644 --- a/tests/data/TestFont-CFF.ttx +++ b/tests/data/TestFont-CFF.ttx @@ -436,7 +436,7 @@ - + diff --git a/tests/data/TestFont-CFF2-cffsubr.ttx b/tests/data/TestFont-CFF2-cffsubr.ttx index 3e4bc7af6..687b56390 100644 --- a/tests/data/TestFont-CFF2-cffsubr.ttx +++ b/tests/data/TestFont-CFF2-cffsubr.ttx @@ -291,6 +291,8 @@ + + @@ -440,7 +442,7 @@ - + diff --git a/tests/data/TestFont-CFF2-compreffor.ttx b/tests/data/TestFont-CFF2-compreffor.ttx index 0e099dc3a..f8b7b60b9 100644 --- a/tests/data/TestFont-CFF2-compreffor.ttx +++ b/tests/data/TestFont-CFF2-compreffor.ttx @@ -294,6 +294,8 @@ + + @@ -433,7 +435,7 @@ - + diff --git a/tests/data/TestFont-CFF2-post3.ttx b/tests/data/TestFont-CFF2-post3.ttx index 0f8e767d2..5975f6a4f 100644 --- a/tests/data/TestFont-CFF2-post3.ttx +++ b/tests/data/TestFont-CFF2-post3.ttx @@ -266,6 +266,8 @@ + + @@ -415,7 +417,7 @@ - + diff --git a/tests/data/TestFont-NoOptimize-CFF.ttx b/tests/data/TestFont-NoOptimize-CFF.ttx index 780064bba..144327bb5 100644 --- a/tests/data/TestFont-NoOptimize-CFF.ttx +++ b/tests/data/TestFont-NoOptimize-CFF.ttx @@ -439,7 +439,7 @@ - + diff --git a/tests/data/TestFont-NoOptimize-CFF2.ttx b/tests/data/TestFont-NoOptimize-CFF2.ttx index 8540b8ec3..76b856f73 100644 --- a/tests/data/TestFont-NoOptimize-CFF2.ttx +++ b/tests/data/TestFont-NoOptimize-CFF2.ttx @@ -294,6 +294,8 @@ + + @@ -449,7 +451,7 @@ - + diff --git a/tests/data/TestFont-NoOverlaps-CFF-pathops.ttx b/tests/data/TestFont-NoOverlaps-CFF-pathops.ttx index 35d0b2219..8801b2f7d 100644 --- a/tests/data/TestFont-NoOverlaps-CFF-pathops.ttx +++ b/tests/data/TestFont-NoOverlaps-CFF-pathops.ttx @@ -431,7 +431,7 @@ - + diff --git a/tests/data/TestFont-NoOverlaps-CFF.ttx b/tests/data/TestFont-NoOverlaps-CFF.ttx index 3c3015eca..5ebd04720 100644 --- a/tests/data/TestFont-NoOverlaps-CFF.ttx +++ b/tests/data/TestFont-NoOverlaps-CFF.ttx @@ -428,7 +428,7 @@ - + diff --git a/tests/data/TestFont-NoOverlaps-TTF-pathops.ttx b/tests/data/TestFont-NoOverlaps-TTF-pathops.ttx index 9dbe2b8f9..7e912b231 100644 --- a/tests/data/TestFont-NoOverlaps-TTF-pathops.ttx +++ b/tests/data/TestFont-NoOverlaps-TTF-pathops.ttx @@ -515,7 +515,7 @@ - + diff --git a/tests/data/TestFont-NoOverlaps-TTF.ttx b/tests/data/TestFont-NoOverlaps-TTF.ttx index f66fd0a15..9632608bf 100644 --- a/tests/data/TestFont-NoOverlaps-TTF.ttx +++ b/tests/data/TestFont-NoOverlaps-TTF.ttx @@ -515,7 +515,7 @@ - + diff --git a/tests/data/TestFont-Specialized-CFF.ttx b/tests/data/TestFont-Specialized-CFF.ttx index 114adffdd..ab7c8219d 100644 --- a/tests/data/TestFont-Specialized-CFF.ttx +++ b/tests/data/TestFont-Specialized-CFF.ttx @@ -417,7 +417,7 @@ - + diff --git a/tests/data/TestFont-Specialized-CFF2.ttx b/tests/data/TestFont-Specialized-CFF2.ttx index abfc01de2..344702e87 100644 --- a/tests/data/TestFont-Specialized-CFF2.ttx +++ b/tests/data/TestFont-Specialized-CFF2.ttx @@ -294,6 +294,8 @@ + + @@ -427,7 +429,7 @@ - + diff --git a/tests/data/TestFont-TTF-post3.ttx b/tests/data/TestFont-TTF-post3.ttx index 32e4f87f9..fbf4798a4 100644 --- a/tests/data/TestFont-TTF-post3.ttx +++ b/tests/data/TestFont-TTF-post3.ttx @@ -488,7 +488,7 @@ - + diff --git a/tests/data/TestFont.ttx b/tests/data/TestFont.ttx index fb820cfd2..76dd3b8d6 100644 --- a/tests/data/TestFont.ttx +++ b/tests/data/TestFont.ttx @@ -513,7 +513,7 @@ - + diff --git a/tests/data/TestVariableFont-CFF2-cffsubr.ttx b/tests/data/TestVariableFont-CFF2-cffsubr.ttx index d5ec5590f..b55692286 100644 --- a/tests/data/TestVariableFont-CFF2-cffsubr.ttx +++ b/tests/data/TestVariableFont-CFF2-cffsubr.ttx @@ -201,6 +201,8 @@ + + @@ -315,7 +317,7 @@ - + @@ -377,10 +379,10 @@ - + - + @@ -450,7 +452,7 @@ - + diff --git a/tests/data/TestVariableFont-CFF2-post3.ttx b/tests/data/TestVariableFont-CFF2-post3.ttx index 5800e8694..f80c8a030 100644 --- a/tests/data/TestVariableFont-CFF2-post3.ttx +++ b/tests/data/TestVariableFont-CFF2-post3.ttx @@ -187,6 +187,8 @@ + + @@ -292,7 +294,7 @@ - + @@ -354,10 +356,10 @@ - + - + @@ -427,7 +429,7 @@ - + diff --git a/tests/data/TestVariableFont-CFF2-useProductionNames.ttx b/tests/data/TestVariableFont-CFF2-useProductionNames.ttx index 3015fd004..e3d3b540f 100644 --- a/tests/data/TestVariableFont-CFF2-useProductionNames.ttx +++ b/tests/data/TestVariableFont-CFF2-useProductionNames.ttx @@ -204,6 +204,8 @@ + + @@ -309,7 +311,7 @@ - + @@ -371,10 +373,10 @@ - + - + @@ -444,7 +446,7 @@ - + diff --git a/tests/data/TestVariableFont-CFF2.ttx b/tests/data/TestVariableFont-CFF2.ttx index 310c85a28..d82ba84f9 100644 --- a/tests/data/TestVariableFont-CFF2.ttx +++ b/tests/data/TestVariableFont-CFF2.ttx @@ -201,6 +201,8 @@ + + @@ -306,7 +308,7 @@ - + @@ -368,10 +370,10 @@ - + - + @@ -441,7 +443,7 @@ - + diff --git a/tests/data/TestVariableFont-TTF-post3.ttx b/tests/data/TestVariableFont-TTF-post3.ttx index 86bb0e4bf..4f83e6bd1 100644 --- a/tests/data/TestVariableFont-TTF-post3.ttx +++ b/tests/data/TestVariableFont-TTF-post3.ttx @@ -297,7 +297,7 @@ - + @@ -359,10 +359,10 @@ - + - + @@ -432,7 +432,7 @@ - + diff --git a/tests/data/TestVariableFont-TTF-useProductionNames.ttx b/tests/data/TestVariableFont-TTF-useProductionNames.ttx index c9e83dfe0..5adc73e7b 100644 --- a/tests/data/TestVariableFont-TTF-useProductionNames.ttx +++ b/tests/data/TestVariableFont-TTF-useProductionNames.ttx @@ -314,7 +314,7 @@ - + @@ -376,10 +376,10 @@ - + - + @@ -449,7 +449,7 @@ - + diff --git a/tests/data/TestVariableFont-TTF.ttx b/tests/data/TestVariableFont-TTF.ttx index 80382c045..e6fab0507 100644 --- a/tests/data/TestVariableFont-TTF.ttx +++ b/tests/data/TestVariableFont-TTF.ttx @@ -311,7 +311,7 @@ - + @@ -373,10 +373,10 @@ - + - + @@ -446,7 +446,7 @@ - +