restrict the rounding to where strictly needed

we don't need to round all simple glyphs' coordinates (which may be costly), only when these are used as components with an interesting transform
This commit is contained in:
Cosimo Lupo 2025-01-24 18:05:18 +00:00
parent 4ea10eb88f
commit bddedc1bc1

View File

@ -1206,9 +1206,7 @@ class Glyph(object):
Return True if bounds were calculated, False otherwise.
"""
for compo in self.components:
if hasattr(compo, "firstPt") or hasattr(compo, "transform"):
return False
if not float(compo.x).is_integer() or not float(compo.y).is_integer():
if not compo._hasOnlyIntegerTranslate():
return False
# All components are untransformed and have an integer x/y translate
@ -1241,7 +1239,7 @@ class Glyph(object):
else:
return self.numberOfContours == -1
def getCoordinates(self, glyfTable, round=noRound):
def getCoordinates(self, glyfTable, *, round=noRound):
"""Return the coordinates, end points and flags
This method returns three values: A :py:class:`GlyphCoordinates` object,
@ -1258,11 +1256,7 @@ class Glyph(object):
"""
if self.numberOfContours > 0:
coordinates = self.coordinates
if round is not noRound:
coordinates = GlyphCoordinates(coordinates)
coordinates.toInt(round=round)
return coordinates, self.endPtsOfContours, self.flags
return self.coordinates, self.endPtsOfContours, self.flags
elif self.isComposite():
# it's a composite
allCoords = GlyphCoordinates()
@ -1280,6 +1274,18 @@ class Glyph(object):
% compo.glyphName
)
coordinates = GlyphCoordinates(coordinates)
# if asked to round e.g. while computing bboxes, it's important we
# do it immediately before a component transform is applied to a
# simple glyph's coordinates in case these might still contain floats;
# however, if the referenced component glyph is another composite, we
# must not round here but only at the end, after all the nested
# transforms have been applied, or else rounding errors will compound.
if (
round is not noRound
and g.numberOfContours > 0
and not compo._hasOnlyIntegerTranslate()
):
coordinates.toInt(round=round)
if hasattr(compo, "firstPt"):
# component uses two reference points: we apply the transform _before_
# computing the offset between the points
@ -1936,6 +1942,18 @@ class GlyphComponent(object):
result = self.__eq__(other)
return result if result is NotImplemented else not result
def _hasOnlyIntegerTranslate(self):
"""Return True if it's a 'simple' component.
That is, it has no anchor points and no transform other than integer translate.
"""
return (
not hasattr(self, "firstPt")
and not hasattr(self, "transform")
and float(self.x).is_integer()
and float(self.y).is_integer()
)
class GlyphCoordinates(object):
"""A list of glyph coordinates.