def buildGlyphHashValue(self, width, outlineXML, glyphName, useDefaultGlyphDir, level=0): """ glyphData must be the official <outline> XML from a GLIF. We skip contours with only one point. """ dataList = ["w%s" % norm_float(round(width, 9))] if level > 10: raise UFOParseError( "In parsing component, exceeded 10 levels of reference. " "'%s'. " % (glyphName)) # <outline> tag is optional per spec., e.g. space glyph # does not necessarily have it. if outlineXML is not None: for childContour in outlineXML: if childContour.tag == "contour": if len(childContour) < 2: continue for child in childContour: if child.tag == "point": ptType = child.get("type") pointType = '' if ptType is None else ptType[0] x = self._rd_val(child.get("x")) y = self._rd_val(child.get("y")) dataList.append("%s%s%s" % (pointType, x, y)) elif childContour.tag == "component": # append the component hash. compGlyphName = childContour.get("base") if compGlyphName is None: raise UFOParseError( "'%s' is missing the 'base' attribute in a " "component." % glyphName) dataList.append("%s%s" % ("base:", compGlyphName)) if useDefaultGlyphDir: try: componentPath = self.getGlyphDefaultPath( compGlyphName) except KeyError: raise UFOParseError( "'%s' component glyph is missing from " "contents.plist." % (compGlyphName)) else: # If we are not necessarily using the default layer # for the main glyph, then a missing component may not # have been processed, and may just be in the default # layer. We need to look for component glyphs in the # src list first, then in the defualt layer. try: componentPath = self.getGlyphSrcPath(compGlyphName) if not os.path.exists(componentPath): componentPath = self.getGlyphDefaultPath( compGlyphName) except KeyError: try: componentPath = self.getGlyphDefaultPath( compGlyphName) except KeyError: raise UFOParseError( "'%s' component glyph is missing from " "contents.plist." % (compGlyphName)) if not os.path.exists(componentPath): raise UFOParseError( "'%s' component file is missing: '%s'." % (compGlyphName, componentPath)) etRoot = ET.ElementTree() # Collect transform values for trans_key, flbk_val in COMP_TRANSFORM.items(): value = childContour.get(trans_key, flbk_val) dataList.append(self._rd_val(value)) componentXML = etRoot.parse(componentPath) componentOutlineXML = componentXML.find("outline") _, componentDataList = self.buildGlyphHashValue( width, componentOutlineXML, glyphName, useDefaultGlyphDir, level + 1) dataList.extend(componentDataList) data = "".join(dataList) if len(data) >= 128: data = hashlib.sha512(data.encode("ascii")).hexdigest() return data, dataList
def _rd_val(str_val): """Round and normalize a (string) GLIF value""" return repr(norm_float(round(ast.literal_eval(str_val), 9)))