From 4dcc7f83d20a889bc0d63e98e1f0312477f5c45d Mon Sep 17 00:00:00 2001 From: Cosimo Lupo Date: Fri, 5 Feb 2021 17:17:34 +0000 Subject: [PATCH] otTables: add Paint.traverse method paint graph traversal mostly adapted from rsheeter's https://github.com/googlefonts/nanoemoji/pull/233 --- Lib/fontTools/ttLib/tables/otTables.py | 34 ++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/Lib/fontTools/ttLib/tables/otTables.py b/Lib/fontTools/ttLib/tables/otTables.py index 43c40d5c5..008909bdd 100644 --- a/Lib/fontTools/ttLib/tables/otTables.py +++ b/Lib/fontTools/ttLib/tables/otTables.py @@ -1367,6 +1367,40 @@ class Paint(getFormatSwitchingBaseTableClass("uint8")): xmlWriter.endtag(tableName) xmlWriter.newline() + def getChildren(self, colr): + if self.Format == PaintFormat.PaintColrLayers: + return colr.LayerV1List.Paint[ + self.FirstLayerIndex : self.FirstLayerIndex + self.NumLayers + ] + + if self.Format == PaintFormat.PaintColrGlyph: + for record in colr.BaseGlyphV1List.BaseGlyphV1Record: + if record.BaseGlyph == self.Glyph: + return [record.Paint] + else: + raise KeyError(f"{self.Glyph!r} not in colr.BaseGlyphV1List") + + children = [] + for conv in self.getConverters(): + if conv.tableClass is not None and issubclass(conv.tableClass, type(self)): + children.append(getattr(self, conv.name)) + + return children + + def traverse(self, colr: COLR, callback): + """Depth-first traversal of graph rooted at self, callback on each node.""" + if not callable(callback): + raise TypeError("callback must be callable") + stack = [self] + visited = set() + while stack: + current = stack.pop() + if id(current) in visited: + continue + callback(current) + visited.add(id(current)) + stack.extend(reversed(current.getChildren(colr))) + # For each subtable format there is a class. However, we don't really distinguish # between "field name" and "format name": often these are the same. Yet there's