diff --git a/Lib/fontTools/agl.py b/Lib/fontTools/agl.py index 5f20f5163..e51d50725 100644 --- a/Lib/fontTools/agl.py +++ b/Lib/fontTools/agl.py @@ -712,11 +712,11 @@ UV2AGL = {} def _builddicts(): import re - + lines = _aglText.splitlines() - + parseAGL_RE = re.compile("([0-9A-F]{4});([A-Za-z_0-9.]+);.*?$") - + for line in lines: if not line or line[:1] == '#': continue @@ -733,5 +733,5 @@ def _builddicts(): else: AGL2UV[glyphName] = unicode UV2AGL[unicode] = glyphName - + _builddicts() diff --git a/Lib/fontTools/cffLib.py b/Lib/fontTools/cffLib.py index 2a2814eef..3169d4878 100644 --- a/Lib/fontTools/cffLib.py +++ b/Lib/fontTools/cffLib.py @@ -18,15 +18,15 @@ cffHeaderFormat = """ """ class CFFFontSet(object): - + def __init__(self): pass - + def decompile(self, file, otFont): sstruct.unpack(cffHeaderFormat, file.read(4), self) assert self.major == 1 and self.minor == 0, \ "unknown CFF format: %d.%d" % (self.major, self.minor) - + file.seek(self.hdrSize) self.fontNames = list(Index(file)) self.topDictIndex = TopDictIndex(file) @@ -34,23 +34,23 @@ class CFFFontSet(object): self.GlobalSubrs = GlobalSubrsIndex(file) self.topDictIndex.strings = self.strings self.topDictIndex.GlobalSubrs = self.GlobalSubrs - + def __len__(self): return len(self.fontNames) - + def keys(self): return list(self.fontNames) - + def values(self): return self.topDictIndex - + def __getitem__(self, name): try: index = self.fontNames.index(name) except ValueError: raise KeyError(name) return self.topDictIndex[index] - + def compile(self, file, otFont): strings = IndexedStrings() writer = CFFWriter() @@ -63,17 +63,17 @@ class CFFFontSet(object): writer.add(topCompiler) writer.add(strings.getCompiler()) writer.add(self.GlobalSubrs.getCompiler(strings, None)) - + for topDict in self.topDictIndex: if not hasattr(topDict, "charset") or topDict.charset is None: charset = otFont.getGlyphOrder() topDict.charset = charset - + for child in topCompiler.getChildren(strings): writer.add(child) - + writer.toFile(file) - + def toXML(self, xmlWriter, progress=None): for fontName in self.fontNames: xmlWriter.begintag("CFFFont", name=tostr(fontName)) @@ -88,7 +88,7 @@ class CFFFontSet(object): self.GlobalSubrs.toXML(xmlWriter, progress) xmlWriter.endtag("GlobalSubrs") xmlWriter.newline() - + def fromXML(self, name, attrs, content): if not hasattr(self, "GlobalSubrs"): self.GlobalSubrs = GlobalSubrsIndex() @@ -121,13 +121,13 @@ class CFFFontSet(object): class CFFWriter(object): - + def __init__(self): self.data = [] - + def add(self, table): self.data.append(table) - + def toFile(self, file): lastPosList = None count = 1 @@ -175,14 +175,14 @@ def calcOffSize(largestOffset): class IndexCompiler(object): - + def __init__(self, items, strings, parent): self.items = self.getItems(items, strings) self.parent = parent - + def getItems(self, items, strings): return items - + def getOffsets(self): pos = 1 offsets = [pos] @@ -193,7 +193,7 @@ class IndexCompiler(object): pos = pos + len(item) offsets.append(pos) return offsets - + def getDataLength(self): lastOffset = self.getOffsets()[-1] offSize = calcOffSize(lastOffset) @@ -204,7 +204,7 @@ class IndexCompiler(object): lastOffset - 1 # size of object data ) return dataLength - + def toFile(self, file): offsets = self.getOffsets() writeCard16(file, len(self.items)) @@ -224,19 +224,19 @@ class IndexCompiler(object): class IndexedStringsCompiler(IndexCompiler): - + def getItems(self, items, strings): return items.strings class TopDictIndexCompiler(IndexCompiler): - + def getItems(self, items, strings): out = [] for item in items: out.append(item.getCompiler(strings, self)) return out - + def getChildren(self, strings): children = [] for topDict in self.items: @@ -245,13 +245,13 @@ class TopDictIndexCompiler(IndexCompiler): class FDArrayIndexCompiler(IndexCompiler): - + def getItems(self, items, strings): out = [] for item in items: out.append(item.getCompiler(strings, self)) return out - + def getChildren(self, strings): children = [] for fontDict in self.items: @@ -298,11 +298,11 @@ class CharStringsCompiler(GlobalSubrsCompiler): class Index(object): - + """This class represents what the CFF spec calls an INDEX.""" - + compilerClass = IndexCompiler - + def __init__(self, file=None): self.items = [] name = self.__class__.__name__ @@ -330,10 +330,10 @@ class Index(object): file.seek(self.offsetBase + offsets[-1]) # pretend we've read the whole lot if DEBUG: print(" end of %s at %s" % (name, file.tell())) - + def __len__(self): return len(self.items) - + def __getitem__(self, index): item = self.items[index] if item is not None: @@ -347,21 +347,21 @@ class Index(object): item = self.produceItem(index, data, file, offset, size) self.items[index] = item return item - + def produceItem(self, index, data, file, offset, size): return data - + def append(self, item): self.items.append(item) - + def getCompiler(self, strings, parent): return self.compilerClass(self, strings, parent) class GlobalSubrsIndex(Index): - + compilerClass = GlobalSubrsCompiler - + def __init__(self, file=None, globalSubrs=None, private=None, fdSelect=None, fdArray=None): Index.__init__(self, file) self.globalSubrs = globalSubrs @@ -370,7 +370,7 @@ class GlobalSubrsIndex(Index): self.fdSelect = fdSelect if fdArray: self.fdArray = fdArray - + def produceItem(self, index, data, file, offset, size): if self.private is not None: private = self.private @@ -379,7 +379,7 @@ class GlobalSubrsIndex(Index): else: private = None return psCharStrings.T2CharString(data, private=private, globalSubrs=self.globalSubrs) - + def toXML(self, xmlWriter, progress): xmlWriter.comment("The 'index' attribute is only for humans; it is ignored when parsed.") xmlWriter.newline() @@ -393,14 +393,14 @@ class GlobalSubrsIndex(Index): subr.toXML(xmlWriter) xmlWriter.endtag("CharString") xmlWriter.newline() - + def fromXML(self, name, attrs, content): if name != "CharString": return subr = psCharStrings.T2CharString() subr.fromXML(name, attrs, content) self.append(subr) - + def getItemAndSelector(self, index): sel = None if hasattr(self, 'fdSelect'): @@ -413,14 +413,14 @@ class SubrsIndex(GlobalSubrsIndex): class TopDictIndex(Index): - + compilerClass = TopDictIndexCompiler - + def produceItem(self, index, data, file, offset, size): top = TopDict(self.strings, file, offset, self.GlobalSubrs) top.decompile(data) return top - + def toXML(self, xmlWriter, progress): for i in range(len(self)): xmlWriter.begintag("FontDict", index=i) @@ -431,7 +431,7 @@ class TopDictIndex(Index): class FDArrayIndex(TopDictIndex): - + compilerClass = FDArrayIndexCompiler def fromXML(self, name, attrs, content): @@ -480,19 +480,19 @@ class FDSelect: def __len__(self): return len(self.gidArray) - + def __getitem__(self, index): return self.gidArray[index] - + def __setitem__(self, index, fdSelectValue): self.gidArray[index] = fdSelectValue def append(self, fdSelectValue): self.gidArray.append(fdSelectValue) - + class CharStrings(object): - + def __init__(self, file, charset, globalSubrs, private, fdSelect, fdArray): if file is not None: self.charStringsIndex = SubrsIndex(file, globalSubrs, private, fdSelect, fdArray) @@ -509,37 +509,37 @@ class CharStrings(object): self.fdSelect = fdSelect if fdArray is not None: self.fdArray = fdArray - + def keys(self): return list(self.charStrings.keys()) - + def values(self): if self.charStringsAreIndexed: return self.charStringsIndex else: return list(self.charStrings.values()) - + def has_key(self, name): return name in self.charStrings __contains__ = has_key - + def __len__(self): return len(self.charStrings) - + def __getitem__(self, name): charString = self.charStrings[name] if self.charStringsAreIndexed: charString = self.charStringsIndex[charString] return charString - + def __setitem__(self, name, charString): if self.charStringsAreIndexed: index = self.charStrings[name] self.charStringsIndex[index] = charString else: self.charStrings[name] = charString - + def getItemAndSelector(self, name): if self.charStringsAreIndexed: index = self.charStrings[name] @@ -550,7 +550,7 @@ class CharStrings(object): else: raise KeyError("fdSelect array not yet defined.") return self.charStrings[name], sel - + def toXML(self, xmlWriter, progress): names = sorted(self.keys()) i = 0 @@ -575,7 +575,7 @@ class CharStrings(object): progress.setLabel("Dumping 'CFF ' table... (%s)" % name) progress.increment(step / numGlyphs) i = i + 1 - + def fromXML(self, name, attrs, content): for element in content: if isinstance(element, basestring): @@ -589,7 +589,7 @@ class CharStrings(object): private = self.fdArray[fdID].Private else: private = self.private - + glyphName = attrs["name"] charString = psCharStrings.T2CharString( private=private, @@ -767,10 +767,10 @@ class CharStringsConverter(TableConverter): return 0 # dummy value def xmlRead(self, name, attrs, content, parent): if hasattr(parent, "ROS"): - # if it is a CID-keyed font, then the private Dict is extracted from the parent.FDArray + # if it is a CID-keyed font, then the private Dict is extracted from the parent.FDArray private, fdSelect, fdArray = None, parent.FDSelect, parent.FDArray else: - # if it is a name-keyed font, then the private dict is in the top dict, and there is no fdArray. + # if it is a name-keyed font, then the private dict is in the top dict, and there is no fdArray. private, fdSelect, fdArray = parent.Private, None, None charStrings = CharStrings(None, None, parent.GlobalSubrs, private, fdSelect, fdArray) charStrings.fromXML(name, attrs, content) @@ -796,7 +796,7 @@ class CharsetConverter(object): if DEBUG: print(" charset end at %s" % file.tell()) else: # offset == 0 -> no charset data. - if isCID or "CharStrings" not in parent.rawDict: + if isCID or "CharStrings" not in parent.rawDict: assert value == 0 # We get here only when processing fontDicts from the FDArray of CFF-CID fonts. Only the real topDict references the chrset. charset = None elif value == 0: @@ -821,7 +821,7 @@ class CharsetConverter(object): class CharsetCompiler(object): - + def __init__(self, strings, charset, parent): assert charset[0] == '.notdef' isCID = hasattr(parent.dictObj, "ROS") @@ -832,13 +832,13 @@ class CharsetCompiler(object): else: self.data = data0 self.parent = parent - + def setPos(self, pos, endPos): self.parent.rawDict["charset"] = pos - + def getDataLength(self): return len(self.data) - + def toFile(self, file): file.write(self.data) @@ -871,7 +871,7 @@ def packCharset(charset, isCID, strings): getNameID = getCIDfromName else: getNameID = getSIDfromName - + for name in charset[1:]: SID = getNameID(name, strings) if first is None: @@ -888,7 +888,7 @@ def packCharset(charset, isCID, strings): if nLeft > 255: fmt = 2 ranges.append((first, nLeft)) - + data = [packCard8(fmt)] if fmt == 1: nLeftFunc = packCard8 @@ -944,10 +944,10 @@ class EncodingCompiler(object): def setPos(self, pos, endPos): self.parent.rawDict["Encoding"] = pos - + def getDataLength(self): return len(self.data) - + def toFile(self, file): file.write(self.data) @@ -1047,7 +1047,7 @@ def packEncoding0(charset, encoding, strings): for name in charset[1:]: code = m.get(name) codes.append(code) - + while codes and codes[-1] is None: codes.pop() @@ -1079,7 +1079,7 @@ def packEncoding1(charset, encoding, strings): end = code nLeft = end - first ranges.append((first, nLeft)) - + # remove unencoded glyphs at the end. while ranges and ranges[-1][0] == -1: ranges.pop() @@ -1138,7 +1138,7 @@ class FDSelectConverter(object): numGlyphs = None fdSelect = FDSelect(file, numGlyphs, fmt) return fdSelect - + def packFDSelect0(fdSelectArray): fmt = 0 @@ -1161,7 +1161,7 @@ def packFDSelect3(fdSelectArray): fdRanges.append([i, fdIndex]) lastFDIndex = fdIndex sentinelGID = i + 1 - + data = [packCard8(fmt)] data.append(packCard16( len(fdRanges) )) for fdRange in fdRanges: @@ -1172,7 +1172,7 @@ def packFDSelect3(fdSelectArray): class FDSelectCompiler(object): - + def __init__(self, fdSelect, parent): fmt = fdSelect.format fdSelectArray = fdSelect.gidArray @@ -1192,13 +1192,13 @@ class FDSelectCompiler(object): fdSelect.format = 3 self.parent = parent - + def setPos(self, pos, endPos): self.parent.rawDict["FDSelect"] = pos - + def getDataLength(self): return len(self.data) - + def toFile(self, file): file.write(self.data) @@ -1309,7 +1309,7 @@ class PrivateDictDecompiler(psCharStrings.DictDecompiler): class DictCompiler(object): - + def __init__(self, dictObj, strings, parent): assert isinstance(strings, IndexedStrings) self.dictObj = dictObj @@ -1326,13 +1326,13 @@ class DictCompiler(object): continue rawDict[name] = value self.rawDict = rawDict - + def setPos(self, pos, endPos): pass - + def getDataLength(self): return len(self.compile("getDataLength")) - + def compile(self, reason): if DEBUG: print("-- compiling %s for %s" % (self.__class__.__name__, reason)) @@ -1357,10 +1357,10 @@ class DictCompiler(object): data.append(arghandler(value)) data.append(op) return bytesjoin(data) - + def toFile(self, file): file.write(self.compile("toFile")) - + def arg_number(self, num): return encodeNumber(num) def arg_SID(self, s): @@ -1390,9 +1390,9 @@ def encodeNumber(num): class TopDictCompiler(DictCompiler): - + opcodes = buildOpcodeDict(topDictOperators) - + def getChildren(self, strings): children = [] if hasattr(self.dictObj, "charset") and self.dictObj.charset: @@ -1435,9 +1435,9 @@ class TopDictCompiler(DictCompiler): class FontDictCompiler(DictCompiler): - + opcodes = buildOpcodeDict(topDictOperators) - + def getChildren(self, strings): children = [] if hasattr(self.dictObj, "Private"): @@ -1448,14 +1448,14 @@ class FontDictCompiler(DictCompiler): class PrivateDictCompiler(DictCompiler): - + opcodes = buildOpcodeDict(privateDictOperators) - + def setPos(self, pos, endPos): size = endPos - pos self.parent.rawDict["Private"] = size, pos self.pos = pos - + def getChildren(self, strings): children = [] if hasattr(self.dictObj, "Subrs"): @@ -1464,7 +1464,7 @@ class PrivateDictCompiler(DictCompiler): class BaseDict(object): - + def __init__(self, strings=None, file=None, offset=None): self.rawDict = {} if DEBUG: @@ -1473,7 +1473,7 @@ class BaseDict(object): self.offset = offset self.strings = strings self.skipNames = [] - + def decompile(self, data): if DEBUG: print(" length %s is %s" % (self.__class__.__name__, len(data))) @@ -1481,13 +1481,13 @@ class BaseDict(object): dec.decompile(data) self.rawDict = dec.getDict() self.postDecompile() - + def postDecompile(self): pass - + def getCompiler(self, strings, parent): return self.compilerClass(self, strings, parent) - + def __getattr__(self, name): value = self.rawDict.get(name) if value is None: @@ -1498,7 +1498,7 @@ class BaseDict(object): value = conv.read(self, value) setattr(self, name, value) return value - + def toXML(self, xmlWriter, progress): for name in self.order: if name in self.skipNames: @@ -1508,7 +1508,7 @@ class BaseDict(object): continue conv = self.converters[name] conv.xmlWrite(xmlWriter, name, value, progress) - + def fromXML(self, name, attrs, content): conv = self.converters[name] value = conv.xmlRead(name, attrs, content, self) @@ -1516,20 +1516,20 @@ class BaseDict(object): class TopDict(BaseDict): - + defaults = buildDefaults(topDictOperators) converters = buildConverters(topDictOperators) order = buildOrder(topDictOperators) decompilerClass = TopDictDecompiler compilerClass = TopDictCompiler - + def __init__(self, strings=None, file=None, offset=None, GlobalSubrs=None): BaseDict.__init__(self, strings, file, offset) self.GlobalSubrs = GlobalSubrs - + def getGlyphOrder(self): return self.charset - + def postDecompile(self): offset = self.rawDict.get("CharStrings") if offset is None: @@ -1537,7 +1537,7 @@ class TopDict(BaseDict): # get the number of glyphs beforehand. self.file.seek(offset) self.numGlyphs = readCard16(self.file) - + def toXML(self, xmlWriter, progress): if hasattr(self, "CharStrings"): self.decompileAllCharStrings(progress) @@ -1549,7 +1549,7 @@ class TopDict(BaseDict): self.skipNames = ['CIDFontVersion', 'CIDFontRevision', 'CIDFontType', 'CIDCount'] BaseDict.toXML(self, xmlWriter, progress) - + def decompileAllCharStrings(self, progress): # XXX only when doing ttdump -i? i = 0 @@ -1567,20 +1567,20 @@ class TopDict(BaseDict): class FontDict(BaseDict): - + defaults = buildDefaults(topDictOperators) converters = buildConverters(topDictOperators) order = buildOrder(topDictOperators) decompilerClass = None compilerClass = FontDictCompiler - + def __init__(self, strings=None, file=None, offset=None, GlobalSubrs=None): BaseDict.__init__(self, strings, file, offset) self.GlobalSubrs = GlobalSubrs - + def getGlyphOrder(self): return self.charset - + def toXML(self, xmlWriter, progress): self.skipNames = ['Encoding'] BaseDict.toXML(self, xmlWriter, progress) @@ -1595,28 +1595,28 @@ class PrivateDict(BaseDict): class IndexedStrings(object): - + """SID -> string mapping.""" - + def __init__(self, file=None): if file is None: strings = [] else: strings = [tostr(s, encoding="latin1") for s in Index(file)] self.strings = strings - + def getCompiler(self): return IndexedStringsCompiler(self, None, None) - + def __len__(self): return len(self.strings) - + def __getitem__(self, SID): if SID < cffStandardStringCount: return cffStandardStrings[SID] else: return self.strings[SID - cffStandardStringCount] - + def getSID(self, s): if not hasattr(self, "stringMapping"): self.buildStringMapping() @@ -1629,10 +1629,10 @@ class IndexedStrings(object): self.strings.append(s) self.stringMapping[s] = SID return SID - + def getStrings(self): return self.strings - + def buildStringMapping(self): self.stringMapping = {} for index in range(len(self.strings)): @@ -1642,68 +1642,68 @@ class IndexedStrings(object): # The 391 Standard Strings as used in the CFF format. # from Adobe Technical None #5176, version 1.0, 18 March 1998 -cffStandardStrings = ['.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', - 'dollar', 'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright', - 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', - 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', - 'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', - 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', - 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', - 'bracketright', 'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c', - 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', - 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', - 'asciitilde', 'exclamdown', 'cent', 'sterling', 'fraction', 'yen', 'florin', - 'section', 'currency', 'quotesingle', 'quotedblleft', 'guillemotleft', - 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'endash', 'dagger', - 'daggerdbl', 'periodcentered', 'paragraph', 'bullet', 'quotesinglbase', - 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', - 'questiondown', 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', - 'dotaccent', 'dieresis', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron', - 'emdash', 'AE', 'ordfeminine', 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae', - 'dotlessi', 'lslash', 'oslash', 'oe', 'germandbls', 'onesuperior', - 'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', - 'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters', - 'twosuperior', 'registered', 'minus', 'eth', 'multiply', 'threesuperior', - 'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', - 'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', - 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', - 'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', - 'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', - 'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla', - 'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex', - 'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis', - 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis', 'ugrave', - 'yacute', 'ydieresis', 'zcaron', 'exclamsmall', 'Hungarumlautsmall', - 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall', - 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader', - 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', - 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', - 'nineoldstyle', 'commasuperior', 'threequartersemdash', 'periodsuperior', - 'questionsmall', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', - 'esuperior', 'isuperior', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', - 'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'ffi', 'ffl', 'parenleftinferior', - 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', - 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', - 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall', - 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall', - 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', - 'exclamdownsmall', 'centoldstyle', 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', - 'Dieresissmall', 'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall', - 'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', - 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', - 'onethird', 'twothirds', 'zerosuperior', 'foursuperior', 'fivesuperior', - 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior', - 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior', - 'sixinferior', 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior', - 'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall', - 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', - 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', - 'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', - 'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', - 'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', - 'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', - 'Yacutesmall', 'Thornsmall', 'Ydieresissmall', '001.000', '001.001', '001.002', - '001.003', 'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman', +cffStandardStrings = ['.notdef', 'space', 'exclam', 'quotedbl', 'numbersign', + 'dollar', 'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright', + 'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one', + 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon', + 'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C', + 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', + 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash', + 'bracketright', 'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c', + 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', + 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright', + 'asciitilde', 'exclamdown', 'cent', 'sterling', 'fraction', 'yen', 'florin', + 'section', 'currency', 'quotesingle', 'quotedblleft', 'guillemotleft', + 'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'endash', 'dagger', + 'daggerdbl', 'periodcentered', 'paragraph', 'bullet', 'quotesinglbase', + 'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand', + 'questiondown', 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve', + 'dotaccent', 'dieresis', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron', + 'emdash', 'AE', 'ordfeminine', 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae', + 'dotlessi', 'lslash', 'oslash', 'oe', 'germandbls', 'onesuperior', + 'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn', + 'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters', + 'twosuperior', 'registered', 'minus', 'eth', 'multiply', 'threesuperior', + 'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring', + 'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave', + 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute', + 'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute', + 'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron', + 'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla', + 'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex', + 'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis', + 'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis', 'ugrave', + 'yacute', 'ydieresis', 'zcaron', 'exclamsmall', 'Hungarumlautsmall', + 'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall', + 'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader', + 'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle', + 'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle', + 'nineoldstyle', 'commasuperior', 'threequartersemdash', 'periodsuperior', + 'questionsmall', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior', + 'esuperior', 'isuperior', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior', + 'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'ffi', 'ffl', 'parenleftinferior', + 'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall', + 'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall', + 'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall', + 'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall', + 'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall', + 'exclamdownsmall', 'centoldstyle', 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall', + 'Dieresissmall', 'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall', + 'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall', + 'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths', + 'onethird', 'twothirds', 'zerosuperior', 'foursuperior', 'fivesuperior', + 'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior', + 'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior', + 'sixinferior', 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior', + 'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall', + 'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall', + 'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall', + 'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall', + 'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall', + 'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall', + 'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall', + 'Yacutesmall', 'Thornsmall', 'Ydieresissmall', '001.000', '001.001', '001.002', + '001.003', 'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman', 'Semibold' ] diff --git a/Lib/fontTools/encodings/MacRoman.py b/Lib/fontTools/encodings/MacRoman.py index e0d54be53..43c58ebb0 100644 --- a/Lib/fontTools/encodings/MacRoman.py +++ b/Lib/fontTools/encodings/MacRoman.py @@ -2,38 +2,38 @@ from __future__ import print_function, division, absolute_import from fontTools.misc.py23 import * MacRoman = [ - 'NUL', 'Eth', 'eth', 'Lslash', 'lslash', 'Scaron', 'scaron', 'Yacute', - 'yacute', 'HT', 'LF', 'Thorn', 'thorn', 'CR', 'Zcaron', 'zcaron', 'DLE', 'DC1', - 'DC2', 'DC3', 'DC4', 'onehalf', 'onequarter', 'onesuperior', 'threequarters', - 'threesuperior', 'twosuperior', 'brokenbar', 'minus', 'multiply', 'RS', 'US', - 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', - 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', - 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', 'five', - 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', - 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', - 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', - 'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', - 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', - 'braceright', 'asciitilde', 'DEL', 'Adieresis', 'Aring', 'Ccedilla', 'Eacute', - 'Ntilde', 'Odieresis', 'Udieresis', 'aacute', 'agrave', 'acircumflex', - 'adieresis', 'atilde', 'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex', - 'edieresis', 'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde', - 'oacute', 'ograve', 'ocircumflex', 'odieresis', 'otilde', 'uacute', 'ugrave', - 'ucircumflex', 'udieresis', 'dagger', 'degree', 'cent', 'sterling', 'section', - 'bullet', 'paragraph', 'germandbls', 'registered', 'copyright', 'trademark', - 'acute', 'dieresis', 'notequal', 'AE', 'Oslash', 'infinity', 'plusminus', - 'lessequal', 'greaterequal', 'yen', 'mu', 'partialdiff', 'summation', - 'product', 'pi', 'integral', 'ordfeminine', 'ordmasculine', 'Omega', 'ae', - 'oslash', 'questiondown', 'exclamdown', 'logicalnot', 'radical', 'florin', - 'approxequal', 'Delta', 'guillemotleft', 'guillemotright', 'ellipsis', - 'nbspace', 'Agrave', 'Atilde', 'Otilde', 'OE', 'oe', 'endash', 'emdash', - 'quotedblleft', 'quotedblright', 'quoteleft', 'quoteright', 'divide', 'lozenge', - 'ydieresis', 'Ydieresis', 'fraction', 'currency', 'guilsinglleft', - 'guilsinglright', 'fi', 'fl', 'daggerdbl', 'periodcentered', 'quotesinglbase', - 'quotedblbase', 'perthousand', 'Acircumflex', 'Ecircumflex', 'Aacute', - 'Edieresis', 'Egrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Oacute', - 'Ocircumflex', 'apple', 'Ograve', 'Uacute', 'Ucircumflex', 'Ugrave', 'dotlessi', - 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'ring', 'cedilla', + 'NUL', 'Eth', 'eth', 'Lslash', 'lslash', 'Scaron', 'scaron', 'Yacute', + 'yacute', 'HT', 'LF', 'Thorn', 'thorn', 'CR', 'Zcaron', 'zcaron', 'DLE', 'DC1', + 'DC2', 'DC3', 'DC4', 'onehalf', 'onequarter', 'onesuperior', 'threequarters', + 'threesuperior', 'twosuperior', 'brokenbar', 'minus', 'multiply', 'RS', 'US', + 'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand', + 'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma', + 'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', 'five', + 'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal', + 'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore', + 'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', + 'braceright', 'asciitilde', 'DEL', 'Adieresis', 'Aring', 'Ccedilla', 'Eacute', + 'Ntilde', 'Odieresis', 'Udieresis', 'aacute', 'agrave', 'acircumflex', + 'adieresis', 'atilde', 'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex', + 'edieresis', 'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde', + 'oacute', 'ograve', 'ocircumflex', 'odieresis', 'otilde', 'uacute', 'ugrave', + 'ucircumflex', 'udieresis', 'dagger', 'degree', 'cent', 'sterling', 'section', + 'bullet', 'paragraph', 'germandbls', 'registered', 'copyright', 'trademark', + 'acute', 'dieresis', 'notequal', 'AE', 'Oslash', 'infinity', 'plusminus', + 'lessequal', 'greaterequal', 'yen', 'mu', 'partialdiff', 'summation', + 'product', 'pi', 'integral', 'ordfeminine', 'ordmasculine', 'Omega', 'ae', + 'oslash', 'questiondown', 'exclamdown', 'logicalnot', 'radical', 'florin', + 'approxequal', 'Delta', 'guillemotleft', 'guillemotright', 'ellipsis', + 'nbspace', 'Agrave', 'Atilde', 'Otilde', 'OE', 'oe', 'endash', 'emdash', + 'quotedblleft', 'quotedblright', 'quoteleft', 'quoteright', 'divide', 'lozenge', + 'ydieresis', 'Ydieresis', 'fraction', 'currency', 'guilsinglleft', + 'guilsinglright', 'fi', 'fl', 'daggerdbl', 'periodcentered', 'quotesinglbase', + 'quotedblbase', 'perthousand', 'Acircumflex', 'Ecircumflex', 'Aacute', + 'Edieresis', 'Egrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Oacute', + 'Ocircumflex', 'apple', 'Ograve', 'Uacute', 'Ucircumflex', 'Ugrave', 'dotlessi', + 'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron' ] diff --git a/Lib/fontTools/merge.py b/Lib/fontTools/merge.py index 0c0e0ae2b..248589f2e 100644 --- a/Lib/fontTools/merge.py +++ b/Lib/fontTools/merge.py @@ -808,7 +808,7 @@ class Merger(object): try: mergeLogic = logic['*'] except KeyError: - raise Exception("Don't know how to merge key %s of class %s" % + raise Exception("Don't know how to merge key %s of class %s" % (key, returnTable.__class__.__name__)) if mergeLogic is NotImplemented: continue diff --git a/Lib/fontTools/misc/arrayTools.py b/Lib/fontTools/misc/arrayTools.py index db5b9edc8..e68cea2b3 100644 --- a/Lib/fontTools/misc/arrayTools.py +++ b/Lib/fontTools/misc/arrayTools.py @@ -43,7 +43,7 @@ def pointInRect(p, rect): return (xMin <= x <= xMax) and (yMin <= y <= yMax) def pointsInRect(array, rect): - """Find out which points or array are inside rect. + """Find out which points or array are inside rect. Returns an array with a boolean for each point. """ if len(array) < 1: @@ -59,7 +59,7 @@ def vectorLength(vector): def asInt16(array): """Round and cast to 16 bit integer.""" return [int(math.floor(i+0.5)) for i in array] - + def normRect(rect): """Normalize the rectangle so that the following holds: diff --git a/Lib/fontTools/misc/bezierTools.py b/Lib/fontTools/misc/bezierTools.py index 9aa294fc8..ce3f3027c 100644 --- a/Lib/fontTools/misc/bezierTools.py +++ b/Lib/fontTools/misc/bezierTools.py @@ -62,7 +62,7 @@ def calcCubicBounds(pt1, pt2, pt3, pt4): xRoots = [t for t in solveQuadratic(ax3, bx2, cx) if 0 <= t < 1] yRoots = [t for t in solveQuadratic(ay3, by2, cy) if 0 <= t < 1] roots = xRoots + yRoots - + points = [(ax*t*t*t + bx*t*t + cx * t + dx, ay*t*t*t + by*t*t + cy * t + dy) for t in roots] + [pt1, pt4] return calcBounds(points) @@ -220,7 +220,7 @@ def _splitQuadraticAtT(a, b, c, *ts): b1y = (2*ay*t1 + by) * delta c1x = ax*t1**2 + bx*t1 + cx c1y = ay*t1**2 + by*t1 + cy - + pt1, pt2, pt3 = calcQuadraticPoints((a1x, a1y), (b1x, b1y), (c1x, c1y)) segments.append((pt1, pt2, pt3)) return segments @@ -306,7 +306,7 @@ def solveCubic(a, b, c, d): a1 = b/a a2 = c/a a3 = d/a - + Q = (a1*a1 - 3.0*a2)/9.0 R = (2.0*a1*a1*a1 - 9.0*a1*a2 + 27.0*a3)/54.0 R2_Q3 = R*R - Q*Q*Q diff --git a/Lib/fontTools/misc/eexec.py b/Lib/fontTools/misc/eexec.py index b7656d7a4..281e3d521 100644 --- a/Lib/fontTools/misc/eexec.py +++ b/Lib/fontTools/misc/eexec.py @@ -1,4 +1,4 @@ -"""fontTools.misc.eexec.py -- Module implementing the eexec and +"""fontTools.misc.eexec.py -- Module implementing the eexec and charstring encryption algorithm as used by PostScript Type 1 fonts. """ diff --git a/Lib/fontTools/misc/fixedTools.py b/Lib/fontTools/misc/fixedTools.py index e55ff249b..cd7f38da4 100644 --- a/Lib/fontTools/misc/fixedTools.py +++ b/Lib/fontTools/misc/fixedTools.py @@ -14,7 +14,7 @@ def fixedToFloat(value, precisionBits): that has the shortest decimal reprentation. Eg. to convert a fixed number in a 2.14 format, use precisionBits=14. This is pretty slow compared to a simple division. Use sporadically. - + >>> "%g" % fixedToFloat(13107, 14) '0.8' >>> "%g" % fixedToFloat(0, 14) diff --git a/Lib/fontTools/misc/homeResFile.py b/Lib/fontTools/misc/homeResFile.py index 3c00bc64a..f804f5306 100644 --- a/Lib/fontTools/misc/homeResFile.py +++ b/Lib/fontTools/misc/homeResFile.py @@ -53,18 +53,18 @@ _FCBPBFormat = """ """ class ParamBlock(object): - + """Wrapper for the very low level FCBPB record.""" - + def __init__(self, refNum): self.__fileName = array.array("c", "\0" * 64) - sstruct.unpack(_FCBPBFormat, + sstruct.unpack(_FCBPBFormat, "\0" * sstruct.calcsize(_FCBPBFormat), self) self.ioNamePtr = self.__fileName.buffer_info()[0] self.ioRefNum = refNum self.ioVRefNum = GetVRefNum(refNum) self.__haveInfo = 0 - + def getInfo(self): if self.__haveInfo: return @@ -76,18 +76,18 @@ class ParamBlock(object): raise Res.Error("can't get file info", err) sstruct.unpack(_FCBPBFormat, buf.tostring(), self) self.__haveInfo = 1 - + def getFileName(self): self.getInfo() data = self.__fileName.tostring() return data[1:byteord(data[0])+1] - + def getFSSpec(self): self.getInfo() vRefNum = self.ioVRefNum parID = self.ioFCBParID return macfs.FSSpec((vRefNum, parID, self.getFileName())) - + def getPath(self): return self.getFSSpec().as_pathname() diff --git a/Lib/fontTools/misc/psCharStrings.py b/Lib/fontTools/misc/psCharStrings.py index 199f444af..5ec1c0879 100644 --- a/Lib/fontTools/misc/psCharStrings.py +++ b/Lib/fontTools/misc/psCharStrings.py @@ -1,4 +1,4 @@ -"""psCharStrings.py -- module implementing various kinds of CharStrings: +"""psCharStrings.py -- module implementing various kinds of CharStrings: CFF dictionary data and Type1/Type2 CharStrings. """ @@ -81,7 +81,7 @@ cffDictOperandEncoding[30] = read_realNumber cffDictOperandEncoding[255] = read_reserved -realNibbles = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', +realNibbles = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', 'E', 'E-', None, '-'] realNibblesDict = dict((v,i) for i,v in enumerate(realNibbles)) @@ -171,7 +171,7 @@ def getIntEncoder(format): else: assert format == "t2" fourByteOp = None - + def encodeInt(value, fourByteOp=fourByteOp, bytechr=bytechr, pack=struct.pack, unpack=struct.unpack): if -107 <= value <= 107: @@ -203,7 +203,7 @@ def getIntEncoder(format): else: code = fourByteOp + pack(">l", value) return code - + return encodeInt @@ -243,10 +243,10 @@ class CharStringCompileError(Exception): pass class T2CharString(ByteCodeBase): - + operandEncoding = t2OperandEncoding operators, opcodes = buildOperatorDict(t2Operators) - + def __init__(self, bytecode=None, program=None, private=None, globalSubrs=None): if program is None: program = [] @@ -254,16 +254,16 @@ class T2CharString(ByteCodeBase): self.program = program self.private = private self.globalSubrs = globalSubrs if globalSubrs is not None else [] - + def __repr__(self): if self.bytecode is None: return "<%s (source) at %x>" % (self.__class__.__name__, id(self)) else: return "<%s (bytecode) at %x>" % (self.__class__.__name__, id(self)) - + def getIntEncoder(self): return encodeIntT2 - + def getFixedEncoder(self): return encodeFixed @@ -273,14 +273,14 @@ class T2CharString(ByteCodeBase): subrs = getattr(self.private, "Subrs", []) decompiler = SimpleT2Decompiler(subrs, self.globalSubrs) decompiler.execute(self) - + def draw(self, pen): subrs = getattr(self.private, "Subrs", []) extractor = T2OutlineExtractor(pen, subrs, self.globalSubrs, self.private.nominalWidthX, self.private.defaultWidthX) extractor.execute(self) self.width = extractor.width - + def compile(self): if self.bytecode is not None: return @@ -318,18 +318,18 @@ class T2CharString(ByteCodeBase): print(bytecode) raise self.setBytecode(bytecode) - + def needsDecompilation(self): return self.bytecode is not None - + def setProgram(self, program): self.program = program self.bytecode = None - + def setBytecode(self, bytecode): self.bytecode = bytecode self.program = None - + def getToken(self, index, len=len, byteord=byteord, basestring=basestring, isinstance=isinstance): @@ -347,7 +347,7 @@ class T2CharString(ByteCodeBase): index = index + 1 isOperator = isinstance(token, basestring) return token, isOperator, index - + def getBytes(self, index, nBytes): if self.bytecode is not None: newIndex = index + nBytes @@ -358,10 +358,10 @@ class T2CharString(ByteCodeBase): index = index + 1 assert len(bytes) == nBytes return bytes, index - + def handle_operator(self, operator): return operator - + def toXML(self, xmlWriter): from fontTools.misc.textTools import num2binary if self.bytecode is not None: @@ -389,7 +389,7 @@ class T2CharString(ByteCodeBase): args = [] else: args.append(token) - + def fromXML(self, name, attrs, content): from fontTools.misc.textTools import binary2num, readHex if attrs.get("raw"): @@ -454,10 +454,10 @@ t1Operators = [ ] class T1CharString(T2CharString): - + operandEncoding = t1OperandEncoding operators, opcodes = buildOperatorDict(t1Operators) - + def __init__(self, bytecode=None, program=None, subrs=None): if program is None: program = [] @@ -491,20 +491,20 @@ class T1CharString(T2CharString): class SimpleT2Decompiler(object): - + def __init__(self, localSubrs, globalSubrs): self.localSubrs = localSubrs self.localBias = calcSubrBias(localSubrs) self.globalSubrs = globalSubrs self.globalBias = calcSubrBias(globalSubrs) self.reset() - + def reset(self): self.callingStack = [] self.operandStack = [] self.hintCount = 0 self.hintMaskBytes = 0 - + def execute(self, charString): self.callingStack.append(charString) needsDecompilation = charString.needsDecompilation() @@ -538,24 +538,24 @@ class SimpleT2Decompiler(object): "seac"), "illegal CharString" charString.setProgram(program) del self.callingStack[-1] - + def pop(self): value = self.operandStack[-1] del self.operandStack[-1] return value - + def popall(self): stack = self.operandStack[:] self.operandStack[:] = [] return stack - + def push(self, value): self.operandStack.append(value) - + def op_return(self, index): if self.operandStack: pass - + def op_endchar(self, index): pass @@ -566,12 +566,12 @@ class SimpleT2Decompiler(object): subrIndex = self.pop() subr = self.localSubrs[subrIndex+self.localBias] self.execute(subr) - + def op_callgsubr(self, index): subrIndex = self.pop() subr = self.globalSubrs[subrIndex+self.globalBias] self.execute(subr) - + def op_hstem(self, index): self.countHints() def op_vstem(self, index): @@ -580,16 +580,16 @@ class SimpleT2Decompiler(object): self.countHints() def op_vstemhm(self, index): self.countHints() - + def op_hintmask(self, index): if not self.hintMaskBytes: self.countHints() self.hintMaskBytes = (self.hintCount + 7) // 8 hintMaskBytes, index = self.callingStack[-1].getBytes(index, self.hintMaskBytes) return hintMaskBytes, index - + op_cntrmask = op_hintmask - + def countHints(self): args = self.popall() self.hintCount = self.hintCount + len(args) // 2 @@ -641,13 +641,13 @@ class SimpleT2Decompiler(object): raise NotImplementedError class T2OutlineExtractor(SimpleT2Decompiler): - + def __init__(self, pen, localSubrs, globalSubrs, nominalWidthX, defaultWidthX): SimpleT2Decompiler.__init__(self, localSubrs, globalSubrs) self.pen = pen self.nominalWidthX = nominalWidthX self.defaultWidthX = defaultWidthX - + def reset(self): SimpleT2Decompiler.reset(self) self.hints = [] @@ -655,13 +655,13 @@ class T2OutlineExtractor(SimpleT2Decompiler): self.width = 0 self.currentPoint = (0, 0) self.sawMoveTo = 0 - + def _nextPoint(self, point): x, y = self.currentPoint point = x + point[0], y + point[1] self.currentPoint = point return point - + def rMoveTo(self, point): self.pen.moveTo(self._nextPoint(point)) self.sawMoveTo = 1 @@ -676,12 +676,12 @@ class T2OutlineExtractor(SimpleT2Decompiler): self.rMoveTo((0, 0)) nextPoint = self._nextPoint self.pen.curveTo(nextPoint(pt1), nextPoint(pt2), nextPoint(pt3)) - + def closePath(self): if self.sawMoveTo: self.pen.closePath() self.sawMoveTo = 0 - + def endPath(self): # In T2 there are no open paths, so always do a closePath when # finishing a sub path. @@ -697,11 +697,11 @@ class T2OutlineExtractor(SimpleT2Decompiler): self.width = self.defaultWidthX self.gotWidth = 1 return args - + def countHints(self): args = self.popallWidth() self.hintCount = self.hintCount + len(args) // 2 - + # # hint operators # @@ -717,7 +717,7 @@ class T2OutlineExtractor(SimpleT2Decompiler): # self.countHints() #def op_cntrmask(self, index): # self.countHints() - + # # path constructors, moveto # @@ -742,7 +742,7 @@ class T2OutlineExtractor(SimpleT2Decompiler): self.pen.addComponent(baseGlyph, (1, 0, 0, 1, 0, 0)) accentGlyph = StandardEncoding[achar] self.pen.addComponent(accentGlyph, (1, 0, 0, 1, adx, ady)) - + # # path constructors, lines # @@ -751,12 +751,12 @@ class T2OutlineExtractor(SimpleT2Decompiler): for i in range(0, len(args), 2): point = args[i:i+2] self.rLineTo(point) - + def op_hlineto(self, index): self.alternatingLineto(1) def op_vlineto(self, index): self.alternatingLineto(0) - + # # path constructors, curves # @@ -766,7 +766,7 @@ class T2OutlineExtractor(SimpleT2Decompiler): for i in range(0, len(args), 6): dxa, dya, dxb, dyb, dxc, dyc, = args[i:i+6] self.rCurveTo((dxa, dya), (dxb, dyb), (dxc, dyc)) - + def op_rcurveline(self, index): """{dxa dya dxb dyb dxc dyc}+ dxd dyd rcurveline""" args = self.popall() @@ -774,7 +774,7 @@ class T2OutlineExtractor(SimpleT2Decompiler): dxb, dyb, dxc, dyc, dxd, dyd = args[i:i+6] self.rCurveTo((dxb, dyb), (dxc, dyc), (dxd, dyd)) self.rLineTo(args[-2:]) - + def op_rlinecurve(self, index): """{dxa dya}+ dxb dyb dxc dyc dxd dyd rlinecurve""" args = self.popall() @@ -783,7 +783,7 @@ class T2OutlineExtractor(SimpleT2Decompiler): self.rLineTo(lineArgs[i:i+2]) dxb, dyb, dxc, dyc, dxd, dyd = args[-6:] self.rCurveTo((dxb, dyb), (dxc, dyc), (dxd, dyd)) - + def op_vvcurveto(self, index): "dx1? {dya dxb dyb dyc}+ vvcurveto" args = self.popall() @@ -796,7 +796,7 @@ class T2OutlineExtractor(SimpleT2Decompiler): dya, dxb, dyb, dyc = args[i:i+4] self.rCurveTo((dx1, dya), (dxb, dyb), (0, dyc)) dx1 = 0 - + def op_hhcurveto(self, index): """dy1? {dxa dxb dyb dxc}+ hhcurveto""" args = self.popall() @@ -809,7 +809,7 @@ class T2OutlineExtractor(SimpleT2Decompiler): dxa, dxb, dyb, dxc = args[i:i+4] self.rCurveTo((dxa, dy1), (dxb, dyb), (dxc, 0)) dy1 = 0 - + def op_vhcurveto(self, index): """dy1 dx2 dy2 dx3 {dxa dxb dyb dyc dyd dxe dye dxf}* dyf? vhcurveto (30) {dya dxb dyb dxc dxd dxe dye dyf}+ dxf? vhcurveto @@ -819,7 +819,7 @@ class T2OutlineExtractor(SimpleT2Decompiler): args = self.vcurveto(args) if args: args = self.hcurveto(args) - + def op_hvcurveto(self, index): """dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* dxf? {dxa dxb dyb dyc dyd dxe dye dxf}+ dyf? @@ -829,7 +829,7 @@ class T2OutlineExtractor(SimpleT2Decompiler): args = self.hcurveto(args) if args: args = self.vcurveto(args) - + # # path constructors, flex # @@ -862,13 +862,13 @@ class T2OutlineExtractor(SimpleT2Decompiler): dy6 = d6 self.rCurveTo((dx1, dy1), (dx2, dy2), (dx3, dy3)) self.rCurveTo((dx4, dy4), (dx5, dy5), (dx6, dy6)) - + # # MultipleMaster. Well... # def op_blend(self, index): self.popall() - + # misc def op_and(self, index): raise NotImplementedError @@ -921,7 +921,7 @@ class T2OutlineExtractor(SimpleT2Decompiler): raise NotImplementedError def op_roll(self, index): raise NotImplementedError - + # # miscellaneous helpers # @@ -934,7 +934,7 @@ class T2OutlineExtractor(SimpleT2Decompiler): point = (0, arg) self.rLineTo(point) isHorizontal = not isHorizontal - + def vcurveto(self, args): dya, dxb, dyb, dxc = args[:4] args = args[4:] @@ -945,7 +945,7 @@ class T2OutlineExtractor(SimpleT2Decompiler): dyc = 0 self.rCurveTo((0, dya), (dxb, dyb), (dxc, dyc)) return args - + def hcurveto(self, args): dxa, dxb, dyb, dyc = args[:4] args = args[4:] @@ -959,18 +959,18 @@ class T2OutlineExtractor(SimpleT2Decompiler): class T1OutlineExtractor(T2OutlineExtractor): - + def __init__(self, pen, subrs): self.pen = pen self.subrs = subrs self.reset() - + def reset(self): self.flexing = 0 self.width = 0 self.sbx = 0 T2OutlineExtractor.reset(self) - + def endPath(self): if self.sawMoveTo: self.pen.endPath() @@ -978,11 +978,11 @@ class T1OutlineExtractor(T2OutlineExtractor): def popallWidth(self, evenOdd=0): return self.popall() - + def exch(self): stack = self.operandStack stack[-1], stack[-2] = stack[-2], stack[-1] - + # # path constructors # @@ -1012,10 +1012,10 @@ class T1OutlineExtractor(T2OutlineExtractor): args = self.popall() x, y = args self.currentPoint = x, y - + def op_endchar(self, index): self.endPath() - + def op_hsbw(self, index): sbx, wx = self.popall() self.width = wx @@ -1023,7 +1023,7 @@ class T1OutlineExtractor(T2OutlineExtractor): self.currentPoint = sbx, self.currentPoint[1] def op_sbw(self, index): self.popall() # XXX - + # def op_callsubr(self, index): subrIndex = self.pop() @@ -1041,12 +1041,12 @@ class T1OutlineExtractor(T2OutlineExtractor): # ignore... def op_pop(self, index): pass # ignore... - + def doFlex(self): finaly = self.pop() finalx = self.pop() self.pop() # flex height is unused - + p3y = self.pop() p3x = self.pop() bcp4y = self.pop() @@ -1061,7 +1061,7 @@ class T1OutlineExtractor(T2OutlineExtractor): bcp1x = self.pop() rpy = self.pop() rpx = self.pop() - + # call rrcurveto self.push(bcp1x+rpx) self.push(bcp1y+rpy) @@ -1070,7 +1070,7 @@ class T1OutlineExtractor(T2OutlineExtractor): self.push(p2x) self.push(p2y) self.op_rrcurveto(None) - + # call rrcurveto self.push(bcp3x) self.push(bcp3y) @@ -1079,11 +1079,11 @@ class T1OutlineExtractor(T2OutlineExtractor): self.push(p3x) self.push(p3y) self.op_rrcurveto(None) - + # Push back final coords so subr 0 can find them self.push(finalx) self.push(finaly) - + def op_dotsection(self, index): self.popall() # XXX def op_hstem3(self, index): @@ -1102,18 +1102,18 @@ class T1OutlineExtractor(T2OutlineExtractor): class DictDecompiler(ByteCodeBase): - + operandEncoding = cffDictOperandEncoding - + def __init__(self, strings): self.stack = [] self.strings = strings self.dict = {} - + def getDict(self): assert len(self.stack) == 0, "non-empty stack" return self.dict - + def decompile(self, data): index = 0 lenData = len(data) @@ -1125,17 +1125,17 @@ class DictDecompiler(ByteCodeBase): value, index = handler(self, b0, data, index) if value is not None: push(value) - + def pop(self): value = self.stack[-1] del self.stack[-1] return value - + def popall(self): args = self.stack[:] del self.stack[:] return args - + def handle_operator(self, operator): operator, argType = operator if isinstance(argType, type(())): @@ -1148,7 +1148,7 @@ class DictDecompiler(ByteCodeBase): arghandler = getattr(self, "arg_" + argType) value = arghandler(operator) self.dict[operator] = value - + def arg_number(self, name): return self.pop() def arg_SID(self, name): diff --git a/Lib/fontTools/misc/psLib.py b/Lib/fontTools/misc/psLib.py index 2fad16bb9..0bba4d3ce 100644 --- a/Lib/fontTools/misc/psLib.py +++ b/Lib/fontTools/misc/psLib.py @@ -39,7 +39,7 @@ class PSError(Exception): pass class PSTokenizer(StringIO): - + def getnexttoken(self, # localize some stuff, for performance len=len, @@ -47,9 +47,9 @@ class PSTokenizer(StringIO): stringmatch=stringRE.match, hexstringmatch=hexstringRE.match, commentmatch=commentRE.match, - endmatch=endofthingRE.match, + endmatch=endofthingRE.match, whitematch=skipwhiteRE.match): - + _, nextpos = whitematch(self.buf, self.pos).span() self.pos = nextpos if self.pos >= self.len: @@ -94,11 +94,11 @@ class PSTokenizer(StringIO): token = buf[pos:nextpos] self.pos = pos + len(token) return tokentype, token - + def skipwhite(self, whitematch=skipwhiteRE.match): _, nextpos = whitematch(self.buf, self.pos).span() self.pos = nextpos - + def starteexec(self): self.pos = self.pos + 1 #self.skipwhite() @@ -106,13 +106,13 @@ class PSTokenizer(StringIO): self.buf, R = eexec.decrypt(self.dirtybuf, 55665) self.len = len(self.buf) self.pos = 4 - + def stopeexec(self): if not hasattr(self, 'dirtybuf'): return self.buf = self.dirtybuf del self.dirtybuf - + def flush(self): if self.buflist: self.buf = self.buf + "".join(self.buflist) @@ -120,7 +120,7 @@ class PSTokenizer(StringIO): class PSInterpreter(PSOperators): - + def __init__(self): systemdict = {} userdict = {} @@ -129,7 +129,7 @@ class PSInterpreter(PSOperators): self.proclevel = 0 self.procmark = ps_procmark() self.fillsystemdict() - + def fillsystemdict(self): systemdict = self.dictstack[0] systemdict['['] = systemdict['mark'] = self.mark = ps_mark() @@ -139,7 +139,7 @@ class PSInterpreter(PSOperators): systemdict['StandardEncoding'] = ps_array(ps_StandardEncoding) systemdict['FontDirectory'] = ps_dict({}) self.suckoperators(systemdict, self.__class__) - + def suckoperators(self, systemdict, klass): for name in dir(klass): attr = getattr(self, name) @@ -148,7 +148,7 @@ class PSInterpreter(PSOperators): systemdict[name] = ps_operator(name, attr) for baseclass in klass.__bases__: self.suckoperators(systemdict, baseclass) - + def interpret(self, data, getattr=getattr): tokenizer = self.tokenizer = PSTokenizer(data) getnexttoken = tokenizer.getnexttoken @@ -177,7 +177,7 @@ class PSInterpreter(PSOperators): print('>>>') print(self.tokenizer.buf[self.tokenizer.pos:self.tokenizer.pos+50]) print('- - - - - - -') - + def handle_object(self, object): if not (self.proclevel or object.literal or object.type == 'proceduretype'): if object.type != 'operatortype': @@ -191,21 +191,21 @@ class PSInterpreter(PSOperators): object.function() else: self.push(object) - + def call_procedure(self, proc): handle_object = self.handle_object for item in proc.value: handle_object(item) - + def resolve_name(self, name): dictstack = self.dictstack for i in range(len(dictstack)-1, -1, -1): if name in dictstack[i]: return dictstack[i][name] raise PSError('name error: ' + str(name)) - + def do_token(self, token, - int=int, + int=int, float=float, ps_name=ps_name, ps_integer=ps_integer, @@ -231,16 +231,16 @@ class PSInterpreter(PSOperators): return ps_real(num) else: return ps_integer(num) - + def do_comment(self, token): pass - + def do_literal(self, token): return ps_literal(token[1:]) - + def do_string(self, token): return ps_string(token[1:-1]) - + def do_hexstring(self, token): hexStr = "".join(token[1:-1].split()) if len(hexStr) % 2: @@ -250,7 +250,7 @@ class PSInterpreter(PSOperators): cleanstr.append(chr(int(hexStr[i:i+2], 16))) cleanstr = "".join(cleanstr) return ps_string(cleanstr) - + def do_special(self, token): if token == '{': self.proclevel = self.proclevel + 1 @@ -271,10 +271,10 @@ class PSInterpreter(PSOperators): return ps_name(']') else: raise PSTokenError('huh?') - + def push(self, object): self.stack.append(object) - + def pop(self, *types): stack = self.stack if not stack: @@ -285,7 +285,7 @@ class PSInterpreter(PSOperators): raise PSError('typecheck, expected %s, found %s' % (repr(types), object.type)) del stack[-1] return object - + def do_makearray(self): array = [] while 1: @@ -295,7 +295,7 @@ class PSInterpreter(PSOperators): array.append(topobject) array.reverse() self.push(ps_array(array)) - + def close(self): """Remove circular references.""" del self.stack diff --git a/Lib/fontTools/misc/psOperators.py b/Lib/fontTools/misc/psOperators.py index b2ed11dfb..47484c63f 100644 --- a/Lib/fontTools/misc/psOperators.py +++ b/Lib/fontTools/misc/psOperators.py @@ -5,23 +5,23 @@ _accessstrings = {0: "", 1: "readonly", 2: "executeonly", 3: "noaccess"} class ps_object: - + literal = 1 access = 0 value = None - + def __init__(self, value): self.value = value self.type = self.__class__.__name__[3:] + "type" - + def __repr__(self): return "<%s %s>" % (self.__class__.__name__[3:], repr(self.value)) class ps_operator(ps_object): - + literal = 0 - + def __init__(self, name, function): self.name = name self.function = function @@ -171,7 +171,7 @@ class ps_dict(ps_object): return "" class ps_mark(ps_object): - def __init__(self): + def __init__(self): self.value = 'mark' self.type = self.__class__.__name__[3:] + "type" @@ -205,17 +205,17 @@ class ps_real(ps_object): class PSOperators: - + def ps_def(self): obj = self.pop() name = self.pop() self.dictstack[-1][name.value] = obj - + def ps_bind(self): proc = self.pop('proceduretype') self.proc_bind(proc) self.push(proc) - + def proc_bind(self, proc): for i in range(len(proc.value)): item = proc.value[i] @@ -230,7 +230,7 @@ class PSOperators: else: if obj.type == 'operatortype': proc.value[i] = obj - + def ps_exch(self): if len(self.stack) < 2: raise RuntimeError('stack underflow') @@ -238,49 +238,49 @@ class PSOperators: obj2 = self.pop() self.push(obj1) self.push(obj2) - + def ps_dup(self): if not self.stack: raise RuntimeError('stack underflow') self.push(self.stack[-1]) - + def ps_exec(self): obj = self.pop() if obj.type == 'proceduretype': self.call_procedure(obj) else: self.handle_object(obj) - + def ps_count(self): self.push(ps_integer(len(self.stack))) - + def ps_eq(self): any1 = self.pop() any2 = self.pop() self.push(ps_boolean(any1.value == any2.value)) - + def ps_ne(self): any1 = self.pop() any2 = self.pop() self.push(ps_boolean(any1.value != any2.value)) - + def ps_cvx(self): obj = self.pop() obj.literal = 0 self.push(obj) - + def ps_matrix(self): matrix = [ps_real(1.0), ps_integer(0), ps_integer(0), ps_real(1.0), ps_integer(0), ps_integer(0)] self.push(ps_array(matrix)) - + def ps_string(self): num = self.pop('integertype').value self.push(ps_string('\0' * num)) - + def ps_type(self): obj = self.pop() self.push(ps_string(obj.type)) - + def ps_store(self): value = self.pop() key = self.pop() @@ -290,38 +290,38 @@ class PSOperators: self.dictstack[i][name] = value break self.dictstack[-1][name] = value - + def ps_where(self): name = self.pop() # XXX self.push(ps_boolean(0)) - + def ps_systemdict(self): self.push(ps_dict(self.dictstack[0])) - + def ps_userdict(self): self.push(ps_dict(self.dictstack[1])) - + def ps_currentdict(self): self.push(ps_dict(self.dictstack[-1])) - + def ps_currentfile(self): self.push(ps_file(self.tokenizer)) - + def ps_eexec(self): f = self.pop('filetype').value f.starteexec() - + def ps_closefile(self): f = self.pop('filetype').value f.skipwhite() f.stopeexec() - + def ps_cleartomark(self): obj = self.pop() while obj != self.mark: obj = self.pop() - + def ps_readstring(self, ps_boolean=ps_boolean, len=len): @@ -335,17 +335,17 @@ class PSOperators: s.value = newstr self.push(s) self.push(ps_boolean(len(oldstr) == len(newstr))) - + def ps_known(self): key = self.pop() d = self.pop('dicttype', 'fonttype') self.push(ps_boolean(key.value in d.value)) - + def ps_if(self): proc = self.pop('proceduretype') if self.pop('booleantype').value: self.call_procedure(proc) - + def ps_ifelse(self): proc2 = self.pop('proceduretype') proc1 = self.pop('proceduretype') @@ -353,36 +353,36 @@ class PSOperators: self.call_procedure(proc1) else: self.call_procedure(proc2) - + def ps_readonly(self): obj = self.pop() if obj.access < 1: obj.access = 1 self.push(obj) - + def ps_executeonly(self): obj = self.pop() if obj.access < 2: obj.access = 2 self.push(obj) - + def ps_noaccess(self): obj = self.pop() if obj.access < 3: obj.access = 3 self.push(obj) - + def ps_not(self): obj = self.pop('booleantype', 'integertype') if obj.type == 'booleantype': self.push(ps_boolean(not obj.value)) else: self.push(ps_integer(~obj.value)) - + def ps_print(self): str = self.pop('stringtype') print('PS output --->', str.value) - + def ps_anchorsearch(self): seek = self.pop('stringtype') s = self.pop('stringtype') @@ -394,22 +394,22 @@ class PSOperators: else: self.push(s) self.push(ps_boolean(0)) - + def ps_array(self): num = self.pop('integertype') array = ps_array([None] * num.value) self.push(array) - + def ps_astore(self): array = self.pop('arraytype') for i in range(len(array.value)-1, -1, -1): array.value[i] = self.pop() self.push(array) - + def ps_load(self): name = self.pop() self.push(self.resolve_name(name.value)) - + def ps_put(self): obj1 = self.pop() obj2 = self.pop() @@ -422,7 +422,7 @@ class PSOperators: elif tp == 'stringtype': index = obj2.value obj3.value = obj3.value[:index] + chr(obj1.value) + obj3.value[index+1:] - + def ps_get(self): obj1 = self.pop() if obj1.value == "Encoding": @@ -437,7 +437,7 @@ class PSOperators: self.push(ps_integer(ord(obj2.value[obj1.value]))) else: assert False, "shouldn't get here" - + def ps_getinterval(self): obj1 = self.pop('integertype') obj2 = self.pop('integertype') @@ -447,7 +447,7 @@ class PSOperators: self.push(ps_array(obj3.value[obj2.value:obj2.value + obj1.value])) elif tp == 'stringtype': self.push(ps_string(obj3.value[obj2.value:obj2.value + obj1.value])) - + def ps_putinterval(self): obj1 = self.pop('arraytype', 'stringtype') obj2 = self.pop('integertype') @@ -460,16 +460,16 @@ class PSOperators: newstr = newstr + obj1.value newstr = newstr + obj3.value[obj2.value + len(obj1.value):] obj3.value = newstr - + def ps_cvn(self): self.push(ps_name(self.pop('stringtype').value)) - + def ps_index(self): n = self.pop('integertype').value if n < 0: raise RuntimeError('index may not be negative') self.push(self.stack[-1-n]) - + def ps_for(self): proc = self.pop('proceduretype') limit = self.pop('integertype', 'realtype').value @@ -488,7 +488,7 @@ class PSOperators: self.push(ps_integer(i)) self.call_procedure(proc) i = i + increment - + def ps_forall(self): proc = self.pop('proceduretype') obj = self.pop('arraytype', 'stringtype', 'dicttype') @@ -505,36 +505,36 @@ class PSOperators: for key, value in obj.value.items(): self.push(ps_name(key)) self.push(value) - self.call_procedure(proc) - + self.call_procedure(proc) + def ps_definefont(self): font = self.pop('dicttype') name = self.pop() font = ps_font(font.value) self.dictstack[0]['FontDirectory'].value[name.value] = font self.push(font) - + def ps_findfont(self): name = self.pop() font = self.dictstack[0]['FontDirectory'].value[name.value] self.push(font) - + def ps_pop(self): self.pop() - + def ps_dict(self): self.pop('integertype') self.push(ps_dict({})) - + def ps_begin(self): self.dictstack.append(self.pop('dicttype').value) - + def ps_end(self): if len(self.dictstack) > 2: del self.dictstack[-1] else: raise RuntimeError('dictstack underflow') - + notdef = '.notdef' from fontTools.encodings.StandardEncoding import StandardEncoding ps_StandardEncoding = list(map(ps_name, StandardEncoding)) diff --git a/Lib/fontTools/misc/sstruct.py b/Lib/fontTools/misc/sstruct.py index 8a2b073d7..c9fd1c52f 100644 --- a/Lib/fontTools/misc/sstruct.py +++ b/Lib/fontTools/misc/sstruct.py @@ -1,44 +1,44 @@ """sstruct.py -- SuperStruct -Higher level layer on top of the struct module, enabling to -bind names to struct elements. The interface is similar to -struct, except the objects passed and returned are not tuples -(or argument lists), but dictionaries or instances. +Higher level layer on top of the struct module, enabling to +bind names to struct elements. The interface is similar to +struct, except the objects passed and returned are not tuples +(or argument lists), but dictionaries or instances. -Just like struct, we use fmt strings to describe a data -structure, except we use one line per element. Lines are -separated by newlines or semi-colons. Each line contains -either one of the special struct characters ('@', '=', '<', -'>' or '!') or a 'name:formatchar' combo (eg. 'myFloat:f'). -Repetitions, like the struct module offers them are not useful -in this context, except for fixed length strings (eg. 'myInt:5h' -is not allowed but 'myString:5s' is). The 'x' fmt character -(pad byte) is treated as 'special', since it is by definition +Just like struct, we use fmt strings to describe a data +structure, except we use one line per element. Lines are +separated by newlines or semi-colons. Each line contains +either one of the special struct characters ('@', '=', '<', +'>' or '!') or a 'name:formatchar' combo (eg. 'myFloat:f'). +Repetitions, like the struct module offers them are not useful +in this context, except for fixed length strings (eg. 'myInt:5h' +is not allowed but 'myString:5s' is). The 'x' fmt character +(pad byte) is treated as 'special', since it is by definition anonymous. Extra whitespace is allowed everywhere. The sstruct module offers one feature that the "normal" struct module doesn't: support for fixed point numbers. These are spelled as "n.mF", where n is the number of bits before the point, and m -the number of bits after the point. Fixed point numbers get +the number of bits after the point. Fixed point numbers get converted to floats. pack(fmt, object): 'object' is either a dictionary or an instance (or actually - anything that has a __dict__ attribute). If it is a dictionary, - its keys are used for names. If it is an instance, it's + anything that has a __dict__ attribute). If it is a dictionary, + its keys are used for names. If it is an instance, it's attributes are used to grab struct elements from. Returns a string containing the data. unpack(fmt, data, object=None) - If 'object' is omitted (or None), a new dictionary will be - returned. If 'object' is a dictionary, it will be used to add + If 'object' is omitted (or None), a new dictionary will be + returned. If 'object' is a dictionary, it will be used to add struct elements to. If it is an instance (or in fact anything - that has a __dict__ attribute), an attribute will be added for - each struct element. In the latter two cases, 'object' itself + that has a __dict__ attribute), an attribute will be added for + each struct element. In the latter two cases, 'object' itself is returned. unpack2(fmt, data, object=None) - Convenience function. Same as unpack, except data may be longer + Convenience function. Same as unpack, except data may be longer than needed. The returned value is a tuple: (object, leftoverdata). calcsize(fmt) @@ -174,7 +174,7 @@ def _test(): # comments are allowed > # big endian (see documentation for struct) # empty lines are allowed: - + ashort: h along: l abyte: b # a byte @@ -183,14 +183,14 @@ def _test(): afloat: f; adouble: d # multiple "statements" are allowed afixed: 16.16F """ - + print('size:', calcsize(fmt)) - + class foo(object): pass - + i = foo() - + i.ashort = 0x7fff i.along = 0x7fffffff i.abyte = 0x7f @@ -199,7 +199,7 @@ def _test(): i.afloat = 0.5 i.adouble = 0.5 i.afixed = 1.5 - + data = pack(fmt, i) print('data:', repr(data)) print(unpack(fmt, data)) diff --git a/Lib/fontTools/misc/textTools.py b/Lib/fontTools/misc/textTools.py index cb4045e97..6e264dbd2 100644 --- a/Lib/fontTools/misc/textTools.py +++ b/Lib/fontTools/misc/textTools.py @@ -66,10 +66,10 @@ def binary2num(bin): def caselessSort(alist): - """Return a sorted copy of a list. If there are only strings + """Return a sorted copy of a list. If there are only strings in the list, it will not consider case. """ - + try: return sorted(alist, key=lambda a: (a.lower(), a)) except TypeError: diff --git a/Lib/fontTools/misc/xmlReader.py b/Lib/fontTools/misc/xmlReader.py index 4fb6cf9cb..f65cf7dba 100644 --- a/Lib/fontTools/misc/xmlReader.py +++ b/Lib/fontTools/misc/xmlReader.py @@ -12,7 +12,7 @@ BUFSIZE = 0x4000 class XMLReader(object): - + def __init__(self, fileName, ttFont, progress=None, quiet=False): self.ttFont = ttFont self.fileName = fileName @@ -21,7 +21,7 @@ class XMLReader(object): self.root = None self.contentStack = [] self.stackSize = 0 - + def read(self): if self.progress: import stat @@ -29,14 +29,14 @@ class XMLReader(object): file = open(self.fileName) self._parseFile(file) file.close() - + def _parseFile(self, file): from xml.parsers.expat import ParserCreate parser = ParserCreate() parser.StartElementHandler = self._startElementHandler parser.EndElementHandler = self._endElementHandler parser.CharacterDataHandler = self._characterDataHandler - + pos = 0 while True: chunk = file.read(BUFSIZE) @@ -47,7 +47,7 @@ class XMLReader(object): if self.progress: self.progress.set(pos // 100) parser.Parse(chunk, 0) - + def _startElementHandler(self, name, attrs): stackSize = self.stackSize self.stackSize = stackSize + 1 @@ -100,11 +100,11 @@ class XMLReader(object): l = [] self.contentStack[-1].append((name, attrs, l)) self.contentStack.append(l) - + def _characterDataHandler(self, data): if self.stackSize > 1: self.contentStack[-1].append(data) - + def _endElementHandler(self, name): self.stackSize = self.stackSize - 1 del self.contentStack[-1] @@ -117,15 +117,15 @@ class XMLReader(object): class ProgressPrinter(object): - + def __init__(self, title, maxval=100): print(title) - + def set(self, val, maxval=None): pass - + def increment(self, val=1): pass - + def setLabel(self, text): print(text) diff --git a/Lib/fontTools/misc/xmlWriter.py b/Lib/fontTools/misc/xmlWriter.py index a44e8b371..9aff744cd 100644 --- a/Lib/fontTools/misc/xmlWriter.py +++ b/Lib/fontTools/misc/xmlWriter.py @@ -10,7 +10,7 @@ INDENT = " " class XMLWriter(object): - + def __init__(self, fileOrPath, indentwhite=INDENT, idlefunc=None, encoding="utf_8"): if encoding.lower().replace('-','').replace('_','') != 'utf8': raise Exception('Only UTF-8 encoding is supported.') @@ -41,10 +41,10 @@ class XMLWriter(object): self.idlecounter = 0 self._writeraw('') self.newline() - + def close(self): self.file.close() - + def write(self, string, indent=True): """Writes text.""" self._writeraw(escape(string), indent=indent) @@ -63,7 +63,7 @@ class XMLWriter(object): def write_noindent(self, string): """Writes text without indentation.""" self._writeraw(escape(string), indent=False) - + def _writeraw(self, data, indent=True, strip=False): """Writes bytes, possibly indented.""" if indent and self.needindent: @@ -73,7 +73,7 @@ class XMLWriter(object): if (strip): s = s.strip() self.file.write(s) - + def newline(self): self.file.write(self.newlinestr) self.needindent = 1 @@ -81,7 +81,7 @@ class XMLWriter(object): if not idlecounter % 100 and self.idlefunc is not None: self.idlefunc() self.idlecounter = idlecounter + 1 - + def comment(self, data): data = escape(data) lines = data.split("\n") @@ -90,26 +90,26 @@ class XMLWriter(object): self.newline() self._writeraw(" " + line) self._writeraw(" -->") - + def simpletag(self, _TAG_, *args, **kwargs): attrdata = self.stringifyattrs(*args, **kwargs) data = "<%s%s/>" % (_TAG_, attrdata) self._writeraw(data) - + def begintag(self, _TAG_, *args, **kwargs): attrdata = self.stringifyattrs(*args, **kwargs) data = "<%s%s>" % (_TAG_, attrdata) self._writeraw(data) self.stack.append(_TAG_) self.indent() - + def endtag(self, _TAG_): assert self.stack and self.stack[-1] == _TAG_, "nonmatching endtag" del self.stack[-1] self.dedent() data = "" % _TAG_ self._writeraw(data) - + def dumphex(self, data): linelength = 16 hexlinelength = linelength * 2 @@ -123,14 +123,14 @@ class XMLWriter(object): white = " " self._writeraw(line) self.newline() - + def indent(self): self.indentlevel = self.indentlevel + 1 - + def dedent(self): assert self.indentlevel > 0 self.indentlevel = self.indentlevel - 1 - + def stringifyattrs(self, *args, **kwargs): if kwargs: assert not args @@ -144,7 +144,7 @@ class XMLWriter(object): for attr, value in attributes: data = data + ' %s="%s"' % (attr, escapeattr(str(value))) return data - + def escape(data): data = tostr(data, 'utf_8') diff --git a/Lib/fontTools/t1Lib.py b/Lib/fontTools/t1Lib.py index f7a9e34e8..5d7f8dc0c 100644 --- a/Lib/fontTools/t1Lib.py +++ b/Lib/fontTools/t1Lib.py @@ -3,13 +3,13 @@ Functions for reading and writing raw Type 1 data: read(path) - reads any Type 1 font file, returns the raw data and a type indicator: - 'LWFN', 'PFB' or 'OTHER', depending on the format of the file pointed - to by 'path'. + reads any Type 1 font file, returns the raw data and a type indicator: + 'LWFN', 'PFB' or 'OTHER', depending on the format of the file pointed + to by 'path'. Raises an error when the file does not contain valid Type 1 data. write(path, data, kind='OTHER', dohex=False) - writes raw Type 1 data to the file pointed to by 'path'. + writes raw Type 1 data to the file pointed to by 'path'. 'kind' can be one of 'LWFN', 'PFB' or 'OTHER'; it defaults to 'OTHER'. 'dohex' is a flag which determines whether the eexec encrypted part should be written as hexadecimal or binary, but only if kind @@ -37,49 +37,49 @@ except ImportError: else: haveMacSupport = 1 import MacOS - + class T1Error(Exception): pass class T1Font(object): - + """Type 1 font class. - + Uses a minimal interpeter that supports just about enough PS to parse Type 1 fonts. """ - + def __init__(self, path=None): if path is not None: self.data, type = read(path) else: pass # XXX - + def saveAs(self, path, type): write(path, self.getData(), type) - + def getData(self): # XXX Todo: if the data has been converted to Python object, # recreate the PS stream return self.data - + def getGlyphSet(self): """Return a generic GlyphSet, which is a dict-like object mapping glyph names to glyph objects. The returned glyph objects have a .draw() method that supports the Pen protocol, and will have an attribute named 'width', but only *after* the .draw() method has been called. - + In the case of Type 1, the GlyphSet is simply the CharStrings dict. """ return self["CharStrings"] - + def __getitem__(self, key): if not hasattr(self, "font"): self.parse() return self.font[key] - + def parse(self): from fontTools.misc import psLib from fontTools.misc import psCharStrings @@ -135,7 +135,7 @@ def write(path, data, kind='OTHER', dohex=False): pass -# -- internal -- +# -- internal -- LWFNCHUNKSIZE = 2000 HEXLINELENGTH = 80 @@ -203,7 +203,7 @@ def readOther(path): data = f.read() f.close() assertType1(data) - + chunks = findEncryptedChunks(data) data = [] for isEncrypted, chunk in chunks: diff --git a/Lib/fontTools/ttLib/__init__.py b/Lib/fontTools/ttLib/__init__.py index 93fadbc0d..ee3ff1fcb 100644 --- a/Lib/fontTools/ttLib/__init__.py +++ b/Lib/fontTools/ttLib/__init__.py @@ -1,6 +1,6 @@ """fontTools.ttLib -- a package for dealing with TrueType fonts. -This package offers translators to convert TrueType fonts to Python +This package offers translators to convert TrueType fonts to Python objects and vice versa, and additionally from Python to TTX (an XML-based text format) and vice versa. @@ -37,7 +37,7 @@ Dumping 'prep' table... >>> tt2.importXML("afont.ttx") >>> tt2['maxp'].numGlyphs 242 ->>> +>>> """ @@ -60,39 +60,39 @@ class TTLibError(Exception): pass class TTFont(object): - + """The main font object. It manages file input and output, and offers - a convenient way of accessing tables. + a convenient way of accessing tables. Tables will be only decompiled when necessary, ie. when they're actually accessed. This means that simple operations can be extremely fast. """ - + def __init__(self, file=None, res_name_or_index=None, sfntVersion="\000\001\000\000", flavor=None, checkChecksums=False, verbose=False, recalcBBoxes=True, allowVID=False, ignoreDecompileErrors=False, recalcTimestamp=True, fontNumber=-1, lazy=None, quiet=False): - + """The constructor can be called with a few different arguments. When reading a font from disk, 'file' should be either a pathname - pointing to a file, or a readable file object. - - It we're running on a Macintosh, 'res_name_or_index' maybe an sfnt - resource name or an sfnt resource index number or zero. The latter - case will cause TTLib to autodetect whether the file is a flat file + pointing to a file, or a readable file object. + + It we're running on a Macintosh, 'res_name_or_index' maybe an sfnt + resource name or an sfnt resource index number or zero. The latter + case will cause TTLib to autodetect whether the file is a flat file or a suitcase. (If it's a suitcase, only the first 'sfnt' resource will be read!) - + The 'checkChecksums' argument is used to specify how sfnt checksums are treated upon reading a file from disk: 0: don't check (default) 1: check, print warnings if a wrong checksum is found 2: check, raise an exception if a wrong checksum is found. - - The TTFont constructor can also be called without a 'file' - argument: this is the way to create a new empty font. + + The TTFont constructor can also be called without a 'file' + argument: this is the way to create a new empty font. In this case you can optionally supply the 'sfntVersion' argument, and a 'flavor' which can be None, or 'woff'. - + If the recalcBBoxes argument is false, a number of things will *not* be recalculated upon save/compile: 1) glyph bounding boxes @@ -100,8 +100,8 @@ class TTFont(object): 3) hhea min/max values (1) is needed for certain kinds of CJK fonts (ask Werner Lemberg ;-). Additionally, upon importing an TTX file, this option cause glyphs - to be compiled right away. This should reduce memory consumption - greatly, and therefore should have some impact on the time needed + to be compiled right away. This should reduce memory consumption + greatly, and therefore should have some impact on the time needed to parse/compile large fonts. If the recalcTimestamp argument is false, the modified timestamp in the @@ -126,7 +126,7 @@ class TTFont(object): access only. If it is set to False, many data structures are loaded immediately. The default is lazy=None which is somewhere in between. """ - + from fontTools.ttLib import sfnt self.verbose = verbose self.quiet = quiet @@ -169,19 +169,19 @@ class TTFont(object): self.sfntVersion = self.reader.sfntVersion self.flavor = self.reader.flavor self.flavorData = self.reader.flavorData - + def close(self): """If we still have a reader object, close it.""" if self.reader is not None: self.reader.close() - + def save(self, file, makeSuitcase=False, reorderTables=True): - """Save the font to disk. Similarly to the constructor, + """Save the font to disk. Similarly to the constructor, the 'file' argument can be either a pathname or a writable file object. - + On the Mac, if makeSuitcase is true, a suitcase (resource fork) - file will we made instead of a flat .ttf file. + file will we made instead of a flat .ttf file. """ from fontTools.ttLib import sfnt if not hasattr(file, "write"): @@ -197,7 +197,7 @@ class TTFont(object): else: # assume "file" is a writable file object closeStream = 0 - + tags = list(self.keys()) if "GlyphOrder" in tags: tags.remove("GlyphOrder") @@ -208,11 +208,11 @@ class TTFont(object): else: tmp = file writer = sfnt.SFNTWriter(tmp, numTables, self.sfntVersion, self.flavor, self.flavorData) - + done = [] for tag in tags: self._writeTable(tag, writer, done) - + writer.close() if reorderTables: @@ -223,7 +223,7 @@ class TTFont(object): if closeStream: file.close() - + def saveXML(self, fileOrPath, progress=None, quiet=False, tables=None, skipTables=None, splitTables=False, disassembleInstructions=True, bitmapGlyphDataFormat='raw'): @@ -236,7 +236,7 @@ class TTFont(object): """ from fontTools import version from fontTools.misc import xmlWriter - + self.disassembleInstructions = disassembleInstructions self.bitmapGlyphDataFormat = bitmapGlyphDataFormat if not tables: @@ -253,19 +253,19 @@ class TTFont(object): idlefunc = getattr(progress, "idle", None) else: idlefunc = None - + writer = xmlWriter.XMLWriter(fileOrPath, idlefunc=idlefunc) - writer.begintag("ttFont", sfntVersion=repr(self.sfntVersion)[1:-1], + writer.begintag("ttFont", sfntVersion=repr(self.sfntVersion)[1:-1], ttLibVersion=version) writer.newline() - + if not splitTables: writer.newline() else: # 'fileOrPath' must now be a path path, ext = os.path.splitext(fileOrPath) fileNameTemplate = path + ".%s" + ext - + for i in range(numTables): if progress: progress.set(i) @@ -292,7 +292,7 @@ class TTFont(object): writer.close() if self.verbose: debugmsg("Done dumping TTX") - + def _tableToXML(self, writer, tag, progress, quiet): if tag in self: table = self[tag] @@ -324,7 +324,7 @@ class TTFont(object): writer.endtag(xmlTag) writer.newline() writer.newline() - + def importXML(self, file, progress=None, quiet=False): """Import a TTX file (an XML-based text format), so as to recreate a font object. @@ -340,12 +340,12 @@ class TTFont(object): reader = xmlReader.XMLReader(file, self, progress, quiet) reader.read() - + def isLoaded(self, tag): - """Return true if the table identified by 'tag' has been + """Return true if the table identified by 'tag' has been decompiled and loaded into memory.""" return tag in self.tables - + def has_key(self, tag): if self.isLoaded(tag): return True @@ -355,9 +355,9 @@ class TTFont(object): return True else: return False - + __contains__ = has_key - + def keys(self): keys = list(self.tables.keys()) if self.reader: @@ -369,10 +369,10 @@ class TTFont(object): keys.remove("GlyphOrder") keys = sortedTagList(keys) return ["GlyphOrder"] + keys - + def __len__(self): return len(list(self.keys())) - + def __getitem__(self, tag): tag = Tag(tag) try: @@ -409,10 +409,10 @@ class TTFont(object): return table else: raise KeyError("'%s' table not found" % tag) - + def __setitem__(self, tag, table): self.tables[Tag(tag)] = table - + def __delitem__(self, tag): if tag not in self: raise KeyError("'%s' table not found" % tag) @@ -426,10 +426,10 @@ class TTFont(object): return self[tag] except KeyError: return default - + def setGlyphOrder(self, glyphOrder): self.glyphOrder = glyphOrder - + def getGlyphOrder(self): try: return self.glyphOrder @@ -444,7 +444,7 @@ class TTFont(object): if glyphOrder is None: # # No names found in the 'post' table. - # Try to create glyph names from the unicode cmap (if available) + # Try to create glyph names from the unicode cmap (if available) # in combination with the Adobe Glyph List (AGL). # self._getGlyphNamesFromCmap() @@ -453,7 +453,7 @@ class TTFont(object): else: self._getGlyphNamesFromCmap() return self.glyphOrder - + def _getGlyphNamesFromCmap(self): # # This is rather convoluted, but then again, it's an interesting problem: @@ -527,19 +527,19 @@ class TTFont(object): # restore partially loaded cmap, so it can continue loading # using the proper names. self.tables['cmap'] = cmapLoading - + def getGlyphNames(self): """Get a list of glyph names, sorted alphabetically.""" glyphNames = sorted(self.getGlyphOrder()[:]) return glyphNames - + def getGlyphNames2(self): - """Get a list of glyph names, sorted alphabetically, + """Get a list of glyph names, sorted alphabetically, but not case sensitive. """ from fontTools.misc import textTools return textTools.caselessSort(self.getGlyphOrder()) - + def getGlyphName(self, glyphID, requireReal=False): try: return self.getGlyphOrder()[glyphID] @@ -549,7 +549,7 @@ class TTFont(object): # the cmap table than there are glyphs. I don't think it's legal... return "glyph%.5d" % glyphID else: - # user intends virtual GID support + # user intends virtual GID support try: glyphName = self.VIDDict[glyphID] except KeyError: @@ -579,7 +579,7 @@ class TTFont(object): except (NameError, ValueError): raise KeyError(glyphName) else: - # user intends virtual GID support + # user intends virtual GID support try: glyphID = self.reverseVIDDict[glyphName] except KeyError: @@ -612,9 +612,9 @@ class TTFont(object): glyphOrder = self.getGlyphOrder() for glyphID in range(len(glyphOrder)): d[glyphOrder[glyphID]] = glyphID - + def _writeTable(self, tag, writer, done): - """Internal helper function for self.save(). Keeps track of + """Internal helper function for self.save(). Keeps track of inter-table dependencies. """ if tag in done: @@ -631,7 +631,7 @@ class TTFont(object): debugmsg("writing '%s' table to disk" % tag) writer[tag] = tabledata done.append(tag) - + def getTableData(self, tag): """Returns raw table data, whether compiled or directly read from disk. """ @@ -646,13 +646,13 @@ class TTFont(object): return self.reader[tag] else: raise KeyError(tag) - + def getGlyphSet(self, preferCFF=True): """Return a generic GlyphSet, which is a dict-like object mapping glyph names to glyph objects. The returned glyph objects have a .draw() method that supports the Pen protocol, and will have an attribute named 'width'. - + If the font is CFF-based, the outlines will be taken from the 'CFF ' table. Otherwise the outlines will be taken from the 'glyf' table. If the font contains both a 'CFF ' and a 'glyf' table, you can use @@ -672,22 +672,22 @@ class TTFont(object): class _TTGlyphSet(object): - + """Generic dict-like GlyphSet class that pulls metrics from hmtx and glyph shape from TrueType or CFF. """ - + def __init__(self, ttFont, glyphs, glyphType): self._glyphs = glyphs self._hmtx = ttFont['hmtx'] self._glyphType = glyphType - + def keys(self): return list(self._glyphs.keys()) - + def has_key(self, glyphName): return glyphName in self._glyphs - + __contains__ = has_key def __getitem__(self, glyphName): @@ -700,12 +700,12 @@ class _TTGlyphSet(object): return default class _TTGlyph(object): - + """Wrapper for a TrueType glyph that supports the Pen protocol, meaning that it has a .draw() method that takes a pen object as its only argument. Additionally there is a 'width' attribute. """ - + def __init__(self, glyphset, glyph, metrics): self._glyphset = glyphset self._glyph = glyph @@ -733,14 +733,14 @@ class _TTGlyphGlyf(_TTGlyph): class GlyphOrder(object): - + """A pseudo table. The glyph order isn't in the font as a separate table, but it's nice to present it as such in the TTX format. """ - + def __init__(self, tag=None): pass - + def toXML(self, writer, ttFont): glyphOrder = ttFont.getGlyphOrder() writer.comment("The 'id' attribute is only for humans; " @@ -750,7 +750,7 @@ class GlyphOrder(object): glyphName = glyphOrder[i] writer.simpletag("GlyphID", id=i, name=glyphName) writer.newline() - + def fromXML(self, name, attrs, content, ttFont): if not hasattr(self, "glyphOrder"): self.glyphOrder = [] @@ -760,7 +760,7 @@ class GlyphOrder(object): def getTableModule(tag): - """Fetch the packer/unpacker module for a table. + """Fetch the packer/unpacker module for a table. Return None when no module is found. """ from . import tables @@ -781,7 +781,7 @@ def getTableModule(tag): def getTableClass(tag): - """Fetch the packer/unpacker class for a table. + """Fetch the packer/unpacker class for a table. Return None when no class is found. """ module = getTableModule(tag) @@ -819,14 +819,14 @@ def _escapechar(c): def tagToIdentifier(tag): - """Convert a table tag to a valid (but UGLY) python identifier, - as well as a filename that's guaranteed to be unique even on a + """Convert a table tag to a valid (but UGLY) python identifier, + as well as a filename that's guaranteed to be unique even on a caseless file system. Each character is mapped to two characters. Lowercase letters get an underscore before the letter, uppercase letters get an underscore after the letter. Trailing spaces are trimmed. Illegal characters are escaped as two hex bytes. If the result starts with a number (as the result of a hex escape), an - extra underscore is prepended. Examples: + extra underscore is prepended. Examples: 'glyf' -> '_g_l_y_f' 'cvt ' -> '_c_v_t' 'OS/2' -> 'O_S_2f_2' diff --git a/Lib/fontTools/ttLib/macUtils.py b/Lib/fontTools/ttLib/macUtils.py index 1c33e9b83..b93cf0665 100644 --- a/Lib/fontTools/ttLib/macUtils.py +++ b/Lib/fontTools/ttLib/macUtils.py @@ -35,7 +35,7 @@ def getSFNTResIndices(path): def openTTFonts(path): - """Given a pathname, return a list of TTFont objects. In the case + """Given a pathname, return a list of TTFont objects. In the case of a flat TTF/OTF file, the list will contain just one font object; but in the case of a Mac font suitcase it will contain as many font objects as there are sfnt resources in the file. @@ -54,9 +54,9 @@ def openTTFonts(path): class SFNTResourceReader(object): - + """Simple (Mac-only) read-only file wrapper for 'sfnt' resources.""" - + def __init__(self, path, res_name_or_index): resref = MyOpenResFile(path) Res.UseResFile(resref) @@ -67,16 +67,16 @@ class SFNTResourceReader(object): self.file = StringIO(res.data) Res.CloseResFile(resref) self.name = path - + def __getattr__(self, attr): # cheap inheritance return getattr(self.file, attr) class SFNTResourceWriter(object): - + """Simple (Mac-only) file wrapper for 'sfnt' resources.""" - + def __init__(self, path, ttFont, res_id=None): self.file = StringIO() self.name = path @@ -97,7 +97,7 @@ class SFNTResourceWriter(object): if self.familyname[i] != self.psname[i]: break self.familyname = self.psname[:i] - + self.ttFont = ttFont self.res_id = res_id if os.path.exists(self.name): @@ -105,7 +105,7 @@ class SFNTResourceWriter(object): # XXX datafork support Res.FSpCreateResFile(self.name, 'DMOV', 'FFIL', 0) self.resref = Res.FSOpenResFile(self.name, 3) # exclusive read/write permission - + def close(self): if self.closed: return @@ -121,20 +121,20 @@ class SFNTResourceWriter(object): self.res_id = Res.Unique1ID('sfnt') res.AddResource('sfnt', self.res_id, self.fullname) res.ChangedResource() - + self.createFond() del self.ttFont Res.CloseResFile(self.resref) self.file.close() self.closed = 1 - + def createFond(self): fond_res = Res.Resource("") fond_res.AddResource('FOND', self.res_id, self.fullname) - + from fontTools import fondLib fond = fondLib.FontFamily(fond_res, "w") - + fond.ffFirstChar = 0 fond.ffLastChar = 255 fond.fondClass = 0 @@ -155,16 +155,16 @@ class SFNTResourceWriter(object): fond.changed = 1 fond.glyphTableOffset = 0 fond.styleMappingReserved = 0 - + # calc: scale = 4096 / self.ttFont['head'].unitsPerEm fond.ffAscent = scale * self.ttFont['hhea'].ascent fond.ffDescent = scale * self.ttFont['hhea'].descent fond.ffWidMax = scale * self.ttFont['hhea'].advanceWidthMax - + fond.ffFamilyName = self.familyname fond.psNames = {0: self.psname} - + fond.widthTables = {} fond.kernTables = {} cmap = self.ttFont['cmap'].getcmap(1, 0) @@ -189,11 +189,11 @@ class SFNTResourceWriter(object): fondwidths[names[name]] = scale * width fond.widthTables = {0: fondwidths} fond.save() - + def __del__(self): if not self.closed: self.close() - + def __getattr__(self, attr): # cheap inheritance return getattr(self.file, attr) diff --git a/Lib/fontTools/ttLib/sfnt.py b/Lib/fontTools/ttLib/sfnt.py index 0a8c1753b..7ba4b8f2d 100644 --- a/Lib/fontTools/ttLib/sfnt.py +++ b/Lib/fontTools/ttLib/sfnt.py @@ -4,10 +4,10 @@ Defines two public classes: SFNTReader SFNTWriter -(Normally you don't have to use these classes explicitly; they are +(Normally you don't have to use these classes explicitly; they are used automatically by ttLib.TTFont.) -The reading and writing of sfnt files is separated in two distinct +The reading and writing of sfnt files is separated in two distinct classes, since whenever to number of tables changes or whenever a table's length chages you need to rewrite the whole file anyway. """ @@ -20,7 +20,7 @@ import struct class SFNTReader(object): - + def __init__(self, file, checkChecksums=1, fontNumber=-1): self.file = file self.checkChecksums = checkChecksums @@ -66,10 +66,10 @@ class SFNTReader(object): return tag in self.tables __contains__ = has_key - + def keys(self): return self.tables.keys() - + def __getitem__(self, tag): """Fetch the raw table data.""" entry = self.tables[Tag(tag)] @@ -87,16 +87,16 @@ class SFNTReader(object): # Be friendly, and just print a warning. print("bad checksum for '%s' table" % tag) return data - + def __delitem__(self, tag): del self.tables[Tag(tag)] - + def close(self): self.file.close() class SFNTWriter(object): - + def __init__(self, file, numTables, sfntVersion="\000\001\000\000", flavor=None, flavorData=None): self.file = file @@ -113,7 +113,7 @@ class SFNTWriter(object): self.signature = "wOFF" # to calculate WOFF checksum adjustment, we also need the original SFNT offsets - self.origNextTableOffset = sfntDirectorySize + numTables * sfntDirectoryEntrySize + self.origNextTableOffset = sfntDirectorySize + numTables * sfntDirectoryEntrySize else: assert not self.flavor, "Unknown flavor '%s'" % self.flavor self.directoryFormat = sfntDirectoryFormat @@ -128,7 +128,7 @@ class SFNTWriter(object): # make sure we're actually where we want to be. (old cStringIO bug) self.file.write(b'\0' * (self.nextTableOffset - self.file.tell())) self.tables = {} - + def __setitem__(self, tag, data): """Write raw table data to disk.""" if tag in self.tables: @@ -157,9 +157,9 @@ class SFNTWriter(object): # in the font. self.file.write(b'\0' * (self.nextTableOffset - self.file.tell())) assert self.nextTableOffset == self.file.tell() - + self.tables[tag] = entry - + def close(self): """All tables must have been written to disk. Now write the directory. @@ -214,9 +214,9 @@ class SFNTWriter(object): else: assert not self.flavor, "Unknown flavor '%s'" % self.flavor pass - + directory = sstruct.pack(self.directoryFormat, self) - + self.file.seek(self.directorySize) seenHead = 0 for tag, entry in tables: @@ -332,19 +332,19 @@ woffDirectoryEntrySize = sstruct.calcsize(woffDirectoryEntryFormat) class DirectoryEntry(object): - + def __init__(self): self.uncompressed = False # if True, always embed entry raw def fromFile(self, file): sstruct.unpack(self.format, file.read(self.formatSize), self) - + def fromString(self, str): sstruct.unpack(self.format, str, self) - + def toString(self): return sstruct.pack(self.format, self) - + def __repr__(self): if hasattr(self, "tag"): return "<%s '%s' at %x>" % (self.__class__.__name__, self.tag, id(self)) @@ -439,9 +439,9 @@ def calcChecksum(data): Optionally takes a 'start' argument, which allows you to calculate a checksum in chunks by feeding it a previous result. - + If the data length is not a multiple of four, it assumes - it is to be padded with null byte. + it is to be padded with null byte. >>> print(calcChecksum(b"abcd")) 1633837924 diff --git a/Lib/fontTools/ttLib/standardGlyphOrder.py b/Lib/fontTools/ttLib/standardGlyphOrder.py index 4b2d0cd96..510773a6c 100644 --- a/Lib/fontTools/ttLib/standardGlyphOrder.py +++ b/Lib/fontTools/ttLib/standardGlyphOrder.py @@ -13,262 +13,262 @@ from fontTools.misc.py23 import * # standardGlyphOrder = [ - ".notdef", # 0 - ".null", # 1 - "nonmarkingreturn", # 2 - "space", # 3 - "exclam", # 4 - "quotedbl", # 5 - "numbersign", # 6 - "dollar", # 7 - "percent", # 8 - "ampersand", # 9 - "quotesingle", # 10 - "parenleft", # 11 - "parenright", # 12 - "asterisk", # 13 - "plus", # 14 - "comma", # 15 - "hyphen", # 16 - "period", # 17 - "slash", # 18 - "zero", # 19 - "one", # 20 - "two", # 21 - "three", # 22 - "four", # 23 - "five", # 24 - "six", # 25 - "seven", # 26 - "eight", # 27 - "nine", # 28 - "colon", # 29 - "semicolon", # 30 - "less", # 31 - "equal", # 32 - "greater", # 33 - "question", # 34 - "at", # 35 - "A", # 36 - "B", # 37 - "C", # 38 - "D", # 39 - "E", # 40 - "F", # 41 - "G", # 42 - "H", # 43 - "I", # 44 - "J", # 45 - "K", # 46 - "L", # 47 - "M", # 48 - "N", # 49 - "O", # 50 - "P", # 51 - "Q", # 52 - "R", # 53 - "S", # 54 - "T", # 55 - "U", # 56 - "V", # 57 - "W", # 58 - "X", # 59 - "Y", # 60 - "Z", # 61 - "bracketleft", # 62 - "backslash", # 63 - "bracketright", # 64 - "asciicircum", # 65 - "underscore", # 66 - "grave", # 67 - "a", # 68 - "b", # 69 - "c", # 70 - "d", # 71 - "e", # 72 - "f", # 73 - "g", # 74 - "h", # 75 - "i", # 76 - "j", # 77 - "k", # 78 - "l", # 79 - "m", # 80 - "n", # 81 - "o", # 82 - "p", # 83 - "q", # 84 - "r", # 85 - "s", # 86 - "t", # 87 - "u", # 88 - "v", # 89 - "w", # 90 - "x", # 91 - "y", # 92 - "z", # 93 - "braceleft", # 94 - "bar", # 95 - "braceright", # 96 - "asciitilde", # 97 - "Adieresis", # 98 - "Aring", # 99 - "Ccedilla", # 100 - "Eacute", # 101 - "Ntilde", # 102 - "Odieresis", # 103 - "Udieresis", # 104 - "aacute", # 105 - "agrave", # 106 - "acircumflex", # 107 - "adieresis", # 108 - "atilde", # 109 - "aring", # 110 - "ccedilla", # 111 - "eacute", # 112 - "egrave", # 113 - "ecircumflex", # 114 - "edieresis", # 115 - "iacute", # 116 - "igrave", # 117 - "icircumflex", # 118 - "idieresis", # 119 - "ntilde", # 120 - "oacute", # 121 - "ograve", # 122 - "ocircumflex", # 123 - "odieresis", # 124 - "otilde", # 125 - "uacute", # 126 - "ugrave", # 127 - "ucircumflex", # 128 - "udieresis", # 129 - "dagger", # 130 - "degree", # 131 - "cent", # 132 - "sterling", # 133 - "section", # 134 - "bullet", # 135 - "paragraph", # 136 - "germandbls", # 137 - "registered", # 138 - "copyright", # 139 - "trademark", # 140 - "acute", # 141 - "dieresis", # 142 - "notequal", # 143 - "AE", # 144 - "Oslash", # 145 - "infinity", # 146 - "plusminus", # 147 - "lessequal", # 148 - "greaterequal", # 149 - "yen", # 150 - "mu", # 151 - "partialdiff", # 152 - "summation", # 153 - "product", # 154 - "pi", # 155 - "integral", # 156 - "ordfeminine", # 157 - "ordmasculine", # 158 - "Omega", # 159 - "ae", # 160 - "oslash", # 161 - "questiondown", # 162 - "exclamdown", # 163 - "logicalnot", # 164 - "radical", # 165 - "florin", # 166 - "approxequal", # 167 - "Delta", # 168 - "guillemotleft", # 169 - "guillemotright", # 170 - "ellipsis", # 171 - "nonbreakingspace", # 172 - "Agrave", # 173 - "Atilde", # 174 - "Otilde", # 175 - "OE", # 176 - "oe", # 177 - "endash", # 178 - "emdash", # 179 - "quotedblleft", # 180 - "quotedblright", # 181 - "quoteleft", # 182 - "quoteright", # 183 - "divide", # 184 - "lozenge", # 185 - "ydieresis", # 186 - "Ydieresis", # 187 + ".notdef", # 0 + ".null", # 1 + "nonmarkingreturn", # 2 + "space", # 3 + "exclam", # 4 + "quotedbl", # 5 + "numbersign", # 6 + "dollar", # 7 + "percent", # 8 + "ampersand", # 9 + "quotesingle", # 10 + "parenleft", # 11 + "parenright", # 12 + "asterisk", # 13 + "plus", # 14 + "comma", # 15 + "hyphen", # 16 + "period", # 17 + "slash", # 18 + "zero", # 19 + "one", # 20 + "two", # 21 + "three", # 22 + "four", # 23 + "five", # 24 + "six", # 25 + "seven", # 26 + "eight", # 27 + "nine", # 28 + "colon", # 29 + "semicolon", # 30 + "less", # 31 + "equal", # 32 + "greater", # 33 + "question", # 34 + "at", # 35 + "A", # 36 + "B", # 37 + "C", # 38 + "D", # 39 + "E", # 40 + "F", # 41 + "G", # 42 + "H", # 43 + "I", # 44 + "J", # 45 + "K", # 46 + "L", # 47 + "M", # 48 + "N", # 49 + "O", # 50 + "P", # 51 + "Q", # 52 + "R", # 53 + "S", # 54 + "T", # 55 + "U", # 56 + "V", # 57 + "W", # 58 + "X", # 59 + "Y", # 60 + "Z", # 61 + "bracketleft", # 62 + "backslash", # 63 + "bracketright", # 64 + "asciicircum", # 65 + "underscore", # 66 + "grave", # 67 + "a", # 68 + "b", # 69 + "c", # 70 + "d", # 71 + "e", # 72 + "f", # 73 + "g", # 74 + "h", # 75 + "i", # 76 + "j", # 77 + "k", # 78 + "l", # 79 + "m", # 80 + "n", # 81 + "o", # 82 + "p", # 83 + "q", # 84 + "r", # 85 + "s", # 86 + "t", # 87 + "u", # 88 + "v", # 89 + "w", # 90 + "x", # 91 + "y", # 92 + "z", # 93 + "braceleft", # 94 + "bar", # 95 + "braceright", # 96 + "asciitilde", # 97 + "Adieresis", # 98 + "Aring", # 99 + "Ccedilla", # 100 + "Eacute", # 101 + "Ntilde", # 102 + "Odieresis", # 103 + "Udieresis", # 104 + "aacute", # 105 + "agrave", # 106 + "acircumflex", # 107 + "adieresis", # 108 + "atilde", # 109 + "aring", # 110 + "ccedilla", # 111 + "eacute", # 112 + "egrave", # 113 + "ecircumflex", # 114 + "edieresis", # 115 + "iacute", # 116 + "igrave", # 117 + "icircumflex", # 118 + "idieresis", # 119 + "ntilde", # 120 + "oacute", # 121 + "ograve", # 122 + "ocircumflex", # 123 + "odieresis", # 124 + "otilde", # 125 + "uacute", # 126 + "ugrave", # 127 + "ucircumflex", # 128 + "udieresis", # 129 + "dagger", # 130 + "degree", # 131 + "cent", # 132 + "sterling", # 133 + "section", # 134 + "bullet", # 135 + "paragraph", # 136 + "germandbls", # 137 + "registered", # 138 + "copyright", # 139 + "trademark", # 140 + "acute", # 141 + "dieresis", # 142 + "notequal", # 143 + "AE", # 144 + "Oslash", # 145 + "infinity", # 146 + "plusminus", # 147 + "lessequal", # 148 + "greaterequal", # 149 + "yen", # 150 + "mu", # 151 + "partialdiff", # 152 + "summation", # 153 + "product", # 154 + "pi", # 155 + "integral", # 156 + "ordfeminine", # 157 + "ordmasculine", # 158 + "Omega", # 159 + "ae", # 160 + "oslash", # 161 + "questiondown", # 162 + "exclamdown", # 163 + "logicalnot", # 164 + "radical", # 165 + "florin", # 166 + "approxequal", # 167 + "Delta", # 168 + "guillemotleft", # 169 + "guillemotright", # 170 + "ellipsis", # 171 + "nonbreakingspace", # 172 + "Agrave", # 173 + "Atilde", # 174 + "Otilde", # 175 + "OE", # 176 + "oe", # 177 + "endash", # 178 + "emdash", # 179 + "quotedblleft", # 180 + "quotedblright", # 181 + "quoteleft", # 182 + "quoteright", # 183 + "divide", # 184 + "lozenge", # 185 + "ydieresis", # 186 + "Ydieresis", # 187 "fraction", # 188 "currency", # 189 - "guilsinglleft", # 190 - "guilsinglright", # 191 - "fi", # 192 - "fl", # 193 - "daggerdbl", # 194 - "periodcentered", # 195 - "quotesinglbase", # 196 - "quotedblbase", # 197 - "perthousand", # 198 - "Acircumflex", # 199 - "Ecircumflex", # 200 - "Aacute", # 201 - "Edieresis", # 202 - "Egrave", # 203 - "Iacute", # 204 - "Icircumflex", # 205 - "Idieresis", # 206 - "Igrave", # 207 - "Oacute", # 208 - "Ocircumflex", # 209 - "apple", # 210 - "Ograve", # 211 - "Uacute", # 212 - "Ucircumflex", # 213 - "Ugrave", # 214 - "dotlessi", # 215 - "circumflex", # 216 - "tilde", # 217 - "macron", # 218 - "breve", # 219 - "dotaccent", # 220 - "ring", # 221 - "cedilla", # 222 - "hungarumlaut", # 223 - "ogonek", # 224 - "caron", # 225 - "Lslash", # 226 - "lslash", # 227 - "Scaron", # 228 - "scaron", # 229 - "Zcaron", # 230 - "zcaron", # 231 - "brokenbar", # 232 - "Eth", # 233 - "eth", # 234 - "Yacute", # 235 - "yacute", # 236 - "Thorn", # 237 - "thorn", # 238 - "minus", # 239 - "multiply", # 240 - "onesuperior", # 241 - "twosuperior", # 242 - "threesuperior", # 243 - "onehalf", # 244 - "onequarter", # 245 - "threequarters", # 246 - "franc", # 247 - "Gbreve", # 248 - "gbreve", # 249 - "Idotaccent", # 250 - "Scedilla", # 251 - "scedilla", # 252 - "Cacute", # 253 - "cacute", # 254 - "Ccaron", # 255 - "ccaron", # 256 - "dcroat" # 257 + "guilsinglleft", # 190 + "guilsinglright", # 191 + "fi", # 192 + "fl", # 193 + "daggerdbl", # 194 + "periodcentered", # 195 + "quotesinglbase", # 196 + "quotedblbase", # 197 + "perthousand", # 198 + "Acircumflex", # 199 + "Ecircumflex", # 200 + "Aacute", # 201 + "Edieresis", # 202 + "Egrave", # 203 + "Iacute", # 204 + "Icircumflex", # 205 + "Idieresis", # 206 + "Igrave", # 207 + "Oacute", # 208 + "Ocircumflex", # 209 + "apple", # 210 + "Ograve", # 211 + "Uacute", # 212 + "Ucircumflex", # 213 + "Ugrave", # 214 + "dotlessi", # 215 + "circumflex", # 216 + "tilde", # 217 + "macron", # 218 + "breve", # 219 + "dotaccent", # 220 + "ring", # 221 + "cedilla", # 222 + "hungarumlaut", # 223 + "ogonek", # 224 + "caron", # 225 + "Lslash", # 226 + "lslash", # 227 + "Scaron", # 228 + "scaron", # 229 + "Zcaron", # 230 + "zcaron", # 231 + "brokenbar", # 232 + "Eth", # 233 + "eth", # 234 + "Yacute", # 235 + "yacute", # 236 + "Thorn", # 237 + "thorn", # 238 + "minus", # 239 + "multiply", # 240 + "onesuperior", # 241 + "twosuperior", # 242 + "threesuperior", # 243 + "onehalf", # 244 + "onequarter", # 245 + "threequarters", # 246 + "franc", # 247 + "Gbreve", # 248 + "gbreve", # 249 + "Idotaccent", # 250 + "Scedilla", # 251 + "scedilla", # 252 + "Cacute", # 253 + "cacute", # 254 + "Ccaron", # 255 + "ccaron", # 256 + "dcroat" # 257 ] diff --git a/Lib/fontTools/ttLib/tables/BitmapGlyphMetrics.py b/Lib/fontTools/ttLib/tables/BitmapGlyphMetrics.py index dfe86f23a..a6b6d661a 100644 --- a/Lib/fontTools/ttLib/tables/BitmapGlyphMetrics.py +++ b/Lib/fontTools/ttLib/tables/BitmapGlyphMetrics.py @@ -53,6 +53,6 @@ class BitmapGlyphMetrics(object): class BigGlyphMetrics(BitmapGlyphMetrics): binaryFormat = bigGlyphMetricsFormat - + class SmallGlyphMetrics(BitmapGlyphMetrics): binaryFormat = smallGlyphMetricsFormat diff --git a/Lib/fontTools/ttLib/tables/C_F_F_.py b/Lib/fontTools/ttLib/tables/C_F_F_.py index ed2183782..e1340b10e 100644 --- a/Lib/fontTools/ttLib/tables/C_F_F_.py +++ b/Lib/fontTools/ttLib/tables/C_F_F_.py @@ -5,42 +5,42 @@ from . import DefaultTable class table_C_F_F_(DefaultTable.DefaultTable): - + def __init__(self, tag): DefaultTable.DefaultTable.__init__(self, tag) self.cff = cffLib.CFFFontSet() self._gaveGlyphOrder = False - + def decompile(self, data, otFont): self.cff.decompile(StringIO(data), otFont) assert len(self.cff) == 1, "can't deal with multi-font CFF tables." - + def compile(self, otFont): f = StringIO() self.cff.compile(f, otFont) return f.getvalue() - + def haveGlyphNames(self): if hasattr(self.cff[self.cff.fontNames[0]], "ROS"): return False # CID-keyed font else: return True - + def getGlyphOrder(self): if self._gaveGlyphOrder: from fontTools import ttLib raise ttLib.TTLibError("illegal use of getGlyphOrder()") self._gaveGlyphOrder = True return self.cff[self.cff.fontNames[0]].getGlyphOrder() - + def setGlyphOrder(self, glyphOrder): pass # XXX #self.cff[self.cff.fontNames[0]].setGlyphOrder(glyphOrder) - + def toXML(self, writer, otFont, progress=None): self.cff.toXML(writer, progress) - + def fromXML(self, name, attrs, content, otFont): if not hasattr(self, "cff"): self.cff = cffLib.CFFFontSet() diff --git a/Lib/fontTools/ttLib/tables/C_O_L_R_.py b/Lib/fontTools/ttLib/tables/C_O_L_R_.py index 2bda3d011..743fa915d 100644 --- a/Lib/fontTools/ttLib/tables/C_O_L_R_.py +++ b/Lib/fontTools/ttLib/tables/C_O_L_R_.py @@ -123,7 +123,7 @@ class table_C_O_L_R_(DefaultTable.DefaultTable): if glyphSelector not in self.ColorLayers: return None - + return self.ColorLayers[glyphSelector] def __setitem__(self, glyphSelector, value): diff --git a/Lib/fontTools/ttLib/tables/D_S_I_G_.py b/Lib/fontTools/ttLib/tables/D_S_I_G_.py index 7794bdad8..af802b956 100644 --- a/Lib/fontTools/ttLib/tables/D_S_I_G_.py +++ b/Lib/fontTools/ttLib/tables/D_S_I_G_.py @@ -40,7 +40,7 @@ DSIG_SignatureBlockFormat = """ # class table_D_S_I_G_(DefaultTable.DefaultTable): - + def decompile(self, data, ttFont): dummy, newData = sstruct.unpack2(DSIG_HeaderFormat, data, self) assert self.ulVersion == 1, "DSIG ulVersion must be 1" @@ -55,7 +55,7 @@ class table_D_S_I_G_(DefaultTable.DefaultTable): assert sigrec.usReserved1 == 0, "DSIG signature record #%d usReserverd1 must be 0" % n assert sigrec.usReserved2 == 0, "DSIG signature record #%d usReserverd2 must be 0" % n sigrec.pkcs7 = newData[:sigrec.cbSignature] - + def compile(self, ttFont): packed = sstruct.pack(DSIG_HeaderFormat, self) headers = [packed] @@ -76,7 +76,7 @@ class table_D_S_I_G_(DefaultTable.DefaultTable): # Pad to even bytes data.append(b'\0') return bytesjoin(headers+data) - + def toXML(self, xmlWriter, ttFont): xmlWriter.comment("note that the Digital Signature will be invalid after recompilation!") xmlWriter.newline() @@ -85,7 +85,7 @@ class table_D_S_I_G_(DefaultTable.DefaultTable): xmlWriter.newline() sigrec.toXML(xmlWriter, ttFont) xmlWriter.newline() - + def fromXML(self, name, attrs, content, ttFont): if name == "tableHeader": self.signatureRecords = [] @@ -115,7 +115,7 @@ def b64encode(b): class SignatureRecord(object): def __repr__(self): return "<%s: %s>" % (self.__class__.__name__, self.__dict__) - + def toXML(self, writer, ttFont): writer.begintag(self.__class__.__name__, format=self.ulFormat) writer.newline() @@ -123,7 +123,7 @@ class SignatureRecord(object): writer.write_noindent(b64encode(self.pkcs7)) writer.write_noindent("-----END PKCS7-----\n") writer.endtag(self.__class__.__name__) - + def fromXML(self, name, attrs, content, ttFont): self.ulFormat = safeEval(attrs["format"]) self.usReserved1 = safeEval(attrs.get("reserved1", "0")) diff --git a/Lib/fontTools/ttLib/tables/DefaultTable.py b/Lib/fontTools/ttLib/tables/DefaultTable.py index 3a6886c4d..544520783 100644 --- a/Lib/fontTools/ttLib/tables/DefaultTable.py +++ b/Lib/fontTools/ttLib/tables/DefaultTable.py @@ -3,20 +3,20 @@ from fontTools.misc.py23 import * from fontTools.ttLib import getClassTag class DefaultTable(object): - + dependencies = [] - + def __init__(self, tag=None): if tag is None: tag = getClassTag(self.__class__) self.tableTag = Tag(tag) - + def decompile(self, data, ttFont): self.data = data - + def compile(self, ttFont): return self.data - + def toXML(self, writer, ttFont, progress=None): if hasattr(self, "ERROR"): writer.comment("An error occurred during the decompilation of this table") @@ -28,17 +28,17 @@ class DefaultTable(object): writer.dumphex(self.compile(ttFont)) writer.endtag("hexdata") writer.newline() - + def fromXML(self, name, attrs, content, ttFont): from fontTools.misc.textTools import readHex from fontTools import ttLib if name != "hexdata": raise ttLib.TTLibError("can't handle '%s' element" % name) self.decompile(readHex(content), ttFont) - + def __repr__(self): return "<'%s' table at %x>" % (self.tableTag, id(self)) - + def __ne__(self, other): return not self.__eq__(other) def __eq__(self, other): diff --git a/Lib/fontTools/ttLib/tables/G_M_A_P_.py b/Lib/fontTools/ttLib/tables/G_M_A_P_.py index ee9f02149..afa8c4dc0 100644 --- a/Lib/fontTools/ttLib/tables/G_M_A_P_.py +++ b/Lib/fontTools/ttLib/tables/G_M_A_P_.py @@ -13,7 +13,7 @@ GMAPFormat = """ recordsOffset: H fontNameLength: H """ -# psFontName is a byte string which follows the record above. This is zero padded +# psFontName is a byte string which follows the record above. This is zero padded # to the beginning of the records array. The recordsOffsst is 32 bit aligned. GMAPRecordFormat1 = """ @@ -71,9 +71,9 @@ class GMAPRecord(object): class table_G_M_A_P_(DefaultTable.DefaultTable): - + dependencies = [] - + def decompile(self, data, ttFont): dummy, newData = sstruct.unpack2(GMAPFormat, data, self) self.psFontName = tostr(newData[:self.fontNameLength]) @@ -108,7 +108,7 @@ class table_G_M_A_P_(DefaultTable.DefaultTable): writer.newline() for gmapRecord in self.gmapRecords: gmapRecord.toXML(writer, ttFont) - + def fromXML(self, name, attrs, content, ttFont): if name == "GMAPRecord": if not hasattr(self, "gmapRecords"): @@ -124,5 +124,5 @@ class table_G_M_A_P_(DefaultTable.DefaultTable): value = attrs["value"] if name == "PSFontName": self.psFontName = value - else: + else: setattr(self, name, safeEval(value)) diff --git a/Lib/fontTools/ttLib/tables/G_P_K_G_.py b/Lib/fontTools/ttLib/tables/G_P_K_G_.py index 5ba7c4f49..ad90f4a88 100644 --- a/Lib/fontTools/ttLib/tables/G_P_K_G_.py +++ b/Lib/fontTools/ttLib/tables/G_P_K_G_.py @@ -13,12 +13,12 @@ GPKGFormat = """ numGMAPs: H numGlyplets: H """ -# psFontName is a byte string which follows the record above. This is zero padded +# psFontName is a byte string which follows the record above. This is zero padded # to the beginning of the records array. The recordsOffsst is 32 bit aligned. class table_G_P_K_G_(DefaultTable.DefaultTable): - + def decompile(self, data, ttFont): dummy, newData = sstruct.unpack2(GPKGFormat, data, self) @@ -74,7 +74,7 @@ class table_G_P_K_G_(DefaultTable.DefaultTable): dataList += self.glyphlets data = bytesjoin(dataList) return data - + def toXML(self, writer, ttFont): writer.comment("Most of this table will be recalculated by the compiler") writer.newline() @@ -125,5 +125,5 @@ class table_G_P_K_G_(DefaultTable.DefaultTable): itemName, itemAttrs, itemContent = element if itemName == "hexdata": self.glyphlets.append(readHex(itemContent)) - else: + else: setattr(self, name, safeEval(value)) diff --git a/Lib/fontTools/ttLib/tables/L_T_S_H_.py b/Lib/fontTools/ttLib/tables/L_T_S_H_.py index 037e7ff61..dd0f1954e 100644 --- a/Lib/fontTools/ttLib/tables/L_T_S_H_.py +++ b/Lib/fontTools/ttLib/tables/L_T_S_H_.py @@ -10,7 +10,7 @@ import array # XXX back to normal eventually. class table_L_T_S_H_(DefaultTable.DefaultTable): - + def decompile(self, data, ttFont): version, numGlyphs = struct.unpack(">HH", data[:4]) data = data[4:] @@ -23,7 +23,7 @@ class table_L_T_S_H_(DefaultTable.DefaultTable): self.yPels = {} for i in range(numGlyphs): self.yPels[ttFont.getGlyphName(i)] = yPels[i] - + def compile(self, ttFont): version = 0 names = list(self.yPels.keys()) @@ -35,13 +35,13 @@ class table_L_T_S_H_(DefaultTable.DefaultTable): yPels[ttFont.getGlyphID(name)] = self.yPels[name] yPels = array.array("B", yPels) return struct.pack(">HH", version, numGlyphs) + yPels.tostring() - + def toXML(self, writer, ttFont): names = sorted(self.yPels.keys()) for name in names: writer.simpletag("yPel", name=name, value=self.yPels[name]) writer.newline() - + def fromXML(self, name, attrs, content, ttFont): if not hasattr(self, "yPels"): self.yPels = {} diff --git a/Lib/fontTools/ttLib/tables/M_E_T_A_.py b/Lib/fontTools/ttLib/tables/M_E_T_A_.py index b866c1506..fb6c8d7da 100644 --- a/Lib/fontTools/ttLib/tables/M_E_T_A_.py +++ b/Lib/fontTools/ttLib/tables/M_E_T_A_.py @@ -26,19 +26,19 @@ METAGlyphRecordFormat = """ nMetaEntry: H """ # This record is followd by a variable data length field: -# USHORT or ULONG hdrOffset +# USHORT or ULONG hdrOffset # Offset from start of META table to the beginning # of this glyphs array of ns Metadata string entries. -# Size determined by metaFlags field +# Size determined by metaFlags field # METAGlyphRecordFormat entries must be sorted by glyph ID - + METAStringRecordFormat = """ > # big endian labelID: H stringLen: H """ # This record is followd by a variable data length field: -# USHORT or ULONG stringOffset +# USHORT or ULONG stringOffset # METAStringRecordFormat entries must be sorted in order of labelID # There may be more than one entry with the same labelID # There may be more than one strign with the same content. @@ -69,9 +69,9 @@ def getLabelString(labelID): class table_M_E_T_A_(DefaultTable.DefaultTable): - + dependencies = [] - + def decompile(self, data, ttFont): dummy, newData = sstruct.unpack2(METAHeaderFormat, data, self) self.glyphRecords = [] @@ -97,8 +97,8 @@ class table_M_E_T_A_(DefaultTable.DefaultTable): newData = newData[4:] stringRec.string = data[stringRec.offset:stringRec.offset + stringRec.stringLen] glyphRecord.stringRecs.append(stringRec) - self.glyphRecords.append(glyphRecord) - + self.glyphRecords.append(glyphRecord) + def compile(self, ttFont): offsetOK = 0 self.nMetaRecs = len(self.glyphRecords) @@ -117,12 +117,12 @@ class table_M_E_T_A_(DefaultTable.DefaultTable): offsetOK = -1 break metaData = metaData + glyphRec.compile(self) - stringRecsOffset = stringRecsOffset + (glyphRec.nMetaEntry * stringRecSize) + stringRecsOffset = stringRecsOffset + (glyphRec.nMetaEntry * stringRecSize) # this will be the String Record offset for the next GlyphRecord. if offsetOK == -1: offsetOK = 0 continue - + # metaData now contains the header and all of the GlyphRecords. Its length should bw # the offset to the first StringRecord. stringOffset = stringRecsOffset @@ -139,7 +139,7 @@ class table_M_E_T_A_(DefaultTable.DefaultTable): if offsetOK == -1: offsetOK = 0 continue - + if ((self.metaFlags & 1) == 1) and (stringOffset < 65536): self.metaFlags = self.metaFlags - 1 continue @@ -152,9 +152,9 @@ class table_M_E_T_A_(DefaultTable.DefaultTable): for stringRec in glyphRec.stringRecs: assert (stringRec.offset == len(metaData)), "String offset did not compile correctly! for string:" + str(stringRec.string) metaData = metaData + stringRec.string - + return metaData - + def toXML(self, writer, ttFont): writer.comment("Lengths and number of entries in this table will be recalculated by the compiler") writer.newline() @@ -165,7 +165,7 @@ class table_M_E_T_A_(DefaultTable.DefaultTable): writer.newline() for glyphRec in self.glyphRecords: glyphRec.toXML(writer, ttFont) - + def fromXML(self, name, attrs, content, ttFont): if name == "GlyphRecord": if not hasattr(self, "glyphRecords"): @@ -179,7 +179,7 @@ class table_M_E_T_A_(DefaultTable.DefaultTable): glyphRec.fromXML(name, attrs, content, ttFont) glyphRec.offset = -1 glyphRec.nMetaEntry = len(glyphRec.stringRecs) - else: + else: setattr(self, name, safeEval(attrs["value"])) @@ -189,7 +189,7 @@ class GlyphRecord(object): self.nMetaEntry = -1 self.offset = -1 self.stringRecs = [] - + def toXML(self, writer, ttFont): writer.begintag("GlyphRecord") writer.newline() @@ -211,7 +211,7 @@ class GlyphRecord(object): continue stringRec.fromXML(name, attrs, content, ttFont) stringRec.stringLen = len(stringRec.string) - else: + else: setattr(self, name, safeEval(attrs["value"])) def compile(self, parentTable): @@ -222,7 +222,7 @@ class GlyphRecord(object): datum = struct.pack(">L", self.offset) data = data + datum return data - + def __repr__(self): return "GlyphRecord[ glyphID: " + str(self.glyphID) + ", nMetaEntry: " + str(self.nMetaEntry) + ", offset: " + str(self.offset) + " ]" @@ -244,12 +244,12 @@ def mapXMLToUTF8(string): while string[i] != ";": i = i+1 valStr = string[j:i] - + uString = uString + unichr(eval('0x' + valStr)) else: uString = uString + unichr(byteord(string[i])) i = i +1 - + return uString.encode('utf_8') @@ -298,7 +298,7 @@ class StringRecord(object): datum = struct.pack(">L", self.offset) data = data + datum return data - + def __repr__(self): return "StringRecord [ labelID: " + str(self.labelID) + " aka " + getLabelString(self.labelID) \ + ", offset: " + str(self.offset) + ", length: " + str(self.stringLen) + ", string: " +self.string + " ]" diff --git a/Lib/fontTools/ttLib/tables/O_S_2f_2.py b/Lib/fontTools/ttLib/tables/O_S_2f_2.py index 3766451e0..523e77f31 100644 --- a/Lib/fontTools/ttLib/tables/O_S_2f_2.py +++ b/Lib/fontTools/ttLib/tables/O_S_2f_2.py @@ -22,13 +22,13 @@ panoseFormat = """ """ class Panose(object): - + def toXML(self, writer, ttFont): formatstring, names, fixes = sstruct.getformat(panoseFormat) for name in names: writer.simpletag(name, value=getattr(self, name)) writer.newline() - + def fromXML(self, name, attrs, content, ttFont): setattr(self, name, safeEval(attrs["value"])) @@ -98,9 +98,9 @@ OS2_format_5_addition = bigendian + OS2_format_5_addition class table_O_S_2f_2(DefaultTable.DefaultTable): - + """the OS/2 table""" - + def decompile(self, data, ttFont): dummy, data = sstruct.unpack2(OS2_format_0, data, self) @@ -119,7 +119,7 @@ class table_O_S_2f_2(DefaultTable.DefaultTable): warnings.warn("too much 'OS/2' table data") self.panose = sstruct.unpack(panoseFormat, self.panose, Panose()) - + def compile(self, ttFont): panose = self.panose self.panose = sstruct.pack(panoseFormat, self.panose) @@ -139,7 +139,7 @@ class table_O_S_2f_2(DefaultTable.DefaultTable): raise ttLib.TTLibError("unknown format for OS/2 table: version %s" % self.version) self.panose = panose return data - + def toXML(self, writer, ttFont): if self.version == 1: format = OS2_format_1 @@ -157,7 +157,7 @@ class table_O_S_2f_2(DefaultTable.DefaultTable): writer.newline() value.toXML(writer, ttFont) writer.endtag("panose") - elif name in ("ulUnicodeRange1", "ulUnicodeRange2", + elif name in ("ulUnicodeRange1", "ulUnicodeRange2", "ulUnicodeRange3", "ulUnicodeRange4", "ulCodePageRange1", "ulCodePageRange2"): writer.simpletag(name, value=num2binary(value)) @@ -168,7 +168,7 @@ class table_O_S_2f_2(DefaultTable.DefaultTable): else: writer.simpletag(name, value=value) writer.newline() - + def fromXML(self, name, attrs, content, ttFont): if name == "panose": self.panose = panose = Panose() @@ -176,7 +176,7 @@ class table_O_S_2f_2(DefaultTable.DefaultTable): if isinstance(element, tuple): name, attrs, content = element panose.fromXML(name, attrs, content, ttFont) - elif name in ("ulUnicodeRange1", "ulUnicodeRange2", + elif name in ("ulUnicodeRange1", "ulUnicodeRange2", "ulUnicodeRange3", "ulUnicodeRange4", "ulCodePageRange1", "ulCodePageRange2", "fsType", "fsSelection"): diff --git a/Lib/fontTools/ttLib/tables/S_I_N_G_.py b/Lib/fontTools/ttLib/tables/S_I_N_G_.py index 59e6e6cd4..413ae4844 100644 --- a/Lib/fontTools/ttLib/tables/S_I_N_G_.py +++ b/Lib/fontTools/ttLib/tables/S_I_N_G_.py @@ -22,22 +22,22 @@ SINGFormat = """ class table_S_I_N_G_(DefaultTable.DefaultTable): - + dependencies = [] - + def decompile(self, data, ttFont): dummy, rest = sstruct.unpack2(SINGFormat, data, self) self.uniqueName = self.decompileUniqueName(self.uniqueName) self.nameLength = byteord(self.nameLength) assert len(rest) == self.nameLength self.baseGlyphName = tostr(rest) - + rawMETAMD5 = self.METAMD5 self.METAMD5 = "[" + hex(byteord(self.METAMD5[0])) for char in rawMETAMD5[1:]: self.METAMD5 = self.METAMD5 + ", " + hex(byteord(char)) self.METAMD5 = self.METAMD5 + "]" - + def decompileUniqueName(self, data): name = "" for char in data: @@ -67,7 +67,7 @@ class table_S_I_N_G_(DefaultTable.DefaultTable): data = sstruct.pack(SINGFormat, d) data = data + tobytes(self.baseGlyphName) return data - + def compilecompileUniqueName(self, name, length): nameLen = len(name) if length <= nameLen: @@ -86,7 +86,7 @@ class table_S_I_N_G_(DefaultTable.DefaultTable): writer.newline() writer.simpletag("baseGlyphName", value=self.baseGlyphName) writer.newline() - + def fromXML(self, name, attrs, content, ttFont): value = attrs["value"] if name in ["uniqueName", "METAMD5", "baseGlyphName"]: diff --git a/Lib/fontTools/ttLib/tables/S_V_G_.py b/Lib/fontTools/ttLib/tables/S_V_G_.py index a8fb509c6..ad67aac54 100644 --- a/Lib/fontTools/ttLib/tables/S_V_G_.py +++ b/Lib/fontTools/ttLib/tables/S_V_G_.py @@ -46,7 +46,7 @@ The XML format is: -Color values must be less than 256. +Color values must be less than 256. The number of color records in each must be the same as the number of elements. @@ -93,13 +93,13 @@ colorRecord_format_0 = """ class table_S_V_G_(DefaultTable.DefaultTable): - + def decompile(self, data, ttFont): self.docList = None self.colorPalettes = None pos = 0 self.version = struct.unpack(">H", data[pos:pos+2])[0] - + if self.version == 1: self.decompile_format_1(data, ttFont) else: @@ -355,7 +355,7 @@ class ColorPalettes(object): class ColorPalette(object): def __init__(self): - self.uiNameID = None # USHORT. name table ID that describes user interface strings associated with this color palette. + self.uiNameID = None # USHORT. name table ID that describes user interface strings associated with this color palette. self.paletteColors = [] # list of ColorRecords def fromXML(self, name, attrs, content, ttFont): diff --git a/Lib/fontTools/ttLib/tables/T_S_I__0.py b/Lib/fontTools/ttLib/tables/T_S_I__0.py index e4d7b2def..97a32b0b2 100644 --- a/Lib/fontTools/ttLib/tables/T_S_I__0.py +++ b/Lib/fontTools/ttLib/tables/T_S_I__0.py @@ -6,13 +6,13 @@ import struct tsi0Format = '>HHl' def fixlongs(glyphID, textLength, textOffset): - return int(glyphID), int(textLength), textOffset + return int(glyphID), int(textLength), textOffset class table_T_S_I__0(DefaultTable.DefaultTable): - + dependencies = ["TSI1"] - + def decompile(self, data, ttFont): numGlyphs = ttFont['maxp'].numGlyphs indices = [] @@ -25,7 +25,7 @@ class table_T_S_I__0(DefaultTable.DefaultTable): assert indices[-5] == (0XFFFE, 0, -1409540300), "bad magic number" # 0xABFC1F34 self.indices = indices[:-5] self.extra_indices = indices[-4:] - + def compile(self, ttFont): if not hasattr(self, "indices"): # We have no corresponding table (TSI1 or TSI3); let's return @@ -38,12 +38,12 @@ class table_T_S_I__0(DefaultTable.DefaultTable): for index, textLength, textOffset in self.extra_indices: data = data + struct.pack(tsi0Format, index, textLength, textOffset) return data - + def set(self, indices, extra_indices): # gets called by 'TSI1' or 'TSI3' self.indices = indices self.extra_indices = extra_indices - + def toXML(self, writer, ttFont): writer.comment("This table will be calculated by the compiler") writer.newline() diff --git a/Lib/fontTools/ttLib/tables/T_S_I__1.py b/Lib/fontTools/ttLib/tables/T_S_I__1.py index 804f68f61..f1122ad47 100644 --- a/Lib/fontTools/ttLib/tables/T_S_I__1.py +++ b/Lib/fontTools/ttLib/tables/T_S_I__1.py @@ -3,11 +3,11 @@ from fontTools.misc.py23 import * from . import DefaultTable class table_T_S_I__1(DefaultTable.DefaultTable): - + extras = {0xfffa: "ppgm", 0xfffb: "cvt", 0xfffc: "reserved", 0xfffd: "fpgm"} - + indextable = "TSI0" - + def decompile(self, data, ttFont): indextable = ttFont[self.indextable] self.glyphPrograms = {} @@ -22,7 +22,7 @@ class table_T_S_I__1(DefaultTable.DefaultTable): assert len(text) == textLength if text: self.glyphPrograms[ttFont.getGlyphName(glyphID)] = text - + self.extraPrograms = {} for i in range(len(indextable.extra_indices)): extraCode, textLength, textOffset = indextable.extra_indices[i] @@ -35,7 +35,7 @@ class table_T_S_I__1(DefaultTable.DefaultTable): assert len(text) == textLength if text: self.extraPrograms[self.extras[extraCode]] = text - + def compile(self, ttFont): if not hasattr(self, "glyphPrograms"): self.glyphPrograms = {} @@ -43,7 +43,7 @@ class table_T_S_I__1(DefaultTable.DefaultTable): data = b'' indextable = ttFont[self.indextable] glyphNames = ttFont.getGlyphOrder() - + indices = [] for i in range(len(glyphNames)): if len(data) % 2: @@ -58,7 +58,7 @@ class table_T_S_I__1(DefaultTable.DefaultTable): textLength = 0x8000 # XXX ??? indices.append((i, textLength, len(data))) data = data + text - + extra_indices = [] codes = sorted(self.extras.items()) for i in range(len(codes)): @@ -76,7 +76,7 @@ class table_T_S_I__1(DefaultTable.DefaultTable): data = data + text indextable.set(indices, extra_indices) return data - + def toXML(self, writer, ttFont): names = sorted(self.glyphPrograms.keys()) writer.newline() @@ -103,7 +103,7 @@ class table_T_S_I__1(DefaultTable.DefaultTable): writer.endtag("extraProgram") writer.newline() writer.newline() - + def fromXML(self, name, attrs, content, ttFont): if not hasattr(self, "glyphPrograms"): self.glyphPrograms = {} diff --git a/Lib/fontTools/ttLib/tables/T_S_I__2.py b/Lib/fontTools/ttLib/tables/T_S_I__2.py index e4c7ce7f6..0a6279062 100644 --- a/Lib/fontTools/ttLib/tables/T_S_I__2.py +++ b/Lib/fontTools/ttLib/tables/T_S_I__2.py @@ -5,5 +5,5 @@ from fontTools import ttLib superclass = ttLib.getTableClass("TSI0") class table_T_S_I__2(superclass): - + dependencies = ["TSI3"] diff --git a/Lib/fontTools/ttLib/tables/T_S_I__3.py b/Lib/fontTools/ttLib/tables/T_S_I__3.py index 7985b1e14..dc1f34ff7 100644 --- a/Lib/fontTools/ttLib/tables/T_S_I__3.py +++ b/Lib/fontTools/ttLib/tables/T_S_I__3.py @@ -5,7 +5,7 @@ from fontTools import ttLib superclass = ttLib.getTableClass("TSI1") class table_T_S_I__3(superclass): - + extras = {0xfffa: "reserved0", 0xfffb: "reserved1", 0xfffc: "reserved2", 0xfffd: "reserved3"} - + indextable = "TSI2" diff --git a/Lib/fontTools/ttLib/tables/T_S_I__5.py b/Lib/fontTools/ttLib/tables/T_S_I__5.py index 2a3790c18..cf29700a9 100644 --- a/Lib/fontTools/ttLib/tables/T_S_I__5.py +++ b/Lib/fontTools/ttLib/tables/T_S_I__5.py @@ -7,7 +7,7 @@ import array class table_T_S_I__5(DefaultTable.DefaultTable): - + def decompile(self, data, ttFont): numGlyphs = ttFont['maxp'].numGlyphs assert len(data) == 2 * numGlyphs @@ -18,7 +18,7 @@ class table_T_S_I__5(DefaultTable.DefaultTable): self.glyphGrouping = {} for i in range(numGlyphs): self.glyphGrouping[ttFont.getGlyphName(i)] = a[i] - + def compile(self, ttFont): glyphNames = ttFont.getGlyphOrder() a = array.array("H") @@ -27,13 +27,13 @@ class table_T_S_I__5(DefaultTable.DefaultTable): if sys.byteorder != "big": a.byteswap() return a.tostring() - + def toXML(self, writer, ttFont): names = sorted(self.glyphGrouping.keys()) for glyphName in names: writer.simpletag("glyphgroup", name=glyphName, value=self.glyphGrouping[glyphName]) writer.newline() - + def fromXML(self, name, attrs, content, ttFont): if not hasattr(self, "glyphGrouping"): self.glyphGrouping = {} diff --git a/Lib/fontTools/ttLib/tables/V_D_M_X_.py b/Lib/fontTools/ttLib/tables/V_D_M_X_.py index ac045874a..2680836e0 100644 --- a/Lib/fontTools/ttLib/tables/V_D_M_X_.py +++ b/Lib/fontTools/ttLib/tables/V_D_M_X_.py @@ -20,7 +20,7 @@ VDMX_RatRangeFmt = """ yStartRatio: B # Starting y-Ratio value yEndRatio: B # Ending y-Ratio value """ -# followed by an array of offset[numRatios] from start of VDMX table to the +# followed by an array of offset[numRatios] from start of VDMX table to the # VDMX Group for this ratio range (offsets will be re-calculated on compile); # followed by an array of Group[numRecs] records; VDMX_GroupFmt = """ diff --git a/Lib/fontTools/ttLib/tables/V_O_R_G_.py b/Lib/fontTools/ttLib/tables/V_O_R_G_.py index dd493a212..8b2c317a5 100644 --- a/Lib/fontTools/ttLib/tables/V_O_R_G_.py +++ b/Lib/fontTools/ttLib/tables/V_O_R_G_.py @@ -41,7 +41,7 @@ class table_V_O_R_G_(DefaultTable.DefaultTable): vorgs = list(self.VOriginRecords.values()) names = list(self.VOriginRecords.keys()) nameMap = ttFont.getReverseGlyphMap() - lenRecords = len(vorgs) + lenRecords = len(vorgs) try: gids = map(operator.getitem, [nameMap]*lenRecords, names) except KeyError: @@ -100,7 +100,7 @@ class table_V_O_R_G_(DefaultTable.DefaultTable): if glyphSelector not in self.VOriginRecords: return self.defaultVertOriginY - + return self.VOriginRecords[glyphSelector] def __setitem__(self, glyphSelector, value): diff --git a/Lib/fontTools/ttLib/tables/_c_m_a_p.py b/Lib/fontTools/ttLib/tables/_c_m_a_p.py index bf3f67296..fad08c574 100644 --- a/Lib/fontTools/ttLib/tables/_c_m_a_p.py +++ b/Lib/fontTools/ttLib/tables/_c_m_a_p.py @@ -12,14 +12,14 @@ import operator class table__c_m_a_p(DefaultTable.DefaultTable): - + def getcmap(self, platformID, platEncID): for subtable in self.tables: - if (subtable.platformID == platformID and + if (subtable.platformID == platformID and subtable.platEncID == platEncID): return subtable return None # not found - + def decompile(self, data, ttFont): tableVersion, numSubTables = struct.unpack(">HH", data[:4]) self.tableVersion = int(tableVersion) @@ -34,7 +34,7 @@ class table__c_m_a_p(DefaultTable.DefaultTable): format, reserved, length = struct.unpack(">HHL", data[offset:offset+8]) elif format in [14]: format, length = struct.unpack(">HL", data[offset:offset+6]) - + if not length: print("Error: cmap subtable is reported as having zero length: platformID %s, platEncID %s, format %s offset %s. Skipping table." % (platformID, platEncID,format, offset)) continue @@ -53,7 +53,7 @@ class table__c_m_a_p(DefaultTable.DefaultTable): else: seenOffsets[offset] = i tables.append(table) - + def compile(self, ttFont): self.tables.sort() # sort according to the spec; see CmapSubtable.__lt__() numSubTables = len(self.tables) @@ -74,13 +74,13 @@ class table__c_m_a_p(DefaultTable.DefaultTable): tableData = tableData + chunk data = data + struct.pack(">HHl", table.platformID, table.platEncID, offset) return data + tableData - + def toXML(self, writer, ttFont): writer.simpletag("tableVersion", version=self.tableVersion) writer.newline() for table in self.tables: table.toXML(writer, ttFont) - + def fromXML(self, name, attrs, content, ttFont): if name == "tableVersion": self.tableVersion = safeEval(attrs["version"]) @@ -101,7 +101,7 @@ class table__c_m_a_p(DefaultTable.DefaultTable): class CmapSubtable(object): - + def __init__(self, format): self.format = format self.data = None @@ -118,7 +118,7 @@ class CmapSubtable(object): # just return the original data. Also avoids recursion when # called with an attribute that the cmap subtable doesn't have. return getattr(self, attr) - + def decompileHeader(self, data, ttFont): format, length, language = struct.unpack(">HHH", data[:6]) assert len(data) == length, "corrupt cmap table format %d (data length: %d, header length: %d)" % (format, len(data), length) @@ -166,7 +166,7 @@ class CmapSubtable(object): if isUnicode: writer.comment(Unicode[code]) writer.newline() - + def __lt__(self, other): if not isinstance(other, CmapSubtable): return NotImplemented @@ -186,7 +186,7 @@ class CmapSubtable(object): class cmap_format_0(CmapSubtable): - + def decompile(self, data, ttFont): # we usually get here indirectly from the subtable __getattr__ function, in which case both args must be None. # If not, someone is calling the subtable decompile() directly, and must provide both args. @@ -218,7 +218,7 @@ class cmap_format_0(CmapSubtable): data = struct.pack(">HHH", 0, 262, self.language) + glyphIdArray.tostring() assert len(data) == 262 return data - + def fromXML(self, name, attrs, content, ttFont): self.language = safeEval(attrs["language"]) if not hasattr(self, "cmap"): @@ -241,9 +241,9 @@ class SubHeader(object): self.idDelta = None self.idRangeOffset = None self.glyphIndexArray = [] - + class cmap_format_2(CmapSubtable): - + def setIDDelta(self, subHeader): subHeader.idDelta = 0 # find the minGI which is not zero. @@ -253,13 +253,13 @@ class cmap_format_2(CmapSubtable): minGI = gid # The lowest gid in glyphIndexArray, after subtracting idDelta, must be 1. # idDelta is a short, and must be between -32K and 32K. minGI can be between 1 and 64K. - # We would like to pick an idDelta such that the first glyphArray GID is 1, + # We would like to pick an idDelta such that the first glyphArray GID is 1, # so that we are more likely to be able to combine glypharray GID subranges. # This means that we have a problem when minGI is > 32K # Since the final gi is reconstructed from the glyphArray GID by: # (short)finalGID = (gid + idDelta) % 0x10000), # we can get from a glypharray GID of 1 to a final GID of 65K by subtracting 2, and casting the - # negative number to an unsigned short. + # negative number to an unsigned short. if (minGI > 1): if minGI > 0x7FFF: @@ -269,8 +269,8 @@ class cmap_format_2(CmapSubtable): idDelta = subHeader.idDelta for i in range(subHeader.entryCount): gid = subHeader.glyphIndexArray[i] - if gid > 0: - subHeader.glyphIndexArray[i] = gid - idDelta + if gid > 0: + subHeader.glyphIndexArray[i] = gid - idDelta def decompile(self, data, ttFont): # we usually get here indirectly from the subtable __getattr__ function, in which case both args must be None. @@ -291,7 +291,7 @@ class cmap_format_2(CmapSubtable): allKeys.byteswap() subHeaderKeys = [ key//8 for key in allKeys] maxSubHeaderindex = max(subHeaderKeys) - + #Load subHeaders subHeaderList = [] pos = 0 @@ -307,14 +307,14 @@ class cmap_format_2(CmapSubtable): giList.byteswap() subHeader.glyphIndexArray = giList subHeaderList.append(subHeader) - # How this gets processed. + # How this gets processed. # Charcodes may be one or two bytes. # The first byte of a charcode is mapped through the subHeaderKeys, to select # a subHeader. For any subheader but 0, the next byte is then mapped through the - # selected subheader. If subheader Index 0 is selected, then the byte itself is + # selected subheader. If subheader Index 0 is selected, then the byte itself is # mapped through the subheader, and there is no second byte. # Then assume that the subsequent byte is the first byte of the next charcode,and repeat. - # + # # Each subheader references a range in the glyphIndexArray whose length is entryCount. # The range in glyphIndexArray referenced by a sunheader may overlap with the range in glyphIndexArray # referenced by another subheader. @@ -326,7 +326,7 @@ class cmap_format_2(CmapSubtable): # firstChar and EntryCount values. If the byte value is outside the subrange, then the glyphIndex is zero # (e.g. glyph not in font). # If the byte index is in the subrange, then an offset index is calculated as (byteIndex - firstChar). - # The index to glyphIndex mapping is a subrange of the glyphIndexArray. You find the start of the subrange by + # The index to glyphIndex mapping is a subrange of the glyphIndexArray. You find the start of the subrange by # counting idRangeOffset bytes from the idRangeOffset word. The first value in this subrange is the # glyphIndex for the index firstChar. The offset index should then be used in this array to get the glyphIndex. # Example for Logocut-Medium @@ -340,10 +340,10 @@ class cmap_format_2(CmapSubtable): # [257], [1]=2 from charcode [129, 65] # [258], [2]=3 from charcode [129, 66] # [259], [3]=4 from charcode [129, 67] - # So, the glyphIndex = 3 from the array. Then if idDelta is not zero and the glyph ID is not zero, + # So, the glyphIndex = 3 from the array. Then if idDelta is not zero and the glyph ID is not zero, # add it to the glyphID to get the final glyphIndex # value. In this case the final glyph index = 3+ 42 -> 45 for the final glyphIndex. Whew! - + self.data = b"" self.cmap = cmap = {} notdefGI = 0 @@ -374,7 +374,7 @@ class cmap_format_2(CmapSubtable): continue cmap[charCode] = gi # If not subHeader.entryCount, then all char codes with this first byte are - # mapped to .notdef. We can skip this subtable, and leave the glyphs un-encoded, which is the + # mapped to .notdef. We can skip this subtable, and leave the glyphs un-encoded, which is the # same as mapping it to .notdef. # cmap values are GID's. glyphOrder = self.ttFont.getGlyphOrder() @@ -387,7 +387,7 @@ class cmap_format_2(CmapSubtable): getGlyphName = self.ttFont.getGlyphName names = list(map(getGlyphName, gids )) list(map(operator.setitem, [cmap]*lenCmap, charCodes, names)) - + def compile(self, ttFont): if self.data: return struct.pack(">HHH", self.format, self.length, self.language) + self.data @@ -398,7 +398,7 @@ class cmap_format_2(CmapSubtable): charCodes = [item[0] for item in items] names = [item[1] for item in items] nameMap = ttFont.getReverseGlyphMap() - lenCharCodes = len(charCodes) + lenCharCodes = len(charCodes) try: gids = list(map(operator.getitem, [nameMap]*lenCharCodes, names)) except KeyError: @@ -423,8 +423,8 @@ class cmap_format_2(CmapSubtable): gids.append(gid) # Process the (char code to gid) item list in char code order. - # By definition, all one byte char codes map to subheader 0. - # For all the two byte char codes, we assume that the first byte maps maps to the empty subhead (with an entry count of 0, + # By definition, all one byte char codes map to subheader 0. + # For all the two byte char codes, we assume that the first byte maps maps to the empty subhead (with an entry count of 0, # which defines all char codes in its range to map to notdef) unless proven otherwise. # Note that since the char code items are processed in char code order, all the char codes with the # same first byte are in sequential order. @@ -443,7 +443,7 @@ class cmap_format_2(CmapSubtable): subHeader.idDelta = 0 subHeader.idRangeOffset = 0 subHeaderList.append(subHeader) - + lastFirstByte = -1 items = zip(charCodes, gids) for charCode, gid in items: @@ -480,7 +480,7 @@ class cmap_format_2(CmapSubtable): subHeader.glyphIndexArray.append(notdefGI) subHeader.glyphIndexArray.append(gid) subHeader.entryCount = subHeader.entryCount + codeDiff + 1 - + # fix GI's and iDelta of last subheader that we we added to the subheader array. self.setIDDelta(subHeader) @@ -497,12 +497,12 @@ class cmap_format_2(CmapSubtable): subHeaderKeys[index] = emptySubheadIndex # Since this is the last subheader, the GlyphIndex Array starts two bytes after the start of the # idRangeOffset word of this subHeader. We can safely point to the first entry in the GlyphIndexArray, - # since the first subrange of the GlyphIndexArray is for subHeader 0, which always starts with + # since the first subrange of the GlyphIndexArray is for subHeader 0, which always starts with # charcode 0 and GID 0. - + idRangeOffset = (len(subHeaderList)-1)*8 + 2 # offset to beginning of glyphIDArray from first subheader idRangeOffset. subheadRangeLen = len(subHeaderList) -1 # skip last special empty-set subheader; we've already hardocodes its idRangeOffset to 2. - for index in range(subheadRangeLen): + for index in range(subheadRangeLen): subHeader = subHeaderList[index] subHeader.idRangeOffset = 0 for j in range(index): @@ -511,7 +511,7 @@ class cmap_format_2(CmapSubtable): subHeader.idRangeOffset = prevSubhead.idRangeOffset - (index-j)*8 subHeader.glyphIndexArray = [] break - if subHeader.idRangeOffset == 0: # didn't find one. + if subHeader.idRangeOffset == 0: # didn't find one. subHeader.idRangeOffset = idRangeOffset idRangeOffset = (idRangeOffset - 8) + subHeader.entryCount*2 # one less subheader, one more subArray. else: @@ -564,17 +564,17 @@ def splitRange(startCode, endCode, cmap): # to do well with the fonts I tested: none became bigger, many became smaller. if startCode == endCode: return [], [endCode] - + lastID = cmap[startCode] lastCode = startCode inOrder = None orderedBegin = None subRanges = [] - + # Gather subranges in which the glyph IDs are consecutive. for code in range(startCode + 1, endCode + 1): glyphID = cmap[code] - + if glyphID - 1 == lastID: if inOrder is None or not inOrder: inOrder = 1 @@ -584,14 +584,14 @@ def splitRange(startCode, endCode, cmap): inOrder = 0 subRanges.append((orderedBegin, lastCode)) orderedBegin = None - + lastID = glyphID lastCode = code - + if inOrder: subRanges.append((orderedBegin, lastCode)) assert lastCode == endCode - + # Now filter out those new subranges that would only make the data bigger. # A new segment cost 8 bytes, not using a new segment costs 2 bytes per # character. @@ -606,15 +606,15 @@ def splitRange(startCode, endCode, cmap): if (e - b + 1) > threshold: newRanges.append((b, e)) subRanges = newRanges - + if not subRanges: return [], [endCode] - + if subRanges[0][0] != startCode: subRanges.insert(0, (startCode, subRanges[0][0] - 1)) if subRanges[-1][1] != endCode: subRanges.append((subRanges[-1][1] + 1, endCode)) - + # Fill the "holes" in the segments list -- those are the segments in which # the glyph IDs are _not_ consecutive. i = 1 @@ -623,7 +623,7 @@ def splitRange(startCode, endCode, cmap): subRanges.insert(i, (subRanges[i-1][1] + 1, subRanges[i][0] - 1)) i = i + 1 i = i + 1 - + # Transform the ranges into startCode/endCode lists. start = [] end = [] @@ -631,13 +631,13 @@ def splitRange(startCode, endCode, cmap): start.append(b) end.append(e) start.pop(0) - + assert len(start) + 1 == len(end) return start, end class cmap_format_4(CmapSubtable): - + def decompile(self, data, ttFont): # we usually get here indirectly from the subtable __getattr__ function, in which case both args must be None. # If not, someone is calling the subtable decompile() directly, and must provide both args. @@ -651,14 +651,14 @@ class cmap_format_4(CmapSubtable): struct.unpack(">4H", data[:8]) data = data[8:] segCount = segCountX2 // 2 - + allCodes = array.array("H") allCodes.fromstring(data) self.data = data = None if sys.byteorder != "big": allCodes.byteswap() - + # divide the data endCode = allCodes[:segCount] allCodes = allCodes[segCount+1:] # the +1 is skipping the reservedPad field @@ -707,7 +707,7 @@ class cmap_format_4(CmapSubtable): def compile(self, ttFont): if self.data: return struct.pack(">HHH", self.format, self.length, self.language) + self.data - + charCodes = list(self.cmap.keys()) lenCharCodes = len(charCodes) if lenCharCodes == 0: @@ -737,11 +737,11 @@ class cmap_format_4(CmapSubtable): gid = ttFont.getGlyphID(name) except: raise KeyError(name) - + gids.append(gid) cmap = {} # code:glyphID mapping list(map(operator.setitem, [cmap]*len(charCodes), charCodes, gids)) - + # Build startCode and endCode lists. # Split the char codes in ranges of consecutive char codes, then split # each range in more ranges of consecutive/not consecutive glyph IDs. @@ -763,7 +763,7 @@ class cmap_format_4(CmapSubtable): endCode.extend(end) startCode.append(0xffff) endCode.append(0xffff) - + # build up rest of cruft idDelta = [] idRangeOffset = [] @@ -782,12 +782,12 @@ class cmap_format_4(CmapSubtable): glyphIndexArray.extend(indices) idDelta.append(1) # 0xffff + 1 == (tadaa!) 0. So this end code maps to .notdef idRangeOffset.append(0) - + # Insane. segCount = len(endCode) segCountX2 = segCount * 2 searchRange, entrySelector, rangeShift = getSearchRange(segCount, 2) - + charCodeArray = array.array("H", endCode + [0] + startCode) idDeltaArray = array.array("H", idDelta) restArray = array.array("H", idRangeOffset + glyphIndexArray) @@ -798,10 +798,10 @@ class cmap_format_4(CmapSubtable): data = charCodeArray.tostring() + idDeltaArray.tostring() + restArray.tostring() length = struct.calcsize(cmap_format_4_format) + len(data) - header = struct.pack(cmap_format_4_format, self.format, length, self.language, + header = struct.pack(cmap_format_4_format, self.format, length, self.language, segCountX2, searchRange, entrySelector, rangeShift) return header + data - + def fromXML(self, name, attrs, content, ttFont): self.language = safeEval(attrs["language"]) if not hasattr(self, "cmap"): @@ -818,7 +818,7 @@ class cmap_format_4(CmapSubtable): class cmap_format_6(CmapSubtable): - + def decompile(self, data, ttFont): # we usually get here indirectly from the subtable __getattr__ function, in which case both args must be None. # If not, someone is calling the subtable decompile() directly, and must provide both args. @@ -849,7 +849,7 @@ class cmap_format_6(CmapSubtable): getGlyphName = self.ttFont.getGlyphName names = list(map(getGlyphName, glyphIndexArray )) list(map(operator.setitem, [cmap]*lenArray, charCodes, names)) - + def compile(self, ttFont): if self.data: return struct.pack(">HHH", self.format, self.length, self.language) + self.data @@ -867,10 +867,10 @@ class cmap_format_6(CmapSubtable): else: data = b"" firstCode = 0 - header = struct.pack(">HHHHH", + header = struct.pack(">HHHHH", 6, len(data) + 10, self.language, firstCode, len(codes)) return header + data - + def fromXML(self, name, attrs, content, ttFont): self.language = safeEval(attrs["language"]) if not hasattr(self, "cmap"): @@ -887,7 +887,7 @@ class cmap_format_6(CmapSubtable): class cmap_format_12_or_13(CmapSubtable): - + def __init__(self, format): self.format = format self.reserved = 0 @@ -933,12 +933,12 @@ class cmap_format_12_or_13(CmapSubtable): getGlyphName = self.ttFont.getGlyphName names = list(map(getGlyphName, gids )) list(map(operator.setitem, [cmap]*lenCmap, charCodes, names)) - + def compile(self, ttFont): if self.data: return struct.pack(">HHLLL", self.format, self.reserved, self.length, self.language, self.nGroups) + self.data charCodes = list(self.cmap.keys()) - lenCharCodes = len(charCodes) + lenCharCodes = len(charCodes) names = list(self.cmap.values()) nameMap = ttFont.getReverseGlyphMap() try: @@ -963,7 +963,7 @@ class cmap_format_12_or_13(CmapSubtable): raise KeyError(name) gids.append(gid) - + cmap = {} # code:glyphID mapping list(map(operator.setitem, [cmap]*len(charCodes), charCodes, gids)) @@ -992,7 +992,7 @@ class cmap_format_12_or_13(CmapSubtable): lengthSubtable = len(data) +16 assert len(data) == (nGroups*12) == (lengthSubtable-16) return struct.pack(">HHLLL", self.format, self.reserved, lengthSubtable, self.language, nGroups) + data - + def toXML(self, writer, ttFont): writer.begintag(self.__class__.__name__, [ ("platformID", self.platformID), @@ -1008,7 +1008,7 @@ class cmap_format_12_or_13(CmapSubtable): self._writeCodes(codes, writer) writer.endtag(self.__class__.__name__) writer.newline() - + def fromXML(self, name, attrs, content, ttFont): self.format = safeEval(attrs["format"]) self.reserved = safeEval(attrs["reserved"]) @@ -1079,12 +1079,12 @@ class cmap_format_14(CmapSubtable): else: assert (data is None and ttFont is None), "Need both data and ttFont arguments" data = self.data - + self.cmap = {} # so that clients that expect this to exist in a cmap table won't fail. uvsDict = {} recOffset = 0 for n in range(self.numVarSelectorRecords): - uvs, defOVSOffset, nonDefUVSOffset = struct.unpack(">3sLL", data[recOffset:recOffset +11]) + uvs, defOVSOffset, nonDefUVSOffset = struct.unpack(">3sLL", data[recOffset:recOffset +11]) recOffset += 11 varUVS = cvtToUVS(uvs) if defOVSOffset: @@ -1103,7 +1103,7 @@ class cmap_format_14(CmapSubtable): uvsDict[varUVS].extend(localUVList) except KeyError: uvsDict[varUVS] = list(localUVList) - + if nonDefUVSOffset: startOffset = nonDefUVSOffset - 10 numRecs, = struct.unpack(">L", data[startOffset:startOffset+4]) @@ -1119,9 +1119,9 @@ class cmap_format_14(CmapSubtable): uvsDict[varUVS].extend(localUVList) except KeyError: uvsDict[varUVS] = localUVList - + self.uvsDict = uvsDict - + def toXML(self, writer, ttFont): writer.begintag(self.__class__.__name__, [ ("platformID", self.platformID), @@ -1154,7 +1154,7 @@ class cmap_format_14(CmapSubtable): self.cmap = {} # so that clients that expect this to exist in a cmap table won't fail. if not hasattr(self, "uvsDict"): self.uvsDict = {} - uvsDict = self.uvsDict + uvsDict = self.uvsDict for element in content: if not isinstance(element, tuple): @@ -1201,7 +1201,7 @@ class cmap_format_14(CmapSubtable): lastUV = defEntry defRecs.append(rec) cnt = 0 - + rec = struct.pack(">3sB", cvtFromUVS(lastUV), cnt) defRecs.append(rec) @@ -1226,20 +1226,20 @@ class cmap_format_14(CmapSubtable): data.append(ndrec) else: nonDefUVSOffset = 0 - + vrec = struct.pack(">3sLL", cvtFromUVS(uvs), defOVSOffset, nonDefUVSOffset) varSelectorRecords.append(vrec) - + data = bytesjoin(varSelectorRecords) + bytesjoin(data) self.length = 10 + len(data) headerdata = struct.pack(">HLL", self.format, self.length, self.numVarSelectorRecords) self.data = headerdata + data - + return self.data - - + + class cmap_format_unknown(CmapSubtable): - + def toXML(self, writer, ttFont): cmapName = self.__class__.__name__[:12] + str(self.format) writer.begintag(cmapName, [ @@ -1250,15 +1250,15 @@ class cmap_format_unknown(CmapSubtable): writer.dumphex(self.data) writer.endtag(cmapName) writer.newline() - + def fromXML(self, name, attrs, content, ttFont): self.data = readHex(content) self.cmap = {} - + def decompileHeader(self, data, ttFont): self.language = 0 # dummy value self.data = data - + def decompile(self, data, ttFont): # we usually get here indirectly from the subtable __getattr__ function, in which case both args must be None. # If not, someone is calling the subtable decompile() directly, and must provide both args. diff --git a/Lib/fontTools/ttLib/tables/_c_v_t.py b/Lib/fontTools/ttLib/tables/_c_v_t.py index 32d05c914..4fbee7bfc 100644 --- a/Lib/fontTools/ttLib/tables/_c_v_t.py +++ b/Lib/fontTools/ttLib/tables/_c_v_t.py @@ -6,26 +6,26 @@ import sys import array class table__c_v_t(DefaultTable.DefaultTable): - + def decompile(self, data, ttFont): values = array.array("h") values.fromstring(data) if sys.byteorder != "big": values.byteswap() self.values = values - + def compile(self, ttFont): values = self.values[:] if sys.byteorder != "big": values.byteswap() return values.tostring() - + def toXML(self, writer, ttFont): for i in range(len(self.values)): value = self.values[i] writer.simpletag("cv", value=value, index=i) writer.newline() - + def fromXML(self, name, attrs, content, ttFont): if not hasattr(self, "values"): self.values = array.array("h") @@ -35,15 +35,15 @@ class table__c_v_t(DefaultTable.DefaultTable): for i in range(1 + index - len(self.values)): self.values.append(0) self.values[index] = value - + def __len__(self): return len(self.values) - + def __getitem__(self, index): return self.values[index] - + def __setitem__(self, index, value): self.values[index] = value - + def __delitem__(self, index): del self.values[index] diff --git a/Lib/fontTools/ttLib/tables/_f_p_g_m.py b/Lib/fontTools/ttLib/tables/_f_p_g_m.py index f65f8ead7..7361b29e7 100644 --- a/Lib/fontTools/ttLib/tables/_f_p_g_m.py +++ b/Lib/fontTools/ttLib/tables/_f_p_g_m.py @@ -4,23 +4,23 @@ from . import DefaultTable from . import ttProgram class table__f_p_g_m(DefaultTable.DefaultTable): - + def decompile(self, data, ttFont): program = ttProgram.Program() program.fromBytecode(data) self.program = program - + def compile(self, ttFont): return self.program.getBytecode() - + def toXML(self, writer, ttFont): self.program.toXML(writer, ttFont) writer.newline() - + def fromXML(self, name, attrs, content, ttFont): program = ttProgram.Program() program.fromXML(name, attrs, content, ttFont) self.program = program - + def __len__(self): return len(self.program) diff --git a/Lib/fontTools/ttLib/tables/_g_a_s_p.py b/Lib/fontTools/ttLib/tables/_g_a_s_p.py index c982b594d..dce356912 100644 --- a/Lib/fontTools/ttLib/tables/_g_a_s_p.py +++ b/Lib/fontTools/ttLib/tables/_g_a_s_p.py @@ -11,7 +11,7 @@ GASP_DOGRAY = 0x0002 GASP_GRIDFIT = 0x0001 class table__g_a_s_p(DefaultTable.DefaultTable): - + def decompile(self, data, ttFont): self.version, numRanges = struct.unpack(">HH", data[:4]) assert 0 <= self.version <= 1, "unknown 'gasp' format: %s" % self.version @@ -22,7 +22,7 @@ class table__g_a_s_p(DefaultTable.DefaultTable): self.gaspRange[int(rangeMaxPPEM)] = int(rangeGaspBehavior) data = data[4:] assert not data, "too much data" - + def compile(self, ttFont): version = 0 # ignore self.version numRanges = len(self.gaspRange) @@ -34,7 +34,7 @@ class table__g_a_s_p(DefaultTable.DefaultTable): version = 1 data = struct.pack(">HH", version, numRanges) + data return data - + def toXML(self, writer, ttFont): items = sorted(self.gaspRange.items()) for rangeMaxPPEM, rangeGaspBehavior in items: @@ -42,7 +42,7 @@ class table__g_a_s_p(DefaultTable.DefaultTable): ("rangeMaxPPEM", rangeMaxPPEM), ("rangeGaspBehavior", rangeGaspBehavior)]) writer.newline() - + def fromXML(self, name, attrs, content, ttFont): if name != "gaspRange": return diff --git a/Lib/fontTools/ttLib/tables/_g_l_y_f.py b/Lib/fontTools/ttLib/tables/_g_l_y_f.py index 6ca970c6f..65c34b978 100644 --- a/Lib/fontTools/ttLib/tables/_g_l_y_f.py +++ b/Lib/fontTools/ttLib/tables/_g_l_y_f.py @@ -16,20 +16,20 @@ import array import warnings # -# The Apple and MS rasterizers behave differently for +# The Apple and MS rasterizers behave differently for # scaled composite components: one does scale first and then translate # and the other does it vice versa. MS defined some flags to indicate # the difference, but it seems nobody actually _sets_ those flags. # # Funny thing: Apple seems to _only_ do their thing in the -# WE_HAVE_A_SCALE (eg. Chicago) case, and not when it's WE_HAVE_AN_X_AND_Y_SCALE +# WE_HAVE_A_SCALE (eg. Chicago) case, and not when it's WE_HAVE_AN_X_AND_Y_SCALE # (eg. Charcoal)... # SCALE_COMPONENT_OFFSET_DEFAULT = 0 # 0 == MS, 1 == Apple class table__g_l_y_f(DefaultTable.DefaultTable): - + def decompile(self, data, ttFont): loca = ttFont['loca'] last = int(loca[0]) @@ -57,7 +57,7 @@ class table__g_l_y_f(DefaultTable.DefaultTable): if ttFont.lazy is False: # Be lazy for None and True for glyph in self.glyphs.values(): glyph.expand(self) - + def compile(self, ttFont): if not hasattr(self, "glyphOrder"): self.glyphOrder = ttFont.getGlyphOrder() @@ -92,7 +92,7 @@ class table__g_l_y_f(DefaultTable.DefaultTable): ttFont['loca'].set(locations) ttFont['maxp'].numGlyphs = len(self.glyphs) return data - + def toXML(self, writer, ttFont, progress=None): writer.newline() glyphNames = ttFont.getGlyphNames() @@ -125,7 +125,7 @@ class table__g_l_y_f(DefaultTable.DefaultTable): writer.comment("contains no outline data") writer.newline() writer.newline() - + def fromXML(self, name, attrs, content, ttFont): if name != "TTGlyph": return @@ -147,39 +147,39 @@ class table__g_l_y_f(DefaultTable.DefaultTable): glyph.fromXML(name, attrs, content, ttFont) if not ttFont.recalcBBoxes: glyph.compact(self, 0) - + def setGlyphOrder(self, glyphOrder): self.glyphOrder = glyphOrder - + def getGlyphName(self, glyphID): return self.glyphOrder[glyphID] - + def getGlyphID(self, glyphName): # XXX optimize with reverse dict!!! return self.glyphOrder.index(glyphName) - + def keys(self): return self.glyphs.keys() - + def has_key(self, glyphName): return glyphName in self.glyphs - + __contains__ = has_key - + def __getitem__(self, glyphName): glyph = self.glyphs[glyphName] glyph.expand(self) return glyph - + def __setitem__(self, glyphName, glyph): self.glyphs[glyphName] = glyph if glyphName not in self.glyphOrder: self.glyphOrder.append(glyphName) - + def __delitem__(self, glyphName): del self.glyphs[glyphName] self.glyphOrder.remove(glyphName) - + def __len__(self): assert len(self.glyphOrder) == len(self.glyphs) return len(self.glyphs) @@ -267,35 +267,35 @@ def flagEncodeCoords(flag, x, y, xBytes, yBytes): flagEncodeCoord(flag, flagYsame|flagYShort, y, yBytes) -ARG_1_AND_2_ARE_WORDS = 0x0001 # if set args are words otherwise they are bytes -ARGS_ARE_XY_VALUES = 0x0002 # if set args are xy values, otherwise they are points -ROUND_XY_TO_GRID = 0x0004 # for the xy values if above is true -WE_HAVE_A_SCALE = 0x0008 # Sx = Sy, otherwise scale == 1.0 +ARG_1_AND_2_ARE_WORDS = 0x0001 # if set args are words otherwise they are bytes +ARGS_ARE_XY_VALUES = 0x0002 # if set args are xy values, otherwise they are points +ROUND_XY_TO_GRID = 0x0004 # for the xy values if above is true +WE_HAVE_A_SCALE = 0x0008 # Sx = Sy, otherwise scale == 1.0 NON_OVERLAPPING = 0x0010 # set to same value for all components (obsolete!) -MORE_COMPONENTS = 0x0020 # indicates at least one more glyph after this one -WE_HAVE_AN_X_AND_Y_SCALE = 0x0040 # Sx, Sy -WE_HAVE_A_TWO_BY_TWO = 0x0080 # t00, t01, t10, t11 -WE_HAVE_INSTRUCTIONS = 0x0100 # instructions follow -USE_MY_METRICS = 0x0200 # apply these metrics to parent glyph -OVERLAP_COMPOUND = 0x0400 # used by Apple in GX fonts -SCALED_COMPONENT_OFFSET = 0x0800 # composite designed to have the component offset scaled (designed for Apple) -UNSCALED_COMPONENT_OFFSET = 0x1000 # composite designed not to have the component offset scaled (designed for MS) +MORE_COMPONENTS = 0x0020 # indicates at least one more glyph after this one +WE_HAVE_AN_X_AND_Y_SCALE = 0x0040 # Sx, Sy +WE_HAVE_A_TWO_BY_TWO = 0x0080 # t00, t01, t10, t11 +WE_HAVE_INSTRUCTIONS = 0x0100 # instructions follow +USE_MY_METRICS = 0x0200 # apply these metrics to parent glyph +OVERLAP_COMPOUND = 0x0400 # used by Apple in GX fonts +SCALED_COMPONENT_OFFSET = 0x0800 # composite designed to have the component offset scaled (designed for Apple) +UNSCALED_COMPONENT_OFFSET = 0x1000 # composite designed not to have the component offset scaled (designed for MS) class Glyph(object): - + def __init__(self, data=""): if not data: # empty char self.numberOfContours = 0 return self.data = data - + def compact(self, glyfTable, recalcBBoxes=True): data = self.compile(glyfTable, recalcBBoxes) self.__dict__.clear() self.data = data - + def expand(self, glyfTable): if not hasattr(self, "data"): # already unpacked @@ -310,7 +310,7 @@ class Glyph(object): self.decompileComponents(data, glyfTable) else: self.decompileCoordinates(data) - + def compile(self, glyfTable, recalcBBoxes=True): if hasattr(self, "data"): return self.data @@ -324,7 +324,7 @@ class Glyph(object): else: data = data + self.compileCoordinates() return data - + def toXML(self, writer, ttFont): if self.isComposite(): for compo in self.components: @@ -341,7 +341,7 @@ class Glyph(object): writer.newline() for j in range(last, self.endPtsOfContours[i] + 1): writer.simpletag("pt", [ - ("x", self.coordinates[j][0]), + ("x", self.coordinates[j][0]), ("y", self.coordinates[j][1]), ("on", self.flags[j] & flagOnCurve)]) writer.newline() @@ -353,7 +353,7 @@ class Glyph(object): self.program.toXML(writer, ttFont) writer.endtag("instructions") writer.newline() - + def fromXML(self, name, attrs, content, ttFont): if name == "contour": if self.numberOfContours < 0: @@ -394,7 +394,7 @@ class Glyph(object): continue name, attrs, content = element self.program.fromXML(name, attrs, content, ttFont) - + def getCompositeMaxpValues(self, glyfTable, maxComponentDepth=1): assert self.isComposite() nContours = 0 @@ -411,11 +411,11 @@ class Glyph(object): nPoints = nPoints + nP nContours = nContours + nC return nPoints, nContours, maxComponentDepth - + def getMaxpValues(self): assert self.numberOfContours > 0 return len(self.coordinates), len(self.endPtsOfContours) - + def decompileComponents(self, data, glyfTable): self.components = [] more = 1 @@ -433,16 +433,16 @@ class Glyph(object): data = data[numInstructions:] if len(data) >= 4: warnings.warn("too much glyph data at the end of composite glyph: %d excess bytes" % len(data)) - + def decompileCoordinates(self, data): endPtsOfContours = array.array("h") endPtsOfContours.fromstring(data[:2*self.numberOfContours]) if sys.byteorder != "big": endPtsOfContours.byteswap() self.endPtsOfContours = endPtsOfContours.tolist() - + data = data[2*self.numberOfContours:] - + instructionLength, = struct.unpack(">h", data[:2]) data = data[2:] self.program = ttProgram.Program() @@ -451,7 +451,7 @@ class Glyph(object): nCoordinates = self.endPtsOfContours[-1] + 1 flags, xCoordinates, yCoordinates = \ self.decompileCoordinatesRaw(nCoordinates, data) - + # fill in repetitions and apply signs self.coordinates = coordinates = GlyphCoordinates.zeros(nCoordinates) xIndex = 0 @@ -528,7 +528,7 @@ class Glyph(object): xCoordinates = struct.unpack(xFormat, data[:xDataLen]) yCoordinates = struct.unpack(yFormat, data[xDataLen:xDataLen+yDataLen]) return flags, xCoordinates, yCoordinates - + def compileComponents(self, glyfTable): data = b"" lastcomponent = len(self.components) - 1 @@ -544,7 +544,7 @@ class Glyph(object): instructions = self.program.getBytecode() data = data + struct.pack(">h", len(instructions)) + instructions return data - + def compileCoordinates(self): assert len(self.coordinates) == len(self.flags) data = [] @@ -676,7 +676,7 @@ class Glyph(object): compressedYs = compressedYs.tostring() return (compressedFlags, compressedXs, compressedYs) - + def recalcBounds(self, glyfTable): coords, endPts, flags = self.getCoordinates(glyfTable) if len(coords) > 0: @@ -734,19 +734,19 @@ class Glyph(object): self.xMin, self.yMin, self.xMax, self.yMax = calcIntBounds(coords) else: self.xMin, self.yMin, self.xMax, self.yMax = (0, 0, 0, 0) - + def isComposite(self): """Can be called on compact or expanded glyph.""" if hasattr(self, "data") and self.data: return struct.unpack(">h", self.data[:2])[0] == -1 else: return self.numberOfContours == -1 - + def __getitem__(self, componentIndex): if not self.isComposite(): raise ttLib.TTLibError("can't use glyph as sequence") return self.components[componentIndex] - + def getCoordinates(self, glyfTable): if self.numberOfContours > 0: return self.coordinates, self.endPtsOfContours, self.flags @@ -765,7 +765,7 @@ class Glyph(object): move = x1-x2, y1-y2 else: move = compo.x, compo.y - + coordinates = GlyphCoordinates(coordinates) if not hasattr(compo, "transform"): coordinates.translate(move) @@ -962,14 +962,14 @@ class Glyph(object): class GlyphComponent(object): - + def __init__(self): pass - + def getComponentInfo(self): """Return the base glyph name and a transform.""" # XXX Ignoring self.firstPt & self.lastpt for now: I need to implement - # something equivalent in fontTools.objects.glyph (I'd rather not + # something equivalent in fontTools.objects.glyph (I'd rather not # convert it to an absolute offset, since it is valuable information). # This method will now raise "AttributeError: x" on glyphs that use # this TT feature. @@ -979,7 +979,7 @@ class GlyphComponent(object): else: trans = (1, 0, 0, 1, self.x, self.y) return self.glyphName, trans - + def decompile(self, data, glyfTable): flags, glyphID = struct.unpack(">HH", data[:4]) self.flags = int(flags) @@ -987,7 +987,7 @@ class GlyphComponent(object): self.glyphName = glyfTable.getGlyphName(int(glyphID)) #print ">>", reprflag(self.flags) data = data[4:] - + if self.flags & ARG_1_AND_2_ARE_WORDS: if self.flags & ARGS_ARE_XY_VALUES: self.x, self.y = struct.unpack(">hh", data[:4]) @@ -1002,7 +1002,7 @@ class GlyphComponent(object): x, y = struct.unpack(">BB", data[:2]) self.firstPt, self.secondPt = int(x), int(y) data = data[2:] - + if self.flags & WE_HAVE_A_SCALE: scale, = struct.unpack(">h", data[:2]) self.transform = [[fi2fl(scale,14), 0], [0, fi2fl(scale,14)]] # fixed 2.14 @@ -1012,30 +1012,30 @@ class GlyphComponent(object): self.transform = [[fi2fl(xscale,14), 0], [0, fi2fl(yscale,14)]] # fixed 2.14 data = data[4:] elif self.flags & WE_HAVE_A_TWO_BY_TWO: - (xscale, scale01, + (xscale, scale01, scale10, yscale) = struct.unpack(">hhhh", data[:8]) self.transform = [[fi2fl(xscale,14), fi2fl(scale01,14)], [fi2fl(scale10,14), fi2fl(yscale,14)]] # fixed 2.14 data = data[8:] more = self.flags & MORE_COMPONENTS haveInstructions = self.flags & WE_HAVE_INSTRUCTIONS - self.flags = self.flags & (ROUND_XY_TO_GRID | USE_MY_METRICS | + self.flags = self.flags & (ROUND_XY_TO_GRID | USE_MY_METRICS | SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET | NON_OVERLAPPING) return more, haveInstructions, data - + def compile(self, more, haveInstructions, glyfTable): data = b"" - + # reset all flags we will calculate ourselves - flags = self.flags & (ROUND_XY_TO_GRID | USE_MY_METRICS | + flags = self.flags & (ROUND_XY_TO_GRID | USE_MY_METRICS | SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET | NON_OVERLAPPING) if more: flags = flags | MORE_COMPONENTS if haveInstructions: flags = flags | WE_HAVE_INSTRUCTIONS - + if hasattr(self, "firstPt"): if (0 <= self.firstPt <= 255) and (0 <= self.secondPt <= 255): data = data + struct.pack(">BB", self.firstPt, self.secondPt) @@ -1049,33 +1049,33 @@ class GlyphComponent(object): else: data = data + struct.pack(">hh", self.x, self.y) flags = flags | ARG_1_AND_2_ARE_WORDS - + if hasattr(self, "transform"): transform = [[fl2fi(x,14) for x in row] for row in self.transform] if transform[0][1] or transform[1][0]: flags = flags | WE_HAVE_A_TWO_BY_TWO - data = data + struct.pack(">hhhh", + data = data + struct.pack(">hhhh", transform[0][0], transform[0][1], transform[1][0], transform[1][1]) elif transform[0][0] != transform[1][1]: flags = flags | WE_HAVE_AN_X_AND_Y_SCALE - data = data + struct.pack(">hh", + data = data + struct.pack(">hh", transform[0][0], transform[1][1]) else: flags = flags | WE_HAVE_A_SCALE - data = data + struct.pack(">h", + data = data + struct.pack(">h", transform[0][0]) - + glyphID = glyfTable.getGlyphID(self.glyphName) return struct.pack(">HH", flags, glyphID) + data - + def toXML(self, writer, ttFont): attrs = [("glyphName", self.glyphName)] if not hasattr(self, "firstPt"): attrs = attrs + [("x", self.x), ("y", self.y)] else: attrs = attrs + [("firstPt", self.firstPt), ("secondPt", self.secondPt)] - + if hasattr(self, "transform"): transform = self.transform if transform[0][1] or transform[1][0]: @@ -1092,7 +1092,7 @@ class GlyphComponent(object): attrs = attrs + [("flags", hex(self.flags))] writer.simpletag("component", attrs) writer.newline() - + def fromXML(self, name, attrs, content, ttFont): self.glyphName = attrs["glyphName"] if "firstPt" in attrs: @@ -1115,7 +1115,7 @@ class GlyphComponent(object): scale = safeEval(attrs["scale"]) self.transform = [[scale, 0], [0, scale]] self.flags = safeEval(attrs["flags"]) - + def __ne__(self, other): return not self.__eq__(other) def __eq__(self, other): diff --git a/Lib/fontTools/ttLib/tables/_h_d_m_x.py b/Lib/fontTools/ttLib/tables/_h_d_m_x.py index a26afea97..3499a8f75 100644 --- a/Lib/fontTools/ttLib/tables/_h_d_m_x.py +++ b/Lib/fontTools/ttLib/tables/_h_d_m_x.py @@ -11,7 +11,7 @@ hdmxHeaderFormat = """ """ class table__h_d_m_x(DefaultTable.DefaultTable): - + def decompile(self, data, ttFont): numGlyphs = ttFont['maxp'].numGlyphs glyphOrder = ttFont.getGlyphOrder() @@ -26,7 +26,7 @@ class table__h_d_m_x(DefaultTable.DefaultTable): self.hdmx[ppem] = widths data = data[self.recordSize:] assert len(data) == 0, "too much hdmx data" - + def compile(self, ttFont): self.version = 0 numGlyphs = ttFont['maxp'].numGlyphs @@ -43,7 +43,7 @@ class table__h_d_m_x(DefaultTable.DefaultTable): data = data + bytechr(width) data = data + pad return data - + def toXML(self, writer, ttFont): writer.begintag("hdmxData") writer.newline() @@ -72,7 +72,7 @@ class table__h_d_m_x(DefaultTable.DefaultTable): writer.newline() writer.endtag("hdmxData") writer.newline() - + def fromXML(self, name, attrs, content, ttFont): if name != "hdmxData": return diff --git a/Lib/fontTools/ttLib/tables/_h_e_a_d.py b/Lib/fontTools/ttLib/tables/_h_e_a_d.py index 02ddf12c1..fd057b5a7 100644 --- a/Lib/fontTools/ttLib/tables/_h_e_a_d.py +++ b/Lib/fontTools/ttLib/tables/_h_e_a_d.py @@ -30,9 +30,9 @@ headFormat = """ """ class table__h_e_a_d(DefaultTable.DefaultTable): - + dependencies = ['maxp', 'loca'] - + def decompile(self, data, ttFont): dummy, rest = sstruct.unpack2(headFormat, data, self) if rest: @@ -55,13 +55,13 @@ class table__h_e_a_d(DefaultTable.DefaultTable): warnings.warn("'%s' timestamp seems very low; regarding as unix timestamp" % stamp) value += 0x7C259DC0 setattr(self, stamp, value) - + def compile(self, ttFont): if ttFont.recalcTimestamp: self.modified = timestampNow() data = sstruct.pack(headFormat, self) return data - + def toXML(self, writer, ttFont): writer.comment("Most of this table will be recalculated by the compiler") writer.newline() @@ -80,7 +80,7 @@ class table__h_e_a_d(DefaultTable.DefaultTable): value = num2binary(value, 16) writer.simpletag(name, value=value) writer.newline() - + def fromXML(self, name, attrs, content, ttFont): value = attrs["value"] if name in ("created", "modified"): diff --git a/Lib/fontTools/ttLib/tables/_h_h_e_a.py b/Lib/fontTools/ttLib/tables/_h_h_e_a.py index 14cfe2fd5..8cf178081 100644 --- a/Lib/fontTools/ttLib/tables/_h_h_e_a.py +++ b/Lib/fontTools/ttLib/tables/_h_h_e_a.py @@ -31,15 +31,15 @@ class table__h_h_e_a(DefaultTable.DefaultTable): # Note: Keep in sync with table__v_h_e_a dependencies = ['hmtx', 'glyf'] - + def decompile(self, data, ttFont): sstruct.unpack(hheaFormat, data, self) - + def compile(self, ttFont): if ttFont.isLoaded('glyf') and ttFont.recalcBBoxes: self.recalc(ttFont) return sstruct.pack(hheaFormat, self) - + def recalc(self, ttFont): hmtxTable = ttFont['hmtx'] if 'glyf' in ttFont: @@ -79,13 +79,13 @@ class table__h_h_e_a(DefaultTable.DefaultTable): else: # XXX CFF recalc... pass - + def toXML(self, writer, ttFont): formatstring, names, fixes = sstruct.getformat(hheaFormat) for name in names: value = getattr(self, name) writer.simpletag(name, value=value) writer.newline() - + def fromXML(self, name, attrs, content, ttFont): setattr(self, name, safeEval(attrs["value"])) diff --git a/Lib/fontTools/ttLib/tables/_h_m_t_x.py b/Lib/fontTools/ttLib/tables/_h_m_t_x.py index 8b9b99e79..1746439c4 100644 --- a/Lib/fontTools/ttLib/tables/_h_m_t_x.py +++ b/Lib/fontTools/ttLib/tables/_h_m_t_x.py @@ -8,12 +8,12 @@ import warnings class table__h_m_t_x(DefaultTable.DefaultTable): - + headerTag = 'hhea' advanceName = 'width' sideBearingName = 'lsb' numberOfMetricsName = 'numberOfHMetrics' - + def decompile(self, data, ttFont): numGlyphs = ttFont['maxp'].numGlyphs numberOfMetrics = int(getattr(ttFont[self.headerTag], self.numberOfMetricsName)) @@ -41,7 +41,7 @@ class table__h_m_t_x(DefaultTable.DefaultTable): for i in range(numberOfSideBearings): glyphName = glyphOrder[i + numberOfMetrics] self.metrics[glyphName] = [lastAdvance, sideBearings[i]] - + def compile(self, ttFont): metrics = [] for glyphName in ttFont.getGlyphOrder(): @@ -58,7 +58,7 @@ class table__h_m_t_x(DefaultTable.DefaultTable): additionalMetrics = [sb for advance, sb in additionalMetrics] metrics = metrics[:lastIndex] setattr(ttFont[self.headerTag], self.numberOfMetricsName, len(metrics)) - + allMetrics = [] for item in metrics: allMetrics.extend(item) @@ -66,36 +66,36 @@ class table__h_m_t_x(DefaultTable.DefaultTable): if sys.byteorder != "big": allMetrics.byteswap() data = allMetrics.tostring() - + additionalMetrics = array.array("h", additionalMetrics) if sys.byteorder != "big": additionalMetrics.byteswap() data = data + additionalMetrics.tostring() return data - + def toXML(self, writer, ttFont): names = sorted(self.metrics.keys()) for glyphName in names: advance, sb = self.metrics[glyphName] writer.simpletag("mtx", [ - ("name", glyphName), - (self.advanceName, advance), + ("name", glyphName), + (self.advanceName, advance), (self.sideBearingName, sb), ]) writer.newline() - + def fromXML(self, name, attrs, content, ttFont): if not hasattr(self, "metrics"): self.metrics = {} if name == "mtx": - self.metrics[attrs["name"]] = [safeEval(attrs[self.advanceName]), + self.metrics[attrs["name"]] = [safeEval(attrs[self.advanceName]), safeEval(attrs[self.sideBearingName])] def __delitem__(self, glyphName): del self.metrics[glyphName] - + def __getitem__(self, glyphName): return self.metrics[glyphName] - + def __setitem__(self, glyphName, advance_sb_pair): self.metrics[glyphName] = tuple(advance_sb_pair) diff --git a/Lib/fontTools/ttLib/tables/_k_e_r_n.py b/Lib/fontTools/ttLib/tables/_k_e_r_n.py index bc633d77e..ae62f792e 100644 --- a/Lib/fontTools/ttLib/tables/_k_e_r_n.py +++ b/Lib/fontTools/ttLib/tables/_k_e_r_n.py @@ -9,13 +9,13 @@ import warnings class table__k_e_r_n(DefaultTable.DefaultTable): - + def getkern(self, format): for subtable in self.kernTables: if subtable.version == format: return subtable return None # not found - + def decompile(self, data, ttFont): version, nTables = struct.unpack(">HH", data[:4]) apple = False @@ -46,7 +46,7 @@ class table__k_e_r_n(DefaultTable.DefaultTable): subtable.decompile(data[:length], ttFont) self.kernTables.append(subtable) data = data[length:] - + def compile(self, ttFont): if hasattr(self, "kernTables"): nTables = len(self.kernTables) @@ -61,13 +61,13 @@ class table__k_e_r_n(DefaultTable.DefaultTable): for subtable in self.kernTables: data = data + subtable.compile(ttFont) return data - + def toXML(self, writer, ttFont): writer.simpletag("version", value=self.version) writer.newline() for subtable in self.kernTables: subtable.toXML(writer, ttFont) - + def fromXML(self, name, attrs, content, ttFont): if name == "version": self.version = safeEval(attrs["value"]) @@ -86,7 +86,7 @@ class table__k_e_r_n(DefaultTable.DefaultTable): class KernTable_format_0(object): - + def decompile(self, data, ttFont): version, length, coverage = (0,0,0) if not self.apple: @@ -96,12 +96,12 @@ class KernTable_format_0(object): version, length, coverage = struct.unpack(">LHH", data[:8]) data = data[8:] self.version, self.coverage = int(version), int(coverage) - + self.kernTable = kernTable = {} - + nPairs, searchRange, entrySelector, rangeShift = struct.unpack(">HHHH", data[:8]) data = data[8:] - + for k in range(nPairs): if len(data) < 6: # buggy kern table @@ -113,19 +113,19 @@ class KernTable_format_0(object): kernTable[(ttFont.getGlyphName(left), ttFont.getGlyphName(right))] = value if len(data): warnings.warn("excess data in 'kern' subtable: %d bytes" % len(data)) - + def compile(self, ttFont): nPairs = len(self.kernTable) searchRange, entrySelector, rangeShift = getSearchRange(nPairs, 6) data = struct.pack(">HHHH", nPairs, searchRange, entrySelector, rangeShift) - + # yeehee! (I mean, turn names into indices) getGlyphID = ttFont.getGlyphID kernTable = sorted((getGlyphID(left), getGlyphID(right), value) for ((left,right),value) in self.kernTable.items()) for left, right, value in kernTable: data = data + struct.pack(">HHh", left, right, value) return struct.pack(">HHH", self.version, len(data) + 6, self.coverage) + data - + def toXML(self, writer, ttFont): writer.begintag("kernsubtable", coverage=self.coverage, format=0) writer.newline() @@ -139,7 +139,7 @@ class KernTable_format_0(object): writer.newline() writer.endtag("kernsubtable") writer.newline() - + def fromXML(self, name, attrs, content, ttFont): self.coverage = safeEval(attrs["coverage"]) self.version = safeEval(attrs["format"]) @@ -150,28 +150,28 @@ class KernTable_format_0(object): continue name, attrs, content = element self.kernTable[(attrs["l"], attrs["r"])] = safeEval(attrs["v"]) - + def __getitem__(self, pair): return self.kernTable[pair] - + def __setitem__(self, pair, value): self.kernTable[pair] = value - + def __delitem__(self, pair): del self.kernTable[pair] class KernTable_format_unkown(object): - + def __init__(self, format): self.format = format - + def decompile(self, data, ttFont): self.data = data - + def compile(self, ttFont): return self.data - + def toXML(self, writer, ttFont): writer.begintag("kernsubtable", format=self.format) writer.newline() @@ -180,7 +180,7 @@ class KernTable_format_unkown(object): writer.dumphex(self.data) writer.endtag("kernsubtable") writer.newline() - + def fromXML(self, name, attrs, content, ttFont): self.decompile(readHex(content), ttFont) diff --git a/Lib/fontTools/ttLib/tables/_l_o_c_a.py b/Lib/fontTools/ttLib/tables/_l_o_c_a.py index aaa8d1f0a..72849cbb8 100644 --- a/Lib/fontTools/ttLib/tables/_l_o_c_a.py +++ b/Lib/fontTools/ttLib/tables/_l_o_c_a.py @@ -6,9 +6,9 @@ import array import warnings class table__l_o_c_a(DefaultTable.DefaultTable): - + dependencies = ['glyf'] - + def decompile(self, data, ttFont): longFormat = ttFont['head'].indexToLocFormat if longFormat: @@ -27,7 +27,7 @@ class table__l_o_c_a(DefaultTable.DefaultTable): if len(locations) < (ttFont['maxp'].numGlyphs + 1): warnings.warn("corrupt 'loca' table, or wrong numGlyphs in 'maxp': %d %d" % (len(locations) - 1, ttFont['maxp'].numGlyphs)) self.locations = locations - + def compile(self, ttFont): try: max_location = max(self.locations) @@ -45,16 +45,16 @@ class table__l_o_c_a(DefaultTable.DefaultTable): if sys.byteorder != "big": locations.byteswap() return locations.tostring() - + def set(self, locations): self.locations = array.array("I", locations) - + def toXML(self, writer, ttFont): writer.comment("The 'loca' table will be calculated by the compiler") writer.newline() - + def __getitem__(self, index): return self.locations[index] - + def __len__(self): return len(self.locations) diff --git a/Lib/fontTools/ttLib/tables/_m_a_x_p.py b/Lib/fontTools/ttLib/tables/_m_a_x_p.py index 4f360ffe8..f318a6a5f 100644 --- a/Lib/fontTools/ttLib/tables/_m_a_x_p.py +++ b/Lib/fontTools/ttLib/tables/_m_a_x_p.py @@ -29,16 +29,16 @@ maxpFormat_1_0_add = """ class table__m_a_x_p(DefaultTable.DefaultTable): - + dependencies = ['glyf'] - + def decompile(self, data, ttFont): dummy, data = sstruct.unpack2(maxpFormat_0_5, data, self) self.numGlyphs = int(self.numGlyphs) if self.tableVersion != 0x00005000: dummy, data = sstruct.unpack2(maxpFormat_1_0_add, data, self) assert len(data) == 0 - + def compile(self, ttFont): if 'glyf' in ttFont: if ttFont.isLoaded('glyf') and ttFont.recalcBBoxes: @@ -52,7 +52,7 @@ class table__m_a_x_p(DefaultTable.DefaultTable): if self.tableVersion == 0x00010000: data = data + sstruct.pack(maxpFormat_1_0_add, self) return data - + def recalc(self, ttFont): """Recalculate the font bounding box, and most other maxp values except for the TT instructions values. Also recalculate the value of bit 1 @@ -112,14 +112,14 @@ class table__m_a_x_p(DefaultTable.DefaultTable): headTable.flags = headTable.flags | 0x2 else: headTable.flags = headTable.flags & ~0x2 - + def testrepr(self): items = sorted(self.__dict__.items()) print(". . . . . . . . .") for combo in items: print(" %s: %s" % combo) print(". . . . . . . . .") - + def toXML(self, writer, ttFont): if self.tableVersion != 0x00005000: writer.comment("Most of this table will be recalculated by the compiler") @@ -134,6 +134,6 @@ class table__m_a_x_p(DefaultTable.DefaultTable): value = hex(value) writer.simpletag(name, value=value) writer.newline() - + def fromXML(self, name, attrs, content, ttFont): setattr(self, name, safeEval(attrs["value"])) diff --git a/Lib/fontTools/ttLib/tables/_n_a_m_e.py b/Lib/fontTools/ttLib/tables/_n_a_m_e.py index 5bc7f812f..32a35635e 100644 --- a/Lib/fontTools/ttLib/tables/_n_a_m_e.py +++ b/Lib/fontTools/ttLib/tables/_n_a_m_e.py @@ -20,7 +20,7 @@ nameRecordSize = sstruct.calcsize(nameRecordFormat) class table__n_a_m_e(DefaultTable.DefaultTable): - + def decompile(self, data, ttFont): format, n, stringOffset = struct.unpack(">HHH", data[:6]) expectedStringOffset = 6 + n * nameRecordSize @@ -43,7 +43,7 @@ class table__n_a_m_e(DefaultTable.DefaultTable): # print name.__dict__ del name.offset, name.length self.names.append(name) - + def compile(self, ttFont): if not hasattr(self, "names"): # only happens when there are NO name table entries read @@ -67,11 +67,11 @@ class table__n_a_m_e(DefaultTable.DefaultTable): stringData = bytesjoin([stringData, string]) data = data + sstruct.pack(nameRecordFormat, name) return data + stringData - + def toXML(self, writer, ttFont): for name in self.names: name.toXML(writer, ttFont) - + def fromXML(self, name, attrs, content, ttFont): if name != "namerecord": return # ignore unknown tags @@ -80,11 +80,11 @@ class table__n_a_m_e(DefaultTable.DefaultTable): name = NameRecord() self.names.append(name) name.fromXML(name, attrs, content, ttFont) - + def getName(self, nameID, platformID, platEncID, langID=None): for namerecord in self.names: - if ( namerecord.nameID == nameID and - namerecord.platformID == platformID and + if ( namerecord.nameID == nameID and + namerecord.platformID == platformID and namerecord.platEncID == platEncID): if langID is None or namerecord.langID == langID: return namerecord @@ -202,7 +202,7 @@ class NameRecord(object): writer.newline() writer.endtag("namerecord") writer.newline() - + def fromXML(self, name, attrs, content, ttFont): self.nameID = safeEval(attrs["nameID"]) self.platformID = safeEval(attrs["platformID"]) @@ -215,7 +215,7 @@ class NameRecord(object): else: # This is the inverse of write8bit... self.string = s.encode("latin1") - + def __lt__(self, other): if type(self) != type(other): return NotImplemented @@ -236,7 +236,7 @@ class NameRecord(object): getattr(other, "string", None), ) return selfTuple < otherTuple - + def __repr__(self): return "" % ( self.nameID, self.platformID, self.langID) diff --git a/Lib/fontTools/ttLib/tables/_p_o_s_t.py b/Lib/fontTools/ttLib/tables/_p_o_s_t.py index 411af9fd8..d4d217c91 100644 --- a/Lib/fontTools/ttLib/tables/_p_o_s_t.py +++ b/Lib/fontTools/ttLib/tables/_p_o_s_t.py @@ -13,7 +13,7 @@ import array postFormat = """ > formatType: 16.16F - italicAngle: 16.16F # italic angle in degrees + italicAngle: 16.16F # italic angle in degrees underlinePosition: h underlineThickness: h isFixedPitch: L @@ -27,7 +27,7 @@ postFormatSize = sstruct.calcsize(postFormat) class table__p_o_s_t(DefaultTable.DefaultTable): - + def decompile(self, data, ttFont): sstruct.unpack(postFormat, data[:postFormatSize], self) data = data[postFormatSize:] @@ -42,7 +42,7 @@ class table__p_o_s_t(DefaultTable.DefaultTable): else: # supported format raise ttLib.TTLibError("'post' table format %f not supported" % self.formatType) - + def compile(self, ttFont): data = sstruct.pack(postFormat, self) if self.formatType == 1.0: @@ -57,7 +57,7 @@ class table__p_o_s_t(DefaultTable.DefaultTable): # supported format raise ttLib.TTLibError("'post' table format %f not supported" % self.formatType) return data - + def getGlyphOrder(self): """This function will get called by a ttLib.TTFont instance. Do not call this function yourself, use TTFont().getGlyphOrder() @@ -68,10 +68,10 @@ class table__p_o_s_t(DefaultTable.DefaultTable): glyphOrder = self.glyphOrder del self.glyphOrder return glyphOrder - + def decode_format_1_0(self, data, ttFont): self.glyphOrder = standardGlyphOrder[:ttFont["maxp"].numGlyphs] - + def decode_format_2_0(self, data, ttFont): numGlyphs, = struct.unpack(">H", data[:2]) numGlyphs = int(numGlyphs) @@ -103,7 +103,7 @@ class table__p_o_s_t(DefaultTable.DefaultTable): name = standardGlyphOrder[index] glyphOrder[glyphID] = name self.build_psNameMapping(ttFont) - + def build_psNameMapping(self, ttFont): mapping = {} allNames = {} @@ -125,12 +125,12 @@ class table__p_o_s_t(DefaultTable.DefaultTable): mapping[glyphName] = psName self.mapping = mapping - + def decode_format_3_0(self, data, ttFont): # Setting self.glyphOrder to None will cause the TTFont object # try and construct glyph names from a Unicode cmap table. self.glyphOrder = None - + def decode_format_4_0(self, data, ttFont): from fontTools import agl numGlyphs = ttFont['maxp'].numGlyphs @@ -178,7 +178,7 @@ class table__p_o_s_t(DefaultTable.DefaultTable): if sys.byteorder != "big": indices.byteswap() return struct.pack(">H", numGlyphs) + indices.tostring() + packPStrings(extraNames) - + def encode_format_4_0(self, ttFont): from fontTools import agl numGlyphs = ttFont['maxp'].numGlyphs @@ -235,7 +235,7 @@ class table__p_o_s_t(DefaultTable.DefaultTable): writer.dumphex(self.data) writer.endtag("hexdata") writer.newline() - + def fromXML(self, name, attrs, content, ttFont): if name not in ("psNames", "extraNames", "hexdata"): setattr(self, name, safeEval(attrs["value"])) diff --git a/Lib/fontTools/ttLib/tables/_v_h_e_a.py b/Lib/fontTools/ttLib/tables/_v_h_e_a.py index 245fbf3bd..79f4d7637 100644 --- a/Lib/fontTools/ttLib/tables/_v_h_e_a.py +++ b/Lib/fontTools/ttLib/tables/_v_h_e_a.py @@ -30,14 +30,14 @@ class table__v_h_e_a(DefaultTable.DefaultTable): # Note: Keep in sync with table__h_h_e_a dependencies = ['vmtx', 'glyf'] - + def decompile(self, data, ttFont): sstruct.unpack(vheaFormat, data, self) - + def compile(self, ttFont): self.recalc(ttFont) return sstruct.pack(vheaFormat, self) - + def recalc(self, ttFont): vtmxTable = ttFont['vmtx'] if 'glyf' in ttFont: @@ -77,13 +77,13 @@ class table__v_h_e_a(DefaultTable.DefaultTable): else: # XXX CFF recalc... pass - + def toXML(self, writer, ttFont): formatstring, names, fixes = sstruct.getformat(vheaFormat) for name in names: value = getattr(self, name) writer.simpletag(name, value=value) writer.newline() - + def fromXML(self, name, attrs, content, ttFont): setattr(self, name, safeEval(attrs["value"])) diff --git a/Lib/fontTools/ttLib/tables/_v_m_t_x.py b/Lib/fontTools/ttLib/tables/_v_m_t_x.py index 2ac497ded..5573225c1 100644 --- a/Lib/fontTools/ttLib/tables/_v_m_t_x.py +++ b/Lib/fontTools/ttLib/tables/_v_m_t_x.py @@ -5,7 +5,7 @@ from fontTools import ttLib superclass = ttLib.getTableClass("hmtx") class table__v_m_t_x(superclass): - + headerTag = 'vhea' advanceName = 'height' sideBearingName = 'tsb' diff --git a/Lib/fontTools/ttLib/tables/asciiTable.py b/Lib/fontTools/ttLib/tables/asciiTable.py index 69adf7c25..514174879 100644 --- a/Lib/fontTools/ttLib/tables/asciiTable.py +++ b/Lib/fontTools/ttLib/tables/asciiTable.py @@ -4,7 +4,7 @@ from . import DefaultTable class asciiTable(DefaultTable.DefaultTable): - + def toXML(self, writer, ttFont): data = tostr(self.data) # removing null bytes. XXX needed?? @@ -16,7 +16,7 @@ class asciiTable(DefaultTable.DefaultTable): writer.newline() writer.endtag("source") writer.newline() - + def fromXML(self, name, attrs, content, ttFont): lines = strjoin(content).replace("\r", "\n").split("\n") self.data = tobytes("\r".join(lines[1:-1])) diff --git a/Lib/fontTools/ttLib/tables/otBase.py b/Lib/fontTools/ttLib/tables/otBase.py index aec1e0ecb..0c26b467a 100644 --- a/Lib/fontTools/ttLib/tables/otBase.py +++ b/Lib/fontTools/ttLib/tables/otBase.py @@ -23,12 +23,12 @@ class OTLOffsetOverflowError(Exception): class BaseTTXConverter(DefaultTable): - + """Generic base class for TTX table converters. It functions as an adapter between the TTX (ttLib actually) table model and the model we use for OpenType tables, which is necessarily subtly different. """ - + def decompile(self, data, font): from . import otTables cachingStats = None if True else {} @@ -51,15 +51,15 @@ class BaseTTXConverter(DefaultTable): break print(v, k) print("---", len(stats)) - + def compile(self, font): """ Create a top-level OTFWriter for the GPOS/GSUB table. Call the compile method for the the table for each 'converter' record in the table converter list - call converter's write method for each item in the value. + call converter's write method for each item in the value. - For simple items, the write method adds a string to the - writer's self.items list. - - For Struct/Table/Subtable items, it add first adds new writer to the + writer's self.items list. + - For Struct/Table/Subtable items, it add first adds new writer to the to the writer's self.items, then calls the item's compile method. This creates a tree of writers, rooted at the GUSB/GPOS writer, with each writer representing a table, and the writer.items list containing @@ -71,7 +71,7 @@ class BaseTTXConverter(DefaultTable): Traverse the flat list of tables again, calling getData each get the data in the table, now that pos's and offset are known. - If a lookup subtable overflows an offset, we have to start all over. + If a lookup subtable overflows an offset, we have to start all over. """ class GlobalState(object): def __init__(self, tableType): @@ -106,7 +106,7 @@ class BaseTTXConverter(DefaultTable): def toXML(self, writer, font): self.table.toXML2(writer, font) - + def fromXML(self, name, attrs, content, font): from . import otTables if not hasattr(self, "table"): @@ -169,7 +169,7 @@ class OTTableReader(object): value, = struct.unpack(">L", self.data[pos:newpos]) self.pos = newpos return value - + def readTag(self): pos = self.pos newpos = pos + 4 @@ -188,9 +188,9 @@ class OTTableReader(object): class OTTableWriter(object): - + """Helper class to gather and assemble data for OpenType tables.""" - + def __init__(self, globalState, localState=None): self.items = [] self.pos = None @@ -207,7 +207,7 @@ class OTTableWriter(object): return self.localState[name] # assembler interface - + def getAllData(self): """Assemble all data, including all subtables.""" self._doneWriting() @@ -235,7 +235,7 @@ class OTTableWriter(object): data.append(tableData) return bytesjoin(data) - + def getDataLength(self): """Return the length of this table in bytes, without subtables.""" l = 0 @@ -248,7 +248,7 @@ class OTTableWriter(object): else: l = l + len(item) return l - + def getData(self): """Assemble the data for this writer/table, without subtables.""" items = list(self.items) # make a shallow copy @@ -256,7 +256,7 @@ class OTTableWriter(object): numItems = len(items) for i in range(numItems): item = items[i] - + if hasattr(item, "getData"): if item.longOffset: items[i] = packULong(item.pos - pos) @@ -271,7 +271,7 @@ class OTTableWriter(object): # overflow is within a subTable. Life is more complicated. # If we split the sub-table just before the current item, we may still suffer overflow. # This is because duplicate table merging is done only within an Extension subTable tree; - # when we split the subtable in two, some items may no longer be duplicates. + # when we split the subtable in two, some items may no longer be duplicates. # Get worst case by adding up all the item lengths, depth first traversal. # and then report the first item that overflows a short. def getDeepItemLength(table): @@ -282,36 +282,36 @@ class OTTableWriter(object): else: length = len(table) return length - + length = self.getDataLength() if hasattr(self, "sortCoverageLast") and item.name == "Coverage": # Coverage is first in the item list, but last in the table list, - # The original overflow is really in the item list. Skip the Coverage + # The original overflow is really in the item list. Skip the Coverage # table in the following test. items = items[i+1:] - + for j in range(len(items)): item = items[j] length = length + getDeepItemLength(item) if length > 65535: break overflowErrorRecord = self.getOverflowErrorRecord(item) - + raise OTLOffsetOverflowError(overflowErrorRecord) return bytesjoin(items) - + def __hash__(self): # only works after self._doneWriting() has been called return hash(self.items) - + def __ne__(self, other): return not self.__eq__(other) def __eq__(self, other): if type(self) != type(other): return NotImplemented return self.items == other.items - + def _doneWriting(self, internedTables=None): # Convert CountData references to data string items # collapse duplicate table references to a unique entry @@ -324,7 +324,7 @@ class OTTableWriter(object): internedTables = {} items = self.items iRange = list(range(len(items))) - + if hasattr(self, "Extension"): newTree = 1 else: @@ -344,12 +344,12 @@ class OTTableWriter(object): else: internedTables[item] = item self.items = tuple(items) - + def _gatherTables(self, tables=None, extTables=None, done=None): # Convert table references in self.items tree to a flat # list of tables in depth-first traversal order. # "tables" are OTTableWriter objects. - # We do the traversal in reverse order at each level, in order to + # We do the traversal in reverse order at each level, in order to # resolve duplicate references to be the last reference in the list of tables. # For extension lookups, duplicate references can be merged only within the # writer tree under the extension lookup. @@ -406,9 +406,9 @@ class OTTableWriter(object): tables.append(self) return tables, extTables - + # interface for gathering data, as used by table.compile() - + def getSubWriter(self): subwriter = self.__class__(self.globalState, self.localState) subwriter.parent = self # because some subtables have idential values, we discard @@ -416,11 +416,11 @@ class OTTableWriter(object): # subtable writers can have more than one parent writer. # But we just care about first one right now. return subwriter - + def writeUShort(self, value): assert 0 <= value < 0x10000 self.items.append(struct.pack(">H", value)) - + def writeShort(self, value): self.items.append(struct.pack(">h", value)) @@ -428,30 +428,30 @@ class OTTableWriter(object): assert 0 <= value < 0x1000000 b = struct.pack(">L", value) self.items.append(b[1:]) - + def writeLong(self, value): self.items.append(struct.pack(">l", value)) - + def writeULong(self, value): self.items.append(struct.pack(">L", value)) - + def writeTag(self, tag): tag = Tag(tag).tobytes() assert len(tag) == 4 self.items.append(tag) - + def writeSubTable(self, subWriter): self.items.append(subWriter) - + def writeCountReference(self, table, name): ref = CountReference(table, name) self.items.append(ref) return ref - + def writeStruct(self, format, values): data = struct.pack(*(format,) + values) self.items.append(data) - + def writeData(self, data): self.items.append(data) @@ -528,13 +528,13 @@ class BaseTable(object): raise AttributeError(attr) """Generic base class for all OpenType (sub)tables.""" - + def getConverters(self): return self.converters - + def getConverterByName(self, name): return self.convertersByName[name] - + def decompile(self, reader, font): self.readFormat(reader) table = {} @@ -624,19 +624,19 @@ class BaseTable(object): conv.write(writer, font, table, value) if conv.isPropagated: writer[conv.name] = value - + def readFormat(self, reader): pass - + def writeFormat(self, writer): pass - + def postRead(self, table, font): self.__dict__.update(table) - + def preWrite(self, font): return self.__dict__.copy() - + def toXML(self, xmlWriter, font, attrs=None, name=None): tableName = name if name else self.__class__.__name__ if attrs is None: @@ -648,7 +648,7 @@ class BaseTable(object): self.toXML2(xmlWriter, font) xmlWriter.endtag(tableName) xmlWriter.newline() - + def toXML2(self, xmlWriter, font): # Simpler variant of toXML, *only* for the top level tables (like GPOS, GSUB). # This is because in TTX our parent writes our main tag, and in otBase.py we @@ -665,7 +665,7 @@ class BaseTable(object): continue value = getattr(self, conv.name) conv.xmlWrite(xmlWriter, font, value, conv.name, []) - + def fromXML(self, name, attrs, content, font): try: conv = self.getConverterByName(name) @@ -680,7 +680,7 @@ class BaseTable(object): seq.append(value) else: setattr(self, conv.name, value) - + def __ne__(self, other): return not self.__eq__(other) def __eq__(self, other): @@ -694,20 +694,20 @@ class BaseTable(object): class FormatSwitchingBaseTable(BaseTable): - + """Minor specialization of BaseTable, for tables that have multiple formats, eg. CoverageFormat1 vs. CoverageFormat2.""" - + def getConverters(self): return self.converters[self.Format] - + def getConverterByName(self, name): return self.convertersByName[self.Format][name] - + def readFormat(self, reader): self.Format = reader.readUShort() assert self.Format != 0, (self, reader.pos, len(reader.data)) - + def writeFormat(self, writer): writer.writeUShort(self.Format) @@ -754,7 +754,7 @@ valueRecordFormatDict = _buildDict() class ValueRecordFactory(object): - + """Given a format code, this object convert ValueRecords.""" def __init__(self, valueFormat): @@ -763,7 +763,7 @@ class ValueRecordFactory(object): if valueFormat & mask: format.append((name, isDevice, signed)) self.format = format - + def readValueRecord(self, reader, font): format = self.format if not format: @@ -784,7 +784,7 @@ class ValueRecordFactory(object): value = None setattr(valueRecord, name, value) return valueRecord - + def writeValueRecord(self, writer, font, valueRecord): for name, isDevice, signed in self.format: value = getattr(valueRecord, name, 0) @@ -802,15 +802,15 @@ class ValueRecordFactory(object): class ValueRecord(object): - + # see ValueRecordFactory - + def getFormat(self): format = 0 for name in self.__dict__.keys(): format = format | valueRecordFormatDict[name][0] return format - + def toXML(self, xmlWriter, font, valueName, attrs=None): if attrs is None: simpleItems = [] @@ -836,7 +836,7 @@ class ValueRecord(object): else: xmlWriter.simpletag(valueName, simpleItems) xmlWriter.newline() - + def fromXML(self, name, attrs, content, font): from . import otTables for k, v in attrs.items(): @@ -852,7 +852,7 @@ class ValueRecord(object): name2, attrs2, content2 = elem2 value.fromXML(name2, attrs2, content2, font) setattr(self, name, value) - + def __ne__(self, other): return not self.__eq__(other) def __eq__(self, other): diff --git a/Lib/fontTools/ttLib/tables/otConverters.py b/Lib/fontTools/ttLib/tables/otConverters.py index aa0ee80a5..a683b3d41 100644 --- a/Lib/fontTools/ttLib/tables/otConverters.py +++ b/Lib/fontTools/ttLib/tables/otConverters.py @@ -51,10 +51,10 @@ def buildConverters(tableSpec, tableNamespace): class BaseConverter(object): - + """Base class for converter objects. Apart from the constructor, this is an abstract class.""" - + def __init__(self, name, repeat, aux, tableClass): self.name = name self.repeat = repeat @@ -63,19 +63,19 @@ class BaseConverter(object): self.isCount = name.endswith("Count") self.isLookupType = name.endswith("LookupType") self.isPropagated = name in ["ClassCount", "Class2Count", "FeatureTag", "SettingsCount", "AxisCount"] - + def read(self, reader, font, tableDict): """Read a value from the reader.""" raise NotImplementedError(self) - + def write(self, writer, font, tableDict, value, repeatIndex=None): """Write a value to the writer.""" raise NotImplementedError(self) - + def xmlRead(self, attrs, content, font): """Read a value from XML.""" raise NotImplementedError(self) - + def xmlWrite(self, xmlWriter, font, value, name, attrs): """Write a value to XML.""" raise NotImplementedError(self) @@ -191,15 +191,15 @@ class Version(BaseConverter): class Struct(BaseConverter): - + def read(self, reader, font, tableDict): table = self.tableClass() table.decompile(reader, font) return table - + def write(self, writer, font, tableDict, value, repeatIndex=None): value.compile(writer, font) - + def xmlWrite(self, xmlWriter, font, value, name, attrs): if value is None: if attrs: @@ -212,7 +212,7 @@ class Struct(BaseConverter): pass # NULL table, ignore else: value.toXML(xmlWriter, font, attrs, name=name) - + def xmlRead(self, attrs, content, font): if "empty" in attrs and safeEval(attrs["empty"]): return None @@ -241,7 +241,7 @@ class Table(Struct): writer.writeULong(0) else: writer.writeUShort(0) - + def read(self, reader, font, tableDict): offset = self.readOffset(reader) if offset == 0: @@ -259,7 +259,7 @@ class Table(Struct): else: table.decompile(reader, font) return table - + def write(self, writer, font, tableDict, value, repeatIndex=None): if value is None: self.writeNullOffset(writer) @@ -287,7 +287,7 @@ class SubTable(Table): class ExtSubTable(LTable, SubTable): - + def write(self, writer, font, tableDict, value, repeatIndex=None): writer.Extension = 1 # actually, mere presence of the field flags it as an Ext Subtable writer. Table.write(self, writer, font, tableDict, value, repeatIndex) @@ -329,7 +329,7 @@ class ValueRecord(ValueFormat): class DeltaValue(BaseConverter): - + def read(self, reader, font, tableDict): StartSize = tableDict["StartSize"] EndSize = tableDict["EndSize"] @@ -340,7 +340,7 @@ class DeltaValue(BaseConverter): minusOffset = 1 << nBits mask = (1 << nBits) - 1 signMask = 1 << (nBits - 1) - + DeltaValue = [] tmp, shift = 0, 0 for i in range(nItems): @@ -352,7 +352,7 @@ class DeltaValue(BaseConverter): value = value - minusOffset DeltaValue.append(value) return DeltaValue - + def write(self, writer, font, tableDict, value, repeatIndex=None): StartSize = tableDict["StartSize"] EndSize = tableDict["EndSize"] @@ -363,7 +363,7 @@ class DeltaValue(BaseConverter): nBits = 1 << DeltaFormat assert len(DeltaValue) == nItems mask = (1 << nBits) - 1 - + tmp, shift = 0, 16 for value in DeltaValue: shift = shift - nBits @@ -373,11 +373,11 @@ class DeltaValue(BaseConverter): tmp, shift = 0, 16 if shift != 16: writer.writeUShort(tmp) - + def xmlWrite(self, xmlWriter, font, value, name, attrs): xmlWriter.simpletag(name, attrs + [("value", value)]) xmlWriter.newline() - + def xmlRead(self, attrs, content, font): return safeEval(attrs["value"]) diff --git a/Lib/fontTools/ttLib/tables/otTables.py b/Lib/fontTools/ttLib/tables/otTables.py index 8926378b1..93581a52b 100644 --- a/Lib/fontTools/ttLib/tables/otTables.py +++ b/Lib/fontTools/ttLib/tables/otTables.py @@ -33,9 +33,9 @@ class FeatureParamsCharacterVariants(FeatureParams): pass class Coverage(FormatSwitchingBaseTable): - + # manual implementation to get rid of glyphID dependencies - + def postRead(self, rawTable, font): if self.Format == 1: # TODO only allow glyphs that are valid? @@ -75,7 +75,7 @@ class Coverage(FormatSwitchingBaseTable): else: assert 0, "unknown format: %s" % self.Format del self.Format # Don't need this anymore - + def preWrite(self, font): glyphs = getattr(self, "glyphs", None) if glyphs is None: @@ -87,7 +87,7 @@ class Coverage(FormatSwitchingBaseTable): # find out whether Format 2 is more compact or not glyphIDs = [getGlyphID(glyphName) for glyphName in glyphs ] brokenOrder = sorted(glyphIDs) != glyphIDs - + last = glyphIDs[0] ranges = [[last]] for glyphID in glyphIDs[1:]: @@ -96,7 +96,7 @@ class Coverage(FormatSwitchingBaseTable): ranges.append([glyphID]) last = glyphID ranges[-1].append(last) - + if brokenOrder or len(ranges) * 3 < len(glyphs): # 3 words vs. 1 word # Format 2 is more compact index = 0 @@ -120,12 +120,12 @@ class Coverage(FormatSwitchingBaseTable): # fallthrough; Format 1 is more compact self.Format = format return rawTable - + def toXML2(self, xmlWriter, font): for glyphName in getattr(self, "glyphs", []): xmlWriter.simpletag("Glyph", value=glyphName) xmlWriter.newline() - + def fromXML(self, name, attrs, content, font): glyphs = getattr(self, "glyphs", None) if glyphs is None: @@ -161,7 +161,7 @@ class SingleSubst(FormatSwitchingBaseTable): assert 0, "unknown format: %s" % self.Format self.mapping = mapping del self.Format # Don't need this anymore - + def preWrite(self, font): mapping = getattr(self, "mapping", None) if mapping is None: @@ -200,14 +200,14 @@ class SingleSubst(FormatSwitchingBaseTable): else: rawTable["Substitute"] = subst return rawTable - + def toXML2(self, xmlWriter, font): items = sorted(self.mapping.items()) for inGlyph, outGlyph in items: xmlWriter.simpletag("Substitution", [("in", inGlyph), ("out", outGlyph)]) xmlWriter.newline() - + def fromXML(self, name, attrs, content, font): mapping = getattr(self, "mapping", None) if mapping is None: @@ -217,7 +217,7 @@ class SingleSubst(FormatSwitchingBaseTable): class ClassDef(FormatSwitchingBaseTable): - + def postRead(self, rawTable, font): classDefs = {} glyphOrder = font.getGlyphOrder() @@ -266,7 +266,7 @@ class ClassDef(FormatSwitchingBaseTable): assert 0, "unknown format: %s" % self.Format self.classDefs = classDefs del self.Format # Don't need this anymore - + def preWrite(self, font): classDefs = getattr(self, "classDefs", None) if classDefs is None: @@ -316,13 +316,13 @@ class ClassDef(FormatSwitchingBaseTable): rawTable = {"StartGlyph": startGlyphName, "ClassValueArray": classes} self.Format = format return rawTable - + def toXML2(self, xmlWriter, font): items = sorted(self.classDefs.items()) for glyphName, cls in items: xmlWriter.simpletag("ClassDef", [("glyph", glyphName), ("class", cls)]) xmlWriter.newline() - + def fromXML(self, name, attrs, content, font): classDefs = getattr(self, "classDefs", None) if classDefs is None: @@ -332,7 +332,7 @@ class ClassDef(FormatSwitchingBaseTable): class AlternateSubst(FormatSwitchingBaseTable): - + def postRead(self, rawTable, font): alternates = {} if self.Format == 1: @@ -346,7 +346,7 @@ class AlternateSubst(FormatSwitchingBaseTable): assert 0, "unknown format: %s" % self.Format self.alternates = alternates del self.Format # Don't need this anymore - + def preWrite(self, font): self.Format = 1 alternates = getattr(self, "alternates", None) @@ -370,9 +370,9 @@ class AlternateSubst(FormatSwitchingBaseTable): # Also useful in that when splitting a sub-table because of an offset overflow # I don't need to calculate the change in the subtable offset due to the change in the coverage table size. # Allows packing more rules in subtable. - self.sortCoverageLast = 1 + self.sortCoverageLast = 1 return {"Coverage": cov, "AlternateSet": alternates} - + def toXML2(self, xmlWriter, font): items = sorted(self.alternates.items()) for glyphName, alternates in items: @@ -383,7 +383,7 @@ class AlternateSubst(FormatSwitchingBaseTable): xmlWriter.newline() xmlWriter.endtag("AlternateSet") xmlWriter.newline() - + def fromXML(self, name, attrs, content, font): alternates = getattr(self, "alternates", None) if alternates is None: @@ -400,7 +400,7 @@ class AlternateSubst(FormatSwitchingBaseTable): class LigatureSubst(FormatSwitchingBaseTable): - + def postRead(self, rawTable, font): ligatures = {} if self.Format == 1: @@ -413,7 +413,7 @@ class LigatureSubst(FormatSwitchingBaseTable): assert 0, "unknown format: %s" % self.Format self.ligatures = ligatures del self.Format # Don't need this anymore - + def preWrite(self, font): self.Format = 1 ligatures = getattr(self, "ligatures", None) @@ -438,9 +438,9 @@ class LigatureSubst(FormatSwitchingBaseTable): # Useful in that when splitting a sub-table because of an offset overflow # I don't need to calculate the change in subtabl offset due to the coverage table size. # Allows packing more rules in subtable. - self.sortCoverageLast = 1 + self.sortCoverageLast = 1 return {"Coverage": cov, "LigatureSet": ligSets} - + def toXML2(self, xmlWriter, font): items = sorted(self.ligatures.items()) for glyphName, ligSets in items: @@ -452,7 +452,7 @@ class LigatureSubst(FormatSwitchingBaseTable): xmlWriter.newline() xmlWriter.endtag("LigatureSet") xmlWriter.newline() - + def fromXML(self, name, attrs, content, font): ligatures = getattr(self, "ligatures", None) if ligatures is None: @@ -513,7 +513,7 @@ _equivalents = { def fixLookupOverFlows(ttf, overflowRecord): """ Either the offset from the LookupList to a lookup overflowed, or - an offset from a lookup to a subtable overflowed. + an offset from a lookup to a subtable overflowed. The table layout is: GPSO/GUSB Script List @@ -532,7 +532,7 @@ def fixLookupOverFlows(ttf, overflowRecord): SubTable[n] and contents If the offset to a lookup overflowed (SubTableIndex is None) we must promote the *previous* lookup to an Extension type. - If the offset from a lookup to subtable overflowed, then we must promote it + If the offset from a lookup to subtable overflowed, then we must promote it to an Extension Lookup type. """ ok = 0 @@ -554,7 +554,7 @@ def fixLookupOverFlows(ttf, overflowRecord): if lookupIndex < 0: return ok lookup = lookups[lookupIndex] - + for si in range(len(lookup.SubTable)): subTable = lookup.SubTable[si] extSubTableClass = lookupTypes[overflowRecord.tableType][extType] @@ -570,7 +570,7 @@ def splitAlternateSubst(oldSubTable, newSubTable, overflowRecord): newSubTable.Format = oldSubTable.Format if hasattr(oldSubTable, 'sortCoverageLast'): newSubTable.sortCoverageLast = oldSubTable.sortCoverageLast - + oldAlts = sorted(oldSubTable.alternates.items()) oldLen = len(oldAlts) @@ -580,7 +580,7 @@ def splitAlternateSubst(oldSubTable, newSubTable, overflowRecord): newLen = oldLen//2 elif overflowRecord.itemName == 'AlternateSet': - # We just need to back up by two items + # We just need to back up by two items # from the overflowed AlternateSet index to make sure the offset # to the Coverage table doesn't overflow. newLen = overflowRecord.itemIndex - 1 @@ -607,7 +607,7 @@ def splitLigatureSubst(oldSubTable, newSubTable, overflowRecord): newLen = oldLen//2 elif overflowRecord.itemName == 'LigatureSet': - # We just need to back up by two items + # We just need to back up by two items # from the overflowed AlternateSet index to make sure the offset # to the Coverage table doesn't overflow. newLen = overflowRecord.itemIndex - 1 @@ -647,7 +647,7 @@ splitTable = { 'GSUB': { } def fixSubTableOverFlows(ttf, overflowRecord): - """ + """ An offset has overflowed within a sub-table. We need to divide this subtable into smaller parts. """ ok = 0 @@ -694,10 +694,10 @@ def fixSubTableOverFlows(ttf, overflowRecord): def _buildClasses(): import re from .otData import otData - + formatPat = re.compile("([A-Za-z0-9]+)Format(\d+)$") namespace = globals() - + # populate module with classes for name, table in otData: baseClass = BaseTable @@ -710,12 +710,12 @@ def _buildClasses(): # the class doesn't exist yet, so the base implementation is used. cls = type(name, (baseClass,), {}) namespace[name] = cls - + for base, alts in _equivalents.items(): base = namespace[base] for alt in alts: namespace[alt] = type(alt, (base,), {}) - + global lookupTypes lookupTypes = { 'GSUB': { @@ -753,7 +753,7 @@ def _buildClasses(): featureParamTypes['ss%02d' % i] = FeatureParamsStylisticSet for i in range(1, 99+1): featureParamTypes['cv%02d' % i] = FeatureParamsCharacterVariants - + # add converters to classes from .otConverters import buildConverters for name, table in otData: diff --git a/Lib/fontTools/ttLib/tables/sbixGlyph.py b/Lib/fontTools/ttLib/tables/sbixGlyph.py index 483afe104..c15702cee 100644 --- a/Lib/fontTools/ttLib/tables/sbixGlyph.py +++ b/Lib/fontTools/ttLib/tables/sbixGlyph.py @@ -31,7 +31,7 @@ class Glyph(object): self.rawdata = rawdata self.graphicType = graphicType self.imageData = imageData - + # fix self.graphicType if it is null terminated or too short if self.graphicType is not None: if self.graphicType[-1] == "\0": diff --git a/Lib/fontTools/ttLib/tables/ttProgram.py b/Lib/fontTools/ttLib/tables/ttProgram.py index f4c2f11cc..6456e6fbb 100644 --- a/Lib/fontTools/ttLib/tables/ttProgram.py +++ b/Lib/fontTools/ttLib/tables/ttProgram.py @@ -199,30 +199,30 @@ def _skipWhite(data, pos): class Program(object): - + def __init__(self): pass - + def fromBytecode(self, bytecode): self.bytecode = array.array("B", bytecode) if hasattr(self, "assembly"): del self.assembly - + def fromAssembly(self, assembly): self.assembly = assembly if hasattr(self, "bytecode"): del self.bytecode - + def getBytecode(self): if not hasattr(self, "bytecode"): self._assemble() return self.bytecode.tostring() - + def getAssembly(self, preserve=False): if not hasattr(self, "assembly"): self._disassemble(preserve=preserve) return self.assembly - + def toXML(self, writer, ttFont): if not hasattr (ttFont, "disassembleInstructions") or ttFont.disassembleInstructions: assembly = self.getAssembly() @@ -255,7 +255,7 @@ class Program(object): writer.newline() writer.dumphex(self.getBytecode()) writer.endtag("bytecode") - + def fromXML(self, name, attrs, content, ttFont): if name == "assembly": self.fromAssembly(strjoin(content)) @@ -264,7 +264,7 @@ class Program(object): else: assert name == "bytecode" self.fromBytecode(readHex(content)) - + def _assemble(self): assembly = self.assembly if isinstance(assembly, type([])): @@ -282,7 +282,7 @@ class Program(object): if comment: pos = _skipWhite(assembly, pos) continue - + arg = arg.strip() if mnemonic.startswith("INSTR"): # Unknown instruction @@ -383,11 +383,11 @@ class Program(object): push(value) pos = _skipWhite(assembly, pos) - + if bytecode: assert max(bytecode) < 256 and min(bytecode) >= 0 self.bytecode = array.array("B", bytecode) - + def _disassemble(self, preserve=False): assembly = [] i = 0 @@ -456,7 +456,7 @@ def _test(): """ bc = b"""@;:9876543210/.-,+*)(\'&%$#"! \037\036\035\034\033\032\031\030\027\026\025\024\023\022\021\020\017\016\015\014\013\012\011\010\007\006\005\004\003\002\001\000,\001\260\030CXEj\260\031C`\260F#D#\020 \260FN\360M/\260\000\022\033!#\0213Y-,\001\260\030CX\260\005+\260\000\023K\260\024PX\261\000@8Y\260\006+\033!#\0213Y-,\001\260\030CXN\260\003%\020\362!\260\000\022M\033 E\260\004%\260\004%#Jad\260(RX!#\020\326\033\260\003%\020\362!\260\000\022YY-,\260\032CX!!\033\260\002%\260\002%I\260\003%\260\003%Ja d\260\020PX!!!\033\260\003%\260\003%I\260\000PX\260\000PX\270\377\3428!\033\260\0208!Y\033\260\000RX\260\0368!\033\270\377\3608!YYYY-,\001\260\030CX\260\005+\260\000\023K\260\024PX\271\000\000\377\3008Y\260\006+\033!#\0213Y-,N\001\212\020\261F\031CD\260\000\024\261\000F\342\260\000\025\271\000\000\377\3608\000\260\000<\260(+\260\002%\020\260\000<-,\001\030\260\000/\260\001\024\362\260\001\023\260\001\025M\260\000\022-,\001\260\030CX\260\005+\260\000\023\271\000\000\377\3408\260\006+\033!#\0213Y-,\001\260\030CXEdj#Edi\260\031Cd``\260F#D#\020 \260F\360/\260\000\022\033!! \212 \212RX\0213\033!!YY-,\001\261\013\012C#Ce\012-,\000\261\012\013C#C\013-,\000\260F#p\261\001F>\001\260F#p\261\002FE:\261\002\000\010\015-,\260\022+\260\002%E\260\002%Ej\260@\213`\260\002%#D!!!-,\260\023+\260\002%E\260\002%Ej\270\377\300\214`\260\002%#D!!!-,\260\000\260\022+!!!-,\260\000\260\023+!!!-,\001\260\006C\260\007Ce\012-, i\260@a\260\000\213 \261,\300\212\214\270\020\000b`+\014d#da\\X\260\003aY-,\261\000\003%EhT\260\034KPZX\260\003%E\260\003%E`h \260\004%#D\260\004%#D\033\260\003% Eh \212#D\260\003%Eh`\260\003%#DY-,\260\003% Eh \212#D\260\003%Edhe`\260\004%\260\001`#D-,\260\011CX\207!\300\033\260\022CX\207E\260\021+\260G#D\260Gz\344\033\003\212E\030i \260G#D\212\212\207 \260\240QX\260\021+\260G#D\260Gz\344\033!\260Gz\344YYY\030-, \212E#Eh`D-,EjB-,\001\030/-,\001\260\030CX\260\004%\260\004%Id#Edi\260@\213a \260\200bj\260\002%\260\002%a\214\260\031C`\260F#D!\212\020\260F\366!\033!!!!Y-,\001\260\030CX\260\002%E\260\002%Ed`j\260\003%Eja \260\004%Ej \212\213e\260\004%#D\214\260\003%#D!!\033 EjD EjDY-,\001 E\260\000U\260\030CZXEh#Ei\260@\213a \260\200bj \212#a \260\003%\213e\260\004%#D\214\260\003%#D!!\033!!\260\031+Y-,\001\212\212Ed#EdadB-,\260\004%\260\004%\260\031+\260\030CX\260\004%\260\004%\260\003%\260\033+\001\260\002%C\260@T\260\002%C\260\000TZX\260\003% E\260@aDY\260\002%C\260\000T\260\002%C\260@TZX\260\004% E\260@`DYY!!!!-,\001KRXC\260\002%E#aD\033!!Y-,\001KRXC\260\002%E#`D\033!!Y-,KRXED\033!!Y-,\001 \260\003%#I\260@`\260 c \260\000RX#\260\002%8#\260\002%e8\000\212c8\033!!!!!Y\001-,KPXED\033!!Y-,\001\260\005%\020# \212\365\000\260\001`#\355\354-,\001\260\005%\020# \212\365\000\260\001a#\355\354-,\001\260\006%\020\365\000\355\354-,F#F`\212\212F# F\212`\212a\270\377\200b# \020#\212\261KK\212pE` \260\000PX\260\001a\270\377\272\213\033\260F\214Y\260\020`h\001:-, E\260\003%FRX\260\002%F ha\260\003%\260\003%?#!8\033!\021Y-, E\260\003%FPX\260\002%F ha\260\003%\260\003%?#!8\033!\021Y-,\000\260\007C\260\006C\013-,\212\020\354-,\260\014CX!\033 F\260\000RX\270\377\3608\033\260\0208YY-, \260\000UX\270\020\000c\260\003%Ed\260\003%Eda\260\000SX\260\002\033\260@a\260\003Y%EiSXED\033!!Y\033!\260\002%E\260\002%Ead\260(QXED\033!!YY-,!!\014d#d\213\270@\000b-,!\260\200QX\014d#d\213\270 \000b\033\262\000@/+Y\260\002`-,!\260\300QX\014d#d\213\270\025Ub\033\262\000\200/+Y\260\002`-,\014d#d\213\270@\000b`#!-,KSX\260\004%\260\004%Id#Edi\260@\213a \260\200bj\260\002%\260\002%a\214\260F#D!\212\020\260F\366!\033!\212\021#\022 9/Y-,\260\002%\260\002%Id\260\300TX\270\377\3708\260\0108\033!!Y-,\260\023CX\003\033\002Y-,\260\023CX\002\033\003Y-,\260\012+#\020 <\260\027+-,\260\002%\270\377\3608\260(+\212\020# \320#\260\020+\260\005CX\300\033