[filterPen] add decomposing filter pens

This commit is contained in:
Cosimo Lupo 2024-03-04 16:41:27 +00:00
parent cccc358c79
commit d84c74c2ab
No known key found for this signature in database
GPG Key ID: DF65A8A5A119C9A8

View File

@ -1,5 +1,7 @@
from fontTools.pens.basePen import AbstractPen
from fontTools.pens.pointPen import AbstractPointPen
from __future__ import annotations
from fontTools.pens.basePen import AbstractPen, DecomposingPen
from fontTools.pens.pointPen import AbstractPointPen, DecomposingPointPen
from fontTools.pens.recordingPen import RecordingPen
@ -150,8 +152,8 @@ class FilterPointPen(_PassThruComponentsMixin, AbstractPointPen):
('endPath', (), {})
"""
def __init__(self, outPointPen):
self._outPen = outPointPen
def __init__(self, outPen):
self._outPen = outPen
def beginPath(self, **kwargs):
self._outPen.beginPath(**kwargs)
@ -161,3 +163,79 @@ class FilterPointPen(_PassThruComponentsMixin, AbstractPointPen):
def addPoint(self, pt, segmentType=None, smooth=False, name=None, **kwargs):
self._outPen.addPoint(pt, segmentType, smooth, name, **kwargs)
class _DecomposingFilterPenMixin:
"""Mixin class that decomposes components as regular contours.
Shared by both DecomposingFilterPen and DecomposingFilterPointPen.
Takes two required parameters, another (segment or point) pen 'outPen' to draw
with, and a 'glyphSet' dict of drawable glyph objects to draw components from.
The 'skipMissingComponents' and 'reverseFlipped' optional arguments work the
same as in the DecomposingPen/DecomposingPointPen. Both are False by default.
In addition, the decomposing filter pens also take the following two options:
'include' is an optional set of component base glyph names to consider for
decomposition; the default include=None means decompose all components no matter
the base glyph name).
'decomposeNested' (bool) controls whether to recurse decomposition into nested
components of components (this only matters when 'include' was also provided);
if False, only decompose top-level components included in the set, but not
also their children.
"""
# raises MissingComponentError if base glyph is not found in glyphSet
skipMissingComponents = False
def __init__(
self,
outPen,
glyphSet,
skipMissingComponents=None,
reverseFlipped=False,
include: set[str] | None = None,
decomposeNested: bool = True,
):
super().__init__(
outPen=outPen,
glyphSet=glyphSet,
skipMissingComponents=skipMissingComponents,
reverseFlipped=reverseFlipped,
)
self.include = include
self.decomposeNested = decomposeNested
def addComponent(self, baseGlyphName, transformation, **kwargs):
# only decompose the component if it's included in the set
if self.include is None or baseGlyphName in self.include:
# if we're decomposing nested components, temporarily set include to None
include_bak = self.include
if self.decomposeNested and self.include:
self.include = None
try:
super().addComponent(baseGlyphName, transformation, **kwargs)
finally:
if self.include != include_bak:
self.include = include_bak
else:
_PassThruComponentsMixin.addComponent(
self, baseGlyphName, transformation, **kwargs
)
class DecomposingFilterPen(_DecomposingFilterPenMixin, DecomposingPen, FilterPen):
"""Filter pen that draws components as regular contours."""
pass
class DecomposingFilterPointPen(
_DecomposingFilterPenMixin, DecomposingPointPen, FilterPointPen
):
"""Filter point pen that draws components as regular contours."""
pass