# Copyright 2013 Google, Inc. All Rights Reserved. # # Google Author(s): Behdad Esfahbod from fontTools.misc.textTools import safeEval from . import DefaultTable class table_C_O_L_R_(DefaultTable.DefaultTable): """ This table is structured so that you can treat it like a dictionary keyed by glyph name. ``ttFont['COLR'][]`` will return the color layers for any glyph. ``ttFont['COLR'][] = `` will set the color layers for any glyph. """ @staticmethod def _decompileColorLayersV0(table): if not table.LayerRecordArray: return {} colorLayerLists = {} layerRecords = table.LayerRecordArray.LayerRecord numLayerRecords = len(layerRecords) for baseRec in table.BaseGlyphRecordArray.BaseGlyphRecord: baseGlyph = baseRec.BaseGlyph firstLayerIndex = baseRec.FirstLayerIndex numLayers = baseRec.NumLayers assert (firstLayerIndex + numLayers <= numLayerRecords) layers = [] for i in range(firstLayerIndex, firstLayerIndex+numLayers): layerRec = layerRecords[i] layers.append( LayerRecord(layerRec.LayerGlyph, layerRec.PaletteIndex) ) colorLayerLists[baseGlyph] = layers return colorLayerLists def _toOTTable(self, ttFont): from . import otTables from fontTools.colorLib.builder import populateCOLRv0 tableClass = getattr(otTables, self.tableTag) table = tableClass() table.Version = self.version populateCOLRv0( table, { baseGlyph: [(layer.name, layer.colorID) for layer in layers] for baseGlyph, layers in self.ColorLayers.items() }, glyphMap=ttFont.getReverseGlyphMap(rebuild=True), ) return table def decompile(self, data, ttFont): from .otBase import OTTableReader from . import otTables # We use otData to decompile, but we adapt the decompiled otTables to the # existing COLR v0 API for backward compatibility. reader = OTTableReader(data, tableTag=self.tableTag) tableClass = getattr(otTables, self.tableTag) table = tableClass() table.decompile(reader, ttFont) self.version = table.Version if self.version == 0: self.ColorLayers = self._decompileColorLayersV0(table) else: # for new versions, keep the raw otTables around self.table = table def compile(self, ttFont): from .otBase import OTTableWriter if hasattr(self, "table"): table = self.table else: table = self._toOTTable(ttFont) writer = OTTableWriter(tableTag=self.tableTag) table.compile(writer, ttFont) return writer.getAllData() def toXML(self, writer, ttFont): if hasattr(self, "table"): self.table.toXML2(writer, ttFont) else: writer.simpletag("version", value=self.version) writer.newline() for baseGlyph in sorted(self.ColorLayers.keys(), key=ttFont.getGlyphID): writer.begintag("ColorGlyph", name=baseGlyph) writer.newline() for layer in self.ColorLayers[baseGlyph]: layer.toXML(writer, ttFont) writer.endtag("ColorGlyph") writer.newline() def fromXML(self, name, attrs, content, ttFont): if name == "version": # old COLR v0 API setattr(self, name, safeEval(attrs["value"])) elif name == "ColorGlyph": if not hasattr(self, "ColorLayers"): self.ColorLayers = {} glyphName = attrs["name"] for element in content: if isinstance(element, str): continue layers = [] for element in content: if isinstance(element, str): continue layer = LayerRecord() layer.fromXML(element[0], element[1], element[2], ttFont) layers.append (layer) self.ColorLayers[glyphName] = layers else: # new COLR v1 API from . import otTables if not hasattr(self, "table"): tableClass = getattr(otTables, self.tableTag) self.table = tableClass() self.table.fromXML(name, attrs, content, ttFont) self.table.populateDefaults() self.version = self.table.Version def __getitem__(self, glyphName): if not isinstance(glyphName, str): raise TypeError(f"expected str, found {type(glyphName).__name__}") return self.ColorLayers[glyphName] def __setitem__(self, glyphName, value): if not isinstance(glyphName, str): raise TypeError(f"expected str, found {type(glyphName).__name__}") if value is not None: self.ColorLayers[glyphName] = value elif glyphName in self.ColorLayers: del self.ColorLayers[glyphName] def __delitem__(self, glyphName): del self.ColorLayers[glyphName] class LayerRecord(object): def __init__(self, name=None, colorID=None): self.name = name self.colorID = colorID def toXML(self, writer, ttFont): writer.simpletag("layer", name=self.name, colorID=self.colorID) writer.newline() def fromXML(self, eltname, attrs, content, ttFont): for (name, value) in attrs.items(): if name == "name": setattr(self, name, value) else: setattr(self, name, safeEval(value))