1
1
mirror of https://github.com/rsms/inter.git synced 2024-10-26 12:39:40 +03:00
inter/misc/fontbuildlib/glyph.py
2020-08-17 17:12:31 -07:00

87 lines
2.8 KiB
Python

import re
from fontTools.pens.transformPen import TransformPen
from fontTools.misc.transform import Transform
from fontTools.pens.reverseContourPen import ReverseContourPen
# Directives are glyph-specific post-processing directives for the compiler.
# A directive is added to the "note" section of a glyph and takes the
# following form:
#
# !post:DIRECTIVE
#
# Where DIRECTIVE is the name of a known directive.
# This string can appear anywhere in the glyph note.
# Directives are _not_ case sensitive but normalized by str.lower(), meaning
# that e.g. "removeoverlap" == "RemoveOverlap" == "REMOVEOVERLAP".
#
knownDirectives = set([
'removeoverlap', # applies overlap removal (boolean union)
'decompose', # decomposes components
])
_findDirectiveRegEx = re.compile(r'\!post:([^ ]+)', re.I | re.U)
def findGlyphDirectives(string): # -> set<string> | None
directives = set()
if string and len(string) > 0:
for directive in _findDirectiveRegEx.findall(string):
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
def composedGlyphIsTrivial(g):
# A trivial glyph is one that does not use components or where component transformation
# does not include mirroring (i.e. "flipped").
if g.components and len(g.components) > 0:
for c in g.components:
# has non-trivial transformation? (i.e. scaled)
# Example of optimally trivial transformation:
# (1, 0, 0, 1, 0, 0) no scale or offset
# Example of scaled transformation matrix:
# (-1.0, 0, 0.3311, 1, 1464.0, 0) flipped x axis, sheered and offset
#
xScale = c.transformation[0]
yScale = c.transformation[3]
# If glyph is reflected along x or y axes, it won't slant well.
if xScale < 0 or yScale < 0:
return False
return True
def decomposeGlyphs(ufos, glyphNamesToDecompose):
for ufo in ufos:
for glyphname in glyphNamesToDecompose:
glyph = ufo[glyphname]
_deepCopyContours(ufo, glyph, glyph, Transform())
glyph.clearComponents()
def _deepCopyContours(ufo, parent, component, transformation):
"""Copy contours from component to parent, including nested components."""
for nested in component.components:
_deepCopyContours(
ufo,
parent,
ufo[nested.baseGlyph],
transformation.transform(nested.transformation)
)
if component != parent:
pen = TransformPen(parent.getPen(), transformation)
# if the transformation has a negative determinant, it will reverse
# the contour direction of the component
xx, xy, yx, yy = transformation[:4]
if xx*yy - xy*yx < 0:
pen = ReverseContourPen(pen)
component.draw(pen)