More whitespace

This commit is contained in:
Behdad Esfahbod 2015-04-26 02:01:01 -04:00
parent bd67253118
commit b30e12ae00
63 changed files with 1327 additions and 1327 deletions

View File

@ -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()

View File

@ -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'
]

View File

@ -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'
]

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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.
"""

View File

@ -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)

View File

@ -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()

View File

@ -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):

View File

@ -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

View File

@ -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 "<dict>"
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))

View File

@ -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))

View File

@ -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:

View File

@ -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)

View File

@ -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('<?xml version="1.0" encoding="UTF-8"?>')
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 = "</%s>" % _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')

View File

@ -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:

View File

@ -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'

View File

@ -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)

View File

@ -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

View File

@ -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
]

View File

@ -53,6 +53,6 @@ class BitmapGlyphMetrics(object):
class BigGlyphMetrics(BitmapGlyphMetrics):
binaryFormat = bigGlyphMetricsFormat
class SmallGlyphMetrics(BitmapGlyphMetrics):
binaryFormat = smallGlyphMetricsFormat

View File

@ -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()

View File

@ -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):

View File

@ -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"))

View File

@ -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):

View File

@ -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))

View File

@ -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))

View File

@ -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 = {}

View File

@ -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 + " ]"

View File

@ -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"):

View File

@ -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"]:

View File

@ -46,7 +46,7 @@ The XML format is:
</colorPalettes>
</SVG>
Color values must be less than 256.
Color values must be less than 256.
The number of color records in each </colorPalette> must be the same as
the number of <colorParamUINameID> 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):

View File

@ -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()

View File

@ -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 = {}

View File

@ -5,5 +5,5 @@ from fontTools import ttLib
superclass = ttLib.getTableClass("TSI0")
class table_T_S_I__2(superclass):
dependencies = ["TSI3"]

View File

@ -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"

View File

@ -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 = {}

View File

@ -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 = """

View File

@ -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):

View File

@ -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.

View File

@ -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]

View File

@ -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)

View File

@ -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

View File

@ -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):

View File

@ -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

View File

@ -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"):

View File

@ -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"]))

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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"]))

View File

@ -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 "<NameRecord NameID=%d; PlatformID=%d; LanguageID=%d>" % (
self.nameID, self.platformID, self.langID)

View File

@ -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"]))

View File

@ -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"]))

View File

@ -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'

View File

@ -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]))

View File

@ -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):

View File

@ -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"])

View File

@ -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:

View File

@ -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":

View File

@ -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<Y \020\021\260\000\022\001-,KS#KQZX8\033!!Y-,\001\260\002%\020\320#\311\001\260\001\023\260\000\024\020\260\001<\260\001\026-,\001\260\000\023\260\001\260\003%I\260\003\0278\260\001\023-,KS#KQZX E\212`D\033!!Y-, 9/-"""
p = Program()
p.fromBytecode(bc)
asm = p.getAssembly(preserve=True)

View File

@ -82,7 +82,7 @@ def usage():
print(__doc__ % version)
sys.exit(2)
numberAddedRE = re.compile("#\d+$")
opentypeheaderRE = re.compile('''sfntVersion=['"]OTTO["']''')
@ -262,13 +262,13 @@ def parseOptions(args):
rawOptions, files = getopt.getopt(args, "ld:o:fvqht:x:sim:z:baey:")
except getopt.GetoptError:
usage()
if not files:
usage()
options = Options(rawOptions, len(files))
jobs = []
for input in files:
tp = guessFileType(input)
if tp in ("OTF", "TTF", "TTC", "WOFF"):
@ -286,7 +286,7 @@ def parseOptions(args):
else:
print('Unknown file type: "%s"' % input)
continue
if options.outputFile:
output = options.outputFile
else:
@ -329,7 +329,7 @@ def main(args):
waitForKeyPress()
else:
raise
if __name__ == "__main__":
main(sys.argv[1:])