Skip to content

Commit

Permalink
VF compilation: post-process fonts once
Browse files Browse the repository at this point in the history
  • Loading branch information
madig committed Apr 1, 2021
1 parent 294f218 commit bf17ab6
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 22 deletions.
55 changes: 37 additions & 18 deletions Lib/ufo2ft/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import logging
from enum import IntEnum
from typing import Any, Optional

from fontTools import varLib

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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

Expand All @@ -185,6 +188,7 @@ def compileTTF(
skipExportGlyphs=None,
debugFeatureFile=None,
notdefGlyph=None,
postProcessorClass: Optional[Any] = PostProcessor,
):
"""Create FontTools TrueType font from a UFO.
Expand Down Expand Up @@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -433,6 +441,7 @@ def compileInterpolatableTTFsFromDS(
skipExportGlyphs=skipExportGlyphs,
debugFeatureFile=debugFeatureFile,
notdefGlyph=notdefGlyph,
postProcessorClass=postProcessorClass,
)

if inplace:
Expand All @@ -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.
Expand Down Expand Up @@ -519,6 +529,7 @@ def compileInterpolatableOTFsFromDS(
debugFeatureFile=debugFeatureFile,
notdefGlyph=notdefGlyph,
_tables=SPARSE_OTF_MASTER_TABLES if source.layerName else None,
postProcessorClass=postProcessorClass,
)
)

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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")
Expand All @@ -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

Expand All @@ -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.
Expand Down Expand Up @@ -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")
Expand All @@ -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
3 changes: 3 additions & 0 deletions Lib/ufo2ft/outlineCompiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,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
Expand Down
21 changes: 17 additions & 4 deletions Lib/ufo2ft/postProcessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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)

0 comments on commit bf17ab6

Please sign in to comment.