fontbuild: adds support for post-processing directives on a per-glyph basis. Add "!post:DIRECTIVE" in glyph notes. Only supported directive is "removeoverlaps"

This commit is contained in:
Rasmus Andersson 2018-11-23 12:52:50 -08:00
parent 783f38a700
commit a8fc89d01f

View file

@ -25,10 +25,11 @@ from fontTools.pens.reverseContourPen import ReverseContourPen
from glyphsLib.interpolation import apply_instance_data
from mutatorMath.ufo.document import DesignSpaceDocumentReader
from multiprocessing import Process, Queue
# from ufo2ft.filters.removeOverlaps import RemoveOverlapsFilter
from ufo2ft.filters.removeOverlaps import RemoveOverlapsFilter
log = logging.getLogger(__name__)
stripItalic_re = re.compile(r'(?:^|\b)italic(?:\b|$)', re.I | re.U)
findPost_re = re.compile(r'\!post:([^ ]+)', re.I | re.U)
def stripItalic(name):
@ -77,6 +78,26 @@ def composedGlyphIsNonTrivial(g, yAxisIsNonTrivial=False):
return False
knownDirectives = set([
'removeoverlap',
])
def findGlyphDirectives(g): # -> set<string> | None
directives = set()
if g.note and len(g.note) > 0:
for directive in findPost_re.findall(g.note):
directive = directive.lower()
if directive in knownDirectives:
directives.add(directive)
else:
print(
'unknown glyph directive !post:%s in glyph %s' % (directive, g.name),
file=sys.stderr
)
return directives
class VarFontProject(FontProject):
def decompose_glyphs(self, ufos, glyph_filter=lambda g: True):
"""Move components of UFOs' glyphs to their outlines."""
@ -100,29 +121,42 @@ class VarFontProject(FontProject):
# the contour direction of the component
xx, xy, yx, yy = transformation[:4]
if xx*yy - xy*yx < 0:
pen = ReverseContourPen(pen)
pen = ReverseContourPen(pen)
component.draw(pen)
def build_interpolatable_ttfs(self, ufos, **kwargs):
"""Build OpenType binaries with interpolatable TrueType outlines."""
# We decompose any glyph with two or more components to make sure
# that fontTools varLib is able to produce properly-slanting interpolation.
decomposeGlyphs = set()
removeOverlapsGlyphs = set()
for ufo in ufos:
updateFontVersion(ufo)
isItalic = ufo.info.italicAngle != 0
for glyph in ufo:
if glyph.components and composedGlyphIsNonTrivial(glyph, yAxisIsNonTrivial=isItalic):
decomposeGlyphs.add(glyph.name)
ufoname = basename(ufo.path)
for g in ufo:
directives = findGlyphDirectives(g)
if g.components and composedGlyphIsNonTrivial(g, yAxisIsNonTrivial=isItalic):
decomposeGlyphs.add(g.name)
if 'removeoverlap' in directives:
if g.components and len(g.components) > 0:
decomposeGlyphs.add(g.name)
removeOverlapsGlyphs.add(g)
self.decompose_glyphs(ufos, lambda g: g.name in decomposeGlyphs)
# for ufo in ufos:
# filter = RemoveOverlapsFilter(backend='pathops')
# filter.start()
# for g in ufo:
# filter.filter(g)
if len(removeOverlapsGlyphs) > 0:
rmoverlapFilter = RemoveOverlapsFilter(backend='pathops')
rmoverlapFilter.start()
for g in removeOverlapsGlyphs:
log.info(
'Removing overlaps in glyph "%s" of %s',
g.name,
basename(g.getParent().path)
)
rmoverlapFilter.filter(g)
self.save_otfs(ufos, ttf=True, interpolatable=True, **kwargs)
@ -268,6 +302,7 @@ class Main(object):
# parse CLI arguments
args = argparser.parse_args(argv[1:i])
logFormat = '%(funcName)s: %(message)s'
if args.quiet:
self.quiet = True
if args.debug:
@ -275,13 +310,14 @@ class Main(object):
if args.verbose:
fatal("--quiet and --verbose are mutually exclusive arguments")
elif args.debug:
logging.basicConfig(level=logging.DEBUG)
logging.basicConfig(level=logging.DEBUG, format=logFormat)
self.logLevelName = 'DEBUG'
elif args.verbose:
logging.basicConfig(level=logging.INFO)
logging.basicConfig(level=logging.INFO, format=logFormat)
self.logLevelName = 'INFO'
else:
logging.basicConfig(level=logging.WARNING)
logFormat = '%(message)s'
logging.basicConfig(level=logging.WARNING, format=logFormat)
self.logLevelName = 'WARNING'
if args.chdir: