diff options
author | Rasmus Andersson <rasmus@notion.se> | 2019-10-23 03:00:58 +0300 |
---|---|---|
committer | Rasmus Andersson <rasmus@notion.se> | 2019-10-23 03:00:58 +0300 |
commit | aa7ad2d7a0e255d4052c4999ec62d88c699586ac (patch) | |
tree | 54e8c771f6b0c5c09cedc3da4d9173c48968e580 /misc/fontbuildlib/glyph.py | |
parent | 9c444dededcb0787d562072a08c909ec463ea4b7 (diff) | |
download | inter-aa7ad2d7a0e255d4052c4999ec62d88c699586ac.tar.xz |
fontbuild: remove use of fontmake, simplifying things.
Diffstat (limited to 'misc/fontbuildlib/glyph.py')
-rw-r--r-- | misc/fontbuildlib/glyph.py | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/misc/fontbuildlib/glyph.py b/misc/fontbuildlib/glyph.py new file mode 100644 index 000000000..734b881e0 --- /dev/null +++ b/misc/fontbuildlib/glyph.py @@ -0,0 +1,86 @@ +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) +]) + + +_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)
\ No newline at end of file |