diff --git a/Lib/fontTools/ttLib/tables/_g_l_y_f.py b/Lib/fontTools/ttLib/tables/_g_l_y_f.py index 095bd3177..eaa9920f0 100644 --- a/Lib/fontTools/ttLib/tables/_g_l_y_f.py +++ b/Lib/fontTools/ttLib/tables/_g_l_y_f.py @@ -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.