Skip to content

Commit

Permalink
Decompose transformed components across masters (#609)
Browse files Browse the repository at this point in the history
* Alter the behaviour of DecomposeTransformedComponents filter to fully decompose a glyph when a transformed component is found.
* Make a note of which glyphs were decomposed by DecomposeTransformedComponents and decompose them in other masters too. Fixes decomposeTransformedComponents does not account for variable fonts #507.
  • Loading branch information
simoncozens authored Apr 27, 2022
1 parent 23c2c0e commit 15f14d3
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 14 deletions.
19 changes: 6 additions & 13 deletions Lib/ufo2ft/filters/decomposeTransformedComponents.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,13 @@ class DecomposeTransformedComponentsFilter(BaseFilter):
def filter(self, glyph):
if not glyph.components:
return False
transformedComponents = []
needs_decomposition = False
for component in glyph.components:
if component.transformation[:4] != Identity[:4]:
transformedComponents.append(component)
if not transformedComponents:
needs_decomposition = True
break
if not needs_decomposition:
return False
specificComponents = [c.baseGlyph for c in transformedComponents]
ufo2ft.util.deepCopyContours(
self.context.glyphSet,
glyph,
glyph,
Transform(),
specificComponents=specificComponents,
)
for component in transformedComponents:
glyph.removeComponent(component)
ufo2ft.util.deepCopyContours(self.context.glyphSet, glyph, glyph, Transform())
glyph.clearComponents()
return True
15 changes: 14 additions & 1 deletion Lib/ufo2ft/preProcessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
)
from ufo2ft.filters import isValidFilter, loadFilters
from ufo2ft.filters.decomposeComponents import DecomposeComponentsFilter
from ufo2ft.filters.decomposeTransformedComponents import (
DecomposeTransformedComponentsFilter,
)
from ufo2ft.fontInfoData import getAttrWithFallback
from ufo2ft.util import _GlyphSet

Expand Down Expand Up @@ -303,10 +306,20 @@ def __init__(
def process(self):
from cu2qu.ufo import fonts_to_quadratic

needs_decomposition = set()

# first apply all custom pre-filters
for funcs, ufo, glyphSet in zip(self.preFilters, self.ufos, self.glyphSets):
for func in funcs:
func(ufo, glyphSet)
if isinstance(func, DecomposeTransformedComponentsFilter):
needs_decomposition |= func(ufo, glyphSet)
else:
func(ufo, glyphSet)
# If we decomposed a glyph in some masters, we must ensure it is decomposed in
# all masters. (https://github.com/googlefonts/ufo2ft/issues/507)
decompose = DecomposeComponentsFilter(include=needs_decomposition)
for ufo, glyphSet in zip(self.ufos, self.glyphSets):
decompose(ufo, glyphSet)

# then apply all default filters
for funcs, ufo, glyphSet in zip(self.defaultFilters, self.ufos, self.glyphSets):
Expand Down
37 changes: 37 additions & 0 deletions tests/filters/decomposeTransformedComponents_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from ufo2ft.filters.decomposeTransformedComponents import (
DecomposeTransformedComponentsFilter,
)
from ufo2ft.preProcessor import TTFInterpolatablePreProcessor


class DecomposeTransformedComponentsFilterTest:
Expand Down Expand Up @@ -56,3 +57,39 @@ def test_transformed_components(self, FontClass):
# nine.of has no outline and one component, it was not decomposed
assert len(ufo["nine.of"]) == 0
assert len(ufo["nine.of"].components) == 1

def test_decompose_compatibly(self, FontClass):
ufo1 = FontClass()
c = ufo1.newGlyph("comp")
c.width = 300
pen = c.getPen()
pen.moveTo((0, 0))
pen.lineTo((300, 0))
pen.lineTo((150, 300))
pen.closePath()

b = ufo1.newGlyph("base")
b.width = 300
pen = b.getPen()
pen.addComponent("comp", (0.5, 0, 0, 0.5, 0, 0))

ufo2 = FontClass()
c = ufo2.newGlyph("comp")
c.width = 600
pen = c.getPen()
pen.moveTo((0, 0))
pen.lineTo((600, 0))
pen.lineTo((300, 600))
pen.closePath()

b = ufo2.newGlyph("base")
b.width = 600
pen = b.getPen()
pen.addComponent("comp", (1, 0, 0, 1, 0, 0))

# Because ufo1.base needs decomposing, so should ufo2.base
glyphsets = TTFInterpolatablePreProcessor(
[ufo1, ufo2], filters=[DecomposeTransformedComponentsFilter(pre=True)]
).process()
assert len(glyphsets[0]["base"]) == 1
assert len(glyphsets[1]["base"]) == 1

0 comments on commit 15f14d3

Please sign in to comment.