From afb06e4f2ec18f9379d048d55f35e3fb799735e5 Mon Sep 17 00:00:00 2001 From: Simon Cozens Date: Wed, 14 Jul 2021 20:38:27 +0100 Subject: [PATCH 1/6] Add translate anchors filter --- Lib/ufo2ft/filters/__init__.py | 2 ++ Lib/ufo2ft/filters/optimizeAnchors.py | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 Lib/ufo2ft/filters/optimizeAnchors.py diff --git a/Lib/ufo2ft/filters/__init__.py b/Lib/ufo2ft/filters/__init__.py index e43223c98..174368e3b 100644 --- a/Lib/ufo2ft/filters/__init__.py +++ b/Lib/ufo2ft/filters/__init__.py @@ -11,6 +11,7 @@ from .decomposeTransformedComponents import DecomposeTransformedComponentsFilter from .explodeColorLayerGlyphs import ExplodeColorLayerGlyphsFilter from .flattenComponents import FlattenComponentsFilter +from .optimizeAnchors import OptimizeAnchorsFilter from .propagateAnchors import PropagateAnchorsFilter from .removeOverlaps import RemoveOverlapsFilter from .sortContours import SortContoursFilter @@ -23,6 +24,7 @@ "DecomposeTransformedComponentsFilter", "ExplodeColorLayerGlyphsFilter", "FlattenComponentsFilter", + "OptimizeAnchorsFilter", "PropagateAnchorsFilter", "RemoveOverlapsFilter", "SortContoursFilter", diff --git a/Lib/ufo2ft/filters/optimizeAnchors.py b/Lib/ufo2ft/filters/optimizeAnchors.py new file mode 100644 index 000000000..773216b8d --- /dev/null +++ b/Lib/ufo2ft/filters/optimizeAnchors.py @@ -0,0 +1,27 @@ +from ufo2ft.filters.transformations import TransformationsFilter +from fontTools.misc.transform import Identity, Transform +import logging + +log = logging.getLogger(__name__) + + +class OptimizeAnchorsFilter(TransformationsFilter): + def set_context(self, font, glyphSet): + # Skip over transformations filter to base filter + return super(TransformationsFilter, self).set_context(font, glyphSet) + + def filter(self, glyph): + if len(glyph.anchors) == 0 or any( + not (a.name.startswith("_")) for a in glyph.anchors + ): + # We're a base! + return False + + # We are a mark glyph with (at least) one attachment point. + theanchor = glyph.anchors[0] + self.context.matrix = Identity.translate(-theanchor.x, -theanchor.y) + log.warn( + "Transforming glyph %s to zero anchor %s: %s" + % (glyph.name, theanchor.name, self.context.matrix) + ) + return super().filter(glyph) From 1637a0f676c9e51140607770b5cf6bab1eb11fc5 Mon Sep 17 00:00:00 2001 From: Simon Cozens Date: Thu, 15 Jul 2021 16:17:48 +0100 Subject: [PATCH 2/6] Sanity check before translating --- Lib/ufo2ft/filters/optimizeAnchors.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Lib/ufo2ft/filters/optimizeAnchors.py b/Lib/ufo2ft/filters/optimizeAnchors.py index 773216b8d..af7395713 100644 --- a/Lib/ufo2ft/filters/optimizeAnchors.py +++ b/Lib/ufo2ft/filters/optimizeAnchors.py @@ -17,6 +17,14 @@ def filter(self, glyph): # We're a base! return False + # More sanity checks: skip over spacing marks + if glyph.width != 0: + return False + # Also skip over marks which are deliberately positioned over the + # previous glyphs + if glyph.getBounds().xMax < 0: + return False + # We are a mark glyph with (at least) one attachment point. theanchor = glyph.anchors[0] self.context.matrix = Identity.translate(-theanchor.x, -theanchor.y) From c3660cb04d980e06ca549695755710ce52d86298 Mon Sep 17 00:00:00 2001 From: Simon Cozens Date: Fri, 16 Jul 2021 13:16:54 +0100 Subject: [PATCH 3/6] Use basefilter directly --- Lib/ufo2ft/filters/optimizeAnchors.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Lib/ufo2ft/filters/optimizeAnchors.py b/Lib/ufo2ft/filters/optimizeAnchors.py index af7395713..1df49e566 100644 --- a/Lib/ufo2ft/filters/optimizeAnchors.py +++ b/Lib/ufo2ft/filters/optimizeAnchors.py @@ -1,4 +1,5 @@ from ufo2ft.filters.transformations import TransformationsFilter +from ufo2ft.filters import BaseFilter from fontTools.misc.transform import Identity, Transform import logging @@ -7,8 +8,9 @@ class OptimizeAnchorsFilter(TransformationsFilter): def set_context(self, font, glyphSet): - # Skip over transformations filter to base filter - return super(TransformationsFilter, self).set_context(font, glyphSet) + self.context = BaseFilter.set_context(self, font, glyphSet) + + return self.context def filter(self, glyph): if len(glyph.anchors) == 0 or any( From 91688b0cee2279aaa63307a55c8ffcb2aa3a93b6 Mon Sep 17 00:00:00 2001 From: Simon Cozens Date: Fri, 16 Jul 2021 13:17:22 +0100 Subject: [PATCH 4/6] Check for component use, fix sanity checks --- Lib/ufo2ft/filters/optimizeAnchors.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Lib/ufo2ft/filters/optimizeAnchors.py b/Lib/ufo2ft/filters/optimizeAnchors.py index 1df49e566..3806a7b20 100644 --- a/Lib/ufo2ft/filters/optimizeAnchors.py +++ b/Lib/ufo2ft/filters/optimizeAnchors.py @@ -10,21 +10,30 @@ class OptimizeAnchorsFilter(TransformationsFilter): def set_context(self, font, glyphSet): self.context = BaseFilter.set_context(self, font, glyphSet) + self.context.component_use = {} + for g in font.layers["public.default"]: + for comp in g.components: + self.context.component_use[comp.baseGlyph] = True + return self.context + def filter(self, glyph): - if len(glyph.anchors) == 0 or any( - not (a.name.startswith("_")) for a in glyph.anchors - ): + if not any(a.name.startswith("_") for a in glyph.anchors): # We're a base! return False - # More sanity checks: skip over spacing marks + # Are we a spacing mark? if glyph.width != 0: return False + + # Are we anywhere used as a component? + if glyph.name in self.context.component_use: + return False + # Also skip over marks which are deliberately positioned over the # previous glyphs - if glyph.getBounds().xMax < 0: + if len(glyph.components) or glyph.getBounds().xMax < 0: return False # We are a mark glyph with (at least) one attachment point. From 626701a116f4dae0f66da22c8ebb933f0b51a0ab Mon Sep 17 00:00:00 2001 From: Simon Cozens Date: Fri, 16 Jul 2021 13:17:29 +0100 Subject: [PATCH 5/6] Downgrade warning to info --- Lib/ufo2ft/filters/optimizeAnchors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/ufo2ft/filters/optimizeAnchors.py b/Lib/ufo2ft/filters/optimizeAnchors.py index 3806a7b20..ded11aff6 100644 --- a/Lib/ufo2ft/filters/optimizeAnchors.py +++ b/Lib/ufo2ft/filters/optimizeAnchors.py @@ -39,7 +39,7 @@ def filter(self, glyph): # We are a mark glyph with (at least) one attachment point. theanchor = glyph.anchors[0] self.context.matrix = Identity.translate(-theanchor.x, -theanchor.y) - log.warn( + log.info( "Transforming glyph %s to zero anchor %s: %s" % (glyph.name, theanchor.name, self.context.matrix) ) From cea39cb7f37e8226976a1485f5438c5308fd854c Mon Sep 17 00:00:00 2001 From: Simon Cozens Date: Fri, 16 Jul 2021 13:21:10 +0100 Subject: [PATCH 6/6] Too stuff --- Lib/ufo2ft/filters/optimizeAnchors.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Lib/ufo2ft/filters/optimizeAnchors.py b/Lib/ufo2ft/filters/optimizeAnchors.py index ded11aff6..942ed61df 100644 --- a/Lib/ufo2ft/filters/optimizeAnchors.py +++ b/Lib/ufo2ft/filters/optimizeAnchors.py @@ -1,8 +1,10 @@ -from ufo2ft.filters.transformations import TransformationsFilter -from ufo2ft.filters import BaseFilter -from fontTools.misc.transform import Identity, Transform import logging +from fontTools.misc.transform import Identity + +from ufo2ft.filters import BaseFilter +from ufo2ft.filters.transformations import TransformationsFilter + log = logging.getLogger(__name__) @@ -17,7 +19,6 @@ def set_context(self, font, glyphSet): return self.context - def filter(self, glyph): if not any(a.name.startswith("_") for a in glyph.anchors): # We're a base! @@ -27,7 +28,7 @@ def filter(self, glyph): if glyph.width != 0: return False - # Are we anywhere used as a component? + # Are we anywhere used as a component? if glyph.name in self.context.component_use: return False