More whitespace
This commit is contained in:
parent
bd67253118
commit
b30e12ae00
@ -712,11 +712,11 @@ UV2AGL = {}
|
|||||||
|
|
||||||
def _builddicts():
|
def _builddicts():
|
||||||
import re
|
import re
|
||||||
|
|
||||||
lines = _aglText.splitlines()
|
lines = _aglText.splitlines()
|
||||||
|
|
||||||
parseAGL_RE = re.compile("([0-9A-F]{4});([A-Za-z_0-9.]+);.*?$")
|
parseAGL_RE = re.compile("([0-9A-F]{4});([A-Za-z_0-9.]+);.*?$")
|
||||||
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if not line or line[:1] == '#':
|
if not line or line[:1] == '#':
|
||||||
continue
|
continue
|
||||||
@ -733,5 +733,5 @@ def _builddicts():
|
|||||||
else:
|
else:
|
||||||
AGL2UV[glyphName] = unicode
|
AGL2UV[glyphName] = unicode
|
||||||
UV2AGL[unicode] = glyphName
|
UV2AGL[unicode] = glyphName
|
||||||
|
|
||||||
_builddicts()
|
_builddicts()
|
||||||
|
@ -18,15 +18,15 @@ cffHeaderFormat = """
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
class CFFFontSet(object):
|
class CFFFontSet(object):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def decompile(self, file, otFont):
|
def decompile(self, file, otFont):
|
||||||
sstruct.unpack(cffHeaderFormat, file.read(4), self)
|
sstruct.unpack(cffHeaderFormat, file.read(4), self)
|
||||||
assert self.major == 1 and self.minor == 0, \
|
assert self.major == 1 and self.minor == 0, \
|
||||||
"unknown CFF format: %d.%d" % (self.major, self.minor)
|
"unknown CFF format: %d.%d" % (self.major, self.minor)
|
||||||
|
|
||||||
file.seek(self.hdrSize)
|
file.seek(self.hdrSize)
|
||||||
self.fontNames = list(Index(file))
|
self.fontNames = list(Index(file))
|
||||||
self.topDictIndex = TopDictIndex(file)
|
self.topDictIndex = TopDictIndex(file)
|
||||||
@ -34,23 +34,23 @@ class CFFFontSet(object):
|
|||||||
self.GlobalSubrs = GlobalSubrsIndex(file)
|
self.GlobalSubrs = GlobalSubrsIndex(file)
|
||||||
self.topDictIndex.strings = self.strings
|
self.topDictIndex.strings = self.strings
|
||||||
self.topDictIndex.GlobalSubrs = self.GlobalSubrs
|
self.topDictIndex.GlobalSubrs = self.GlobalSubrs
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self.fontNames)
|
return len(self.fontNames)
|
||||||
|
|
||||||
def keys(self):
|
def keys(self):
|
||||||
return list(self.fontNames)
|
return list(self.fontNames)
|
||||||
|
|
||||||
def values(self):
|
def values(self):
|
||||||
return self.topDictIndex
|
return self.topDictIndex
|
||||||
|
|
||||||
def __getitem__(self, name):
|
def __getitem__(self, name):
|
||||||
try:
|
try:
|
||||||
index = self.fontNames.index(name)
|
index = self.fontNames.index(name)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise KeyError(name)
|
raise KeyError(name)
|
||||||
return self.topDictIndex[index]
|
return self.topDictIndex[index]
|
||||||
|
|
||||||
def compile(self, file, otFont):
|
def compile(self, file, otFont):
|
||||||
strings = IndexedStrings()
|
strings = IndexedStrings()
|
||||||
writer = CFFWriter()
|
writer = CFFWriter()
|
||||||
@ -63,17 +63,17 @@ class CFFFontSet(object):
|
|||||||
writer.add(topCompiler)
|
writer.add(topCompiler)
|
||||||
writer.add(strings.getCompiler())
|
writer.add(strings.getCompiler())
|
||||||
writer.add(self.GlobalSubrs.getCompiler(strings, None))
|
writer.add(self.GlobalSubrs.getCompiler(strings, None))
|
||||||
|
|
||||||
for topDict in self.topDictIndex:
|
for topDict in self.topDictIndex:
|
||||||
if not hasattr(topDict, "charset") or topDict.charset is None:
|
if not hasattr(topDict, "charset") or topDict.charset is None:
|
||||||
charset = otFont.getGlyphOrder()
|
charset = otFont.getGlyphOrder()
|
||||||
topDict.charset = charset
|
topDict.charset = charset
|
||||||
|
|
||||||
for child in topCompiler.getChildren(strings):
|
for child in topCompiler.getChildren(strings):
|
||||||
writer.add(child)
|
writer.add(child)
|
||||||
|
|
||||||
writer.toFile(file)
|
writer.toFile(file)
|
||||||
|
|
||||||
def toXML(self, xmlWriter, progress=None):
|
def toXML(self, xmlWriter, progress=None):
|
||||||
for fontName in self.fontNames:
|
for fontName in self.fontNames:
|
||||||
xmlWriter.begintag("CFFFont", name=tostr(fontName))
|
xmlWriter.begintag("CFFFont", name=tostr(fontName))
|
||||||
@ -88,7 +88,7 @@ class CFFFontSet(object):
|
|||||||
self.GlobalSubrs.toXML(xmlWriter, progress)
|
self.GlobalSubrs.toXML(xmlWriter, progress)
|
||||||
xmlWriter.endtag("GlobalSubrs")
|
xmlWriter.endtag("GlobalSubrs")
|
||||||
xmlWriter.newline()
|
xmlWriter.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content):
|
def fromXML(self, name, attrs, content):
|
||||||
if not hasattr(self, "GlobalSubrs"):
|
if not hasattr(self, "GlobalSubrs"):
|
||||||
self.GlobalSubrs = GlobalSubrsIndex()
|
self.GlobalSubrs = GlobalSubrsIndex()
|
||||||
@ -121,13 +121,13 @@ class CFFFontSet(object):
|
|||||||
|
|
||||||
|
|
||||||
class CFFWriter(object):
|
class CFFWriter(object):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.data = []
|
self.data = []
|
||||||
|
|
||||||
def add(self, table):
|
def add(self, table):
|
||||||
self.data.append(table)
|
self.data.append(table)
|
||||||
|
|
||||||
def toFile(self, file):
|
def toFile(self, file):
|
||||||
lastPosList = None
|
lastPosList = None
|
||||||
count = 1
|
count = 1
|
||||||
@ -175,14 +175,14 @@ def calcOffSize(largestOffset):
|
|||||||
|
|
||||||
|
|
||||||
class IndexCompiler(object):
|
class IndexCompiler(object):
|
||||||
|
|
||||||
def __init__(self, items, strings, parent):
|
def __init__(self, items, strings, parent):
|
||||||
self.items = self.getItems(items, strings)
|
self.items = self.getItems(items, strings)
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
|
||||||
def getItems(self, items, strings):
|
def getItems(self, items, strings):
|
||||||
return items
|
return items
|
||||||
|
|
||||||
def getOffsets(self):
|
def getOffsets(self):
|
||||||
pos = 1
|
pos = 1
|
||||||
offsets = [pos]
|
offsets = [pos]
|
||||||
@ -193,7 +193,7 @@ class IndexCompiler(object):
|
|||||||
pos = pos + len(item)
|
pos = pos + len(item)
|
||||||
offsets.append(pos)
|
offsets.append(pos)
|
||||||
return offsets
|
return offsets
|
||||||
|
|
||||||
def getDataLength(self):
|
def getDataLength(self):
|
||||||
lastOffset = self.getOffsets()[-1]
|
lastOffset = self.getOffsets()[-1]
|
||||||
offSize = calcOffSize(lastOffset)
|
offSize = calcOffSize(lastOffset)
|
||||||
@ -204,7 +204,7 @@ class IndexCompiler(object):
|
|||||||
lastOffset - 1 # size of object data
|
lastOffset - 1 # size of object data
|
||||||
)
|
)
|
||||||
return dataLength
|
return dataLength
|
||||||
|
|
||||||
def toFile(self, file):
|
def toFile(self, file):
|
||||||
offsets = self.getOffsets()
|
offsets = self.getOffsets()
|
||||||
writeCard16(file, len(self.items))
|
writeCard16(file, len(self.items))
|
||||||
@ -224,19 +224,19 @@ class IndexCompiler(object):
|
|||||||
|
|
||||||
|
|
||||||
class IndexedStringsCompiler(IndexCompiler):
|
class IndexedStringsCompiler(IndexCompiler):
|
||||||
|
|
||||||
def getItems(self, items, strings):
|
def getItems(self, items, strings):
|
||||||
return items.strings
|
return items.strings
|
||||||
|
|
||||||
|
|
||||||
class TopDictIndexCompiler(IndexCompiler):
|
class TopDictIndexCompiler(IndexCompiler):
|
||||||
|
|
||||||
def getItems(self, items, strings):
|
def getItems(self, items, strings):
|
||||||
out = []
|
out = []
|
||||||
for item in items:
|
for item in items:
|
||||||
out.append(item.getCompiler(strings, self))
|
out.append(item.getCompiler(strings, self))
|
||||||
return out
|
return out
|
||||||
|
|
||||||
def getChildren(self, strings):
|
def getChildren(self, strings):
|
||||||
children = []
|
children = []
|
||||||
for topDict in self.items:
|
for topDict in self.items:
|
||||||
@ -245,13 +245,13 @@ class TopDictIndexCompiler(IndexCompiler):
|
|||||||
|
|
||||||
|
|
||||||
class FDArrayIndexCompiler(IndexCompiler):
|
class FDArrayIndexCompiler(IndexCompiler):
|
||||||
|
|
||||||
def getItems(self, items, strings):
|
def getItems(self, items, strings):
|
||||||
out = []
|
out = []
|
||||||
for item in items:
|
for item in items:
|
||||||
out.append(item.getCompiler(strings, self))
|
out.append(item.getCompiler(strings, self))
|
||||||
return out
|
return out
|
||||||
|
|
||||||
def getChildren(self, strings):
|
def getChildren(self, strings):
|
||||||
children = []
|
children = []
|
||||||
for fontDict in self.items:
|
for fontDict in self.items:
|
||||||
@ -298,11 +298,11 @@ class CharStringsCompiler(GlobalSubrsCompiler):
|
|||||||
|
|
||||||
|
|
||||||
class Index(object):
|
class Index(object):
|
||||||
|
|
||||||
"""This class represents what the CFF spec calls an INDEX."""
|
"""This class represents what the CFF spec calls an INDEX."""
|
||||||
|
|
||||||
compilerClass = IndexCompiler
|
compilerClass = IndexCompiler
|
||||||
|
|
||||||
def __init__(self, file=None):
|
def __init__(self, file=None):
|
||||||
self.items = []
|
self.items = []
|
||||||
name = self.__class__.__name__
|
name = self.__class__.__name__
|
||||||
@ -330,10 +330,10 @@ class Index(object):
|
|||||||
file.seek(self.offsetBase + offsets[-1]) # pretend we've read the whole lot
|
file.seek(self.offsetBase + offsets[-1]) # pretend we've read the whole lot
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print(" end of %s at %s" % (name, file.tell()))
|
print(" end of %s at %s" % (name, file.tell()))
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self.items)
|
return len(self.items)
|
||||||
|
|
||||||
def __getitem__(self, index):
|
def __getitem__(self, index):
|
||||||
item = self.items[index]
|
item = self.items[index]
|
||||||
if item is not None:
|
if item is not None:
|
||||||
@ -347,21 +347,21 @@ class Index(object):
|
|||||||
item = self.produceItem(index, data, file, offset, size)
|
item = self.produceItem(index, data, file, offset, size)
|
||||||
self.items[index] = item
|
self.items[index] = item
|
||||||
return item
|
return item
|
||||||
|
|
||||||
def produceItem(self, index, data, file, offset, size):
|
def produceItem(self, index, data, file, offset, size):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def append(self, item):
|
def append(self, item):
|
||||||
self.items.append(item)
|
self.items.append(item)
|
||||||
|
|
||||||
def getCompiler(self, strings, parent):
|
def getCompiler(self, strings, parent):
|
||||||
return self.compilerClass(self, strings, parent)
|
return self.compilerClass(self, strings, parent)
|
||||||
|
|
||||||
|
|
||||||
class GlobalSubrsIndex(Index):
|
class GlobalSubrsIndex(Index):
|
||||||
|
|
||||||
compilerClass = GlobalSubrsCompiler
|
compilerClass = GlobalSubrsCompiler
|
||||||
|
|
||||||
def __init__(self, file=None, globalSubrs=None, private=None, fdSelect=None, fdArray=None):
|
def __init__(self, file=None, globalSubrs=None, private=None, fdSelect=None, fdArray=None):
|
||||||
Index.__init__(self, file)
|
Index.__init__(self, file)
|
||||||
self.globalSubrs = globalSubrs
|
self.globalSubrs = globalSubrs
|
||||||
@ -370,7 +370,7 @@ class GlobalSubrsIndex(Index):
|
|||||||
self.fdSelect = fdSelect
|
self.fdSelect = fdSelect
|
||||||
if fdArray:
|
if fdArray:
|
||||||
self.fdArray = fdArray
|
self.fdArray = fdArray
|
||||||
|
|
||||||
def produceItem(self, index, data, file, offset, size):
|
def produceItem(self, index, data, file, offset, size):
|
||||||
if self.private is not None:
|
if self.private is not None:
|
||||||
private = self.private
|
private = self.private
|
||||||
@ -379,7 +379,7 @@ class GlobalSubrsIndex(Index):
|
|||||||
else:
|
else:
|
||||||
private = None
|
private = None
|
||||||
return psCharStrings.T2CharString(data, private=private, globalSubrs=self.globalSubrs)
|
return psCharStrings.T2CharString(data, private=private, globalSubrs=self.globalSubrs)
|
||||||
|
|
||||||
def toXML(self, xmlWriter, progress):
|
def toXML(self, xmlWriter, progress):
|
||||||
xmlWriter.comment("The 'index' attribute is only for humans; it is ignored when parsed.")
|
xmlWriter.comment("The 'index' attribute is only for humans; it is ignored when parsed.")
|
||||||
xmlWriter.newline()
|
xmlWriter.newline()
|
||||||
@ -393,14 +393,14 @@ class GlobalSubrsIndex(Index):
|
|||||||
subr.toXML(xmlWriter)
|
subr.toXML(xmlWriter)
|
||||||
xmlWriter.endtag("CharString")
|
xmlWriter.endtag("CharString")
|
||||||
xmlWriter.newline()
|
xmlWriter.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content):
|
def fromXML(self, name, attrs, content):
|
||||||
if name != "CharString":
|
if name != "CharString":
|
||||||
return
|
return
|
||||||
subr = psCharStrings.T2CharString()
|
subr = psCharStrings.T2CharString()
|
||||||
subr.fromXML(name, attrs, content)
|
subr.fromXML(name, attrs, content)
|
||||||
self.append(subr)
|
self.append(subr)
|
||||||
|
|
||||||
def getItemAndSelector(self, index):
|
def getItemAndSelector(self, index):
|
||||||
sel = None
|
sel = None
|
||||||
if hasattr(self, 'fdSelect'):
|
if hasattr(self, 'fdSelect'):
|
||||||
@ -413,14 +413,14 @@ class SubrsIndex(GlobalSubrsIndex):
|
|||||||
|
|
||||||
|
|
||||||
class TopDictIndex(Index):
|
class TopDictIndex(Index):
|
||||||
|
|
||||||
compilerClass = TopDictIndexCompiler
|
compilerClass = TopDictIndexCompiler
|
||||||
|
|
||||||
def produceItem(self, index, data, file, offset, size):
|
def produceItem(self, index, data, file, offset, size):
|
||||||
top = TopDict(self.strings, file, offset, self.GlobalSubrs)
|
top = TopDict(self.strings, file, offset, self.GlobalSubrs)
|
||||||
top.decompile(data)
|
top.decompile(data)
|
||||||
return top
|
return top
|
||||||
|
|
||||||
def toXML(self, xmlWriter, progress):
|
def toXML(self, xmlWriter, progress):
|
||||||
for i in range(len(self)):
|
for i in range(len(self)):
|
||||||
xmlWriter.begintag("FontDict", index=i)
|
xmlWriter.begintag("FontDict", index=i)
|
||||||
@ -431,7 +431,7 @@ class TopDictIndex(Index):
|
|||||||
|
|
||||||
|
|
||||||
class FDArrayIndex(TopDictIndex):
|
class FDArrayIndex(TopDictIndex):
|
||||||
|
|
||||||
compilerClass = FDArrayIndexCompiler
|
compilerClass = FDArrayIndexCompiler
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content):
|
def fromXML(self, name, attrs, content):
|
||||||
@ -480,19 +480,19 @@ class FDSelect:
|
|||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self.gidArray)
|
return len(self.gidArray)
|
||||||
|
|
||||||
def __getitem__(self, index):
|
def __getitem__(self, index):
|
||||||
return self.gidArray[index]
|
return self.gidArray[index]
|
||||||
|
|
||||||
def __setitem__(self, index, fdSelectValue):
|
def __setitem__(self, index, fdSelectValue):
|
||||||
self.gidArray[index] = fdSelectValue
|
self.gidArray[index] = fdSelectValue
|
||||||
|
|
||||||
def append(self, fdSelectValue):
|
def append(self, fdSelectValue):
|
||||||
self.gidArray.append(fdSelectValue)
|
self.gidArray.append(fdSelectValue)
|
||||||
|
|
||||||
|
|
||||||
class CharStrings(object):
|
class CharStrings(object):
|
||||||
|
|
||||||
def __init__(self, file, charset, globalSubrs, private, fdSelect, fdArray):
|
def __init__(self, file, charset, globalSubrs, private, fdSelect, fdArray):
|
||||||
if file is not None:
|
if file is not None:
|
||||||
self.charStringsIndex = SubrsIndex(file, globalSubrs, private, fdSelect, fdArray)
|
self.charStringsIndex = SubrsIndex(file, globalSubrs, private, fdSelect, fdArray)
|
||||||
@ -509,37 +509,37 @@ class CharStrings(object):
|
|||||||
self.fdSelect = fdSelect
|
self.fdSelect = fdSelect
|
||||||
if fdArray is not None:
|
if fdArray is not None:
|
||||||
self.fdArray = fdArray
|
self.fdArray = fdArray
|
||||||
|
|
||||||
def keys(self):
|
def keys(self):
|
||||||
return list(self.charStrings.keys())
|
return list(self.charStrings.keys())
|
||||||
|
|
||||||
def values(self):
|
def values(self):
|
||||||
if self.charStringsAreIndexed:
|
if self.charStringsAreIndexed:
|
||||||
return self.charStringsIndex
|
return self.charStringsIndex
|
||||||
else:
|
else:
|
||||||
return list(self.charStrings.values())
|
return list(self.charStrings.values())
|
||||||
|
|
||||||
def has_key(self, name):
|
def has_key(self, name):
|
||||||
return name in self.charStrings
|
return name in self.charStrings
|
||||||
|
|
||||||
__contains__ = has_key
|
__contains__ = has_key
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self.charStrings)
|
return len(self.charStrings)
|
||||||
|
|
||||||
def __getitem__(self, name):
|
def __getitem__(self, name):
|
||||||
charString = self.charStrings[name]
|
charString = self.charStrings[name]
|
||||||
if self.charStringsAreIndexed:
|
if self.charStringsAreIndexed:
|
||||||
charString = self.charStringsIndex[charString]
|
charString = self.charStringsIndex[charString]
|
||||||
return charString
|
return charString
|
||||||
|
|
||||||
def __setitem__(self, name, charString):
|
def __setitem__(self, name, charString):
|
||||||
if self.charStringsAreIndexed:
|
if self.charStringsAreIndexed:
|
||||||
index = self.charStrings[name]
|
index = self.charStrings[name]
|
||||||
self.charStringsIndex[index] = charString
|
self.charStringsIndex[index] = charString
|
||||||
else:
|
else:
|
||||||
self.charStrings[name] = charString
|
self.charStrings[name] = charString
|
||||||
|
|
||||||
def getItemAndSelector(self, name):
|
def getItemAndSelector(self, name):
|
||||||
if self.charStringsAreIndexed:
|
if self.charStringsAreIndexed:
|
||||||
index = self.charStrings[name]
|
index = self.charStrings[name]
|
||||||
@ -550,7 +550,7 @@ class CharStrings(object):
|
|||||||
else:
|
else:
|
||||||
raise KeyError("fdSelect array not yet defined.")
|
raise KeyError("fdSelect array not yet defined.")
|
||||||
return self.charStrings[name], sel
|
return self.charStrings[name], sel
|
||||||
|
|
||||||
def toXML(self, xmlWriter, progress):
|
def toXML(self, xmlWriter, progress):
|
||||||
names = sorted(self.keys())
|
names = sorted(self.keys())
|
||||||
i = 0
|
i = 0
|
||||||
@ -575,7 +575,7 @@ class CharStrings(object):
|
|||||||
progress.setLabel("Dumping 'CFF ' table... (%s)" % name)
|
progress.setLabel("Dumping 'CFF ' table... (%s)" % name)
|
||||||
progress.increment(step / numGlyphs)
|
progress.increment(step / numGlyphs)
|
||||||
i = i + 1
|
i = i + 1
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content):
|
def fromXML(self, name, attrs, content):
|
||||||
for element in content:
|
for element in content:
|
||||||
if isinstance(element, basestring):
|
if isinstance(element, basestring):
|
||||||
@ -589,7 +589,7 @@ class CharStrings(object):
|
|||||||
private = self.fdArray[fdID].Private
|
private = self.fdArray[fdID].Private
|
||||||
else:
|
else:
|
||||||
private = self.private
|
private = self.private
|
||||||
|
|
||||||
glyphName = attrs["name"]
|
glyphName = attrs["name"]
|
||||||
charString = psCharStrings.T2CharString(
|
charString = psCharStrings.T2CharString(
|
||||||
private=private,
|
private=private,
|
||||||
@ -767,10 +767,10 @@ class CharStringsConverter(TableConverter):
|
|||||||
return 0 # dummy value
|
return 0 # dummy value
|
||||||
def xmlRead(self, name, attrs, content, parent):
|
def xmlRead(self, name, attrs, content, parent):
|
||||||
if hasattr(parent, "ROS"):
|
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
|
private, fdSelect, fdArray = None, parent.FDSelect, parent.FDArray
|
||||||
else:
|
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
|
private, fdSelect, fdArray = parent.Private, None, None
|
||||||
charStrings = CharStrings(None, None, parent.GlobalSubrs, private, fdSelect, fdArray)
|
charStrings = CharStrings(None, None, parent.GlobalSubrs, private, fdSelect, fdArray)
|
||||||
charStrings.fromXML(name, attrs, content)
|
charStrings.fromXML(name, attrs, content)
|
||||||
@ -796,7 +796,7 @@ class CharsetConverter(object):
|
|||||||
if DEBUG:
|
if DEBUG:
|
||||||
print(" charset end at %s" % file.tell())
|
print(" charset end at %s" % file.tell())
|
||||||
else: # offset == 0 -> no charset data.
|
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.
|
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
|
charset = None
|
||||||
elif value == 0:
|
elif value == 0:
|
||||||
@ -821,7 +821,7 @@ class CharsetConverter(object):
|
|||||||
|
|
||||||
|
|
||||||
class CharsetCompiler(object):
|
class CharsetCompiler(object):
|
||||||
|
|
||||||
def __init__(self, strings, charset, parent):
|
def __init__(self, strings, charset, parent):
|
||||||
assert charset[0] == '.notdef'
|
assert charset[0] == '.notdef'
|
||||||
isCID = hasattr(parent.dictObj, "ROS")
|
isCID = hasattr(parent.dictObj, "ROS")
|
||||||
@ -832,13 +832,13 @@ class CharsetCompiler(object):
|
|||||||
else:
|
else:
|
||||||
self.data = data0
|
self.data = data0
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
|
||||||
def setPos(self, pos, endPos):
|
def setPos(self, pos, endPos):
|
||||||
self.parent.rawDict["charset"] = pos
|
self.parent.rawDict["charset"] = pos
|
||||||
|
|
||||||
def getDataLength(self):
|
def getDataLength(self):
|
||||||
return len(self.data)
|
return len(self.data)
|
||||||
|
|
||||||
def toFile(self, file):
|
def toFile(self, file):
|
||||||
file.write(self.data)
|
file.write(self.data)
|
||||||
|
|
||||||
@ -871,7 +871,7 @@ def packCharset(charset, isCID, strings):
|
|||||||
getNameID = getCIDfromName
|
getNameID = getCIDfromName
|
||||||
else:
|
else:
|
||||||
getNameID = getSIDfromName
|
getNameID = getSIDfromName
|
||||||
|
|
||||||
for name in charset[1:]:
|
for name in charset[1:]:
|
||||||
SID = getNameID(name, strings)
|
SID = getNameID(name, strings)
|
||||||
if first is None:
|
if first is None:
|
||||||
@ -888,7 +888,7 @@ def packCharset(charset, isCID, strings):
|
|||||||
if nLeft > 255:
|
if nLeft > 255:
|
||||||
fmt = 2
|
fmt = 2
|
||||||
ranges.append((first, nLeft))
|
ranges.append((first, nLeft))
|
||||||
|
|
||||||
data = [packCard8(fmt)]
|
data = [packCard8(fmt)]
|
||||||
if fmt == 1:
|
if fmt == 1:
|
||||||
nLeftFunc = packCard8
|
nLeftFunc = packCard8
|
||||||
@ -944,10 +944,10 @@ class EncodingCompiler(object):
|
|||||||
|
|
||||||
def setPos(self, pos, endPos):
|
def setPos(self, pos, endPos):
|
||||||
self.parent.rawDict["Encoding"] = pos
|
self.parent.rawDict["Encoding"] = pos
|
||||||
|
|
||||||
def getDataLength(self):
|
def getDataLength(self):
|
||||||
return len(self.data)
|
return len(self.data)
|
||||||
|
|
||||||
def toFile(self, file):
|
def toFile(self, file):
|
||||||
file.write(self.data)
|
file.write(self.data)
|
||||||
|
|
||||||
@ -1047,7 +1047,7 @@ def packEncoding0(charset, encoding, strings):
|
|||||||
for name in charset[1:]:
|
for name in charset[1:]:
|
||||||
code = m.get(name)
|
code = m.get(name)
|
||||||
codes.append(code)
|
codes.append(code)
|
||||||
|
|
||||||
while codes and codes[-1] is None:
|
while codes and codes[-1] is None:
|
||||||
codes.pop()
|
codes.pop()
|
||||||
|
|
||||||
@ -1079,7 +1079,7 @@ def packEncoding1(charset, encoding, strings):
|
|||||||
end = code
|
end = code
|
||||||
nLeft = end - first
|
nLeft = end - first
|
||||||
ranges.append((first, nLeft))
|
ranges.append((first, nLeft))
|
||||||
|
|
||||||
# remove unencoded glyphs at the end.
|
# remove unencoded glyphs at the end.
|
||||||
while ranges and ranges[-1][0] == -1:
|
while ranges and ranges[-1][0] == -1:
|
||||||
ranges.pop()
|
ranges.pop()
|
||||||
@ -1138,7 +1138,7 @@ class FDSelectConverter(object):
|
|||||||
numGlyphs = None
|
numGlyphs = None
|
||||||
fdSelect = FDSelect(file, numGlyphs, fmt)
|
fdSelect = FDSelect(file, numGlyphs, fmt)
|
||||||
return fdSelect
|
return fdSelect
|
||||||
|
|
||||||
|
|
||||||
def packFDSelect0(fdSelectArray):
|
def packFDSelect0(fdSelectArray):
|
||||||
fmt = 0
|
fmt = 0
|
||||||
@ -1161,7 +1161,7 @@ def packFDSelect3(fdSelectArray):
|
|||||||
fdRanges.append([i, fdIndex])
|
fdRanges.append([i, fdIndex])
|
||||||
lastFDIndex = fdIndex
|
lastFDIndex = fdIndex
|
||||||
sentinelGID = i + 1
|
sentinelGID = i + 1
|
||||||
|
|
||||||
data = [packCard8(fmt)]
|
data = [packCard8(fmt)]
|
||||||
data.append(packCard16( len(fdRanges) ))
|
data.append(packCard16( len(fdRanges) ))
|
||||||
for fdRange in fdRanges:
|
for fdRange in fdRanges:
|
||||||
@ -1172,7 +1172,7 @@ def packFDSelect3(fdSelectArray):
|
|||||||
|
|
||||||
|
|
||||||
class FDSelectCompiler(object):
|
class FDSelectCompiler(object):
|
||||||
|
|
||||||
def __init__(self, fdSelect, parent):
|
def __init__(self, fdSelect, parent):
|
||||||
fmt = fdSelect.format
|
fmt = fdSelect.format
|
||||||
fdSelectArray = fdSelect.gidArray
|
fdSelectArray = fdSelect.gidArray
|
||||||
@ -1192,13 +1192,13 @@ class FDSelectCompiler(object):
|
|||||||
fdSelect.format = 3
|
fdSelect.format = 3
|
||||||
|
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
|
||||||
def setPos(self, pos, endPos):
|
def setPos(self, pos, endPos):
|
||||||
self.parent.rawDict["FDSelect"] = pos
|
self.parent.rawDict["FDSelect"] = pos
|
||||||
|
|
||||||
def getDataLength(self):
|
def getDataLength(self):
|
||||||
return len(self.data)
|
return len(self.data)
|
||||||
|
|
||||||
def toFile(self, file):
|
def toFile(self, file):
|
||||||
file.write(self.data)
|
file.write(self.data)
|
||||||
|
|
||||||
@ -1309,7 +1309,7 @@ class PrivateDictDecompiler(psCharStrings.DictDecompiler):
|
|||||||
|
|
||||||
|
|
||||||
class DictCompiler(object):
|
class DictCompiler(object):
|
||||||
|
|
||||||
def __init__(self, dictObj, strings, parent):
|
def __init__(self, dictObj, strings, parent):
|
||||||
assert isinstance(strings, IndexedStrings)
|
assert isinstance(strings, IndexedStrings)
|
||||||
self.dictObj = dictObj
|
self.dictObj = dictObj
|
||||||
@ -1326,13 +1326,13 @@ class DictCompiler(object):
|
|||||||
continue
|
continue
|
||||||
rawDict[name] = value
|
rawDict[name] = value
|
||||||
self.rawDict = rawDict
|
self.rawDict = rawDict
|
||||||
|
|
||||||
def setPos(self, pos, endPos):
|
def setPos(self, pos, endPos):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def getDataLength(self):
|
def getDataLength(self):
|
||||||
return len(self.compile("getDataLength"))
|
return len(self.compile("getDataLength"))
|
||||||
|
|
||||||
def compile(self, reason):
|
def compile(self, reason):
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print("-- compiling %s for %s" % (self.__class__.__name__, reason))
|
print("-- compiling %s for %s" % (self.__class__.__name__, reason))
|
||||||
@ -1357,10 +1357,10 @@ class DictCompiler(object):
|
|||||||
data.append(arghandler(value))
|
data.append(arghandler(value))
|
||||||
data.append(op)
|
data.append(op)
|
||||||
return bytesjoin(data)
|
return bytesjoin(data)
|
||||||
|
|
||||||
def toFile(self, file):
|
def toFile(self, file):
|
||||||
file.write(self.compile("toFile"))
|
file.write(self.compile("toFile"))
|
||||||
|
|
||||||
def arg_number(self, num):
|
def arg_number(self, num):
|
||||||
return encodeNumber(num)
|
return encodeNumber(num)
|
||||||
def arg_SID(self, s):
|
def arg_SID(self, s):
|
||||||
@ -1390,9 +1390,9 @@ def encodeNumber(num):
|
|||||||
|
|
||||||
|
|
||||||
class TopDictCompiler(DictCompiler):
|
class TopDictCompiler(DictCompiler):
|
||||||
|
|
||||||
opcodes = buildOpcodeDict(topDictOperators)
|
opcodes = buildOpcodeDict(topDictOperators)
|
||||||
|
|
||||||
def getChildren(self, strings):
|
def getChildren(self, strings):
|
||||||
children = []
|
children = []
|
||||||
if hasattr(self.dictObj, "charset") and self.dictObj.charset:
|
if hasattr(self.dictObj, "charset") and self.dictObj.charset:
|
||||||
@ -1435,9 +1435,9 @@ class TopDictCompiler(DictCompiler):
|
|||||||
|
|
||||||
|
|
||||||
class FontDictCompiler(DictCompiler):
|
class FontDictCompiler(DictCompiler):
|
||||||
|
|
||||||
opcodes = buildOpcodeDict(topDictOperators)
|
opcodes = buildOpcodeDict(topDictOperators)
|
||||||
|
|
||||||
def getChildren(self, strings):
|
def getChildren(self, strings):
|
||||||
children = []
|
children = []
|
||||||
if hasattr(self.dictObj, "Private"):
|
if hasattr(self.dictObj, "Private"):
|
||||||
@ -1448,14 +1448,14 @@ class FontDictCompiler(DictCompiler):
|
|||||||
|
|
||||||
|
|
||||||
class PrivateDictCompiler(DictCompiler):
|
class PrivateDictCompiler(DictCompiler):
|
||||||
|
|
||||||
opcodes = buildOpcodeDict(privateDictOperators)
|
opcodes = buildOpcodeDict(privateDictOperators)
|
||||||
|
|
||||||
def setPos(self, pos, endPos):
|
def setPos(self, pos, endPos):
|
||||||
size = endPos - pos
|
size = endPos - pos
|
||||||
self.parent.rawDict["Private"] = size, pos
|
self.parent.rawDict["Private"] = size, pos
|
||||||
self.pos = pos
|
self.pos = pos
|
||||||
|
|
||||||
def getChildren(self, strings):
|
def getChildren(self, strings):
|
||||||
children = []
|
children = []
|
||||||
if hasattr(self.dictObj, "Subrs"):
|
if hasattr(self.dictObj, "Subrs"):
|
||||||
@ -1464,7 +1464,7 @@ class PrivateDictCompiler(DictCompiler):
|
|||||||
|
|
||||||
|
|
||||||
class BaseDict(object):
|
class BaseDict(object):
|
||||||
|
|
||||||
def __init__(self, strings=None, file=None, offset=None):
|
def __init__(self, strings=None, file=None, offset=None):
|
||||||
self.rawDict = {}
|
self.rawDict = {}
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
@ -1473,7 +1473,7 @@ class BaseDict(object):
|
|||||||
self.offset = offset
|
self.offset = offset
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
self.skipNames = []
|
self.skipNames = []
|
||||||
|
|
||||||
def decompile(self, data):
|
def decompile(self, data):
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print(" length %s is %s" % (self.__class__.__name__, len(data)))
|
print(" length %s is %s" % (self.__class__.__name__, len(data)))
|
||||||
@ -1481,13 +1481,13 @@ class BaseDict(object):
|
|||||||
dec.decompile(data)
|
dec.decompile(data)
|
||||||
self.rawDict = dec.getDict()
|
self.rawDict = dec.getDict()
|
||||||
self.postDecompile()
|
self.postDecompile()
|
||||||
|
|
||||||
def postDecompile(self):
|
def postDecompile(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def getCompiler(self, strings, parent):
|
def getCompiler(self, strings, parent):
|
||||||
return self.compilerClass(self, strings, parent)
|
return self.compilerClass(self, strings, parent)
|
||||||
|
|
||||||
def __getattr__(self, name):
|
def __getattr__(self, name):
|
||||||
value = self.rawDict.get(name)
|
value = self.rawDict.get(name)
|
||||||
if value is None:
|
if value is None:
|
||||||
@ -1498,7 +1498,7 @@ class BaseDict(object):
|
|||||||
value = conv.read(self, value)
|
value = conv.read(self, value)
|
||||||
setattr(self, name, value)
|
setattr(self, name, value)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def toXML(self, xmlWriter, progress):
|
def toXML(self, xmlWriter, progress):
|
||||||
for name in self.order:
|
for name in self.order:
|
||||||
if name in self.skipNames:
|
if name in self.skipNames:
|
||||||
@ -1508,7 +1508,7 @@ class BaseDict(object):
|
|||||||
continue
|
continue
|
||||||
conv = self.converters[name]
|
conv = self.converters[name]
|
||||||
conv.xmlWrite(xmlWriter, name, value, progress)
|
conv.xmlWrite(xmlWriter, name, value, progress)
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content):
|
def fromXML(self, name, attrs, content):
|
||||||
conv = self.converters[name]
|
conv = self.converters[name]
|
||||||
value = conv.xmlRead(name, attrs, content, self)
|
value = conv.xmlRead(name, attrs, content, self)
|
||||||
@ -1516,20 +1516,20 @@ class BaseDict(object):
|
|||||||
|
|
||||||
|
|
||||||
class TopDict(BaseDict):
|
class TopDict(BaseDict):
|
||||||
|
|
||||||
defaults = buildDefaults(topDictOperators)
|
defaults = buildDefaults(topDictOperators)
|
||||||
converters = buildConverters(topDictOperators)
|
converters = buildConverters(topDictOperators)
|
||||||
order = buildOrder(topDictOperators)
|
order = buildOrder(topDictOperators)
|
||||||
decompilerClass = TopDictDecompiler
|
decompilerClass = TopDictDecompiler
|
||||||
compilerClass = TopDictCompiler
|
compilerClass = TopDictCompiler
|
||||||
|
|
||||||
def __init__(self, strings=None, file=None, offset=None, GlobalSubrs=None):
|
def __init__(self, strings=None, file=None, offset=None, GlobalSubrs=None):
|
||||||
BaseDict.__init__(self, strings, file, offset)
|
BaseDict.__init__(self, strings, file, offset)
|
||||||
self.GlobalSubrs = GlobalSubrs
|
self.GlobalSubrs = GlobalSubrs
|
||||||
|
|
||||||
def getGlyphOrder(self):
|
def getGlyphOrder(self):
|
||||||
return self.charset
|
return self.charset
|
||||||
|
|
||||||
def postDecompile(self):
|
def postDecompile(self):
|
||||||
offset = self.rawDict.get("CharStrings")
|
offset = self.rawDict.get("CharStrings")
|
||||||
if offset is None:
|
if offset is None:
|
||||||
@ -1537,7 +1537,7 @@ class TopDict(BaseDict):
|
|||||||
# get the number of glyphs beforehand.
|
# get the number of glyphs beforehand.
|
||||||
self.file.seek(offset)
|
self.file.seek(offset)
|
||||||
self.numGlyphs = readCard16(self.file)
|
self.numGlyphs = readCard16(self.file)
|
||||||
|
|
||||||
def toXML(self, xmlWriter, progress):
|
def toXML(self, xmlWriter, progress):
|
||||||
if hasattr(self, "CharStrings"):
|
if hasattr(self, "CharStrings"):
|
||||||
self.decompileAllCharStrings(progress)
|
self.decompileAllCharStrings(progress)
|
||||||
@ -1549,7 +1549,7 @@ class TopDict(BaseDict):
|
|||||||
self.skipNames = ['CIDFontVersion', 'CIDFontRevision', 'CIDFontType',
|
self.skipNames = ['CIDFontVersion', 'CIDFontRevision', 'CIDFontType',
|
||||||
'CIDCount']
|
'CIDCount']
|
||||||
BaseDict.toXML(self, xmlWriter, progress)
|
BaseDict.toXML(self, xmlWriter, progress)
|
||||||
|
|
||||||
def decompileAllCharStrings(self, progress):
|
def decompileAllCharStrings(self, progress):
|
||||||
# XXX only when doing ttdump -i?
|
# XXX only when doing ttdump -i?
|
||||||
i = 0
|
i = 0
|
||||||
@ -1567,20 +1567,20 @@ class TopDict(BaseDict):
|
|||||||
|
|
||||||
|
|
||||||
class FontDict(BaseDict):
|
class FontDict(BaseDict):
|
||||||
|
|
||||||
defaults = buildDefaults(topDictOperators)
|
defaults = buildDefaults(topDictOperators)
|
||||||
converters = buildConverters(topDictOperators)
|
converters = buildConverters(topDictOperators)
|
||||||
order = buildOrder(topDictOperators)
|
order = buildOrder(topDictOperators)
|
||||||
decompilerClass = None
|
decompilerClass = None
|
||||||
compilerClass = FontDictCompiler
|
compilerClass = FontDictCompiler
|
||||||
|
|
||||||
def __init__(self, strings=None, file=None, offset=None, GlobalSubrs=None):
|
def __init__(self, strings=None, file=None, offset=None, GlobalSubrs=None):
|
||||||
BaseDict.__init__(self, strings, file, offset)
|
BaseDict.__init__(self, strings, file, offset)
|
||||||
self.GlobalSubrs = GlobalSubrs
|
self.GlobalSubrs = GlobalSubrs
|
||||||
|
|
||||||
def getGlyphOrder(self):
|
def getGlyphOrder(self):
|
||||||
return self.charset
|
return self.charset
|
||||||
|
|
||||||
def toXML(self, xmlWriter, progress):
|
def toXML(self, xmlWriter, progress):
|
||||||
self.skipNames = ['Encoding']
|
self.skipNames = ['Encoding']
|
||||||
BaseDict.toXML(self, xmlWriter, progress)
|
BaseDict.toXML(self, xmlWriter, progress)
|
||||||
@ -1595,28 +1595,28 @@ class PrivateDict(BaseDict):
|
|||||||
|
|
||||||
|
|
||||||
class IndexedStrings(object):
|
class IndexedStrings(object):
|
||||||
|
|
||||||
"""SID -> string mapping."""
|
"""SID -> string mapping."""
|
||||||
|
|
||||||
def __init__(self, file=None):
|
def __init__(self, file=None):
|
||||||
if file is None:
|
if file is None:
|
||||||
strings = []
|
strings = []
|
||||||
else:
|
else:
|
||||||
strings = [tostr(s, encoding="latin1") for s in Index(file)]
|
strings = [tostr(s, encoding="latin1") for s in Index(file)]
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
|
|
||||||
def getCompiler(self):
|
def getCompiler(self):
|
||||||
return IndexedStringsCompiler(self, None, None)
|
return IndexedStringsCompiler(self, None, None)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self.strings)
|
return len(self.strings)
|
||||||
|
|
||||||
def __getitem__(self, SID):
|
def __getitem__(self, SID):
|
||||||
if SID < cffStandardStringCount:
|
if SID < cffStandardStringCount:
|
||||||
return cffStandardStrings[SID]
|
return cffStandardStrings[SID]
|
||||||
else:
|
else:
|
||||||
return self.strings[SID - cffStandardStringCount]
|
return self.strings[SID - cffStandardStringCount]
|
||||||
|
|
||||||
def getSID(self, s):
|
def getSID(self, s):
|
||||||
if not hasattr(self, "stringMapping"):
|
if not hasattr(self, "stringMapping"):
|
||||||
self.buildStringMapping()
|
self.buildStringMapping()
|
||||||
@ -1629,10 +1629,10 @@ class IndexedStrings(object):
|
|||||||
self.strings.append(s)
|
self.strings.append(s)
|
||||||
self.stringMapping[s] = SID
|
self.stringMapping[s] = SID
|
||||||
return SID
|
return SID
|
||||||
|
|
||||||
def getStrings(self):
|
def getStrings(self):
|
||||||
return self.strings
|
return self.strings
|
||||||
|
|
||||||
def buildStringMapping(self):
|
def buildStringMapping(self):
|
||||||
self.stringMapping = {}
|
self.stringMapping = {}
|
||||||
for index in range(len(self.strings)):
|
for index in range(len(self.strings)):
|
||||||
@ -1642,68 +1642,68 @@ class IndexedStrings(object):
|
|||||||
# The 391 Standard Strings as used in the CFF format.
|
# The 391 Standard Strings as used in the CFF format.
|
||||||
# from Adobe Technical None #5176, version 1.0, 18 March 1998
|
# from Adobe Technical None #5176, version 1.0, 18 March 1998
|
||||||
|
|
||||||
cffStandardStrings = ['.notdef', 'space', 'exclam', 'quotedbl', 'numbersign',
|
cffStandardStrings = ['.notdef', 'space', 'exclam', 'quotedbl', 'numbersign',
|
||||||
'dollar', 'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright',
|
'dollar', 'percent', 'ampersand', 'quoteright', 'parenleft', 'parenright',
|
||||||
'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one',
|
'asterisk', 'plus', 'comma', 'hyphen', 'period', 'slash', 'zero', 'one',
|
||||||
'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon',
|
'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'colon',
|
||||||
'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C',
|
'semicolon', 'less', 'equal', 'greater', 'question', 'at', 'A', 'B', 'C',
|
||||||
'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
|
'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',
|
'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'bracketleft', 'backslash',
|
||||||
'bracketright', 'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c',
|
'bracketright', 'asciicircum', 'underscore', 'quoteleft', 'a', 'b', 'c',
|
||||||
'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
|
'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',
|
's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar', 'braceright',
|
||||||
'asciitilde', 'exclamdown', 'cent', 'sterling', 'fraction', 'yen', 'florin',
|
'asciitilde', 'exclamdown', 'cent', 'sterling', 'fraction', 'yen', 'florin',
|
||||||
'section', 'currency', 'quotesingle', 'quotedblleft', 'guillemotleft',
|
'section', 'currency', 'quotesingle', 'quotedblleft', 'guillemotleft',
|
||||||
'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'endash', 'dagger',
|
'guilsinglleft', 'guilsinglright', 'fi', 'fl', 'endash', 'dagger',
|
||||||
'daggerdbl', 'periodcentered', 'paragraph', 'bullet', 'quotesinglbase',
|
'daggerdbl', 'periodcentered', 'paragraph', 'bullet', 'quotesinglbase',
|
||||||
'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand',
|
'quotedblbase', 'quotedblright', 'guillemotright', 'ellipsis', 'perthousand',
|
||||||
'questiondown', 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve',
|
'questiondown', 'grave', 'acute', 'circumflex', 'tilde', 'macron', 'breve',
|
||||||
'dotaccent', 'dieresis', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron',
|
'dotaccent', 'dieresis', 'ring', 'cedilla', 'hungarumlaut', 'ogonek', 'caron',
|
||||||
'emdash', 'AE', 'ordfeminine', 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae',
|
'emdash', 'AE', 'ordfeminine', 'Lslash', 'Oslash', 'OE', 'ordmasculine', 'ae',
|
||||||
'dotlessi', 'lslash', 'oslash', 'oe', 'germandbls', 'onesuperior',
|
'dotlessi', 'lslash', 'oslash', 'oe', 'germandbls', 'onesuperior',
|
||||||
'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn',
|
'logicalnot', 'mu', 'trademark', 'Eth', 'onehalf', 'plusminus', 'Thorn',
|
||||||
'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters',
|
'onequarter', 'divide', 'brokenbar', 'degree', 'thorn', 'threequarters',
|
||||||
'twosuperior', 'registered', 'minus', 'eth', 'multiply', 'threesuperior',
|
'twosuperior', 'registered', 'minus', 'eth', 'multiply', 'threesuperior',
|
||||||
'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring',
|
'copyright', 'Aacute', 'Acircumflex', 'Adieresis', 'Agrave', 'Aring',
|
||||||
'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave',
|
'Atilde', 'Ccedilla', 'Eacute', 'Ecircumflex', 'Edieresis', 'Egrave',
|
||||||
'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute',
|
'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Ntilde', 'Oacute',
|
||||||
'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute',
|
'Ocircumflex', 'Odieresis', 'Ograve', 'Otilde', 'Scaron', 'Uacute',
|
||||||
'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron',
|
'Ucircumflex', 'Udieresis', 'Ugrave', 'Yacute', 'Ydieresis', 'Zcaron',
|
||||||
'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla',
|
'aacute', 'acircumflex', 'adieresis', 'agrave', 'aring', 'atilde', 'ccedilla',
|
||||||
'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex',
|
'eacute', 'ecircumflex', 'edieresis', 'egrave', 'iacute', 'icircumflex',
|
||||||
'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis',
|
'idieresis', 'igrave', 'ntilde', 'oacute', 'ocircumflex', 'odieresis',
|
||||||
'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis', 'ugrave',
|
'ograve', 'otilde', 'scaron', 'uacute', 'ucircumflex', 'udieresis', 'ugrave',
|
||||||
'yacute', 'ydieresis', 'zcaron', 'exclamsmall', 'Hungarumlautsmall',
|
'yacute', 'ydieresis', 'zcaron', 'exclamsmall', 'Hungarumlautsmall',
|
||||||
'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall',
|
'dollaroldstyle', 'dollarsuperior', 'ampersandsmall', 'Acutesmall',
|
||||||
'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader',
|
'parenleftsuperior', 'parenrightsuperior', 'twodotenleader', 'onedotenleader',
|
||||||
'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle',
|
'zerooldstyle', 'oneoldstyle', 'twooldstyle', 'threeoldstyle', 'fouroldstyle',
|
||||||
'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle',
|
'fiveoldstyle', 'sixoldstyle', 'sevenoldstyle', 'eightoldstyle',
|
||||||
'nineoldstyle', 'commasuperior', 'threequartersemdash', 'periodsuperior',
|
'nineoldstyle', 'commasuperior', 'threequartersemdash', 'periodsuperior',
|
||||||
'questionsmall', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior',
|
'questionsmall', 'asuperior', 'bsuperior', 'centsuperior', 'dsuperior',
|
||||||
'esuperior', 'isuperior', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior',
|
'esuperior', 'isuperior', 'lsuperior', 'msuperior', 'nsuperior', 'osuperior',
|
||||||
'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'ffi', 'ffl', 'parenleftinferior',
|
'rsuperior', 'ssuperior', 'tsuperior', 'ff', 'ffi', 'ffl', 'parenleftinferior',
|
||||||
'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall',
|
'parenrightinferior', 'Circumflexsmall', 'hyphensuperior', 'Gravesmall',
|
||||||
'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall',
|
'Asmall', 'Bsmall', 'Csmall', 'Dsmall', 'Esmall', 'Fsmall', 'Gsmall', 'Hsmall',
|
||||||
'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall',
|
'Ismall', 'Jsmall', 'Ksmall', 'Lsmall', 'Msmall', 'Nsmall', 'Osmall', 'Psmall',
|
||||||
'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall',
|
'Qsmall', 'Rsmall', 'Ssmall', 'Tsmall', 'Usmall', 'Vsmall', 'Wsmall', 'Xsmall',
|
||||||
'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall',
|
'Ysmall', 'Zsmall', 'colonmonetary', 'onefitted', 'rupiah', 'Tildesmall',
|
||||||
'exclamdownsmall', 'centoldstyle', 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall',
|
'exclamdownsmall', 'centoldstyle', 'Lslashsmall', 'Scaronsmall', 'Zcaronsmall',
|
||||||
'Dieresissmall', 'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall',
|
'Dieresissmall', 'Brevesmall', 'Caronsmall', 'Dotaccentsmall', 'Macronsmall',
|
||||||
'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall',
|
'figuredash', 'hypheninferior', 'Ogoneksmall', 'Ringsmall', 'Cedillasmall',
|
||||||
'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths',
|
'questiondownsmall', 'oneeighth', 'threeeighths', 'fiveeighths', 'seveneighths',
|
||||||
'onethird', 'twothirds', 'zerosuperior', 'foursuperior', 'fivesuperior',
|
'onethird', 'twothirds', 'zerosuperior', 'foursuperior', 'fivesuperior',
|
||||||
'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior',
|
'sixsuperior', 'sevensuperior', 'eightsuperior', 'ninesuperior', 'zeroinferior',
|
||||||
'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior',
|
'oneinferior', 'twoinferior', 'threeinferior', 'fourinferior', 'fiveinferior',
|
||||||
'sixinferior', 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior',
|
'sixinferior', 'seveninferior', 'eightinferior', 'nineinferior', 'centinferior',
|
||||||
'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall',
|
'dollarinferior', 'periodinferior', 'commainferior', 'Agravesmall',
|
||||||
'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall',
|
'Aacutesmall', 'Acircumflexsmall', 'Atildesmall', 'Adieresissmall', 'Aringsmall',
|
||||||
'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall',
|
'AEsmall', 'Ccedillasmall', 'Egravesmall', 'Eacutesmall', 'Ecircumflexsmall',
|
||||||
'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall',
|
'Edieresissmall', 'Igravesmall', 'Iacutesmall', 'Icircumflexsmall',
|
||||||
'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall',
|
'Idieresissmall', 'Ethsmall', 'Ntildesmall', 'Ogravesmall', 'Oacutesmall',
|
||||||
'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall',
|
'Ocircumflexsmall', 'Otildesmall', 'Odieresissmall', 'OEsmall', 'Oslashsmall',
|
||||||
'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall',
|
'Ugravesmall', 'Uacutesmall', 'Ucircumflexsmall', 'Udieresissmall',
|
||||||
'Yacutesmall', 'Thornsmall', 'Ydieresissmall', '001.000', '001.001', '001.002',
|
'Yacutesmall', 'Thornsmall', 'Ydieresissmall', '001.000', '001.001', '001.002',
|
||||||
'001.003', 'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman',
|
'001.003', 'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman',
|
||||||
'Semibold'
|
'Semibold'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -2,38 +2,38 @@ from __future__ import print_function, division, absolute_import
|
|||||||
from fontTools.misc.py23 import *
|
from fontTools.misc.py23 import *
|
||||||
|
|
||||||
MacRoman = [
|
MacRoman = [
|
||||||
'NUL', 'Eth', 'eth', 'Lslash', 'lslash', 'Scaron', 'scaron', 'Yacute',
|
'NUL', 'Eth', 'eth', 'Lslash', 'lslash', 'Scaron', 'scaron', 'Yacute',
|
||||||
'yacute', 'HT', 'LF', 'Thorn', 'thorn', 'CR', 'Zcaron', 'zcaron', 'DLE', 'DC1',
|
'yacute', 'HT', 'LF', 'Thorn', 'thorn', 'CR', 'Zcaron', 'zcaron', 'DLE', 'DC1',
|
||||||
'DC2', 'DC3', 'DC4', 'onehalf', 'onequarter', 'onesuperior', 'threequarters',
|
'DC2', 'DC3', 'DC4', 'onehalf', 'onequarter', 'onesuperior', 'threequarters',
|
||||||
'threesuperior', 'twosuperior', 'brokenbar', 'minus', 'multiply', 'RS', 'US',
|
'threesuperior', 'twosuperior', 'brokenbar', 'minus', 'multiply', 'RS', 'US',
|
||||||
'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand',
|
'space', 'exclam', 'quotedbl', 'numbersign', 'dollar', 'percent', 'ampersand',
|
||||||
'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma',
|
'quotesingle', 'parenleft', 'parenright', 'asterisk', 'plus', 'comma',
|
||||||
'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', 'five',
|
'hyphen', 'period', 'slash', 'zero', 'one', 'two', 'three', 'four', 'five',
|
||||||
'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal',
|
'six', 'seven', 'eight', 'nine', 'colon', 'semicolon', 'less', 'equal',
|
||||||
'greater', 'question', 'at', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
|
'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',
|
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||||
'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore',
|
'bracketleft', 'backslash', 'bracketright', 'asciicircum', 'underscore',
|
||||||
'grave', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
'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',
|
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'braceleft', 'bar',
|
||||||
'braceright', 'asciitilde', 'DEL', 'Adieresis', 'Aring', 'Ccedilla', 'Eacute',
|
'braceright', 'asciitilde', 'DEL', 'Adieresis', 'Aring', 'Ccedilla', 'Eacute',
|
||||||
'Ntilde', 'Odieresis', 'Udieresis', 'aacute', 'agrave', 'acircumflex',
|
'Ntilde', 'Odieresis', 'Udieresis', 'aacute', 'agrave', 'acircumflex',
|
||||||
'adieresis', 'atilde', 'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex',
|
'adieresis', 'atilde', 'aring', 'ccedilla', 'eacute', 'egrave', 'ecircumflex',
|
||||||
'edieresis', 'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde',
|
'edieresis', 'iacute', 'igrave', 'icircumflex', 'idieresis', 'ntilde',
|
||||||
'oacute', 'ograve', 'ocircumflex', 'odieresis', 'otilde', 'uacute', 'ugrave',
|
'oacute', 'ograve', 'ocircumflex', 'odieresis', 'otilde', 'uacute', 'ugrave',
|
||||||
'ucircumflex', 'udieresis', 'dagger', 'degree', 'cent', 'sterling', 'section',
|
'ucircumflex', 'udieresis', 'dagger', 'degree', 'cent', 'sterling', 'section',
|
||||||
'bullet', 'paragraph', 'germandbls', 'registered', 'copyright', 'trademark',
|
'bullet', 'paragraph', 'germandbls', 'registered', 'copyright', 'trademark',
|
||||||
'acute', 'dieresis', 'notequal', 'AE', 'Oslash', 'infinity', 'plusminus',
|
'acute', 'dieresis', 'notequal', 'AE', 'Oslash', 'infinity', 'plusminus',
|
||||||
'lessequal', 'greaterequal', 'yen', 'mu', 'partialdiff', 'summation',
|
'lessequal', 'greaterequal', 'yen', 'mu', 'partialdiff', 'summation',
|
||||||
'product', 'pi', 'integral', 'ordfeminine', 'ordmasculine', 'Omega', 'ae',
|
'product', 'pi', 'integral', 'ordfeminine', 'ordmasculine', 'Omega', 'ae',
|
||||||
'oslash', 'questiondown', 'exclamdown', 'logicalnot', 'radical', 'florin',
|
'oslash', 'questiondown', 'exclamdown', 'logicalnot', 'radical', 'florin',
|
||||||
'approxequal', 'Delta', 'guillemotleft', 'guillemotright', 'ellipsis',
|
'approxequal', 'Delta', 'guillemotleft', 'guillemotright', 'ellipsis',
|
||||||
'nbspace', 'Agrave', 'Atilde', 'Otilde', 'OE', 'oe', 'endash', 'emdash',
|
'nbspace', 'Agrave', 'Atilde', 'Otilde', 'OE', 'oe', 'endash', 'emdash',
|
||||||
'quotedblleft', 'quotedblright', 'quoteleft', 'quoteright', 'divide', 'lozenge',
|
'quotedblleft', 'quotedblright', 'quoteleft', 'quoteright', 'divide', 'lozenge',
|
||||||
'ydieresis', 'Ydieresis', 'fraction', 'currency', 'guilsinglleft',
|
'ydieresis', 'Ydieresis', 'fraction', 'currency', 'guilsinglleft',
|
||||||
'guilsinglright', 'fi', 'fl', 'daggerdbl', 'periodcentered', 'quotesinglbase',
|
'guilsinglright', 'fi', 'fl', 'daggerdbl', 'periodcentered', 'quotesinglbase',
|
||||||
'quotedblbase', 'perthousand', 'Acircumflex', 'Ecircumflex', 'Aacute',
|
'quotedblbase', 'perthousand', 'Acircumflex', 'Ecircumflex', 'Aacute',
|
||||||
'Edieresis', 'Egrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Oacute',
|
'Edieresis', 'Egrave', 'Iacute', 'Icircumflex', 'Idieresis', 'Igrave', 'Oacute',
|
||||||
'Ocircumflex', 'apple', 'Ograve', 'Uacute', 'Ucircumflex', 'Ugrave', 'dotlessi',
|
'Ocircumflex', 'apple', 'Ograve', 'Uacute', 'Ucircumflex', 'Ugrave', 'dotlessi',
|
||||||
'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'ring', 'cedilla',
|
'circumflex', 'tilde', 'macron', 'breve', 'dotaccent', 'ring', 'cedilla',
|
||||||
'hungarumlaut', 'ogonek', 'caron'
|
'hungarumlaut', 'ogonek', 'caron'
|
||||||
]
|
]
|
||||||
|
@ -808,7 +808,7 @@ class Merger(object):
|
|||||||
try:
|
try:
|
||||||
mergeLogic = logic['*']
|
mergeLogic = logic['*']
|
||||||
except KeyError:
|
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__))
|
(key, returnTable.__class__.__name__))
|
||||||
if mergeLogic is NotImplemented:
|
if mergeLogic is NotImplemented:
|
||||||
continue
|
continue
|
||||||
|
@ -43,7 +43,7 @@ def pointInRect(p, rect):
|
|||||||
return (xMin <= x <= xMax) and (yMin <= y <= yMax)
|
return (xMin <= x <= xMax) and (yMin <= y <= yMax)
|
||||||
|
|
||||||
def pointsInRect(array, rect):
|
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.
|
Returns an array with a boolean for each point.
|
||||||
"""
|
"""
|
||||||
if len(array) < 1:
|
if len(array) < 1:
|
||||||
@ -59,7 +59,7 @@ def vectorLength(vector):
|
|||||||
def asInt16(array):
|
def asInt16(array):
|
||||||
"""Round and cast to 16 bit integer."""
|
"""Round and cast to 16 bit integer."""
|
||||||
return [int(math.floor(i+0.5)) for i in array]
|
return [int(math.floor(i+0.5)) for i in array]
|
||||||
|
|
||||||
|
|
||||||
def normRect(rect):
|
def normRect(rect):
|
||||||
"""Normalize the rectangle so that the following holds:
|
"""Normalize the rectangle so that the following holds:
|
||||||
|
@ -62,7 +62,7 @@ def calcCubicBounds(pt1, pt2, pt3, pt4):
|
|||||||
xRoots = [t for t in solveQuadratic(ax3, bx2, cx) if 0 <= t < 1]
|
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]
|
yRoots = [t for t in solveQuadratic(ay3, by2, cy) if 0 <= t < 1]
|
||||||
roots = xRoots + yRoots
|
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]
|
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)
|
return calcBounds(points)
|
||||||
|
|
||||||
@ -220,7 +220,7 @@ def _splitQuadraticAtT(a, b, c, *ts):
|
|||||||
b1y = (2*ay*t1 + by) * delta
|
b1y = (2*ay*t1 + by) * delta
|
||||||
c1x = ax*t1**2 + bx*t1 + cx
|
c1x = ax*t1**2 + bx*t1 + cx
|
||||||
c1y = ay*t1**2 + by*t1 + cy
|
c1y = ay*t1**2 + by*t1 + cy
|
||||||
|
|
||||||
pt1, pt2, pt3 = calcQuadraticPoints((a1x, a1y), (b1x, b1y), (c1x, c1y))
|
pt1, pt2, pt3 = calcQuadraticPoints((a1x, a1y), (b1x, b1y), (c1x, c1y))
|
||||||
segments.append((pt1, pt2, pt3))
|
segments.append((pt1, pt2, pt3))
|
||||||
return segments
|
return segments
|
||||||
@ -306,7 +306,7 @@ def solveCubic(a, b, c, d):
|
|||||||
a1 = b/a
|
a1 = b/a
|
||||||
a2 = c/a
|
a2 = c/a
|
||||||
a3 = d/a
|
a3 = d/a
|
||||||
|
|
||||||
Q = (a1*a1 - 3.0*a2)/9.0
|
Q = (a1*a1 - 3.0*a2)/9.0
|
||||||
R = (2.0*a1*a1*a1 - 9.0*a1*a2 + 27.0*a3)/54.0
|
R = (2.0*a1*a1*a1 - 9.0*a1*a2 + 27.0*a3)/54.0
|
||||||
R2_Q3 = R*R - Q*Q*Q
|
R2_Q3 = R*R - Q*Q*Q
|
||||||
|
@ -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.
|
charstring encryption algorithm as used by PostScript Type 1 fonts.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ def fixedToFloat(value, precisionBits):
|
|||||||
that has the shortest decimal reprentation. Eg. to convert a
|
that has the shortest decimal reprentation. Eg. to convert a
|
||||||
fixed number in a 2.14 format, use precisionBits=14. This is
|
fixed number in a 2.14 format, use precisionBits=14. This is
|
||||||
pretty slow compared to a simple division. Use sporadically.
|
pretty slow compared to a simple division. Use sporadically.
|
||||||
|
|
||||||
>>> "%g" % fixedToFloat(13107, 14)
|
>>> "%g" % fixedToFloat(13107, 14)
|
||||||
'0.8'
|
'0.8'
|
||||||
>>> "%g" % fixedToFloat(0, 14)
|
>>> "%g" % fixedToFloat(0, 14)
|
||||||
|
@ -53,18 +53,18 @@ _FCBPBFormat = """
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
class ParamBlock(object):
|
class ParamBlock(object):
|
||||||
|
|
||||||
"""Wrapper for the very low level FCBPB record."""
|
"""Wrapper for the very low level FCBPB record."""
|
||||||
|
|
||||||
def __init__(self, refNum):
|
def __init__(self, refNum):
|
||||||
self.__fileName = array.array("c", "\0" * 64)
|
self.__fileName = array.array("c", "\0" * 64)
|
||||||
sstruct.unpack(_FCBPBFormat,
|
sstruct.unpack(_FCBPBFormat,
|
||||||
"\0" * sstruct.calcsize(_FCBPBFormat), self)
|
"\0" * sstruct.calcsize(_FCBPBFormat), self)
|
||||||
self.ioNamePtr = self.__fileName.buffer_info()[0]
|
self.ioNamePtr = self.__fileName.buffer_info()[0]
|
||||||
self.ioRefNum = refNum
|
self.ioRefNum = refNum
|
||||||
self.ioVRefNum = GetVRefNum(refNum)
|
self.ioVRefNum = GetVRefNum(refNum)
|
||||||
self.__haveInfo = 0
|
self.__haveInfo = 0
|
||||||
|
|
||||||
def getInfo(self):
|
def getInfo(self):
|
||||||
if self.__haveInfo:
|
if self.__haveInfo:
|
||||||
return
|
return
|
||||||
@ -76,18 +76,18 @@ class ParamBlock(object):
|
|||||||
raise Res.Error("can't get file info", err)
|
raise Res.Error("can't get file info", err)
|
||||||
sstruct.unpack(_FCBPBFormat, buf.tostring(), self)
|
sstruct.unpack(_FCBPBFormat, buf.tostring(), self)
|
||||||
self.__haveInfo = 1
|
self.__haveInfo = 1
|
||||||
|
|
||||||
def getFileName(self):
|
def getFileName(self):
|
||||||
self.getInfo()
|
self.getInfo()
|
||||||
data = self.__fileName.tostring()
|
data = self.__fileName.tostring()
|
||||||
return data[1:byteord(data[0])+1]
|
return data[1:byteord(data[0])+1]
|
||||||
|
|
||||||
def getFSSpec(self):
|
def getFSSpec(self):
|
||||||
self.getInfo()
|
self.getInfo()
|
||||||
vRefNum = self.ioVRefNum
|
vRefNum = self.ioVRefNum
|
||||||
parID = self.ioFCBParID
|
parID = self.ioFCBParID
|
||||||
return macfs.FSSpec((vRefNum, parID, self.getFileName()))
|
return macfs.FSSpec((vRefNum, parID, self.getFileName()))
|
||||||
|
|
||||||
def getPath(self):
|
def getPath(self):
|
||||||
return self.getFSSpec().as_pathname()
|
return self.getFSSpec().as_pathname()
|
||||||
|
|
||||||
|
@ -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.
|
CFF dictionary data and Type1/Type2 CharStrings.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ cffDictOperandEncoding[30] = read_realNumber
|
|||||||
cffDictOperandEncoding[255] = read_reserved
|
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, '-']
|
'.', 'E', 'E-', None, '-']
|
||||||
realNibblesDict = dict((v,i) for i,v in enumerate(realNibbles))
|
realNibblesDict = dict((v,i) for i,v in enumerate(realNibbles))
|
||||||
|
|
||||||
@ -171,7 +171,7 @@ def getIntEncoder(format):
|
|||||||
else:
|
else:
|
||||||
assert format == "t2"
|
assert format == "t2"
|
||||||
fourByteOp = None
|
fourByteOp = None
|
||||||
|
|
||||||
def encodeInt(value, fourByteOp=fourByteOp, bytechr=bytechr,
|
def encodeInt(value, fourByteOp=fourByteOp, bytechr=bytechr,
|
||||||
pack=struct.pack, unpack=struct.unpack):
|
pack=struct.pack, unpack=struct.unpack):
|
||||||
if -107 <= value <= 107:
|
if -107 <= value <= 107:
|
||||||
@ -203,7 +203,7 @@ def getIntEncoder(format):
|
|||||||
else:
|
else:
|
||||||
code = fourByteOp + pack(">l", value)
|
code = fourByteOp + pack(">l", value)
|
||||||
return code
|
return code
|
||||||
|
|
||||||
return encodeInt
|
return encodeInt
|
||||||
|
|
||||||
|
|
||||||
@ -243,10 +243,10 @@ class CharStringCompileError(Exception): pass
|
|||||||
|
|
||||||
|
|
||||||
class T2CharString(ByteCodeBase):
|
class T2CharString(ByteCodeBase):
|
||||||
|
|
||||||
operandEncoding = t2OperandEncoding
|
operandEncoding = t2OperandEncoding
|
||||||
operators, opcodes = buildOperatorDict(t2Operators)
|
operators, opcodes = buildOperatorDict(t2Operators)
|
||||||
|
|
||||||
def __init__(self, bytecode=None, program=None, private=None, globalSubrs=None):
|
def __init__(self, bytecode=None, program=None, private=None, globalSubrs=None):
|
||||||
if program is None:
|
if program is None:
|
||||||
program = []
|
program = []
|
||||||
@ -254,16 +254,16 @@ class T2CharString(ByteCodeBase):
|
|||||||
self.program = program
|
self.program = program
|
||||||
self.private = private
|
self.private = private
|
||||||
self.globalSubrs = globalSubrs if globalSubrs is not None else []
|
self.globalSubrs = globalSubrs if globalSubrs is not None else []
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
if self.bytecode is None:
|
if self.bytecode is None:
|
||||||
return "<%s (source) at %x>" % (self.__class__.__name__, id(self))
|
return "<%s (source) at %x>" % (self.__class__.__name__, id(self))
|
||||||
else:
|
else:
|
||||||
return "<%s (bytecode) at %x>" % (self.__class__.__name__, id(self))
|
return "<%s (bytecode) at %x>" % (self.__class__.__name__, id(self))
|
||||||
|
|
||||||
def getIntEncoder(self):
|
def getIntEncoder(self):
|
||||||
return encodeIntT2
|
return encodeIntT2
|
||||||
|
|
||||||
def getFixedEncoder(self):
|
def getFixedEncoder(self):
|
||||||
return encodeFixed
|
return encodeFixed
|
||||||
|
|
||||||
@ -273,14 +273,14 @@ class T2CharString(ByteCodeBase):
|
|||||||
subrs = getattr(self.private, "Subrs", [])
|
subrs = getattr(self.private, "Subrs", [])
|
||||||
decompiler = SimpleT2Decompiler(subrs, self.globalSubrs)
|
decompiler = SimpleT2Decompiler(subrs, self.globalSubrs)
|
||||||
decompiler.execute(self)
|
decompiler.execute(self)
|
||||||
|
|
||||||
def draw(self, pen):
|
def draw(self, pen):
|
||||||
subrs = getattr(self.private, "Subrs", [])
|
subrs = getattr(self.private, "Subrs", [])
|
||||||
extractor = T2OutlineExtractor(pen, subrs, self.globalSubrs,
|
extractor = T2OutlineExtractor(pen, subrs, self.globalSubrs,
|
||||||
self.private.nominalWidthX, self.private.defaultWidthX)
|
self.private.nominalWidthX, self.private.defaultWidthX)
|
||||||
extractor.execute(self)
|
extractor.execute(self)
|
||||||
self.width = extractor.width
|
self.width = extractor.width
|
||||||
|
|
||||||
def compile(self):
|
def compile(self):
|
||||||
if self.bytecode is not None:
|
if self.bytecode is not None:
|
||||||
return
|
return
|
||||||
@ -318,18 +318,18 @@ class T2CharString(ByteCodeBase):
|
|||||||
print(bytecode)
|
print(bytecode)
|
||||||
raise
|
raise
|
||||||
self.setBytecode(bytecode)
|
self.setBytecode(bytecode)
|
||||||
|
|
||||||
def needsDecompilation(self):
|
def needsDecompilation(self):
|
||||||
return self.bytecode is not None
|
return self.bytecode is not None
|
||||||
|
|
||||||
def setProgram(self, program):
|
def setProgram(self, program):
|
||||||
self.program = program
|
self.program = program
|
||||||
self.bytecode = None
|
self.bytecode = None
|
||||||
|
|
||||||
def setBytecode(self, bytecode):
|
def setBytecode(self, bytecode):
|
||||||
self.bytecode = bytecode
|
self.bytecode = bytecode
|
||||||
self.program = None
|
self.program = None
|
||||||
|
|
||||||
def getToken(self, index,
|
def getToken(self, index,
|
||||||
len=len, byteord=byteord, basestring=basestring,
|
len=len, byteord=byteord, basestring=basestring,
|
||||||
isinstance=isinstance):
|
isinstance=isinstance):
|
||||||
@ -347,7 +347,7 @@ class T2CharString(ByteCodeBase):
|
|||||||
index = index + 1
|
index = index + 1
|
||||||
isOperator = isinstance(token, basestring)
|
isOperator = isinstance(token, basestring)
|
||||||
return token, isOperator, index
|
return token, isOperator, index
|
||||||
|
|
||||||
def getBytes(self, index, nBytes):
|
def getBytes(self, index, nBytes):
|
||||||
if self.bytecode is not None:
|
if self.bytecode is not None:
|
||||||
newIndex = index + nBytes
|
newIndex = index + nBytes
|
||||||
@ -358,10 +358,10 @@ class T2CharString(ByteCodeBase):
|
|||||||
index = index + 1
|
index = index + 1
|
||||||
assert len(bytes) == nBytes
|
assert len(bytes) == nBytes
|
||||||
return bytes, index
|
return bytes, index
|
||||||
|
|
||||||
def handle_operator(self, operator):
|
def handle_operator(self, operator):
|
||||||
return operator
|
return operator
|
||||||
|
|
||||||
def toXML(self, xmlWriter):
|
def toXML(self, xmlWriter):
|
||||||
from fontTools.misc.textTools import num2binary
|
from fontTools.misc.textTools import num2binary
|
||||||
if self.bytecode is not None:
|
if self.bytecode is not None:
|
||||||
@ -389,7 +389,7 @@ class T2CharString(ByteCodeBase):
|
|||||||
args = []
|
args = []
|
||||||
else:
|
else:
|
||||||
args.append(token)
|
args.append(token)
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content):
|
def fromXML(self, name, attrs, content):
|
||||||
from fontTools.misc.textTools import binary2num, readHex
|
from fontTools.misc.textTools import binary2num, readHex
|
||||||
if attrs.get("raw"):
|
if attrs.get("raw"):
|
||||||
@ -454,10 +454,10 @@ t1Operators = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
class T1CharString(T2CharString):
|
class T1CharString(T2CharString):
|
||||||
|
|
||||||
operandEncoding = t1OperandEncoding
|
operandEncoding = t1OperandEncoding
|
||||||
operators, opcodes = buildOperatorDict(t1Operators)
|
operators, opcodes = buildOperatorDict(t1Operators)
|
||||||
|
|
||||||
def __init__(self, bytecode=None, program=None, subrs=None):
|
def __init__(self, bytecode=None, program=None, subrs=None):
|
||||||
if program is None:
|
if program is None:
|
||||||
program = []
|
program = []
|
||||||
@ -491,20 +491,20 @@ class T1CharString(T2CharString):
|
|||||||
|
|
||||||
|
|
||||||
class SimpleT2Decompiler(object):
|
class SimpleT2Decompiler(object):
|
||||||
|
|
||||||
def __init__(self, localSubrs, globalSubrs):
|
def __init__(self, localSubrs, globalSubrs):
|
||||||
self.localSubrs = localSubrs
|
self.localSubrs = localSubrs
|
||||||
self.localBias = calcSubrBias(localSubrs)
|
self.localBias = calcSubrBias(localSubrs)
|
||||||
self.globalSubrs = globalSubrs
|
self.globalSubrs = globalSubrs
|
||||||
self.globalBias = calcSubrBias(globalSubrs)
|
self.globalBias = calcSubrBias(globalSubrs)
|
||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
self.callingStack = []
|
self.callingStack = []
|
||||||
self.operandStack = []
|
self.operandStack = []
|
||||||
self.hintCount = 0
|
self.hintCount = 0
|
||||||
self.hintMaskBytes = 0
|
self.hintMaskBytes = 0
|
||||||
|
|
||||||
def execute(self, charString):
|
def execute(self, charString):
|
||||||
self.callingStack.append(charString)
|
self.callingStack.append(charString)
|
||||||
needsDecompilation = charString.needsDecompilation()
|
needsDecompilation = charString.needsDecompilation()
|
||||||
@ -538,24 +538,24 @@ class SimpleT2Decompiler(object):
|
|||||||
"seac"), "illegal CharString"
|
"seac"), "illegal CharString"
|
||||||
charString.setProgram(program)
|
charString.setProgram(program)
|
||||||
del self.callingStack[-1]
|
del self.callingStack[-1]
|
||||||
|
|
||||||
def pop(self):
|
def pop(self):
|
||||||
value = self.operandStack[-1]
|
value = self.operandStack[-1]
|
||||||
del self.operandStack[-1]
|
del self.operandStack[-1]
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def popall(self):
|
def popall(self):
|
||||||
stack = self.operandStack[:]
|
stack = self.operandStack[:]
|
||||||
self.operandStack[:] = []
|
self.operandStack[:] = []
|
||||||
return stack
|
return stack
|
||||||
|
|
||||||
def push(self, value):
|
def push(self, value):
|
||||||
self.operandStack.append(value)
|
self.operandStack.append(value)
|
||||||
|
|
||||||
def op_return(self, index):
|
def op_return(self, index):
|
||||||
if self.operandStack:
|
if self.operandStack:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def op_endchar(self, index):
|
def op_endchar(self, index):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -566,12 +566,12 @@ class SimpleT2Decompiler(object):
|
|||||||
subrIndex = self.pop()
|
subrIndex = self.pop()
|
||||||
subr = self.localSubrs[subrIndex+self.localBias]
|
subr = self.localSubrs[subrIndex+self.localBias]
|
||||||
self.execute(subr)
|
self.execute(subr)
|
||||||
|
|
||||||
def op_callgsubr(self, index):
|
def op_callgsubr(self, index):
|
||||||
subrIndex = self.pop()
|
subrIndex = self.pop()
|
||||||
subr = self.globalSubrs[subrIndex+self.globalBias]
|
subr = self.globalSubrs[subrIndex+self.globalBias]
|
||||||
self.execute(subr)
|
self.execute(subr)
|
||||||
|
|
||||||
def op_hstem(self, index):
|
def op_hstem(self, index):
|
||||||
self.countHints()
|
self.countHints()
|
||||||
def op_vstem(self, index):
|
def op_vstem(self, index):
|
||||||
@ -580,16 +580,16 @@ class SimpleT2Decompiler(object):
|
|||||||
self.countHints()
|
self.countHints()
|
||||||
def op_vstemhm(self, index):
|
def op_vstemhm(self, index):
|
||||||
self.countHints()
|
self.countHints()
|
||||||
|
|
||||||
def op_hintmask(self, index):
|
def op_hintmask(self, index):
|
||||||
if not self.hintMaskBytes:
|
if not self.hintMaskBytes:
|
||||||
self.countHints()
|
self.countHints()
|
||||||
self.hintMaskBytes = (self.hintCount + 7) // 8
|
self.hintMaskBytes = (self.hintCount + 7) // 8
|
||||||
hintMaskBytes, index = self.callingStack[-1].getBytes(index, self.hintMaskBytes)
|
hintMaskBytes, index = self.callingStack[-1].getBytes(index, self.hintMaskBytes)
|
||||||
return hintMaskBytes, index
|
return hintMaskBytes, index
|
||||||
|
|
||||||
op_cntrmask = op_hintmask
|
op_cntrmask = op_hintmask
|
||||||
|
|
||||||
def countHints(self):
|
def countHints(self):
|
||||||
args = self.popall()
|
args = self.popall()
|
||||||
self.hintCount = self.hintCount + len(args) // 2
|
self.hintCount = self.hintCount + len(args) // 2
|
||||||
@ -641,13 +641,13 @@ class SimpleT2Decompiler(object):
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
class T2OutlineExtractor(SimpleT2Decompiler):
|
class T2OutlineExtractor(SimpleT2Decompiler):
|
||||||
|
|
||||||
def __init__(self, pen, localSubrs, globalSubrs, nominalWidthX, defaultWidthX):
|
def __init__(self, pen, localSubrs, globalSubrs, nominalWidthX, defaultWidthX):
|
||||||
SimpleT2Decompiler.__init__(self, localSubrs, globalSubrs)
|
SimpleT2Decompiler.__init__(self, localSubrs, globalSubrs)
|
||||||
self.pen = pen
|
self.pen = pen
|
||||||
self.nominalWidthX = nominalWidthX
|
self.nominalWidthX = nominalWidthX
|
||||||
self.defaultWidthX = defaultWidthX
|
self.defaultWidthX = defaultWidthX
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
SimpleT2Decompiler.reset(self)
|
SimpleT2Decompiler.reset(self)
|
||||||
self.hints = []
|
self.hints = []
|
||||||
@ -655,13 +655,13 @@ class T2OutlineExtractor(SimpleT2Decompiler):
|
|||||||
self.width = 0
|
self.width = 0
|
||||||
self.currentPoint = (0, 0)
|
self.currentPoint = (0, 0)
|
||||||
self.sawMoveTo = 0
|
self.sawMoveTo = 0
|
||||||
|
|
||||||
def _nextPoint(self, point):
|
def _nextPoint(self, point):
|
||||||
x, y = self.currentPoint
|
x, y = self.currentPoint
|
||||||
point = x + point[0], y + point[1]
|
point = x + point[0], y + point[1]
|
||||||
self.currentPoint = point
|
self.currentPoint = point
|
||||||
return point
|
return point
|
||||||
|
|
||||||
def rMoveTo(self, point):
|
def rMoveTo(self, point):
|
||||||
self.pen.moveTo(self._nextPoint(point))
|
self.pen.moveTo(self._nextPoint(point))
|
||||||
self.sawMoveTo = 1
|
self.sawMoveTo = 1
|
||||||
@ -676,12 +676,12 @@ class T2OutlineExtractor(SimpleT2Decompiler):
|
|||||||
self.rMoveTo((0, 0))
|
self.rMoveTo((0, 0))
|
||||||
nextPoint = self._nextPoint
|
nextPoint = self._nextPoint
|
||||||
self.pen.curveTo(nextPoint(pt1), nextPoint(pt2), nextPoint(pt3))
|
self.pen.curveTo(nextPoint(pt1), nextPoint(pt2), nextPoint(pt3))
|
||||||
|
|
||||||
def closePath(self):
|
def closePath(self):
|
||||||
if self.sawMoveTo:
|
if self.sawMoveTo:
|
||||||
self.pen.closePath()
|
self.pen.closePath()
|
||||||
self.sawMoveTo = 0
|
self.sawMoveTo = 0
|
||||||
|
|
||||||
def endPath(self):
|
def endPath(self):
|
||||||
# In T2 there are no open paths, so always do a closePath when
|
# In T2 there are no open paths, so always do a closePath when
|
||||||
# finishing a sub path.
|
# finishing a sub path.
|
||||||
@ -697,11 +697,11 @@ class T2OutlineExtractor(SimpleT2Decompiler):
|
|||||||
self.width = self.defaultWidthX
|
self.width = self.defaultWidthX
|
||||||
self.gotWidth = 1
|
self.gotWidth = 1
|
||||||
return args
|
return args
|
||||||
|
|
||||||
def countHints(self):
|
def countHints(self):
|
||||||
args = self.popallWidth()
|
args = self.popallWidth()
|
||||||
self.hintCount = self.hintCount + len(args) // 2
|
self.hintCount = self.hintCount + len(args) // 2
|
||||||
|
|
||||||
#
|
#
|
||||||
# hint operators
|
# hint operators
|
||||||
#
|
#
|
||||||
@ -717,7 +717,7 @@ class T2OutlineExtractor(SimpleT2Decompiler):
|
|||||||
# self.countHints()
|
# self.countHints()
|
||||||
#def op_cntrmask(self, index):
|
#def op_cntrmask(self, index):
|
||||||
# self.countHints()
|
# self.countHints()
|
||||||
|
|
||||||
#
|
#
|
||||||
# path constructors, moveto
|
# path constructors, moveto
|
||||||
#
|
#
|
||||||
@ -742,7 +742,7 @@ class T2OutlineExtractor(SimpleT2Decompiler):
|
|||||||
self.pen.addComponent(baseGlyph, (1, 0, 0, 1, 0, 0))
|
self.pen.addComponent(baseGlyph, (1, 0, 0, 1, 0, 0))
|
||||||
accentGlyph = StandardEncoding[achar]
|
accentGlyph = StandardEncoding[achar]
|
||||||
self.pen.addComponent(accentGlyph, (1, 0, 0, 1, adx, ady))
|
self.pen.addComponent(accentGlyph, (1, 0, 0, 1, adx, ady))
|
||||||
|
|
||||||
#
|
#
|
||||||
# path constructors, lines
|
# path constructors, lines
|
||||||
#
|
#
|
||||||
@ -751,12 +751,12 @@ class T2OutlineExtractor(SimpleT2Decompiler):
|
|||||||
for i in range(0, len(args), 2):
|
for i in range(0, len(args), 2):
|
||||||
point = args[i:i+2]
|
point = args[i:i+2]
|
||||||
self.rLineTo(point)
|
self.rLineTo(point)
|
||||||
|
|
||||||
def op_hlineto(self, index):
|
def op_hlineto(self, index):
|
||||||
self.alternatingLineto(1)
|
self.alternatingLineto(1)
|
||||||
def op_vlineto(self, index):
|
def op_vlineto(self, index):
|
||||||
self.alternatingLineto(0)
|
self.alternatingLineto(0)
|
||||||
|
|
||||||
#
|
#
|
||||||
# path constructors, curves
|
# path constructors, curves
|
||||||
#
|
#
|
||||||
@ -766,7 +766,7 @@ class T2OutlineExtractor(SimpleT2Decompiler):
|
|||||||
for i in range(0, len(args), 6):
|
for i in range(0, len(args), 6):
|
||||||
dxa, dya, dxb, dyb, dxc, dyc, = args[i:i+6]
|
dxa, dya, dxb, dyb, dxc, dyc, = args[i:i+6]
|
||||||
self.rCurveTo((dxa, dya), (dxb, dyb), (dxc, dyc))
|
self.rCurveTo((dxa, dya), (dxb, dyb), (dxc, dyc))
|
||||||
|
|
||||||
def op_rcurveline(self, index):
|
def op_rcurveline(self, index):
|
||||||
"""{dxa dya dxb dyb dxc dyc}+ dxd dyd rcurveline"""
|
"""{dxa dya dxb dyb dxc dyc}+ dxd dyd rcurveline"""
|
||||||
args = self.popall()
|
args = self.popall()
|
||||||
@ -774,7 +774,7 @@ class T2OutlineExtractor(SimpleT2Decompiler):
|
|||||||
dxb, dyb, dxc, dyc, dxd, dyd = args[i:i+6]
|
dxb, dyb, dxc, dyc, dxd, dyd = args[i:i+6]
|
||||||
self.rCurveTo((dxb, dyb), (dxc, dyc), (dxd, dyd))
|
self.rCurveTo((dxb, dyb), (dxc, dyc), (dxd, dyd))
|
||||||
self.rLineTo(args[-2:])
|
self.rLineTo(args[-2:])
|
||||||
|
|
||||||
def op_rlinecurve(self, index):
|
def op_rlinecurve(self, index):
|
||||||
"""{dxa dya}+ dxb dyb dxc dyc dxd dyd rlinecurve"""
|
"""{dxa dya}+ dxb dyb dxc dyc dxd dyd rlinecurve"""
|
||||||
args = self.popall()
|
args = self.popall()
|
||||||
@ -783,7 +783,7 @@ class T2OutlineExtractor(SimpleT2Decompiler):
|
|||||||
self.rLineTo(lineArgs[i:i+2])
|
self.rLineTo(lineArgs[i:i+2])
|
||||||
dxb, dyb, dxc, dyc, dxd, dyd = args[-6:]
|
dxb, dyb, dxc, dyc, dxd, dyd = args[-6:]
|
||||||
self.rCurveTo((dxb, dyb), (dxc, dyc), (dxd, dyd))
|
self.rCurveTo((dxb, dyb), (dxc, dyc), (dxd, dyd))
|
||||||
|
|
||||||
def op_vvcurveto(self, index):
|
def op_vvcurveto(self, index):
|
||||||
"dx1? {dya dxb dyb dyc}+ vvcurveto"
|
"dx1? {dya dxb dyb dyc}+ vvcurveto"
|
||||||
args = self.popall()
|
args = self.popall()
|
||||||
@ -796,7 +796,7 @@ class T2OutlineExtractor(SimpleT2Decompiler):
|
|||||||
dya, dxb, dyb, dyc = args[i:i+4]
|
dya, dxb, dyb, dyc = args[i:i+4]
|
||||||
self.rCurveTo((dx1, dya), (dxb, dyb), (0, dyc))
|
self.rCurveTo((dx1, dya), (dxb, dyb), (0, dyc))
|
||||||
dx1 = 0
|
dx1 = 0
|
||||||
|
|
||||||
def op_hhcurveto(self, index):
|
def op_hhcurveto(self, index):
|
||||||
"""dy1? {dxa dxb dyb dxc}+ hhcurveto"""
|
"""dy1? {dxa dxb dyb dxc}+ hhcurveto"""
|
||||||
args = self.popall()
|
args = self.popall()
|
||||||
@ -809,7 +809,7 @@ class T2OutlineExtractor(SimpleT2Decompiler):
|
|||||||
dxa, dxb, dyb, dxc = args[i:i+4]
|
dxa, dxb, dyb, dxc = args[i:i+4]
|
||||||
self.rCurveTo((dxa, dy1), (dxb, dyb), (dxc, 0))
|
self.rCurveTo((dxa, dy1), (dxb, dyb), (dxc, 0))
|
||||||
dy1 = 0
|
dy1 = 0
|
||||||
|
|
||||||
def op_vhcurveto(self, index):
|
def op_vhcurveto(self, index):
|
||||||
"""dy1 dx2 dy2 dx3 {dxa dxb dyb dyc dyd dxe dye dxf}* dyf? vhcurveto (30)
|
"""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
|
{dya dxb dyb dxc dxd dxe dye dyf}+ dxf? vhcurveto
|
||||||
@ -819,7 +819,7 @@ class T2OutlineExtractor(SimpleT2Decompiler):
|
|||||||
args = self.vcurveto(args)
|
args = self.vcurveto(args)
|
||||||
if args:
|
if args:
|
||||||
args = self.hcurveto(args)
|
args = self.hcurveto(args)
|
||||||
|
|
||||||
def op_hvcurveto(self, index):
|
def op_hvcurveto(self, index):
|
||||||
"""dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* dxf?
|
"""dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* dxf?
|
||||||
{dxa dxb dyb dyc dyd dxe dye dxf}+ dyf?
|
{dxa dxb dyb dyc dyd dxe dye dxf}+ dyf?
|
||||||
@ -829,7 +829,7 @@ class T2OutlineExtractor(SimpleT2Decompiler):
|
|||||||
args = self.hcurveto(args)
|
args = self.hcurveto(args)
|
||||||
if args:
|
if args:
|
||||||
args = self.vcurveto(args)
|
args = self.vcurveto(args)
|
||||||
|
|
||||||
#
|
#
|
||||||
# path constructors, flex
|
# path constructors, flex
|
||||||
#
|
#
|
||||||
@ -862,13 +862,13 @@ class T2OutlineExtractor(SimpleT2Decompiler):
|
|||||||
dy6 = d6
|
dy6 = d6
|
||||||
self.rCurveTo((dx1, dy1), (dx2, dy2), (dx3, dy3))
|
self.rCurveTo((dx1, dy1), (dx2, dy2), (dx3, dy3))
|
||||||
self.rCurveTo((dx4, dy4), (dx5, dy5), (dx6, dy6))
|
self.rCurveTo((dx4, dy4), (dx5, dy5), (dx6, dy6))
|
||||||
|
|
||||||
#
|
#
|
||||||
# MultipleMaster. Well...
|
# MultipleMaster. Well...
|
||||||
#
|
#
|
||||||
def op_blend(self, index):
|
def op_blend(self, index):
|
||||||
self.popall()
|
self.popall()
|
||||||
|
|
||||||
# misc
|
# misc
|
||||||
def op_and(self, index):
|
def op_and(self, index):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
@ -921,7 +921,7 @@ class T2OutlineExtractor(SimpleT2Decompiler):
|
|||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
def op_roll(self, index):
|
def op_roll(self, index):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
#
|
#
|
||||||
# miscellaneous helpers
|
# miscellaneous helpers
|
||||||
#
|
#
|
||||||
@ -934,7 +934,7 @@ class T2OutlineExtractor(SimpleT2Decompiler):
|
|||||||
point = (0, arg)
|
point = (0, arg)
|
||||||
self.rLineTo(point)
|
self.rLineTo(point)
|
||||||
isHorizontal = not isHorizontal
|
isHorizontal = not isHorizontal
|
||||||
|
|
||||||
def vcurveto(self, args):
|
def vcurveto(self, args):
|
||||||
dya, dxb, dyb, dxc = args[:4]
|
dya, dxb, dyb, dxc = args[:4]
|
||||||
args = args[4:]
|
args = args[4:]
|
||||||
@ -945,7 +945,7 @@ class T2OutlineExtractor(SimpleT2Decompiler):
|
|||||||
dyc = 0
|
dyc = 0
|
||||||
self.rCurveTo((0, dya), (dxb, dyb), (dxc, dyc))
|
self.rCurveTo((0, dya), (dxb, dyb), (dxc, dyc))
|
||||||
return args
|
return args
|
||||||
|
|
||||||
def hcurveto(self, args):
|
def hcurveto(self, args):
|
||||||
dxa, dxb, dyb, dyc = args[:4]
|
dxa, dxb, dyb, dyc = args[:4]
|
||||||
args = args[4:]
|
args = args[4:]
|
||||||
@ -959,18 +959,18 @@ class T2OutlineExtractor(SimpleT2Decompiler):
|
|||||||
|
|
||||||
|
|
||||||
class T1OutlineExtractor(T2OutlineExtractor):
|
class T1OutlineExtractor(T2OutlineExtractor):
|
||||||
|
|
||||||
def __init__(self, pen, subrs):
|
def __init__(self, pen, subrs):
|
||||||
self.pen = pen
|
self.pen = pen
|
||||||
self.subrs = subrs
|
self.subrs = subrs
|
||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
self.flexing = 0
|
self.flexing = 0
|
||||||
self.width = 0
|
self.width = 0
|
||||||
self.sbx = 0
|
self.sbx = 0
|
||||||
T2OutlineExtractor.reset(self)
|
T2OutlineExtractor.reset(self)
|
||||||
|
|
||||||
def endPath(self):
|
def endPath(self):
|
||||||
if self.sawMoveTo:
|
if self.sawMoveTo:
|
||||||
self.pen.endPath()
|
self.pen.endPath()
|
||||||
@ -978,11 +978,11 @@ class T1OutlineExtractor(T2OutlineExtractor):
|
|||||||
|
|
||||||
def popallWidth(self, evenOdd=0):
|
def popallWidth(self, evenOdd=0):
|
||||||
return self.popall()
|
return self.popall()
|
||||||
|
|
||||||
def exch(self):
|
def exch(self):
|
||||||
stack = self.operandStack
|
stack = self.operandStack
|
||||||
stack[-1], stack[-2] = stack[-2], stack[-1]
|
stack[-1], stack[-2] = stack[-2], stack[-1]
|
||||||
|
|
||||||
#
|
#
|
||||||
# path constructors
|
# path constructors
|
||||||
#
|
#
|
||||||
@ -1012,10 +1012,10 @@ class T1OutlineExtractor(T2OutlineExtractor):
|
|||||||
args = self.popall()
|
args = self.popall()
|
||||||
x, y = args
|
x, y = args
|
||||||
self.currentPoint = x, y
|
self.currentPoint = x, y
|
||||||
|
|
||||||
def op_endchar(self, index):
|
def op_endchar(self, index):
|
||||||
self.endPath()
|
self.endPath()
|
||||||
|
|
||||||
def op_hsbw(self, index):
|
def op_hsbw(self, index):
|
||||||
sbx, wx = self.popall()
|
sbx, wx = self.popall()
|
||||||
self.width = wx
|
self.width = wx
|
||||||
@ -1023,7 +1023,7 @@ class T1OutlineExtractor(T2OutlineExtractor):
|
|||||||
self.currentPoint = sbx, self.currentPoint[1]
|
self.currentPoint = sbx, self.currentPoint[1]
|
||||||
def op_sbw(self, index):
|
def op_sbw(self, index):
|
||||||
self.popall() # XXX
|
self.popall() # XXX
|
||||||
|
|
||||||
#
|
#
|
||||||
def op_callsubr(self, index):
|
def op_callsubr(self, index):
|
||||||
subrIndex = self.pop()
|
subrIndex = self.pop()
|
||||||
@ -1041,12 +1041,12 @@ class T1OutlineExtractor(T2OutlineExtractor):
|
|||||||
# ignore...
|
# ignore...
|
||||||
def op_pop(self, index):
|
def op_pop(self, index):
|
||||||
pass # ignore...
|
pass # ignore...
|
||||||
|
|
||||||
def doFlex(self):
|
def doFlex(self):
|
||||||
finaly = self.pop()
|
finaly = self.pop()
|
||||||
finalx = self.pop()
|
finalx = self.pop()
|
||||||
self.pop() # flex height is unused
|
self.pop() # flex height is unused
|
||||||
|
|
||||||
p3y = self.pop()
|
p3y = self.pop()
|
||||||
p3x = self.pop()
|
p3x = self.pop()
|
||||||
bcp4y = self.pop()
|
bcp4y = self.pop()
|
||||||
@ -1061,7 +1061,7 @@ class T1OutlineExtractor(T2OutlineExtractor):
|
|||||||
bcp1x = self.pop()
|
bcp1x = self.pop()
|
||||||
rpy = self.pop()
|
rpy = self.pop()
|
||||||
rpx = self.pop()
|
rpx = self.pop()
|
||||||
|
|
||||||
# call rrcurveto
|
# call rrcurveto
|
||||||
self.push(bcp1x+rpx)
|
self.push(bcp1x+rpx)
|
||||||
self.push(bcp1y+rpy)
|
self.push(bcp1y+rpy)
|
||||||
@ -1070,7 +1070,7 @@ class T1OutlineExtractor(T2OutlineExtractor):
|
|||||||
self.push(p2x)
|
self.push(p2x)
|
||||||
self.push(p2y)
|
self.push(p2y)
|
||||||
self.op_rrcurveto(None)
|
self.op_rrcurveto(None)
|
||||||
|
|
||||||
# call rrcurveto
|
# call rrcurveto
|
||||||
self.push(bcp3x)
|
self.push(bcp3x)
|
||||||
self.push(bcp3y)
|
self.push(bcp3y)
|
||||||
@ -1079,11 +1079,11 @@ class T1OutlineExtractor(T2OutlineExtractor):
|
|||||||
self.push(p3x)
|
self.push(p3x)
|
||||||
self.push(p3y)
|
self.push(p3y)
|
||||||
self.op_rrcurveto(None)
|
self.op_rrcurveto(None)
|
||||||
|
|
||||||
# Push back final coords so subr 0 can find them
|
# Push back final coords so subr 0 can find them
|
||||||
self.push(finalx)
|
self.push(finalx)
|
||||||
self.push(finaly)
|
self.push(finaly)
|
||||||
|
|
||||||
def op_dotsection(self, index):
|
def op_dotsection(self, index):
|
||||||
self.popall() # XXX
|
self.popall() # XXX
|
||||||
def op_hstem3(self, index):
|
def op_hstem3(self, index):
|
||||||
@ -1102,18 +1102,18 @@ class T1OutlineExtractor(T2OutlineExtractor):
|
|||||||
|
|
||||||
|
|
||||||
class DictDecompiler(ByteCodeBase):
|
class DictDecompiler(ByteCodeBase):
|
||||||
|
|
||||||
operandEncoding = cffDictOperandEncoding
|
operandEncoding = cffDictOperandEncoding
|
||||||
|
|
||||||
def __init__(self, strings):
|
def __init__(self, strings):
|
||||||
self.stack = []
|
self.stack = []
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
self.dict = {}
|
self.dict = {}
|
||||||
|
|
||||||
def getDict(self):
|
def getDict(self):
|
||||||
assert len(self.stack) == 0, "non-empty stack"
|
assert len(self.stack) == 0, "non-empty stack"
|
||||||
return self.dict
|
return self.dict
|
||||||
|
|
||||||
def decompile(self, data):
|
def decompile(self, data):
|
||||||
index = 0
|
index = 0
|
||||||
lenData = len(data)
|
lenData = len(data)
|
||||||
@ -1125,17 +1125,17 @@ class DictDecompiler(ByteCodeBase):
|
|||||||
value, index = handler(self, b0, data, index)
|
value, index = handler(self, b0, data, index)
|
||||||
if value is not None:
|
if value is not None:
|
||||||
push(value)
|
push(value)
|
||||||
|
|
||||||
def pop(self):
|
def pop(self):
|
||||||
value = self.stack[-1]
|
value = self.stack[-1]
|
||||||
del self.stack[-1]
|
del self.stack[-1]
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def popall(self):
|
def popall(self):
|
||||||
args = self.stack[:]
|
args = self.stack[:]
|
||||||
del self.stack[:]
|
del self.stack[:]
|
||||||
return args
|
return args
|
||||||
|
|
||||||
def handle_operator(self, operator):
|
def handle_operator(self, operator):
|
||||||
operator, argType = operator
|
operator, argType = operator
|
||||||
if isinstance(argType, type(())):
|
if isinstance(argType, type(())):
|
||||||
@ -1148,7 +1148,7 @@ class DictDecompiler(ByteCodeBase):
|
|||||||
arghandler = getattr(self, "arg_" + argType)
|
arghandler = getattr(self, "arg_" + argType)
|
||||||
value = arghandler(operator)
|
value = arghandler(operator)
|
||||||
self.dict[operator] = value
|
self.dict[operator] = value
|
||||||
|
|
||||||
def arg_number(self, name):
|
def arg_number(self, name):
|
||||||
return self.pop()
|
return self.pop()
|
||||||
def arg_SID(self, name):
|
def arg_SID(self, name):
|
||||||
|
@ -39,7 +39,7 @@ class PSError(Exception): pass
|
|||||||
|
|
||||||
|
|
||||||
class PSTokenizer(StringIO):
|
class PSTokenizer(StringIO):
|
||||||
|
|
||||||
def getnexttoken(self,
|
def getnexttoken(self,
|
||||||
# localize some stuff, for performance
|
# localize some stuff, for performance
|
||||||
len=len,
|
len=len,
|
||||||
@ -47,9 +47,9 @@ class PSTokenizer(StringIO):
|
|||||||
stringmatch=stringRE.match,
|
stringmatch=stringRE.match,
|
||||||
hexstringmatch=hexstringRE.match,
|
hexstringmatch=hexstringRE.match,
|
||||||
commentmatch=commentRE.match,
|
commentmatch=commentRE.match,
|
||||||
endmatch=endofthingRE.match,
|
endmatch=endofthingRE.match,
|
||||||
whitematch=skipwhiteRE.match):
|
whitematch=skipwhiteRE.match):
|
||||||
|
|
||||||
_, nextpos = whitematch(self.buf, self.pos).span()
|
_, nextpos = whitematch(self.buf, self.pos).span()
|
||||||
self.pos = nextpos
|
self.pos = nextpos
|
||||||
if self.pos >= self.len:
|
if self.pos >= self.len:
|
||||||
@ -94,11 +94,11 @@ class PSTokenizer(StringIO):
|
|||||||
token = buf[pos:nextpos]
|
token = buf[pos:nextpos]
|
||||||
self.pos = pos + len(token)
|
self.pos = pos + len(token)
|
||||||
return tokentype, token
|
return tokentype, token
|
||||||
|
|
||||||
def skipwhite(self, whitematch=skipwhiteRE.match):
|
def skipwhite(self, whitematch=skipwhiteRE.match):
|
||||||
_, nextpos = whitematch(self.buf, self.pos).span()
|
_, nextpos = whitematch(self.buf, self.pos).span()
|
||||||
self.pos = nextpos
|
self.pos = nextpos
|
||||||
|
|
||||||
def starteexec(self):
|
def starteexec(self):
|
||||||
self.pos = self.pos + 1
|
self.pos = self.pos + 1
|
||||||
#self.skipwhite()
|
#self.skipwhite()
|
||||||
@ -106,13 +106,13 @@ class PSTokenizer(StringIO):
|
|||||||
self.buf, R = eexec.decrypt(self.dirtybuf, 55665)
|
self.buf, R = eexec.decrypt(self.dirtybuf, 55665)
|
||||||
self.len = len(self.buf)
|
self.len = len(self.buf)
|
||||||
self.pos = 4
|
self.pos = 4
|
||||||
|
|
||||||
def stopeexec(self):
|
def stopeexec(self):
|
||||||
if not hasattr(self, 'dirtybuf'):
|
if not hasattr(self, 'dirtybuf'):
|
||||||
return
|
return
|
||||||
self.buf = self.dirtybuf
|
self.buf = self.dirtybuf
|
||||||
del self.dirtybuf
|
del self.dirtybuf
|
||||||
|
|
||||||
def flush(self):
|
def flush(self):
|
||||||
if self.buflist:
|
if self.buflist:
|
||||||
self.buf = self.buf + "".join(self.buflist)
|
self.buf = self.buf + "".join(self.buflist)
|
||||||
@ -120,7 +120,7 @@ class PSTokenizer(StringIO):
|
|||||||
|
|
||||||
|
|
||||||
class PSInterpreter(PSOperators):
|
class PSInterpreter(PSOperators):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
systemdict = {}
|
systemdict = {}
|
||||||
userdict = {}
|
userdict = {}
|
||||||
@ -129,7 +129,7 @@ class PSInterpreter(PSOperators):
|
|||||||
self.proclevel = 0
|
self.proclevel = 0
|
||||||
self.procmark = ps_procmark()
|
self.procmark = ps_procmark()
|
||||||
self.fillsystemdict()
|
self.fillsystemdict()
|
||||||
|
|
||||||
def fillsystemdict(self):
|
def fillsystemdict(self):
|
||||||
systemdict = self.dictstack[0]
|
systemdict = self.dictstack[0]
|
||||||
systemdict['['] = systemdict['mark'] = self.mark = ps_mark()
|
systemdict['['] = systemdict['mark'] = self.mark = ps_mark()
|
||||||
@ -139,7 +139,7 @@ class PSInterpreter(PSOperators):
|
|||||||
systemdict['StandardEncoding'] = ps_array(ps_StandardEncoding)
|
systemdict['StandardEncoding'] = ps_array(ps_StandardEncoding)
|
||||||
systemdict['FontDirectory'] = ps_dict({})
|
systemdict['FontDirectory'] = ps_dict({})
|
||||||
self.suckoperators(systemdict, self.__class__)
|
self.suckoperators(systemdict, self.__class__)
|
||||||
|
|
||||||
def suckoperators(self, systemdict, klass):
|
def suckoperators(self, systemdict, klass):
|
||||||
for name in dir(klass):
|
for name in dir(klass):
|
||||||
attr = getattr(self, name)
|
attr = getattr(self, name)
|
||||||
@ -148,7 +148,7 @@ class PSInterpreter(PSOperators):
|
|||||||
systemdict[name] = ps_operator(name, attr)
|
systemdict[name] = ps_operator(name, attr)
|
||||||
for baseclass in klass.__bases__:
|
for baseclass in klass.__bases__:
|
||||||
self.suckoperators(systemdict, baseclass)
|
self.suckoperators(systemdict, baseclass)
|
||||||
|
|
||||||
def interpret(self, data, getattr=getattr):
|
def interpret(self, data, getattr=getattr):
|
||||||
tokenizer = self.tokenizer = PSTokenizer(data)
|
tokenizer = self.tokenizer = PSTokenizer(data)
|
||||||
getnexttoken = tokenizer.getnexttoken
|
getnexttoken = tokenizer.getnexttoken
|
||||||
@ -177,7 +177,7 @@ class PSInterpreter(PSOperators):
|
|||||||
print('>>>')
|
print('>>>')
|
||||||
print(self.tokenizer.buf[self.tokenizer.pos:self.tokenizer.pos+50])
|
print(self.tokenizer.buf[self.tokenizer.pos:self.tokenizer.pos+50])
|
||||||
print('- - - - - - -')
|
print('- - - - - - -')
|
||||||
|
|
||||||
def handle_object(self, object):
|
def handle_object(self, object):
|
||||||
if not (self.proclevel or object.literal or object.type == 'proceduretype'):
|
if not (self.proclevel or object.literal or object.type == 'proceduretype'):
|
||||||
if object.type != 'operatortype':
|
if object.type != 'operatortype':
|
||||||
@ -191,21 +191,21 @@ class PSInterpreter(PSOperators):
|
|||||||
object.function()
|
object.function()
|
||||||
else:
|
else:
|
||||||
self.push(object)
|
self.push(object)
|
||||||
|
|
||||||
def call_procedure(self, proc):
|
def call_procedure(self, proc):
|
||||||
handle_object = self.handle_object
|
handle_object = self.handle_object
|
||||||
for item in proc.value:
|
for item in proc.value:
|
||||||
handle_object(item)
|
handle_object(item)
|
||||||
|
|
||||||
def resolve_name(self, name):
|
def resolve_name(self, name):
|
||||||
dictstack = self.dictstack
|
dictstack = self.dictstack
|
||||||
for i in range(len(dictstack)-1, -1, -1):
|
for i in range(len(dictstack)-1, -1, -1):
|
||||||
if name in dictstack[i]:
|
if name in dictstack[i]:
|
||||||
return dictstack[i][name]
|
return dictstack[i][name]
|
||||||
raise PSError('name error: ' + str(name))
|
raise PSError('name error: ' + str(name))
|
||||||
|
|
||||||
def do_token(self, token,
|
def do_token(self, token,
|
||||||
int=int,
|
int=int,
|
||||||
float=float,
|
float=float,
|
||||||
ps_name=ps_name,
|
ps_name=ps_name,
|
||||||
ps_integer=ps_integer,
|
ps_integer=ps_integer,
|
||||||
@ -231,16 +231,16 @@ class PSInterpreter(PSOperators):
|
|||||||
return ps_real(num)
|
return ps_real(num)
|
||||||
else:
|
else:
|
||||||
return ps_integer(num)
|
return ps_integer(num)
|
||||||
|
|
||||||
def do_comment(self, token):
|
def do_comment(self, token):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def do_literal(self, token):
|
def do_literal(self, token):
|
||||||
return ps_literal(token[1:])
|
return ps_literal(token[1:])
|
||||||
|
|
||||||
def do_string(self, token):
|
def do_string(self, token):
|
||||||
return ps_string(token[1:-1])
|
return ps_string(token[1:-1])
|
||||||
|
|
||||||
def do_hexstring(self, token):
|
def do_hexstring(self, token):
|
||||||
hexStr = "".join(token[1:-1].split())
|
hexStr = "".join(token[1:-1].split())
|
||||||
if len(hexStr) % 2:
|
if len(hexStr) % 2:
|
||||||
@ -250,7 +250,7 @@ class PSInterpreter(PSOperators):
|
|||||||
cleanstr.append(chr(int(hexStr[i:i+2], 16)))
|
cleanstr.append(chr(int(hexStr[i:i+2], 16)))
|
||||||
cleanstr = "".join(cleanstr)
|
cleanstr = "".join(cleanstr)
|
||||||
return ps_string(cleanstr)
|
return ps_string(cleanstr)
|
||||||
|
|
||||||
def do_special(self, token):
|
def do_special(self, token):
|
||||||
if token == '{':
|
if token == '{':
|
||||||
self.proclevel = self.proclevel + 1
|
self.proclevel = self.proclevel + 1
|
||||||
@ -271,10 +271,10 @@ class PSInterpreter(PSOperators):
|
|||||||
return ps_name(']')
|
return ps_name(']')
|
||||||
else:
|
else:
|
||||||
raise PSTokenError('huh?')
|
raise PSTokenError('huh?')
|
||||||
|
|
||||||
def push(self, object):
|
def push(self, object):
|
||||||
self.stack.append(object)
|
self.stack.append(object)
|
||||||
|
|
||||||
def pop(self, *types):
|
def pop(self, *types):
|
||||||
stack = self.stack
|
stack = self.stack
|
||||||
if not stack:
|
if not stack:
|
||||||
@ -285,7 +285,7 @@ class PSInterpreter(PSOperators):
|
|||||||
raise PSError('typecheck, expected %s, found %s' % (repr(types), object.type))
|
raise PSError('typecheck, expected %s, found %s' % (repr(types), object.type))
|
||||||
del stack[-1]
|
del stack[-1]
|
||||||
return object
|
return object
|
||||||
|
|
||||||
def do_makearray(self):
|
def do_makearray(self):
|
||||||
array = []
|
array = []
|
||||||
while 1:
|
while 1:
|
||||||
@ -295,7 +295,7 @@ class PSInterpreter(PSOperators):
|
|||||||
array.append(topobject)
|
array.append(topobject)
|
||||||
array.reverse()
|
array.reverse()
|
||||||
self.push(ps_array(array))
|
self.push(ps_array(array))
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""Remove circular references."""
|
"""Remove circular references."""
|
||||||
del self.stack
|
del self.stack
|
||||||
|
@ -5,23 +5,23 @@ _accessstrings = {0: "", 1: "readonly", 2: "executeonly", 3: "noaccess"}
|
|||||||
|
|
||||||
|
|
||||||
class ps_object:
|
class ps_object:
|
||||||
|
|
||||||
literal = 1
|
literal = 1
|
||||||
access = 0
|
access = 0
|
||||||
value = None
|
value = None
|
||||||
|
|
||||||
def __init__(self, value):
|
def __init__(self, value):
|
||||||
self.value = value
|
self.value = value
|
||||||
self.type = self.__class__.__name__[3:] + "type"
|
self.type = self.__class__.__name__[3:] + "type"
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s %s>" % (self.__class__.__name__[3:], repr(self.value))
|
return "<%s %s>" % (self.__class__.__name__[3:], repr(self.value))
|
||||||
|
|
||||||
|
|
||||||
class ps_operator(ps_object):
|
class ps_operator(ps_object):
|
||||||
|
|
||||||
literal = 0
|
literal = 0
|
||||||
|
|
||||||
def __init__(self, name, function):
|
def __init__(self, name, function):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.function = function
|
self.function = function
|
||||||
@ -171,7 +171,7 @@ class ps_dict(ps_object):
|
|||||||
return "<dict>"
|
return "<dict>"
|
||||||
|
|
||||||
class ps_mark(ps_object):
|
class ps_mark(ps_object):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.value = 'mark'
|
self.value = 'mark'
|
||||||
self.type = self.__class__.__name__[3:] + "type"
|
self.type = self.__class__.__name__[3:] + "type"
|
||||||
|
|
||||||
@ -205,17 +205,17 @@ class ps_real(ps_object):
|
|||||||
|
|
||||||
|
|
||||||
class PSOperators:
|
class PSOperators:
|
||||||
|
|
||||||
def ps_def(self):
|
def ps_def(self):
|
||||||
obj = self.pop()
|
obj = self.pop()
|
||||||
name = self.pop()
|
name = self.pop()
|
||||||
self.dictstack[-1][name.value] = obj
|
self.dictstack[-1][name.value] = obj
|
||||||
|
|
||||||
def ps_bind(self):
|
def ps_bind(self):
|
||||||
proc = self.pop('proceduretype')
|
proc = self.pop('proceduretype')
|
||||||
self.proc_bind(proc)
|
self.proc_bind(proc)
|
||||||
self.push(proc)
|
self.push(proc)
|
||||||
|
|
||||||
def proc_bind(self, proc):
|
def proc_bind(self, proc):
|
||||||
for i in range(len(proc.value)):
|
for i in range(len(proc.value)):
|
||||||
item = proc.value[i]
|
item = proc.value[i]
|
||||||
@ -230,7 +230,7 @@ class PSOperators:
|
|||||||
else:
|
else:
|
||||||
if obj.type == 'operatortype':
|
if obj.type == 'operatortype':
|
||||||
proc.value[i] = obj
|
proc.value[i] = obj
|
||||||
|
|
||||||
def ps_exch(self):
|
def ps_exch(self):
|
||||||
if len(self.stack) < 2:
|
if len(self.stack) < 2:
|
||||||
raise RuntimeError('stack underflow')
|
raise RuntimeError('stack underflow')
|
||||||
@ -238,49 +238,49 @@ class PSOperators:
|
|||||||
obj2 = self.pop()
|
obj2 = self.pop()
|
||||||
self.push(obj1)
|
self.push(obj1)
|
||||||
self.push(obj2)
|
self.push(obj2)
|
||||||
|
|
||||||
def ps_dup(self):
|
def ps_dup(self):
|
||||||
if not self.stack:
|
if not self.stack:
|
||||||
raise RuntimeError('stack underflow')
|
raise RuntimeError('stack underflow')
|
||||||
self.push(self.stack[-1])
|
self.push(self.stack[-1])
|
||||||
|
|
||||||
def ps_exec(self):
|
def ps_exec(self):
|
||||||
obj = self.pop()
|
obj = self.pop()
|
||||||
if obj.type == 'proceduretype':
|
if obj.type == 'proceduretype':
|
||||||
self.call_procedure(obj)
|
self.call_procedure(obj)
|
||||||
else:
|
else:
|
||||||
self.handle_object(obj)
|
self.handle_object(obj)
|
||||||
|
|
||||||
def ps_count(self):
|
def ps_count(self):
|
||||||
self.push(ps_integer(len(self.stack)))
|
self.push(ps_integer(len(self.stack)))
|
||||||
|
|
||||||
def ps_eq(self):
|
def ps_eq(self):
|
||||||
any1 = self.pop()
|
any1 = self.pop()
|
||||||
any2 = self.pop()
|
any2 = self.pop()
|
||||||
self.push(ps_boolean(any1.value == any2.value))
|
self.push(ps_boolean(any1.value == any2.value))
|
||||||
|
|
||||||
def ps_ne(self):
|
def ps_ne(self):
|
||||||
any1 = self.pop()
|
any1 = self.pop()
|
||||||
any2 = self.pop()
|
any2 = self.pop()
|
||||||
self.push(ps_boolean(any1.value != any2.value))
|
self.push(ps_boolean(any1.value != any2.value))
|
||||||
|
|
||||||
def ps_cvx(self):
|
def ps_cvx(self):
|
||||||
obj = self.pop()
|
obj = self.pop()
|
||||||
obj.literal = 0
|
obj.literal = 0
|
||||||
self.push(obj)
|
self.push(obj)
|
||||||
|
|
||||||
def ps_matrix(self):
|
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)]
|
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))
|
self.push(ps_array(matrix))
|
||||||
|
|
||||||
def ps_string(self):
|
def ps_string(self):
|
||||||
num = self.pop('integertype').value
|
num = self.pop('integertype').value
|
||||||
self.push(ps_string('\0' * num))
|
self.push(ps_string('\0' * num))
|
||||||
|
|
||||||
def ps_type(self):
|
def ps_type(self):
|
||||||
obj = self.pop()
|
obj = self.pop()
|
||||||
self.push(ps_string(obj.type))
|
self.push(ps_string(obj.type))
|
||||||
|
|
||||||
def ps_store(self):
|
def ps_store(self):
|
||||||
value = self.pop()
|
value = self.pop()
|
||||||
key = self.pop()
|
key = self.pop()
|
||||||
@ -290,38 +290,38 @@ class PSOperators:
|
|||||||
self.dictstack[i][name] = value
|
self.dictstack[i][name] = value
|
||||||
break
|
break
|
||||||
self.dictstack[-1][name] = value
|
self.dictstack[-1][name] = value
|
||||||
|
|
||||||
def ps_where(self):
|
def ps_where(self):
|
||||||
name = self.pop()
|
name = self.pop()
|
||||||
# XXX
|
# XXX
|
||||||
self.push(ps_boolean(0))
|
self.push(ps_boolean(0))
|
||||||
|
|
||||||
def ps_systemdict(self):
|
def ps_systemdict(self):
|
||||||
self.push(ps_dict(self.dictstack[0]))
|
self.push(ps_dict(self.dictstack[0]))
|
||||||
|
|
||||||
def ps_userdict(self):
|
def ps_userdict(self):
|
||||||
self.push(ps_dict(self.dictstack[1]))
|
self.push(ps_dict(self.dictstack[1]))
|
||||||
|
|
||||||
def ps_currentdict(self):
|
def ps_currentdict(self):
|
||||||
self.push(ps_dict(self.dictstack[-1]))
|
self.push(ps_dict(self.dictstack[-1]))
|
||||||
|
|
||||||
def ps_currentfile(self):
|
def ps_currentfile(self):
|
||||||
self.push(ps_file(self.tokenizer))
|
self.push(ps_file(self.tokenizer))
|
||||||
|
|
||||||
def ps_eexec(self):
|
def ps_eexec(self):
|
||||||
f = self.pop('filetype').value
|
f = self.pop('filetype').value
|
||||||
f.starteexec()
|
f.starteexec()
|
||||||
|
|
||||||
def ps_closefile(self):
|
def ps_closefile(self):
|
||||||
f = self.pop('filetype').value
|
f = self.pop('filetype').value
|
||||||
f.skipwhite()
|
f.skipwhite()
|
||||||
f.stopeexec()
|
f.stopeexec()
|
||||||
|
|
||||||
def ps_cleartomark(self):
|
def ps_cleartomark(self):
|
||||||
obj = self.pop()
|
obj = self.pop()
|
||||||
while obj != self.mark:
|
while obj != self.mark:
|
||||||
obj = self.pop()
|
obj = self.pop()
|
||||||
|
|
||||||
def ps_readstring(self,
|
def ps_readstring(self,
|
||||||
ps_boolean=ps_boolean,
|
ps_boolean=ps_boolean,
|
||||||
len=len):
|
len=len):
|
||||||
@ -335,17 +335,17 @@ class PSOperators:
|
|||||||
s.value = newstr
|
s.value = newstr
|
||||||
self.push(s)
|
self.push(s)
|
||||||
self.push(ps_boolean(len(oldstr) == len(newstr)))
|
self.push(ps_boolean(len(oldstr) == len(newstr)))
|
||||||
|
|
||||||
def ps_known(self):
|
def ps_known(self):
|
||||||
key = self.pop()
|
key = self.pop()
|
||||||
d = self.pop('dicttype', 'fonttype')
|
d = self.pop('dicttype', 'fonttype')
|
||||||
self.push(ps_boolean(key.value in d.value))
|
self.push(ps_boolean(key.value in d.value))
|
||||||
|
|
||||||
def ps_if(self):
|
def ps_if(self):
|
||||||
proc = self.pop('proceduretype')
|
proc = self.pop('proceduretype')
|
||||||
if self.pop('booleantype').value:
|
if self.pop('booleantype').value:
|
||||||
self.call_procedure(proc)
|
self.call_procedure(proc)
|
||||||
|
|
||||||
def ps_ifelse(self):
|
def ps_ifelse(self):
|
||||||
proc2 = self.pop('proceduretype')
|
proc2 = self.pop('proceduretype')
|
||||||
proc1 = self.pop('proceduretype')
|
proc1 = self.pop('proceduretype')
|
||||||
@ -353,36 +353,36 @@ class PSOperators:
|
|||||||
self.call_procedure(proc1)
|
self.call_procedure(proc1)
|
||||||
else:
|
else:
|
||||||
self.call_procedure(proc2)
|
self.call_procedure(proc2)
|
||||||
|
|
||||||
def ps_readonly(self):
|
def ps_readonly(self):
|
||||||
obj = self.pop()
|
obj = self.pop()
|
||||||
if obj.access < 1:
|
if obj.access < 1:
|
||||||
obj.access = 1
|
obj.access = 1
|
||||||
self.push(obj)
|
self.push(obj)
|
||||||
|
|
||||||
def ps_executeonly(self):
|
def ps_executeonly(self):
|
||||||
obj = self.pop()
|
obj = self.pop()
|
||||||
if obj.access < 2:
|
if obj.access < 2:
|
||||||
obj.access = 2
|
obj.access = 2
|
||||||
self.push(obj)
|
self.push(obj)
|
||||||
|
|
||||||
def ps_noaccess(self):
|
def ps_noaccess(self):
|
||||||
obj = self.pop()
|
obj = self.pop()
|
||||||
if obj.access < 3:
|
if obj.access < 3:
|
||||||
obj.access = 3
|
obj.access = 3
|
||||||
self.push(obj)
|
self.push(obj)
|
||||||
|
|
||||||
def ps_not(self):
|
def ps_not(self):
|
||||||
obj = self.pop('booleantype', 'integertype')
|
obj = self.pop('booleantype', 'integertype')
|
||||||
if obj.type == 'booleantype':
|
if obj.type == 'booleantype':
|
||||||
self.push(ps_boolean(not obj.value))
|
self.push(ps_boolean(not obj.value))
|
||||||
else:
|
else:
|
||||||
self.push(ps_integer(~obj.value))
|
self.push(ps_integer(~obj.value))
|
||||||
|
|
||||||
def ps_print(self):
|
def ps_print(self):
|
||||||
str = self.pop('stringtype')
|
str = self.pop('stringtype')
|
||||||
print('PS output --->', str.value)
|
print('PS output --->', str.value)
|
||||||
|
|
||||||
def ps_anchorsearch(self):
|
def ps_anchorsearch(self):
|
||||||
seek = self.pop('stringtype')
|
seek = self.pop('stringtype')
|
||||||
s = self.pop('stringtype')
|
s = self.pop('stringtype')
|
||||||
@ -394,22 +394,22 @@ class PSOperators:
|
|||||||
else:
|
else:
|
||||||
self.push(s)
|
self.push(s)
|
||||||
self.push(ps_boolean(0))
|
self.push(ps_boolean(0))
|
||||||
|
|
||||||
def ps_array(self):
|
def ps_array(self):
|
||||||
num = self.pop('integertype')
|
num = self.pop('integertype')
|
||||||
array = ps_array([None] * num.value)
|
array = ps_array([None] * num.value)
|
||||||
self.push(array)
|
self.push(array)
|
||||||
|
|
||||||
def ps_astore(self):
|
def ps_astore(self):
|
||||||
array = self.pop('arraytype')
|
array = self.pop('arraytype')
|
||||||
for i in range(len(array.value)-1, -1, -1):
|
for i in range(len(array.value)-1, -1, -1):
|
||||||
array.value[i] = self.pop()
|
array.value[i] = self.pop()
|
||||||
self.push(array)
|
self.push(array)
|
||||||
|
|
||||||
def ps_load(self):
|
def ps_load(self):
|
||||||
name = self.pop()
|
name = self.pop()
|
||||||
self.push(self.resolve_name(name.value))
|
self.push(self.resolve_name(name.value))
|
||||||
|
|
||||||
def ps_put(self):
|
def ps_put(self):
|
||||||
obj1 = self.pop()
|
obj1 = self.pop()
|
||||||
obj2 = self.pop()
|
obj2 = self.pop()
|
||||||
@ -422,7 +422,7 @@ class PSOperators:
|
|||||||
elif tp == 'stringtype':
|
elif tp == 'stringtype':
|
||||||
index = obj2.value
|
index = obj2.value
|
||||||
obj3.value = obj3.value[:index] + chr(obj1.value) + obj3.value[index+1:]
|
obj3.value = obj3.value[:index] + chr(obj1.value) + obj3.value[index+1:]
|
||||||
|
|
||||||
def ps_get(self):
|
def ps_get(self):
|
||||||
obj1 = self.pop()
|
obj1 = self.pop()
|
||||||
if obj1.value == "Encoding":
|
if obj1.value == "Encoding":
|
||||||
@ -437,7 +437,7 @@ class PSOperators:
|
|||||||
self.push(ps_integer(ord(obj2.value[obj1.value])))
|
self.push(ps_integer(ord(obj2.value[obj1.value])))
|
||||||
else:
|
else:
|
||||||
assert False, "shouldn't get here"
|
assert False, "shouldn't get here"
|
||||||
|
|
||||||
def ps_getinterval(self):
|
def ps_getinterval(self):
|
||||||
obj1 = self.pop('integertype')
|
obj1 = self.pop('integertype')
|
||||||
obj2 = 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]))
|
self.push(ps_array(obj3.value[obj2.value:obj2.value + obj1.value]))
|
||||||
elif tp == 'stringtype':
|
elif tp == 'stringtype':
|
||||||
self.push(ps_string(obj3.value[obj2.value:obj2.value + obj1.value]))
|
self.push(ps_string(obj3.value[obj2.value:obj2.value + obj1.value]))
|
||||||
|
|
||||||
def ps_putinterval(self):
|
def ps_putinterval(self):
|
||||||
obj1 = self.pop('arraytype', 'stringtype')
|
obj1 = self.pop('arraytype', 'stringtype')
|
||||||
obj2 = self.pop('integertype')
|
obj2 = self.pop('integertype')
|
||||||
@ -460,16 +460,16 @@ class PSOperators:
|
|||||||
newstr = newstr + obj1.value
|
newstr = newstr + obj1.value
|
||||||
newstr = newstr + obj3.value[obj2.value + len(obj1.value):]
|
newstr = newstr + obj3.value[obj2.value + len(obj1.value):]
|
||||||
obj3.value = newstr
|
obj3.value = newstr
|
||||||
|
|
||||||
def ps_cvn(self):
|
def ps_cvn(self):
|
||||||
self.push(ps_name(self.pop('stringtype').value))
|
self.push(ps_name(self.pop('stringtype').value))
|
||||||
|
|
||||||
def ps_index(self):
|
def ps_index(self):
|
||||||
n = self.pop('integertype').value
|
n = self.pop('integertype').value
|
||||||
if n < 0:
|
if n < 0:
|
||||||
raise RuntimeError('index may not be negative')
|
raise RuntimeError('index may not be negative')
|
||||||
self.push(self.stack[-1-n])
|
self.push(self.stack[-1-n])
|
||||||
|
|
||||||
def ps_for(self):
|
def ps_for(self):
|
||||||
proc = self.pop('proceduretype')
|
proc = self.pop('proceduretype')
|
||||||
limit = self.pop('integertype', 'realtype').value
|
limit = self.pop('integertype', 'realtype').value
|
||||||
@ -488,7 +488,7 @@ class PSOperators:
|
|||||||
self.push(ps_integer(i))
|
self.push(ps_integer(i))
|
||||||
self.call_procedure(proc)
|
self.call_procedure(proc)
|
||||||
i = i + increment
|
i = i + increment
|
||||||
|
|
||||||
def ps_forall(self):
|
def ps_forall(self):
|
||||||
proc = self.pop('proceduretype')
|
proc = self.pop('proceduretype')
|
||||||
obj = self.pop('arraytype', 'stringtype', 'dicttype')
|
obj = self.pop('arraytype', 'stringtype', 'dicttype')
|
||||||
@ -505,36 +505,36 @@ class PSOperators:
|
|||||||
for key, value in obj.value.items():
|
for key, value in obj.value.items():
|
||||||
self.push(ps_name(key))
|
self.push(ps_name(key))
|
||||||
self.push(value)
|
self.push(value)
|
||||||
self.call_procedure(proc)
|
self.call_procedure(proc)
|
||||||
|
|
||||||
def ps_definefont(self):
|
def ps_definefont(self):
|
||||||
font = self.pop('dicttype')
|
font = self.pop('dicttype')
|
||||||
name = self.pop()
|
name = self.pop()
|
||||||
font = ps_font(font.value)
|
font = ps_font(font.value)
|
||||||
self.dictstack[0]['FontDirectory'].value[name.value] = font
|
self.dictstack[0]['FontDirectory'].value[name.value] = font
|
||||||
self.push(font)
|
self.push(font)
|
||||||
|
|
||||||
def ps_findfont(self):
|
def ps_findfont(self):
|
||||||
name = self.pop()
|
name = self.pop()
|
||||||
font = self.dictstack[0]['FontDirectory'].value[name.value]
|
font = self.dictstack[0]['FontDirectory'].value[name.value]
|
||||||
self.push(font)
|
self.push(font)
|
||||||
|
|
||||||
def ps_pop(self):
|
def ps_pop(self):
|
||||||
self.pop()
|
self.pop()
|
||||||
|
|
||||||
def ps_dict(self):
|
def ps_dict(self):
|
||||||
self.pop('integertype')
|
self.pop('integertype')
|
||||||
self.push(ps_dict({}))
|
self.push(ps_dict({}))
|
||||||
|
|
||||||
def ps_begin(self):
|
def ps_begin(self):
|
||||||
self.dictstack.append(self.pop('dicttype').value)
|
self.dictstack.append(self.pop('dicttype').value)
|
||||||
|
|
||||||
def ps_end(self):
|
def ps_end(self):
|
||||||
if len(self.dictstack) > 2:
|
if len(self.dictstack) > 2:
|
||||||
del self.dictstack[-1]
|
del self.dictstack[-1]
|
||||||
else:
|
else:
|
||||||
raise RuntimeError('dictstack underflow')
|
raise RuntimeError('dictstack underflow')
|
||||||
|
|
||||||
notdef = '.notdef'
|
notdef = '.notdef'
|
||||||
from fontTools.encodings.StandardEncoding import StandardEncoding
|
from fontTools.encodings.StandardEncoding import StandardEncoding
|
||||||
ps_StandardEncoding = list(map(ps_name, StandardEncoding))
|
ps_StandardEncoding = list(map(ps_name, StandardEncoding))
|
||||||
|
@ -1,44 +1,44 @@
|
|||||||
"""sstruct.py -- SuperStruct
|
"""sstruct.py -- SuperStruct
|
||||||
|
|
||||||
Higher level layer on top of the struct module, enabling to
|
Higher level layer on top of the struct module, enabling to
|
||||||
bind names to struct elements. The interface is similar to
|
bind names to struct elements. The interface is similar to
|
||||||
struct, except the objects passed and returned are not tuples
|
struct, except the objects passed and returned are not tuples
|
||||||
(or argument lists), but dictionaries or instances.
|
(or argument lists), but dictionaries or instances.
|
||||||
|
|
||||||
Just like struct, we use fmt strings to describe a data
|
Just like struct, we use fmt strings to describe a data
|
||||||
structure, except we use one line per element. Lines are
|
structure, except we use one line per element. Lines are
|
||||||
separated by newlines or semi-colons. Each line contains
|
separated by newlines or semi-colons. Each line contains
|
||||||
either one of the special struct characters ('@', '=', '<',
|
either one of the special struct characters ('@', '=', '<',
|
||||||
'>' or '!') or a 'name:formatchar' combo (eg. 'myFloat:f').
|
'>' or '!') or a 'name:formatchar' combo (eg. 'myFloat:f').
|
||||||
Repetitions, like the struct module offers them are not useful
|
Repetitions, like the struct module offers them are not useful
|
||||||
in this context, except for fixed length strings (eg. 'myInt:5h'
|
in this context, except for fixed length strings (eg. 'myInt:5h'
|
||||||
is not allowed but 'myString:5s' is). The 'x' fmt character
|
is not allowed but 'myString:5s' is). The 'x' fmt character
|
||||||
(pad byte) is treated as 'special', since it is by definition
|
(pad byte) is treated as 'special', since it is by definition
|
||||||
anonymous. Extra whitespace is allowed everywhere.
|
anonymous. Extra whitespace is allowed everywhere.
|
||||||
|
|
||||||
The sstruct module offers one feature that the "normal" struct
|
The sstruct module offers one feature that the "normal" struct
|
||||||
module doesn't: support for fixed point numbers. These are spelled
|
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
|
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.
|
converted to floats.
|
||||||
|
|
||||||
pack(fmt, object):
|
pack(fmt, object):
|
||||||
'object' is either a dictionary or an instance (or actually
|
'object' is either a dictionary or an instance (or actually
|
||||||
anything that has a __dict__ attribute). If it is a dictionary,
|
anything that has a __dict__ attribute). If it is a dictionary,
|
||||||
its keys are used for names. If it is an instance, it's
|
its keys are used for names. If it is an instance, it's
|
||||||
attributes are used to grab struct elements from. Returns
|
attributes are used to grab struct elements from. Returns
|
||||||
a string containing the data.
|
a string containing the data.
|
||||||
|
|
||||||
unpack(fmt, data, object=None)
|
unpack(fmt, data, object=None)
|
||||||
If 'object' is omitted (or None), a new dictionary will be
|
If 'object' is omitted (or None), a new dictionary will be
|
||||||
returned. If 'object' is a dictionary, it will be used to add
|
returned. If 'object' is a dictionary, it will be used to add
|
||||||
struct elements to. If it is an instance (or in fact anything
|
struct elements to. If it is an instance (or in fact anything
|
||||||
that has a __dict__ attribute), an attribute will be added for
|
that has a __dict__ attribute), an attribute will be added for
|
||||||
each struct element. In the latter two cases, 'object' itself
|
each struct element. In the latter two cases, 'object' itself
|
||||||
is returned.
|
is returned.
|
||||||
|
|
||||||
unpack2(fmt, data, object=None)
|
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).
|
than needed. The returned value is a tuple: (object, leftoverdata).
|
||||||
|
|
||||||
calcsize(fmt)
|
calcsize(fmt)
|
||||||
@ -174,7 +174,7 @@ def _test():
|
|||||||
# comments are allowed
|
# comments are allowed
|
||||||
> # big endian (see documentation for struct)
|
> # big endian (see documentation for struct)
|
||||||
# empty lines are allowed:
|
# empty lines are allowed:
|
||||||
|
|
||||||
ashort: h
|
ashort: h
|
||||||
along: l
|
along: l
|
||||||
abyte: b # a byte
|
abyte: b # a byte
|
||||||
@ -183,14 +183,14 @@ def _test():
|
|||||||
afloat: f; adouble: d # multiple "statements" are allowed
|
afloat: f; adouble: d # multiple "statements" are allowed
|
||||||
afixed: 16.16F
|
afixed: 16.16F
|
||||||
"""
|
"""
|
||||||
|
|
||||||
print('size:', calcsize(fmt))
|
print('size:', calcsize(fmt))
|
||||||
|
|
||||||
class foo(object):
|
class foo(object):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
i = foo()
|
i = foo()
|
||||||
|
|
||||||
i.ashort = 0x7fff
|
i.ashort = 0x7fff
|
||||||
i.along = 0x7fffffff
|
i.along = 0x7fffffff
|
||||||
i.abyte = 0x7f
|
i.abyte = 0x7f
|
||||||
@ -199,7 +199,7 @@ def _test():
|
|||||||
i.afloat = 0.5
|
i.afloat = 0.5
|
||||||
i.adouble = 0.5
|
i.adouble = 0.5
|
||||||
i.afixed = 1.5
|
i.afixed = 1.5
|
||||||
|
|
||||||
data = pack(fmt, i)
|
data = pack(fmt, i)
|
||||||
print('data:', repr(data))
|
print('data:', repr(data))
|
||||||
print(unpack(fmt, data))
|
print(unpack(fmt, data))
|
||||||
|
@ -66,10 +66,10 @@ def binary2num(bin):
|
|||||||
|
|
||||||
|
|
||||||
def caselessSort(alist):
|
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.
|
in the list, it will not consider case.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return sorted(alist, key=lambda a: (a.lower(), a))
|
return sorted(alist, key=lambda a: (a.lower(), a))
|
||||||
except TypeError:
|
except TypeError:
|
||||||
|
@ -12,7 +12,7 @@ BUFSIZE = 0x4000
|
|||||||
|
|
||||||
|
|
||||||
class XMLReader(object):
|
class XMLReader(object):
|
||||||
|
|
||||||
def __init__(self, fileName, ttFont, progress=None, quiet=False):
|
def __init__(self, fileName, ttFont, progress=None, quiet=False):
|
||||||
self.ttFont = ttFont
|
self.ttFont = ttFont
|
||||||
self.fileName = fileName
|
self.fileName = fileName
|
||||||
@ -21,7 +21,7 @@ class XMLReader(object):
|
|||||||
self.root = None
|
self.root = None
|
||||||
self.contentStack = []
|
self.contentStack = []
|
||||||
self.stackSize = 0
|
self.stackSize = 0
|
||||||
|
|
||||||
def read(self):
|
def read(self):
|
||||||
if self.progress:
|
if self.progress:
|
||||||
import stat
|
import stat
|
||||||
@ -29,14 +29,14 @@ class XMLReader(object):
|
|||||||
file = open(self.fileName)
|
file = open(self.fileName)
|
||||||
self._parseFile(file)
|
self._parseFile(file)
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
def _parseFile(self, file):
|
def _parseFile(self, file):
|
||||||
from xml.parsers.expat import ParserCreate
|
from xml.parsers.expat import ParserCreate
|
||||||
parser = ParserCreate()
|
parser = ParserCreate()
|
||||||
parser.StartElementHandler = self._startElementHandler
|
parser.StartElementHandler = self._startElementHandler
|
||||||
parser.EndElementHandler = self._endElementHandler
|
parser.EndElementHandler = self._endElementHandler
|
||||||
parser.CharacterDataHandler = self._characterDataHandler
|
parser.CharacterDataHandler = self._characterDataHandler
|
||||||
|
|
||||||
pos = 0
|
pos = 0
|
||||||
while True:
|
while True:
|
||||||
chunk = file.read(BUFSIZE)
|
chunk = file.read(BUFSIZE)
|
||||||
@ -47,7 +47,7 @@ class XMLReader(object):
|
|||||||
if self.progress:
|
if self.progress:
|
||||||
self.progress.set(pos // 100)
|
self.progress.set(pos // 100)
|
||||||
parser.Parse(chunk, 0)
|
parser.Parse(chunk, 0)
|
||||||
|
|
||||||
def _startElementHandler(self, name, attrs):
|
def _startElementHandler(self, name, attrs):
|
||||||
stackSize = self.stackSize
|
stackSize = self.stackSize
|
||||||
self.stackSize = stackSize + 1
|
self.stackSize = stackSize + 1
|
||||||
@ -100,11 +100,11 @@ class XMLReader(object):
|
|||||||
l = []
|
l = []
|
||||||
self.contentStack[-1].append((name, attrs, l))
|
self.contentStack[-1].append((name, attrs, l))
|
||||||
self.contentStack.append(l)
|
self.contentStack.append(l)
|
||||||
|
|
||||||
def _characterDataHandler(self, data):
|
def _characterDataHandler(self, data):
|
||||||
if self.stackSize > 1:
|
if self.stackSize > 1:
|
||||||
self.contentStack[-1].append(data)
|
self.contentStack[-1].append(data)
|
||||||
|
|
||||||
def _endElementHandler(self, name):
|
def _endElementHandler(self, name):
|
||||||
self.stackSize = self.stackSize - 1
|
self.stackSize = self.stackSize - 1
|
||||||
del self.contentStack[-1]
|
del self.contentStack[-1]
|
||||||
@ -117,15 +117,15 @@ class XMLReader(object):
|
|||||||
|
|
||||||
|
|
||||||
class ProgressPrinter(object):
|
class ProgressPrinter(object):
|
||||||
|
|
||||||
def __init__(self, title, maxval=100):
|
def __init__(self, title, maxval=100):
|
||||||
print(title)
|
print(title)
|
||||||
|
|
||||||
def set(self, val, maxval=None):
|
def set(self, val, maxval=None):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def increment(self, val=1):
|
def increment(self, val=1):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def setLabel(self, text):
|
def setLabel(self, text):
|
||||||
print(text)
|
print(text)
|
||||||
|
@ -10,7 +10,7 @@ INDENT = " "
|
|||||||
|
|
||||||
|
|
||||||
class XMLWriter(object):
|
class XMLWriter(object):
|
||||||
|
|
||||||
def __init__(self, fileOrPath, indentwhite=INDENT, idlefunc=None, encoding="utf_8"):
|
def __init__(self, fileOrPath, indentwhite=INDENT, idlefunc=None, encoding="utf_8"):
|
||||||
if encoding.lower().replace('-','').replace('_','') != 'utf8':
|
if encoding.lower().replace('-','').replace('_','') != 'utf8':
|
||||||
raise Exception('Only UTF-8 encoding is supported.')
|
raise Exception('Only UTF-8 encoding is supported.')
|
||||||
@ -41,10 +41,10 @@ class XMLWriter(object):
|
|||||||
self.idlecounter = 0
|
self.idlecounter = 0
|
||||||
self._writeraw('<?xml version="1.0" encoding="UTF-8"?>')
|
self._writeraw('<?xml version="1.0" encoding="UTF-8"?>')
|
||||||
self.newline()
|
self.newline()
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self.file.close()
|
self.file.close()
|
||||||
|
|
||||||
def write(self, string, indent=True):
|
def write(self, string, indent=True):
|
||||||
"""Writes text."""
|
"""Writes text."""
|
||||||
self._writeraw(escape(string), indent=indent)
|
self._writeraw(escape(string), indent=indent)
|
||||||
@ -63,7 +63,7 @@ class XMLWriter(object):
|
|||||||
def write_noindent(self, string):
|
def write_noindent(self, string):
|
||||||
"""Writes text without indentation."""
|
"""Writes text without indentation."""
|
||||||
self._writeraw(escape(string), indent=False)
|
self._writeraw(escape(string), indent=False)
|
||||||
|
|
||||||
def _writeraw(self, data, indent=True, strip=False):
|
def _writeraw(self, data, indent=True, strip=False):
|
||||||
"""Writes bytes, possibly indented."""
|
"""Writes bytes, possibly indented."""
|
||||||
if indent and self.needindent:
|
if indent and self.needindent:
|
||||||
@ -73,7 +73,7 @@ class XMLWriter(object):
|
|||||||
if (strip):
|
if (strip):
|
||||||
s = s.strip()
|
s = s.strip()
|
||||||
self.file.write(s)
|
self.file.write(s)
|
||||||
|
|
||||||
def newline(self):
|
def newline(self):
|
||||||
self.file.write(self.newlinestr)
|
self.file.write(self.newlinestr)
|
||||||
self.needindent = 1
|
self.needindent = 1
|
||||||
@ -81,7 +81,7 @@ class XMLWriter(object):
|
|||||||
if not idlecounter % 100 and self.idlefunc is not None:
|
if not idlecounter % 100 and self.idlefunc is not None:
|
||||||
self.idlefunc()
|
self.idlefunc()
|
||||||
self.idlecounter = idlecounter + 1
|
self.idlecounter = idlecounter + 1
|
||||||
|
|
||||||
def comment(self, data):
|
def comment(self, data):
|
||||||
data = escape(data)
|
data = escape(data)
|
||||||
lines = data.split("\n")
|
lines = data.split("\n")
|
||||||
@ -90,26 +90,26 @@ class XMLWriter(object):
|
|||||||
self.newline()
|
self.newline()
|
||||||
self._writeraw(" " + line)
|
self._writeraw(" " + line)
|
||||||
self._writeraw(" -->")
|
self._writeraw(" -->")
|
||||||
|
|
||||||
def simpletag(self, _TAG_, *args, **kwargs):
|
def simpletag(self, _TAG_, *args, **kwargs):
|
||||||
attrdata = self.stringifyattrs(*args, **kwargs)
|
attrdata = self.stringifyattrs(*args, **kwargs)
|
||||||
data = "<%s%s/>" % (_TAG_, attrdata)
|
data = "<%s%s/>" % (_TAG_, attrdata)
|
||||||
self._writeraw(data)
|
self._writeraw(data)
|
||||||
|
|
||||||
def begintag(self, _TAG_, *args, **kwargs):
|
def begintag(self, _TAG_, *args, **kwargs):
|
||||||
attrdata = self.stringifyattrs(*args, **kwargs)
|
attrdata = self.stringifyattrs(*args, **kwargs)
|
||||||
data = "<%s%s>" % (_TAG_, attrdata)
|
data = "<%s%s>" % (_TAG_, attrdata)
|
||||||
self._writeraw(data)
|
self._writeraw(data)
|
||||||
self.stack.append(_TAG_)
|
self.stack.append(_TAG_)
|
||||||
self.indent()
|
self.indent()
|
||||||
|
|
||||||
def endtag(self, _TAG_):
|
def endtag(self, _TAG_):
|
||||||
assert self.stack and self.stack[-1] == _TAG_, "nonmatching endtag"
|
assert self.stack and self.stack[-1] == _TAG_, "nonmatching endtag"
|
||||||
del self.stack[-1]
|
del self.stack[-1]
|
||||||
self.dedent()
|
self.dedent()
|
||||||
data = "</%s>" % _TAG_
|
data = "</%s>" % _TAG_
|
||||||
self._writeraw(data)
|
self._writeraw(data)
|
||||||
|
|
||||||
def dumphex(self, data):
|
def dumphex(self, data):
|
||||||
linelength = 16
|
linelength = 16
|
||||||
hexlinelength = linelength * 2
|
hexlinelength = linelength * 2
|
||||||
@ -123,14 +123,14 @@ class XMLWriter(object):
|
|||||||
white = " "
|
white = " "
|
||||||
self._writeraw(line)
|
self._writeraw(line)
|
||||||
self.newline()
|
self.newline()
|
||||||
|
|
||||||
def indent(self):
|
def indent(self):
|
||||||
self.indentlevel = self.indentlevel + 1
|
self.indentlevel = self.indentlevel + 1
|
||||||
|
|
||||||
def dedent(self):
|
def dedent(self):
|
||||||
assert self.indentlevel > 0
|
assert self.indentlevel > 0
|
||||||
self.indentlevel = self.indentlevel - 1
|
self.indentlevel = self.indentlevel - 1
|
||||||
|
|
||||||
def stringifyattrs(self, *args, **kwargs):
|
def stringifyattrs(self, *args, **kwargs):
|
||||||
if kwargs:
|
if kwargs:
|
||||||
assert not args
|
assert not args
|
||||||
@ -144,7 +144,7 @@ class XMLWriter(object):
|
|||||||
for attr, value in attributes:
|
for attr, value in attributes:
|
||||||
data = data + ' %s="%s"' % (attr, escapeattr(str(value)))
|
data = data + ' %s="%s"' % (attr, escapeattr(str(value)))
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def escape(data):
|
def escape(data):
|
||||||
data = tostr(data, 'utf_8')
|
data = tostr(data, 'utf_8')
|
||||||
|
@ -3,13 +3,13 @@
|
|||||||
Functions for reading and writing raw Type 1 data:
|
Functions for reading and writing raw Type 1 data:
|
||||||
|
|
||||||
read(path)
|
read(path)
|
||||||
reads any Type 1 font file, returns the raw data and a type indicator:
|
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
|
'LWFN', 'PFB' or 'OTHER', depending on the format of the file pointed
|
||||||
to by 'path'.
|
to by 'path'.
|
||||||
Raises an error when the file does not contain valid Type 1 data.
|
Raises an error when the file does not contain valid Type 1 data.
|
||||||
|
|
||||||
write(path, data, kind='OTHER', dohex=False)
|
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'.
|
'kind' can be one of 'LWFN', 'PFB' or 'OTHER'; it defaults to 'OTHER'.
|
||||||
'dohex' is a flag which determines whether the eexec encrypted
|
'dohex' is a flag which determines whether the eexec encrypted
|
||||||
part should be written as hexadecimal or binary, but only if kind
|
part should be written as hexadecimal or binary, but only if kind
|
||||||
@ -37,49 +37,49 @@ except ImportError:
|
|||||||
else:
|
else:
|
||||||
haveMacSupport = 1
|
haveMacSupport = 1
|
||||||
import MacOS
|
import MacOS
|
||||||
|
|
||||||
|
|
||||||
class T1Error(Exception): pass
|
class T1Error(Exception): pass
|
||||||
|
|
||||||
|
|
||||||
class T1Font(object):
|
class T1Font(object):
|
||||||
|
|
||||||
"""Type 1 font class.
|
"""Type 1 font class.
|
||||||
|
|
||||||
Uses a minimal interpeter that supports just about enough PS to parse
|
Uses a minimal interpeter that supports just about enough PS to parse
|
||||||
Type 1 fonts.
|
Type 1 fonts.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, path=None):
|
def __init__(self, path=None):
|
||||||
if path is not None:
|
if path is not None:
|
||||||
self.data, type = read(path)
|
self.data, type = read(path)
|
||||||
else:
|
else:
|
||||||
pass # XXX
|
pass # XXX
|
||||||
|
|
||||||
def saveAs(self, path, type):
|
def saveAs(self, path, type):
|
||||||
write(path, self.getData(), type)
|
write(path, self.getData(), type)
|
||||||
|
|
||||||
def getData(self):
|
def getData(self):
|
||||||
# XXX Todo: if the data has been converted to Python object,
|
# XXX Todo: if the data has been converted to Python object,
|
||||||
# recreate the PS stream
|
# recreate the PS stream
|
||||||
return self.data
|
return self.data
|
||||||
|
|
||||||
def getGlyphSet(self):
|
def getGlyphSet(self):
|
||||||
"""Return a generic GlyphSet, which is a dict-like object
|
"""Return a generic GlyphSet, which is a dict-like object
|
||||||
mapping glyph names to glyph objects. The returned glyph objects
|
mapping glyph names to glyph objects. The returned glyph objects
|
||||||
have a .draw() method that supports the Pen protocol, and will
|
have a .draw() method that supports the Pen protocol, and will
|
||||||
have an attribute named 'width', but only *after* the .draw() method
|
have an attribute named 'width', but only *after* the .draw() method
|
||||||
has been called.
|
has been called.
|
||||||
|
|
||||||
In the case of Type 1, the GlyphSet is simply the CharStrings dict.
|
In the case of Type 1, the GlyphSet is simply the CharStrings dict.
|
||||||
"""
|
"""
|
||||||
return self["CharStrings"]
|
return self["CharStrings"]
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
if not hasattr(self, "font"):
|
if not hasattr(self, "font"):
|
||||||
self.parse()
|
self.parse()
|
||||||
return self.font[key]
|
return self.font[key]
|
||||||
|
|
||||||
def parse(self):
|
def parse(self):
|
||||||
from fontTools.misc import psLib
|
from fontTools.misc import psLib
|
||||||
from fontTools.misc import psCharStrings
|
from fontTools.misc import psCharStrings
|
||||||
@ -135,7 +135,7 @@ def write(path, data, kind='OTHER', dohex=False):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
# -- internal --
|
# -- internal --
|
||||||
|
|
||||||
LWFNCHUNKSIZE = 2000
|
LWFNCHUNKSIZE = 2000
|
||||||
HEXLINELENGTH = 80
|
HEXLINELENGTH = 80
|
||||||
@ -203,7 +203,7 @@ def readOther(path):
|
|||||||
data = f.read()
|
data = f.read()
|
||||||
f.close()
|
f.close()
|
||||||
assertType1(data)
|
assertType1(data)
|
||||||
|
|
||||||
chunks = findEncryptedChunks(data)
|
chunks = findEncryptedChunks(data)
|
||||||
data = []
|
data = []
|
||||||
for isEncrypted, chunk in chunks:
|
for isEncrypted, chunk in chunks:
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"""fontTools.ttLib -- a package for dealing with TrueType fonts.
|
"""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
|
objects and vice versa, and additionally from Python to TTX (an XML-based
|
||||||
text format) and vice versa.
|
text format) and vice versa.
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ Dumping 'prep' table...
|
|||||||
>>> tt2.importXML("afont.ttx")
|
>>> tt2.importXML("afont.ttx")
|
||||||
>>> tt2['maxp'].numGlyphs
|
>>> tt2['maxp'].numGlyphs
|
||||||
242
|
242
|
||||||
>>>
|
>>>
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@ -60,39 +60,39 @@ class TTLibError(Exception): pass
|
|||||||
|
|
||||||
|
|
||||||
class TTFont(object):
|
class TTFont(object):
|
||||||
|
|
||||||
"""The main font object. It manages file input and output, and offers
|
"""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
|
Tables will be only decompiled when necessary, ie. when they're actually
|
||||||
accessed. This means that simple operations can be extremely fast.
|
accessed. This means that simple operations can be extremely fast.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, file=None, res_name_or_index=None,
|
def __init__(self, file=None, res_name_or_index=None,
|
||||||
sfntVersion="\000\001\000\000", flavor=None, checkChecksums=False,
|
sfntVersion="\000\001\000\000", flavor=None, checkChecksums=False,
|
||||||
verbose=False, recalcBBoxes=True, allowVID=False, ignoreDecompileErrors=False,
|
verbose=False, recalcBBoxes=True, allowVID=False, ignoreDecompileErrors=False,
|
||||||
recalcTimestamp=True, fontNumber=-1, lazy=None, quiet=False):
|
recalcTimestamp=True, fontNumber=-1, lazy=None, quiet=False):
|
||||||
|
|
||||||
"""The constructor can be called with a few different arguments.
|
"""The constructor can be called with a few different arguments.
|
||||||
When reading a font from disk, 'file' should be either a pathname
|
When reading a font from disk, 'file' should be either a pathname
|
||||||
pointing to a file, or a readable file object.
|
pointing to a file, or a readable file object.
|
||||||
|
|
||||||
It we're running on a Macintosh, 'res_name_or_index' maybe an sfnt
|
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
|
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
|
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
|
or a suitcase. (If it's a suitcase, only the first 'sfnt' resource
|
||||||
will be read!)
|
will be read!)
|
||||||
|
|
||||||
The 'checkChecksums' argument is used to specify how sfnt
|
The 'checkChecksums' argument is used to specify how sfnt
|
||||||
checksums are treated upon reading a file from disk:
|
checksums are treated upon reading a file from disk:
|
||||||
0: don't check (default)
|
0: don't check (default)
|
||||||
1: check, print warnings if a wrong checksum is found
|
1: check, print warnings if a wrong checksum is found
|
||||||
2: check, raise an exception 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'
|
The TTFont constructor can also be called without a 'file'
|
||||||
argument: this is the way to create a new empty font.
|
argument: this is the way to create a new empty font.
|
||||||
In this case you can optionally supply the 'sfntVersion' argument,
|
In this case you can optionally supply the 'sfntVersion' argument,
|
||||||
and a 'flavor' which can be None, or 'woff'.
|
and a 'flavor' which can be None, or 'woff'.
|
||||||
|
|
||||||
If the recalcBBoxes argument is false, a number of things will *not*
|
If the recalcBBoxes argument is false, a number of things will *not*
|
||||||
be recalculated upon save/compile:
|
be recalculated upon save/compile:
|
||||||
1) glyph bounding boxes
|
1) glyph bounding boxes
|
||||||
@ -100,8 +100,8 @@ class TTFont(object):
|
|||||||
3) hhea min/max values
|
3) hhea min/max values
|
||||||
(1) is needed for certain kinds of CJK fonts (ask Werner Lemberg ;-).
|
(1) is needed for certain kinds of CJK fonts (ask Werner Lemberg ;-).
|
||||||
Additionally, upon importing an TTX file, this option cause glyphs
|
Additionally, upon importing an TTX file, this option cause glyphs
|
||||||
to be compiled right away. This should reduce memory consumption
|
to be compiled right away. This should reduce memory consumption
|
||||||
greatly, and therefore should have some impact on the time needed
|
greatly, and therefore should have some impact on the time needed
|
||||||
to parse/compile large fonts.
|
to parse/compile large fonts.
|
||||||
|
|
||||||
If the recalcTimestamp argument is false, the modified timestamp in the
|
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
|
access only. If it is set to False, many data structures are loaded
|
||||||
immediately. The default is lazy=None which is somewhere in between.
|
immediately. The default is lazy=None which is somewhere in between.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from fontTools.ttLib import sfnt
|
from fontTools.ttLib import sfnt
|
||||||
self.verbose = verbose
|
self.verbose = verbose
|
||||||
self.quiet = quiet
|
self.quiet = quiet
|
||||||
@ -169,19 +169,19 @@ class TTFont(object):
|
|||||||
self.sfntVersion = self.reader.sfntVersion
|
self.sfntVersion = self.reader.sfntVersion
|
||||||
self.flavor = self.reader.flavor
|
self.flavor = self.reader.flavor
|
||||||
self.flavorData = self.reader.flavorData
|
self.flavorData = self.reader.flavorData
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""If we still have a reader object, close it."""
|
"""If we still have a reader object, close it."""
|
||||||
if self.reader is not None:
|
if self.reader is not None:
|
||||||
self.reader.close()
|
self.reader.close()
|
||||||
|
|
||||||
def save(self, file, makeSuitcase=False, reorderTables=True):
|
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
|
the 'file' argument can be either a pathname or a writable
|
||||||
file object.
|
file object.
|
||||||
|
|
||||||
On the Mac, if makeSuitcase is true, a suitcase (resource fork)
|
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
|
from fontTools.ttLib import sfnt
|
||||||
if not hasattr(file, "write"):
|
if not hasattr(file, "write"):
|
||||||
@ -197,7 +197,7 @@ class TTFont(object):
|
|||||||
else:
|
else:
|
||||||
# assume "file" is a writable file object
|
# assume "file" is a writable file object
|
||||||
closeStream = 0
|
closeStream = 0
|
||||||
|
|
||||||
tags = list(self.keys())
|
tags = list(self.keys())
|
||||||
if "GlyphOrder" in tags:
|
if "GlyphOrder" in tags:
|
||||||
tags.remove("GlyphOrder")
|
tags.remove("GlyphOrder")
|
||||||
@ -208,11 +208,11 @@ class TTFont(object):
|
|||||||
else:
|
else:
|
||||||
tmp = file
|
tmp = file
|
||||||
writer = sfnt.SFNTWriter(tmp, numTables, self.sfntVersion, self.flavor, self.flavorData)
|
writer = sfnt.SFNTWriter(tmp, numTables, self.sfntVersion, self.flavor, self.flavorData)
|
||||||
|
|
||||||
done = []
|
done = []
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
self._writeTable(tag, writer, done)
|
self._writeTable(tag, writer, done)
|
||||||
|
|
||||||
writer.close()
|
writer.close()
|
||||||
|
|
||||||
if reorderTables:
|
if reorderTables:
|
||||||
@ -223,7 +223,7 @@ class TTFont(object):
|
|||||||
|
|
||||||
if closeStream:
|
if closeStream:
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
def saveXML(self, fileOrPath, progress=None, quiet=False,
|
def saveXML(self, fileOrPath, progress=None, quiet=False,
|
||||||
tables=None, skipTables=None, splitTables=False, disassembleInstructions=True,
|
tables=None, skipTables=None, splitTables=False, disassembleInstructions=True,
|
||||||
bitmapGlyphDataFormat='raw'):
|
bitmapGlyphDataFormat='raw'):
|
||||||
@ -236,7 +236,7 @@ class TTFont(object):
|
|||||||
"""
|
"""
|
||||||
from fontTools import version
|
from fontTools import version
|
||||||
from fontTools.misc import xmlWriter
|
from fontTools.misc import xmlWriter
|
||||||
|
|
||||||
self.disassembleInstructions = disassembleInstructions
|
self.disassembleInstructions = disassembleInstructions
|
||||||
self.bitmapGlyphDataFormat = bitmapGlyphDataFormat
|
self.bitmapGlyphDataFormat = bitmapGlyphDataFormat
|
||||||
if not tables:
|
if not tables:
|
||||||
@ -253,19 +253,19 @@ class TTFont(object):
|
|||||||
idlefunc = getattr(progress, "idle", None)
|
idlefunc = getattr(progress, "idle", None)
|
||||||
else:
|
else:
|
||||||
idlefunc = None
|
idlefunc = None
|
||||||
|
|
||||||
writer = xmlWriter.XMLWriter(fileOrPath, idlefunc=idlefunc)
|
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)
|
ttLibVersion=version)
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
if not splitTables:
|
if not splitTables:
|
||||||
writer.newline()
|
writer.newline()
|
||||||
else:
|
else:
|
||||||
# 'fileOrPath' must now be a path
|
# 'fileOrPath' must now be a path
|
||||||
path, ext = os.path.splitext(fileOrPath)
|
path, ext = os.path.splitext(fileOrPath)
|
||||||
fileNameTemplate = path + ".%s" + ext
|
fileNameTemplate = path + ".%s" + ext
|
||||||
|
|
||||||
for i in range(numTables):
|
for i in range(numTables):
|
||||||
if progress:
|
if progress:
|
||||||
progress.set(i)
|
progress.set(i)
|
||||||
@ -292,7 +292,7 @@ class TTFont(object):
|
|||||||
writer.close()
|
writer.close()
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
debugmsg("Done dumping TTX")
|
debugmsg("Done dumping TTX")
|
||||||
|
|
||||||
def _tableToXML(self, writer, tag, progress, quiet):
|
def _tableToXML(self, writer, tag, progress, quiet):
|
||||||
if tag in self:
|
if tag in self:
|
||||||
table = self[tag]
|
table = self[tag]
|
||||||
@ -324,7 +324,7 @@ class TTFont(object):
|
|||||||
writer.endtag(xmlTag)
|
writer.endtag(xmlTag)
|
||||||
writer.newline()
|
writer.newline()
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def importXML(self, file, progress=None, quiet=False):
|
def importXML(self, file, progress=None, quiet=False):
|
||||||
"""Import a TTX file (an XML-based text format), so as to recreate
|
"""Import a TTX file (an XML-based text format), so as to recreate
|
||||||
a font object.
|
a font object.
|
||||||
@ -340,12 +340,12 @@ class TTFont(object):
|
|||||||
|
|
||||||
reader = xmlReader.XMLReader(file, self, progress, quiet)
|
reader = xmlReader.XMLReader(file, self, progress, quiet)
|
||||||
reader.read()
|
reader.read()
|
||||||
|
|
||||||
def isLoaded(self, tag):
|
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."""
|
decompiled and loaded into memory."""
|
||||||
return tag in self.tables
|
return tag in self.tables
|
||||||
|
|
||||||
def has_key(self, tag):
|
def has_key(self, tag):
|
||||||
if self.isLoaded(tag):
|
if self.isLoaded(tag):
|
||||||
return True
|
return True
|
||||||
@ -355,9 +355,9 @@ class TTFont(object):
|
|||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
__contains__ = has_key
|
__contains__ = has_key
|
||||||
|
|
||||||
def keys(self):
|
def keys(self):
|
||||||
keys = list(self.tables.keys())
|
keys = list(self.tables.keys())
|
||||||
if self.reader:
|
if self.reader:
|
||||||
@ -369,10 +369,10 @@ class TTFont(object):
|
|||||||
keys.remove("GlyphOrder")
|
keys.remove("GlyphOrder")
|
||||||
keys = sortedTagList(keys)
|
keys = sortedTagList(keys)
|
||||||
return ["GlyphOrder"] + keys
|
return ["GlyphOrder"] + keys
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(list(self.keys()))
|
return len(list(self.keys()))
|
||||||
|
|
||||||
def __getitem__(self, tag):
|
def __getitem__(self, tag):
|
||||||
tag = Tag(tag)
|
tag = Tag(tag)
|
||||||
try:
|
try:
|
||||||
@ -409,10 +409,10 @@ class TTFont(object):
|
|||||||
return table
|
return table
|
||||||
else:
|
else:
|
||||||
raise KeyError("'%s' table not found" % tag)
|
raise KeyError("'%s' table not found" % tag)
|
||||||
|
|
||||||
def __setitem__(self, tag, table):
|
def __setitem__(self, tag, table):
|
||||||
self.tables[Tag(tag)] = table
|
self.tables[Tag(tag)] = table
|
||||||
|
|
||||||
def __delitem__(self, tag):
|
def __delitem__(self, tag):
|
||||||
if tag not in self:
|
if tag not in self:
|
||||||
raise KeyError("'%s' table not found" % tag)
|
raise KeyError("'%s' table not found" % tag)
|
||||||
@ -426,10 +426,10 @@ class TTFont(object):
|
|||||||
return self[tag]
|
return self[tag]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return default
|
return default
|
||||||
|
|
||||||
def setGlyphOrder(self, glyphOrder):
|
def setGlyphOrder(self, glyphOrder):
|
||||||
self.glyphOrder = glyphOrder
|
self.glyphOrder = glyphOrder
|
||||||
|
|
||||||
def getGlyphOrder(self):
|
def getGlyphOrder(self):
|
||||||
try:
|
try:
|
||||||
return self.glyphOrder
|
return self.glyphOrder
|
||||||
@ -444,7 +444,7 @@ class TTFont(object):
|
|||||||
if glyphOrder is None:
|
if glyphOrder is None:
|
||||||
#
|
#
|
||||||
# No names found in the 'post' table.
|
# 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).
|
# in combination with the Adobe Glyph List (AGL).
|
||||||
#
|
#
|
||||||
self._getGlyphNamesFromCmap()
|
self._getGlyphNamesFromCmap()
|
||||||
@ -453,7 +453,7 @@ class TTFont(object):
|
|||||||
else:
|
else:
|
||||||
self._getGlyphNamesFromCmap()
|
self._getGlyphNamesFromCmap()
|
||||||
return self.glyphOrder
|
return self.glyphOrder
|
||||||
|
|
||||||
def _getGlyphNamesFromCmap(self):
|
def _getGlyphNamesFromCmap(self):
|
||||||
#
|
#
|
||||||
# This is rather convoluted, but then again, it's an interesting problem:
|
# 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
|
# restore partially loaded cmap, so it can continue loading
|
||||||
# using the proper names.
|
# using the proper names.
|
||||||
self.tables['cmap'] = cmapLoading
|
self.tables['cmap'] = cmapLoading
|
||||||
|
|
||||||
def getGlyphNames(self):
|
def getGlyphNames(self):
|
||||||
"""Get a list of glyph names, sorted alphabetically."""
|
"""Get a list of glyph names, sorted alphabetically."""
|
||||||
glyphNames = sorted(self.getGlyphOrder()[:])
|
glyphNames = sorted(self.getGlyphOrder()[:])
|
||||||
return glyphNames
|
return glyphNames
|
||||||
|
|
||||||
def getGlyphNames2(self):
|
def getGlyphNames2(self):
|
||||||
"""Get a list of glyph names, sorted alphabetically,
|
"""Get a list of glyph names, sorted alphabetically,
|
||||||
but not case sensitive.
|
but not case sensitive.
|
||||||
"""
|
"""
|
||||||
from fontTools.misc import textTools
|
from fontTools.misc import textTools
|
||||||
return textTools.caselessSort(self.getGlyphOrder())
|
return textTools.caselessSort(self.getGlyphOrder())
|
||||||
|
|
||||||
def getGlyphName(self, glyphID, requireReal=False):
|
def getGlyphName(self, glyphID, requireReal=False):
|
||||||
try:
|
try:
|
||||||
return self.getGlyphOrder()[glyphID]
|
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...
|
# the cmap table than there are glyphs. I don't think it's legal...
|
||||||
return "glyph%.5d" % glyphID
|
return "glyph%.5d" % glyphID
|
||||||
else:
|
else:
|
||||||
# user intends virtual GID support
|
# user intends virtual GID support
|
||||||
try:
|
try:
|
||||||
glyphName = self.VIDDict[glyphID]
|
glyphName = self.VIDDict[glyphID]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -579,7 +579,7 @@ class TTFont(object):
|
|||||||
except (NameError, ValueError):
|
except (NameError, ValueError):
|
||||||
raise KeyError(glyphName)
|
raise KeyError(glyphName)
|
||||||
else:
|
else:
|
||||||
# user intends virtual GID support
|
# user intends virtual GID support
|
||||||
try:
|
try:
|
||||||
glyphID = self.reverseVIDDict[glyphName]
|
glyphID = self.reverseVIDDict[glyphName]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -612,9 +612,9 @@ class TTFont(object):
|
|||||||
glyphOrder = self.getGlyphOrder()
|
glyphOrder = self.getGlyphOrder()
|
||||||
for glyphID in range(len(glyphOrder)):
|
for glyphID in range(len(glyphOrder)):
|
||||||
d[glyphOrder[glyphID]] = glyphID
|
d[glyphOrder[glyphID]] = glyphID
|
||||||
|
|
||||||
def _writeTable(self, tag, writer, done):
|
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.
|
inter-table dependencies.
|
||||||
"""
|
"""
|
||||||
if tag in done:
|
if tag in done:
|
||||||
@ -631,7 +631,7 @@ class TTFont(object):
|
|||||||
debugmsg("writing '%s' table to disk" % tag)
|
debugmsg("writing '%s' table to disk" % tag)
|
||||||
writer[tag] = tabledata
|
writer[tag] = tabledata
|
||||||
done.append(tag)
|
done.append(tag)
|
||||||
|
|
||||||
def getTableData(self, tag):
|
def getTableData(self, tag):
|
||||||
"""Returns raw table data, whether compiled or directly read from disk.
|
"""Returns raw table data, whether compiled or directly read from disk.
|
||||||
"""
|
"""
|
||||||
@ -646,13 +646,13 @@ class TTFont(object):
|
|||||||
return self.reader[tag]
|
return self.reader[tag]
|
||||||
else:
|
else:
|
||||||
raise KeyError(tag)
|
raise KeyError(tag)
|
||||||
|
|
||||||
def getGlyphSet(self, preferCFF=True):
|
def getGlyphSet(self, preferCFF=True):
|
||||||
"""Return a generic GlyphSet, which is a dict-like object
|
"""Return a generic GlyphSet, which is a dict-like object
|
||||||
mapping glyph names to glyph objects. The returned glyph objects
|
mapping glyph names to glyph objects. The returned glyph objects
|
||||||
have a .draw() method that supports the Pen protocol, and will
|
have a .draw() method that supports the Pen protocol, and will
|
||||||
have an attribute named 'width'.
|
have an attribute named 'width'.
|
||||||
|
|
||||||
If the font is CFF-based, the outlines will be taken from the 'CFF '
|
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.
|
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
|
If the font contains both a 'CFF ' and a 'glyf' table, you can use
|
||||||
@ -672,22 +672,22 @@ class TTFont(object):
|
|||||||
|
|
||||||
|
|
||||||
class _TTGlyphSet(object):
|
class _TTGlyphSet(object):
|
||||||
|
|
||||||
"""Generic dict-like GlyphSet class that pulls metrics from hmtx and
|
"""Generic dict-like GlyphSet class that pulls metrics from hmtx and
|
||||||
glyph shape from TrueType or CFF.
|
glyph shape from TrueType or CFF.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, ttFont, glyphs, glyphType):
|
def __init__(self, ttFont, glyphs, glyphType):
|
||||||
self._glyphs = glyphs
|
self._glyphs = glyphs
|
||||||
self._hmtx = ttFont['hmtx']
|
self._hmtx = ttFont['hmtx']
|
||||||
self._glyphType = glyphType
|
self._glyphType = glyphType
|
||||||
|
|
||||||
def keys(self):
|
def keys(self):
|
||||||
return list(self._glyphs.keys())
|
return list(self._glyphs.keys())
|
||||||
|
|
||||||
def has_key(self, glyphName):
|
def has_key(self, glyphName):
|
||||||
return glyphName in self._glyphs
|
return glyphName in self._glyphs
|
||||||
|
|
||||||
__contains__ = has_key
|
__contains__ = has_key
|
||||||
|
|
||||||
def __getitem__(self, glyphName):
|
def __getitem__(self, glyphName):
|
||||||
@ -700,12 +700,12 @@ class _TTGlyphSet(object):
|
|||||||
return default
|
return default
|
||||||
|
|
||||||
class _TTGlyph(object):
|
class _TTGlyph(object):
|
||||||
|
|
||||||
"""Wrapper for a TrueType glyph that supports the Pen protocol, meaning
|
"""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
|
that it has a .draw() method that takes a pen object as its only
|
||||||
argument. Additionally there is a 'width' attribute.
|
argument. Additionally there is a 'width' attribute.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, glyphset, glyph, metrics):
|
def __init__(self, glyphset, glyph, metrics):
|
||||||
self._glyphset = glyphset
|
self._glyphset = glyphset
|
||||||
self._glyph = glyph
|
self._glyph = glyph
|
||||||
@ -733,14 +733,14 @@ class _TTGlyphGlyf(_TTGlyph):
|
|||||||
|
|
||||||
|
|
||||||
class GlyphOrder(object):
|
class GlyphOrder(object):
|
||||||
|
|
||||||
"""A pseudo table. The glyph order isn't in the font as a separate
|
"""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.
|
table, but it's nice to present it as such in the TTX format.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, tag=None):
|
def __init__(self, tag=None):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
glyphOrder = ttFont.getGlyphOrder()
|
glyphOrder = ttFont.getGlyphOrder()
|
||||||
writer.comment("The 'id' attribute is only for humans; "
|
writer.comment("The 'id' attribute is only for humans; "
|
||||||
@ -750,7 +750,7 @@ class GlyphOrder(object):
|
|||||||
glyphName = glyphOrder[i]
|
glyphName = glyphOrder[i]
|
||||||
writer.simpletag("GlyphID", id=i, name=glyphName)
|
writer.simpletag("GlyphID", id=i, name=glyphName)
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
if not hasattr(self, "glyphOrder"):
|
if not hasattr(self, "glyphOrder"):
|
||||||
self.glyphOrder = []
|
self.glyphOrder = []
|
||||||
@ -760,7 +760,7 @@ class GlyphOrder(object):
|
|||||||
|
|
||||||
|
|
||||||
def getTableModule(tag):
|
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.
|
Return None when no module is found.
|
||||||
"""
|
"""
|
||||||
from . import tables
|
from . import tables
|
||||||
@ -781,7 +781,7 @@ def getTableModule(tag):
|
|||||||
|
|
||||||
|
|
||||||
def getTableClass(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.
|
Return None when no class is found.
|
||||||
"""
|
"""
|
||||||
module = getTableModule(tag)
|
module = getTableModule(tag)
|
||||||
@ -819,14 +819,14 @@ def _escapechar(c):
|
|||||||
|
|
||||||
|
|
||||||
def tagToIdentifier(tag):
|
def tagToIdentifier(tag):
|
||||||
"""Convert a table tag to a valid (but UGLY) python identifier,
|
"""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
|
as well as a filename that's guaranteed to be unique even on a
|
||||||
caseless file system. Each character is mapped to two characters.
|
caseless file system. Each character is mapped to two characters.
|
||||||
Lowercase letters get an underscore before the letter, uppercase
|
Lowercase letters get an underscore before the letter, uppercase
|
||||||
letters get an underscore after the letter. Trailing spaces are
|
letters get an underscore after the letter. Trailing spaces are
|
||||||
trimmed. Illegal characters are escaped as two hex bytes. If the
|
trimmed. Illegal characters are escaped as two hex bytes. If the
|
||||||
result starts with a number (as the result of a hex escape), an
|
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'
|
'glyf' -> '_g_l_y_f'
|
||||||
'cvt ' -> '_c_v_t'
|
'cvt ' -> '_c_v_t'
|
||||||
'OS/2' -> 'O_S_2f_2'
|
'OS/2' -> 'O_S_2f_2'
|
||||||
|
@ -35,7 +35,7 @@ def getSFNTResIndices(path):
|
|||||||
|
|
||||||
|
|
||||||
def openTTFonts(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;
|
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
|
but in the case of a Mac font suitcase it will contain as many
|
||||||
font objects as there are sfnt resources in the file.
|
font objects as there are sfnt resources in the file.
|
||||||
@ -54,9 +54,9 @@ def openTTFonts(path):
|
|||||||
|
|
||||||
|
|
||||||
class SFNTResourceReader(object):
|
class SFNTResourceReader(object):
|
||||||
|
|
||||||
"""Simple (Mac-only) read-only file wrapper for 'sfnt' resources."""
|
"""Simple (Mac-only) read-only file wrapper for 'sfnt' resources."""
|
||||||
|
|
||||||
def __init__(self, path, res_name_or_index):
|
def __init__(self, path, res_name_or_index):
|
||||||
resref = MyOpenResFile(path)
|
resref = MyOpenResFile(path)
|
||||||
Res.UseResFile(resref)
|
Res.UseResFile(resref)
|
||||||
@ -67,16 +67,16 @@ class SFNTResourceReader(object):
|
|||||||
self.file = StringIO(res.data)
|
self.file = StringIO(res.data)
|
||||||
Res.CloseResFile(resref)
|
Res.CloseResFile(resref)
|
||||||
self.name = path
|
self.name = path
|
||||||
|
|
||||||
def __getattr__(self, attr):
|
def __getattr__(self, attr):
|
||||||
# cheap inheritance
|
# cheap inheritance
|
||||||
return getattr(self.file, attr)
|
return getattr(self.file, attr)
|
||||||
|
|
||||||
|
|
||||||
class SFNTResourceWriter(object):
|
class SFNTResourceWriter(object):
|
||||||
|
|
||||||
"""Simple (Mac-only) file wrapper for 'sfnt' resources."""
|
"""Simple (Mac-only) file wrapper for 'sfnt' resources."""
|
||||||
|
|
||||||
def __init__(self, path, ttFont, res_id=None):
|
def __init__(self, path, ttFont, res_id=None):
|
||||||
self.file = StringIO()
|
self.file = StringIO()
|
||||||
self.name = path
|
self.name = path
|
||||||
@ -97,7 +97,7 @@ class SFNTResourceWriter(object):
|
|||||||
if self.familyname[i] != self.psname[i]:
|
if self.familyname[i] != self.psname[i]:
|
||||||
break
|
break
|
||||||
self.familyname = self.psname[:i]
|
self.familyname = self.psname[:i]
|
||||||
|
|
||||||
self.ttFont = ttFont
|
self.ttFont = ttFont
|
||||||
self.res_id = res_id
|
self.res_id = res_id
|
||||||
if os.path.exists(self.name):
|
if os.path.exists(self.name):
|
||||||
@ -105,7 +105,7 @@ class SFNTResourceWriter(object):
|
|||||||
# XXX datafork support
|
# XXX datafork support
|
||||||
Res.FSpCreateResFile(self.name, 'DMOV', 'FFIL', 0)
|
Res.FSpCreateResFile(self.name, 'DMOV', 'FFIL', 0)
|
||||||
self.resref = Res.FSOpenResFile(self.name, 3) # exclusive read/write permission
|
self.resref = Res.FSOpenResFile(self.name, 3) # exclusive read/write permission
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
if self.closed:
|
if self.closed:
|
||||||
return
|
return
|
||||||
@ -121,20 +121,20 @@ class SFNTResourceWriter(object):
|
|||||||
self.res_id = Res.Unique1ID('sfnt')
|
self.res_id = Res.Unique1ID('sfnt')
|
||||||
res.AddResource('sfnt', self.res_id, self.fullname)
|
res.AddResource('sfnt', self.res_id, self.fullname)
|
||||||
res.ChangedResource()
|
res.ChangedResource()
|
||||||
|
|
||||||
self.createFond()
|
self.createFond()
|
||||||
del self.ttFont
|
del self.ttFont
|
||||||
Res.CloseResFile(self.resref)
|
Res.CloseResFile(self.resref)
|
||||||
self.file.close()
|
self.file.close()
|
||||||
self.closed = 1
|
self.closed = 1
|
||||||
|
|
||||||
def createFond(self):
|
def createFond(self):
|
||||||
fond_res = Res.Resource("")
|
fond_res = Res.Resource("")
|
||||||
fond_res.AddResource('FOND', self.res_id, self.fullname)
|
fond_res.AddResource('FOND', self.res_id, self.fullname)
|
||||||
|
|
||||||
from fontTools import fondLib
|
from fontTools import fondLib
|
||||||
fond = fondLib.FontFamily(fond_res, "w")
|
fond = fondLib.FontFamily(fond_res, "w")
|
||||||
|
|
||||||
fond.ffFirstChar = 0
|
fond.ffFirstChar = 0
|
||||||
fond.ffLastChar = 255
|
fond.ffLastChar = 255
|
||||||
fond.fondClass = 0
|
fond.fondClass = 0
|
||||||
@ -155,16 +155,16 @@ class SFNTResourceWriter(object):
|
|||||||
fond.changed = 1
|
fond.changed = 1
|
||||||
fond.glyphTableOffset = 0
|
fond.glyphTableOffset = 0
|
||||||
fond.styleMappingReserved = 0
|
fond.styleMappingReserved = 0
|
||||||
|
|
||||||
# calc:
|
# calc:
|
||||||
scale = 4096 / self.ttFont['head'].unitsPerEm
|
scale = 4096 / self.ttFont['head'].unitsPerEm
|
||||||
fond.ffAscent = scale * self.ttFont['hhea'].ascent
|
fond.ffAscent = scale * self.ttFont['hhea'].ascent
|
||||||
fond.ffDescent = scale * self.ttFont['hhea'].descent
|
fond.ffDescent = scale * self.ttFont['hhea'].descent
|
||||||
fond.ffWidMax = scale * self.ttFont['hhea'].advanceWidthMax
|
fond.ffWidMax = scale * self.ttFont['hhea'].advanceWidthMax
|
||||||
|
|
||||||
fond.ffFamilyName = self.familyname
|
fond.ffFamilyName = self.familyname
|
||||||
fond.psNames = {0: self.psname}
|
fond.psNames = {0: self.psname}
|
||||||
|
|
||||||
fond.widthTables = {}
|
fond.widthTables = {}
|
||||||
fond.kernTables = {}
|
fond.kernTables = {}
|
||||||
cmap = self.ttFont['cmap'].getcmap(1, 0)
|
cmap = self.ttFont['cmap'].getcmap(1, 0)
|
||||||
@ -189,11 +189,11 @@ class SFNTResourceWriter(object):
|
|||||||
fondwidths[names[name]] = scale * width
|
fondwidths[names[name]] = scale * width
|
||||||
fond.widthTables = {0: fondwidths}
|
fond.widthTables = {0: fondwidths}
|
||||||
fond.save()
|
fond.save()
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
if not self.closed:
|
if not self.closed:
|
||||||
self.close()
|
self.close()
|
||||||
|
|
||||||
def __getattr__(self, attr):
|
def __getattr__(self, attr):
|
||||||
# cheap inheritance
|
# cheap inheritance
|
||||||
return getattr(self.file, attr)
|
return getattr(self.file, attr)
|
||||||
|
@ -4,10 +4,10 @@ Defines two public classes:
|
|||||||
SFNTReader
|
SFNTReader
|
||||||
SFNTWriter
|
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.)
|
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
|
classes, since whenever to number of tables changes or whenever
|
||||||
a table's length chages you need to rewrite the whole file anyway.
|
a table's length chages you need to rewrite the whole file anyway.
|
||||||
"""
|
"""
|
||||||
@ -20,7 +20,7 @@ import struct
|
|||||||
|
|
||||||
|
|
||||||
class SFNTReader(object):
|
class SFNTReader(object):
|
||||||
|
|
||||||
def __init__(self, file, checkChecksums=1, fontNumber=-1):
|
def __init__(self, file, checkChecksums=1, fontNumber=-1):
|
||||||
self.file = file
|
self.file = file
|
||||||
self.checkChecksums = checkChecksums
|
self.checkChecksums = checkChecksums
|
||||||
@ -66,10 +66,10 @@ class SFNTReader(object):
|
|||||||
return tag in self.tables
|
return tag in self.tables
|
||||||
|
|
||||||
__contains__ = has_key
|
__contains__ = has_key
|
||||||
|
|
||||||
def keys(self):
|
def keys(self):
|
||||||
return self.tables.keys()
|
return self.tables.keys()
|
||||||
|
|
||||||
def __getitem__(self, tag):
|
def __getitem__(self, tag):
|
||||||
"""Fetch the raw table data."""
|
"""Fetch the raw table data."""
|
||||||
entry = self.tables[Tag(tag)]
|
entry = self.tables[Tag(tag)]
|
||||||
@ -87,16 +87,16 @@ class SFNTReader(object):
|
|||||||
# Be friendly, and just print a warning.
|
# Be friendly, and just print a warning.
|
||||||
print("bad checksum for '%s' table" % tag)
|
print("bad checksum for '%s' table" % tag)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def __delitem__(self, tag):
|
def __delitem__(self, tag):
|
||||||
del self.tables[Tag(tag)]
|
del self.tables[Tag(tag)]
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
self.file.close()
|
self.file.close()
|
||||||
|
|
||||||
|
|
||||||
class SFNTWriter(object):
|
class SFNTWriter(object):
|
||||||
|
|
||||||
def __init__(self, file, numTables, sfntVersion="\000\001\000\000",
|
def __init__(self, file, numTables, sfntVersion="\000\001\000\000",
|
||||||
flavor=None, flavorData=None):
|
flavor=None, flavorData=None):
|
||||||
self.file = file
|
self.file = file
|
||||||
@ -113,7 +113,7 @@ class SFNTWriter(object):
|
|||||||
self.signature = "wOFF"
|
self.signature = "wOFF"
|
||||||
|
|
||||||
# to calculate WOFF checksum adjustment, we also need the original SFNT offsets
|
# to calculate WOFF checksum adjustment, we also need the original SFNT offsets
|
||||||
self.origNextTableOffset = sfntDirectorySize + numTables * sfntDirectoryEntrySize
|
self.origNextTableOffset = sfntDirectorySize + numTables * sfntDirectoryEntrySize
|
||||||
else:
|
else:
|
||||||
assert not self.flavor, "Unknown flavor '%s'" % self.flavor
|
assert not self.flavor, "Unknown flavor '%s'" % self.flavor
|
||||||
self.directoryFormat = sfntDirectoryFormat
|
self.directoryFormat = sfntDirectoryFormat
|
||||||
@ -128,7 +128,7 @@ class SFNTWriter(object):
|
|||||||
# make sure we're actually where we want to be. (old cStringIO bug)
|
# make sure we're actually where we want to be. (old cStringIO bug)
|
||||||
self.file.write(b'\0' * (self.nextTableOffset - self.file.tell()))
|
self.file.write(b'\0' * (self.nextTableOffset - self.file.tell()))
|
||||||
self.tables = {}
|
self.tables = {}
|
||||||
|
|
||||||
def __setitem__(self, tag, data):
|
def __setitem__(self, tag, data):
|
||||||
"""Write raw table data to disk."""
|
"""Write raw table data to disk."""
|
||||||
if tag in self.tables:
|
if tag in self.tables:
|
||||||
@ -157,9 +157,9 @@ class SFNTWriter(object):
|
|||||||
# in the font.
|
# in the font.
|
||||||
self.file.write(b'\0' * (self.nextTableOffset - self.file.tell()))
|
self.file.write(b'\0' * (self.nextTableOffset - self.file.tell()))
|
||||||
assert self.nextTableOffset == self.file.tell()
|
assert self.nextTableOffset == self.file.tell()
|
||||||
|
|
||||||
self.tables[tag] = entry
|
self.tables[tag] = entry
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""All tables must have been written to disk. Now write the
|
"""All tables must have been written to disk. Now write the
|
||||||
directory.
|
directory.
|
||||||
@ -214,9 +214,9 @@ class SFNTWriter(object):
|
|||||||
else:
|
else:
|
||||||
assert not self.flavor, "Unknown flavor '%s'" % self.flavor
|
assert not self.flavor, "Unknown flavor '%s'" % self.flavor
|
||||||
pass
|
pass
|
||||||
|
|
||||||
directory = sstruct.pack(self.directoryFormat, self)
|
directory = sstruct.pack(self.directoryFormat, self)
|
||||||
|
|
||||||
self.file.seek(self.directorySize)
|
self.file.seek(self.directorySize)
|
||||||
seenHead = 0
|
seenHead = 0
|
||||||
for tag, entry in tables:
|
for tag, entry in tables:
|
||||||
@ -332,19 +332,19 @@ woffDirectoryEntrySize = sstruct.calcsize(woffDirectoryEntryFormat)
|
|||||||
|
|
||||||
|
|
||||||
class DirectoryEntry(object):
|
class DirectoryEntry(object):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.uncompressed = False # if True, always embed entry raw
|
self.uncompressed = False # if True, always embed entry raw
|
||||||
|
|
||||||
def fromFile(self, file):
|
def fromFile(self, file):
|
||||||
sstruct.unpack(self.format, file.read(self.formatSize), self)
|
sstruct.unpack(self.format, file.read(self.formatSize), self)
|
||||||
|
|
||||||
def fromString(self, str):
|
def fromString(self, str):
|
||||||
sstruct.unpack(self.format, str, self)
|
sstruct.unpack(self.format, str, self)
|
||||||
|
|
||||||
def toString(self):
|
def toString(self):
|
||||||
return sstruct.pack(self.format, self)
|
return sstruct.pack(self.format, self)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
if hasattr(self, "tag"):
|
if hasattr(self, "tag"):
|
||||||
return "<%s '%s' at %x>" % (self.__class__.__name__, self.tag, id(self))
|
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
|
Optionally takes a 'start' argument, which allows you to
|
||||||
calculate a checksum in chunks by feeding it a previous
|
calculate a checksum in chunks by feeding it a previous
|
||||||
result.
|
result.
|
||||||
|
|
||||||
If the data length is not a multiple of four, it assumes
|
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"))
|
>>> print(calcChecksum(b"abcd"))
|
||||||
1633837924
|
1633837924
|
||||||
|
@ -13,262 +13,262 @@ from fontTools.misc.py23 import *
|
|||||||
#
|
#
|
||||||
|
|
||||||
standardGlyphOrder = [
|
standardGlyphOrder = [
|
||||||
".notdef", # 0
|
".notdef", # 0
|
||||||
".null", # 1
|
".null", # 1
|
||||||
"nonmarkingreturn", # 2
|
"nonmarkingreturn", # 2
|
||||||
"space", # 3
|
"space", # 3
|
||||||
"exclam", # 4
|
"exclam", # 4
|
||||||
"quotedbl", # 5
|
"quotedbl", # 5
|
||||||
"numbersign", # 6
|
"numbersign", # 6
|
||||||
"dollar", # 7
|
"dollar", # 7
|
||||||
"percent", # 8
|
"percent", # 8
|
||||||
"ampersand", # 9
|
"ampersand", # 9
|
||||||
"quotesingle", # 10
|
"quotesingle", # 10
|
||||||
"parenleft", # 11
|
"parenleft", # 11
|
||||||
"parenright", # 12
|
"parenright", # 12
|
||||||
"asterisk", # 13
|
"asterisk", # 13
|
||||||
"plus", # 14
|
"plus", # 14
|
||||||
"comma", # 15
|
"comma", # 15
|
||||||
"hyphen", # 16
|
"hyphen", # 16
|
||||||
"period", # 17
|
"period", # 17
|
||||||
"slash", # 18
|
"slash", # 18
|
||||||
"zero", # 19
|
"zero", # 19
|
||||||
"one", # 20
|
"one", # 20
|
||||||
"two", # 21
|
"two", # 21
|
||||||
"three", # 22
|
"three", # 22
|
||||||
"four", # 23
|
"four", # 23
|
||||||
"five", # 24
|
"five", # 24
|
||||||
"six", # 25
|
"six", # 25
|
||||||
"seven", # 26
|
"seven", # 26
|
||||||
"eight", # 27
|
"eight", # 27
|
||||||
"nine", # 28
|
"nine", # 28
|
||||||
"colon", # 29
|
"colon", # 29
|
||||||
"semicolon", # 30
|
"semicolon", # 30
|
||||||
"less", # 31
|
"less", # 31
|
||||||
"equal", # 32
|
"equal", # 32
|
||||||
"greater", # 33
|
"greater", # 33
|
||||||
"question", # 34
|
"question", # 34
|
||||||
"at", # 35
|
"at", # 35
|
||||||
"A", # 36
|
"A", # 36
|
||||||
"B", # 37
|
"B", # 37
|
||||||
"C", # 38
|
"C", # 38
|
||||||
"D", # 39
|
"D", # 39
|
||||||
"E", # 40
|
"E", # 40
|
||||||
"F", # 41
|
"F", # 41
|
||||||
"G", # 42
|
"G", # 42
|
||||||
"H", # 43
|
"H", # 43
|
||||||
"I", # 44
|
"I", # 44
|
||||||
"J", # 45
|
"J", # 45
|
||||||
"K", # 46
|
"K", # 46
|
||||||
"L", # 47
|
"L", # 47
|
||||||
"M", # 48
|
"M", # 48
|
||||||
"N", # 49
|
"N", # 49
|
||||||
"O", # 50
|
"O", # 50
|
||||||
"P", # 51
|
"P", # 51
|
||||||
"Q", # 52
|
"Q", # 52
|
||||||
"R", # 53
|
"R", # 53
|
||||||
"S", # 54
|
"S", # 54
|
||||||
"T", # 55
|
"T", # 55
|
||||||
"U", # 56
|
"U", # 56
|
||||||
"V", # 57
|
"V", # 57
|
||||||
"W", # 58
|
"W", # 58
|
||||||
"X", # 59
|
"X", # 59
|
||||||
"Y", # 60
|
"Y", # 60
|
||||||
"Z", # 61
|
"Z", # 61
|
||||||
"bracketleft", # 62
|
"bracketleft", # 62
|
||||||
"backslash", # 63
|
"backslash", # 63
|
||||||
"bracketright", # 64
|
"bracketright", # 64
|
||||||
"asciicircum", # 65
|
"asciicircum", # 65
|
||||||
"underscore", # 66
|
"underscore", # 66
|
||||||
"grave", # 67
|
"grave", # 67
|
||||||
"a", # 68
|
"a", # 68
|
||||||
"b", # 69
|
"b", # 69
|
||||||
"c", # 70
|
"c", # 70
|
||||||
"d", # 71
|
"d", # 71
|
||||||
"e", # 72
|
"e", # 72
|
||||||
"f", # 73
|
"f", # 73
|
||||||
"g", # 74
|
"g", # 74
|
||||||
"h", # 75
|
"h", # 75
|
||||||
"i", # 76
|
"i", # 76
|
||||||
"j", # 77
|
"j", # 77
|
||||||
"k", # 78
|
"k", # 78
|
||||||
"l", # 79
|
"l", # 79
|
||||||
"m", # 80
|
"m", # 80
|
||||||
"n", # 81
|
"n", # 81
|
||||||
"o", # 82
|
"o", # 82
|
||||||
"p", # 83
|
"p", # 83
|
||||||
"q", # 84
|
"q", # 84
|
||||||
"r", # 85
|
"r", # 85
|
||||||
"s", # 86
|
"s", # 86
|
||||||
"t", # 87
|
"t", # 87
|
||||||
"u", # 88
|
"u", # 88
|
||||||
"v", # 89
|
"v", # 89
|
||||||
"w", # 90
|
"w", # 90
|
||||||
"x", # 91
|
"x", # 91
|
||||||
"y", # 92
|
"y", # 92
|
||||||
"z", # 93
|
"z", # 93
|
||||||
"braceleft", # 94
|
"braceleft", # 94
|
||||||
"bar", # 95
|
"bar", # 95
|
||||||
"braceright", # 96
|
"braceright", # 96
|
||||||
"asciitilde", # 97
|
"asciitilde", # 97
|
||||||
"Adieresis", # 98
|
"Adieresis", # 98
|
||||||
"Aring", # 99
|
"Aring", # 99
|
||||||
"Ccedilla", # 100
|
"Ccedilla", # 100
|
||||||
"Eacute", # 101
|
"Eacute", # 101
|
||||||
"Ntilde", # 102
|
"Ntilde", # 102
|
||||||
"Odieresis", # 103
|
"Odieresis", # 103
|
||||||
"Udieresis", # 104
|
"Udieresis", # 104
|
||||||
"aacute", # 105
|
"aacute", # 105
|
||||||
"agrave", # 106
|
"agrave", # 106
|
||||||
"acircumflex", # 107
|
"acircumflex", # 107
|
||||||
"adieresis", # 108
|
"adieresis", # 108
|
||||||
"atilde", # 109
|
"atilde", # 109
|
||||||
"aring", # 110
|
"aring", # 110
|
||||||
"ccedilla", # 111
|
"ccedilla", # 111
|
||||||
"eacute", # 112
|
"eacute", # 112
|
||||||
"egrave", # 113
|
"egrave", # 113
|
||||||
"ecircumflex", # 114
|
"ecircumflex", # 114
|
||||||
"edieresis", # 115
|
"edieresis", # 115
|
||||||
"iacute", # 116
|
"iacute", # 116
|
||||||
"igrave", # 117
|
"igrave", # 117
|
||||||
"icircumflex", # 118
|
"icircumflex", # 118
|
||||||
"idieresis", # 119
|
"idieresis", # 119
|
||||||
"ntilde", # 120
|
"ntilde", # 120
|
||||||
"oacute", # 121
|
"oacute", # 121
|
||||||
"ograve", # 122
|
"ograve", # 122
|
||||||
"ocircumflex", # 123
|
"ocircumflex", # 123
|
||||||
"odieresis", # 124
|
"odieresis", # 124
|
||||||
"otilde", # 125
|
"otilde", # 125
|
||||||
"uacute", # 126
|
"uacute", # 126
|
||||||
"ugrave", # 127
|
"ugrave", # 127
|
||||||
"ucircumflex", # 128
|
"ucircumflex", # 128
|
||||||
"udieresis", # 129
|
"udieresis", # 129
|
||||||
"dagger", # 130
|
"dagger", # 130
|
||||||
"degree", # 131
|
"degree", # 131
|
||||||
"cent", # 132
|
"cent", # 132
|
||||||
"sterling", # 133
|
"sterling", # 133
|
||||||
"section", # 134
|
"section", # 134
|
||||||
"bullet", # 135
|
"bullet", # 135
|
||||||
"paragraph", # 136
|
"paragraph", # 136
|
||||||
"germandbls", # 137
|
"germandbls", # 137
|
||||||
"registered", # 138
|
"registered", # 138
|
||||||
"copyright", # 139
|
"copyright", # 139
|
||||||
"trademark", # 140
|
"trademark", # 140
|
||||||
"acute", # 141
|
"acute", # 141
|
||||||
"dieresis", # 142
|
"dieresis", # 142
|
||||||
"notequal", # 143
|
"notequal", # 143
|
||||||
"AE", # 144
|
"AE", # 144
|
||||||
"Oslash", # 145
|
"Oslash", # 145
|
||||||
"infinity", # 146
|
"infinity", # 146
|
||||||
"plusminus", # 147
|
"plusminus", # 147
|
||||||
"lessequal", # 148
|
"lessequal", # 148
|
||||||
"greaterequal", # 149
|
"greaterequal", # 149
|
||||||
"yen", # 150
|
"yen", # 150
|
||||||
"mu", # 151
|
"mu", # 151
|
||||||
"partialdiff", # 152
|
"partialdiff", # 152
|
||||||
"summation", # 153
|
"summation", # 153
|
||||||
"product", # 154
|
"product", # 154
|
||||||
"pi", # 155
|
"pi", # 155
|
||||||
"integral", # 156
|
"integral", # 156
|
||||||
"ordfeminine", # 157
|
"ordfeminine", # 157
|
||||||
"ordmasculine", # 158
|
"ordmasculine", # 158
|
||||||
"Omega", # 159
|
"Omega", # 159
|
||||||
"ae", # 160
|
"ae", # 160
|
||||||
"oslash", # 161
|
"oslash", # 161
|
||||||
"questiondown", # 162
|
"questiondown", # 162
|
||||||
"exclamdown", # 163
|
"exclamdown", # 163
|
||||||
"logicalnot", # 164
|
"logicalnot", # 164
|
||||||
"radical", # 165
|
"radical", # 165
|
||||||
"florin", # 166
|
"florin", # 166
|
||||||
"approxequal", # 167
|
"approxequal", # 167
|
||||||
"Delta", # 168
|
"Delta", # 168
|
||||||
"guillemotleft", # 169
|
"guillemotleft", # 169
|
||||||
"guillemotright", # 170
|
"guillemotright", # 170
|
||||||
"ellipsis", # 171
|
"ellipsis", # 171
|
||||||
"nonbreakingspace", # 172
|
"nonbreakingspace", # 172
|
||||||
"Agrave", # 173
|
"Agrave", # 173
|
||||||
"Atilde", # 174
|
"Atilde", # 174
|
||||||
"Otilde", # 175
|
"Otilde", # 175
|
||||||
"OE", # 176
|
"OE", # 176
|
||||||
"oe", # 177
|
"oe", # 177
|
||||||
"endash", # 178
|
"endash", # 178
|
||||||
"emdash", # 179
|
"emdash", # 179
|
||||||
"quotedblleft", # 180
|
"quotedblleft", # 180
|
||||||
"quotedblright", # 181
|
"quotedblright", # 181
|
||||||
"quoteleft", # 182
|
"quoteleft", # 182
|
||||||
"quoteright", # 183
|
"quoteright", # 183
|
||||||
"divide", # 184
|
"divide", # 184
|
||||||
"lozenge", # 185
|
"lozenge", # 185
|
||||||
"ydieresis", # 186
|
"ydieresis", # 186
|
||||||
"Ydieresis", # 187
|
"Ydieresis", # 187
|
||||||
"fraction", # 188
|
"fraction", # 188
|
||||||
"currency", # 189
|
"currency", # 189
|
||||||
"guilsinglleft", # 190
|
"guilsinglleft", # 190
|
||||||
"guilsinglright", # 191
|
"guilsinglright", # 191
|
||||||
"fi", # 192
|
"fi", # 192
|
||||||
"fl", # 193
|
"fl", # 193
|
||||||
"daggerdbl", # 194
|
"daggerdbl", # 194
|
||||||
"periodcentered", # 195
|
"periodcentered", # 195
|
||||||
"quotesinglbase", # 196
|
"quotesinglbase", # 196
|
||||||
"quotedblbase", # 197
|
"quotedblbase", # 197
|
||||||
"perthousand", # 198
|
"perthousand", # 198
|
||||||
"Acircumflex", # 199
|
"Acircumflex", # 199
|
||||||
"Ecircumflex", # 200
|
"Ecircumflex", # 200
|
||||||
"Aacute", # 201
|
"Aacute", # 201
|
||||||
"Edieresis", # 202
|
"Edieresis", # 202
|
||||||
"Egrave", # 203
|
"Egrave", # 203
|
||||||
"Iacute", # 204
|
"Iacute", # 204
|
||||||
"Icircumflex", # 205
|
"Icircumflex", # 205
|
||||||
"Idieresis", # 206
|
"Idieresis", # 206
|
||||||
"Igrave", # 207
|
"Igrave", # 207
|
||||||
"Oacute", # 208
|
"Oacute", # 208
|
||||||
"Ocircumflex", # 209
|
"Ocircumflex", # 209
|
||||||
"apple", # 210
|
"apple", # 210
|
||||||
"Ograve", # 211
|
"Ograve", # 211
|
||||||
"Uacute", # 212
|
"Uacute", # 212
|
||||||
"Ucircumflex", # 213
|
"Ucircumflex", # 213
|
||||||
"Ugrave", # 214
|
"Ugrave", # 214
|
||||||
"dotlessi", # 215
|
"dotlessi", # 215
|
||||||
"circumflex", # 216
|
"circumflex", # 216
|
||||||
"tilde", # 217
|
"tilde", # 217
|
||||||
"macron", # 218
|
"macron", # 218
|
||||||
"breve", # 219
|
"breve", # 219
|
||||||
"dotaccent", # 220
|
"dotaccent", # 220
|
||||||
"ring", # 221
|
"ring", # 221
|
||||||
"cedilla", # 222
|
"cedilla", # 222
|
||||||
"hungarumlaut", # 223
|
"hungarumlaut", # 223
|
||||||
"ogonek", # 224
|
"ogonek", # 224
|
||||||
"caron", # 225
|
"caron", # 225
|
||||||
"Lslash", # 226
|
"Lslash", # 226
|
||||||
"lslash", # 227
|
"lslash", # 227
|
||||||
"Scaron", # 228
|
"Scaron", # 228
|
||||||
"scaron", # 229
|
"scaron", # 229
|
||||||
"Zcaron", # 230
|
"Zcaron", # 230
|
||||||
"zcaron", # 231
|
"zcaron", # 231
|
||||||
"brokenbar", # 232
|
"brokenbar", # 232
|
||||||
"Eth", # 233
|
"Eth", # 233
|
||||||
"eth", # 234
|
"eth", # 234
|
||||||
"Yacute", # 235
|
"Yacute", # 235
|
||||||
"yacute", # 236
|
"yacute", # 236
|
||||||
"Thorn", # 237
|
"Thorn", # 237
|
||||||
"thorn", # 238
|
"thorn", # 238
|
||||||
"minus", # 239
|
"minus", # 239
|
||||||
"multiply", # 240
|
"multiply", # 240
|
||||||
"onesuperior", # 241
|
"onesuperior", # 241
|
||||||
"twosuperior", # 242
|
"twosuperior", # 242
|
||||||
"threesuperior", # 243
|
"threesuperior", # 243
|
||||||
"onehalf", # 244
|
"onehalf", # 244
|
||||||
"onequarter", # 245
|
"onequarter", # 245
|
||||||
"threequarters", # 246
|
"threequarters", # 246
|
||||||
"franc", # 247
|
"franc", # 247
|
||||||
"Gbreve", # 248
|
"Gbreve", # 248
|
||||||
"gbreve", # 249
|
"gbreve", # 249
|
||||||
"Idotaccent", # 250
|
"Idotaccent", # 250
|
||||||
"Scedilla", # 251
|
"Scedilla", # 251
|
||||||
"scedilla", # 252
|
"scedilla", # 252
|
||||||
"Cacute", # 253
|
"Cacute", # 253
|
||||||
"cacute", # 254
|
"cacute", # 254
|
||||||
"Ccaron", # 255
|
"Ccaron", # 255
|
||||||
"ccaron", # 256
|
"ccaron", # 256
|
||||||
"dcroat" # 257
|
"dcroat" # 257
|
||||||
]
|
]
|
||||||
|
@ -53,6 +53,6 @@ class BitmapGlyphMetrics(object):
|
|||||||
|
|
||||||
class BigGlyphMetrics(BitmapGlyphMetrics):
|
class BigGlyphMetrics(BitmapGlyphMetrics):
|
||||||
binaryFormat = bigGlyphMetricsFormat
|
binaryFormat = bigGlyphMetricsFormat
|
||||||
|
|
||||||
class SmallGlyphMetrics(BitmapGlyphMetrics):
|
class SmallGlyphMetrics(BitmapGlyphMetrics):
|
||||||
binaryFormat = smallGlyphMetricsFormat
|
binaryFormat = smallGlyphMetricsFormat
|
||||||
|
@ -5,42 +5,42 @@ from . import DefaultTable
|
|||||||
|
|
||||||
|
|
||||||
class table_C_F_F_(DefaultTable.DefaultTable):
|
class table_C_F_F_(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
def __init__(self, tag):
|
def __init__(self, tag):
|
||||||
DefaultTable.DefaultTable.__init__(self, tag)
|
DefaultTable.DefaultTable.__init__(self, tag)
|
||||||
self.cff = cffLib.CFFFontSet()
|
self.cff = cffLib.CFFFontSet()
|
||||||
self._gaveGlyphOrder = False
|
self._gaveGlyphOrder = False
|
||||||
|
|
||||||
def decompile(self, data, otFont):
|
def decompile(self, data, otFont):
|
||||||
self.cff.decompile(StringIO(data), otFont)
|
self.cff.decompile(StringIO(data), otFont)
|
||||||
assert len(self.cff) == 1, "can't deal with multi-font CFF tables."
|
assert len(self.cff) == 1, "can't deal with multi-font CFF tables."
|
||||||
|
|
||||||
def compile(self, otFont):
|
def compile(self, otFont):
|
||||||
f = StringIO()
|
f = StringIO()
|
||||||
self.cff.compile(f, otFont)
|
self.cff.compile(f, otFont)
|
||||||
return f.getvalue()
|
return f.getvalue()
|
||||||
|
|
||||||
def haveGlyphNames(self):
|
def haveGlyphNames(self):
|
||||||
if hasattr(self.cff[self.cff.fontNames[0]], "ROS"):
|
if hasattr(self.cff[self.cff.fontNames[0]], "ROS"):
|
||||||
return False # CID-keyed font
|
return False # CID-keyed font
|
||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def getGlyphOrder(self):
|
def getGlyphOrder(self):
|
||||||
if self._gaveGlyphOrder:
|
if self._gaveGlyphOrder:
|
||||||
from fontTools import ttLib
|
from fontTools import ttLib
|
||||||
raise ttLib.TTLibError("illegal use of getGlyphOrder()")
|
raise ttLib.TTLibError("illegal use of getGlyphOrder()")
|
||||||
self._gaveGlyphOrder = True
|
self._gaveGlyphOrder = True
|
||||||
return self.cff[self.cff.fontNames[0]].getGlyphOrder()
|
return self.cff[self.cff.fontNames[0]].getGlyphOrder()
|
||||||
|
|
||||||
def setGlyphOrder(self, glyphOrder):
|
def setGlyphOrder(self, glyphOrder):
|
||||||
pass
|
pass
|
||||||
# XXX
|
# XXX
|
||||||
#self.cff[self.cff.fontNames[0]].setGlyphOrder(glyphOrder)
|
#self.cff[self.cff.fontNames[0]].setGlyphOrder(glyphOrder)
|
||||||
|
|
||||||
def toXML(self, writer, otFont, progress=None):
|
def toXML(self, writer, otFont, progress=None):
|
||||||
self.cff.toXML(writer, progress)
|
self.cff.toXML(writer, progress)
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, otFont):
|
def fromXML(self, name, attrs, content, otFont):
|
||||||
if not hasattr(self, "cff"):
|
if not hasattr(self, "cff"):
|
||||||
self.cff = cffLib.CFFFontSet()
|
self.cff = cffLib.CFFFontSet()
|
||||||
|
@ -123,7 +123,7 @@ class table_C_O_L_R_(DefaultTable.DefaultTable):
|
|||||||
|
|
||||||
if glyphSelector not in self.ColorLayers:
|
if glyphSelector not in self.ColorLayers:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return self.ColorLayers[glyphSelector]
|
return self.ColorLayers[glyphSelector]
|
||||||
|
|
||||||
def __setitem__(self, glyphSelector, value):
|
def __setitem__(self, glyphSelector, value):
|
||||||
|
@ -40,7 +40,7 @@ DSIG_SignatureBlockFormat = """
|
|||||||
#
|
#
|
||||||
|
|
||||||
class table_D_S_I_G_(DefaultTable.DefaultTable):
|
class table_D_S_I_G_(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
dummy, newData = sstruct.unpack2(DSIG_HeaderFormat, data, self)
|
dummy, newData = sstruct.unpack2(DSIG_HeaderFormat, data, self)
|
||||||
assert self.ulVersion == 1, "DSIG ulVersion must be 1"
|
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.usReserved1 == 0, "DSIG signature record #%d usReserverd1 must be 0" % n
|
||||||
assert sigrec.usReserved2 == 0, "DSIG signature record #%d usReserverd2 must be 0" % n
|
assert sigrec.usReserved2 == 0, "DSIG signature record #%d usReserverd2 must be 0" % n
|
||||||
sigrec.pkcs7 = newData[:sigrec.cbSignature]
|
sigrec.pkcs7 = newData[:sigrec.cbSignature]
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
packed = sstruct.pack(DSIG_HeaderFormat, self)
|
packed = sstruct.pack(DSIG_HeaderFormat, self)
|
||||||
headers = [packed]
|
headers = [packed]
|
||||||
@ -76,7 +76,7 @@ class table_D_S_I_G_(DefaultTable.DefaultTable):
|
|||||||
# Pad to even bytes
|
# Pad to even bytes
|
||||||
data.append(b'\0')
|
data.append(b'\0')
|
||||||
return bytesjoin(headers+data)
|
return bytesjoin(headers+data)
|
||||||
|
|
||||||
def toXML(self, xmlWriter, ttFont):
|
def toXML(self, xmlWriter, ttFont):
|
||||||
xmlWriter.comment("note that the Digital Signature will be invalid after recompilation!")
|
xmlWriter.comment("note that the Digital Signature will be invalid after recompilation!")
|
||||||
xmlWriter.newline()
|
xmlWriter.newline()
|
||||||
@ -85,7 +85,7 @@ class table_D_S_I_G_(DefaultTable.DefaultTable):
|
|||||||
xmlWriter.newline()
|
xmlWriter.newline()
|
||||||
sigrec.toXML(xmlWriter, ttFont)
|
sigrec.toXML(xmlWriter, ttFont)
|
||||||
xmlWriter.newline()
|
xmlWriter.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
if name == "tableHeader":
|
if name == "tableHeader":
|
||||||
self.signatureRecords = []
|
self.signatureRecords = []
|
||||||
@ -115,7 +115,7 @@ def b64encode(b):
|
|||||||
class SignatureRecord(object):
|
class SignatureRecord(object):
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<%s: %s>" % (self.__class__.__name__, self.__dict__)
|
return "<%s: %s>" % (self.__class__.__name__, self.__dict__)
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
writer.begintag(self.__class__.__name__, format=self.ulFormat)
|
writer.begintag(self.__class__.__name__, format=self.ulFormat)
|
||||||
writer.newline()
|
writer.newline()
|
||||||
@ -123,7 +123,7 @@ class SignatureRecord(object):
|
|||||||
writer.write_noindent(b64encode(self.pkcs7))
|
writer.write_noindent(b64encode(self.pkcs7))
|
||||||
writer.write_noindent("-----END PKCS7-----\n")
|
writer.write_noindent("-----END PKCS7-----\n")
|
||||||
writer.endtag(self.__class__.__name__)
|
writer.endtag(self.__class__.__name__)
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
self.ulFormat = safeEval(attrs["format"])
|
self.ulFormat = safeEval(attrs["format"])
|
||||||
self.usReserved1 = safeEval(attrs.get("reserved1", "0"))
|
self.usReserved1 = safeEval(attrs.get("reserved1", "0"))
|
||||||
|
@ -3,20 +3,20 @@ from fontTools.misc.py23 import *
|
|||||||
from fontTools.ttLib import getClassTag
|
from fontTools.ttLib import getClassTag
|
||||||
|
|
||||||
class DefaultTable(object):
|
class DefaultTable(object):
|
||||||
|
|
||||||
dependencies = []
|
dependencies = []
|
||||||
|
|
||||||
def __init__(self, tag=None):
|
def __init__(self, tag=None):
|
||||||
if tag is None:
|
if tag is None:
|
||||||
tag = getClassTag(self.__class__)
|
tag = getClassTag(self.__class__)
|
||||||
self.tableTag = Tag(tag)
|
self.tableTag = Tag(tag)
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
self.data = data
|
self.data = data
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
return self.data
|
return self.data
|
||||||
|
|
||||||
def toXML(self, writer, ttFont, progress=None):
|
def toXML(self, writer, ttFont, progress=None):
|
||||||
if hasattr(self, "ERROR"):
|
if hasattr(self, "ERROR"):
|
||||||
writer.comment("An error occurred during the decompilation of this table")
|
writer.comment("An error occurred during the decompilation of this table")
|
||||||
@ -28,17 +28,17 @@ class DefaultTable(object):
|
|||||||
writer.dumphex(self.compile(ttFont))
|
writer.dumphex(self.compile(ttFont))
|
||||||
writer.endtag("hexdata")
|
writer.endtag("hexdata")
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
from fontTools.misc.textTools import readHex
|
from fontTools.misc.textTools import readHex
|
||||||
from fontTools import ttLib
|
from fontTools import ttLib
|
||||||
if name != "hexdata":
|
if name != "hexdata":
|
||||||
raise ttLib.TTLibError("can't handle '%s' element" % name)
|
raise ttLib.TTLibError("can't handle '%s' element" % name)
|
||||||
self.decompile(readHex(content), ttFont)
|
self.decompile(readHex(content), ttFont)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<'%s' table at %x>" % (self.tableTag, id(self))
|
return "<'%s' table at %x>" % (self.tableTag, id(self))
|
||||||
|
|
||||||
def __ne__(self, other):
|
def __ne__(self, other):
|
||||||
return not self.__eq__(other)
|
return not self.__eq__(other)
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
|
@ -13,7 +13,7 @@ GMAPFormat = """
|
|||||||
recordsOffset: H
|
recordsOffset: H
|
||||||
fontNameLength: 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.
|
# to the beginning of the records array. The recordsOffsst is 32 bit aligned.
|
||||||
|
|
||||||
GMAPRecordFormat1 = """
|
GMAPRecordFormat1 = """
|
||||||
@ -71,9 +71,9 @@ class GMAPRecord(object):
|
|||||||
|
|
||||||
|
|
||||||
class table_G_M_A_P_(DefaultTable.DefaultTable):
|
class table_G_M_A_P_(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
dependencies = []
|
dependencies = []
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
dummy, newData = sstruct.unpack2(GMAPFormat, data, self)
|
dummy, newData = sstruct.unpack2(GMAPFormat, data, self)
|
||||||
self.psFontName = tostr(newData[:self.fontNameLength])
|
self.psFontName = tostr(newData[:self.fontNameLength])
|
||||||
@ -108,7 +108,7 @@ class table_G_M_A_P_(DefaultTable.DefaultTable):
|
|||||||
writer.newline()
|
writer.newline()
|
||||||
for gmapRecord in self.gmapRecords:
|
for gmapRecord in self.gmapRecords:
|
||||||
gmapRecord.toXML(writer, ttFont)
|
gmapRecord.toXML(writer, ttFont)
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
if name == "GMAPRecord":
|
if name == "GMAPRecord":
|
||||||
if not hasattr(self, "gmapRecords"):
|
if not hasattr(self, "gmapRecords"):
|
||||||
@ -124,5 +124,5 @@ class table_G_M_A_P_(DefaultTable.DefaultTable):
|
|||||||
value = attrs["value"]
|
value = attrs["value"]
|
||||||
if name == "PSFontName":
|
if name == "PSFontName":
|
||||||
self.psFontName = value
|
self.psFontName = value
|
||||||
else:
|
else:
|
||||||
setattr(self, name, safeEval(value))
|
setattr(self, name, safeEval(value))
|
||||||
|
@ -13,12 +13,12 @@ GPKGFormat = """
|
|||||||
numGMAPs: H
|
numGMAPs: H
|
||||||
numGlyplets: 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.
|
# to the beginning of the records array. The recordsOffsst is 32 bit aligned.
|
||||||
|
|
||||||
|
|
||||||
class table_G_P_K_G_(DefaultTable.DefaultTable):
|
class table_G_P_K_G_(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
dummy, newData = sstruct.unpack2(GPKGFormat, data, self)
|
dummy, newData = sstruct.unpack2(GPKGFormat, data, self)
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ class table_G_P_K_G_(DefaultTable.DefaultTable):
|
|||||||
dataList += self.glyphlets
|
dataList += self.glyphlets
|
||||||
data = bytesjoin(dataList)
|
data = bytesjoin(dataList)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
writer.comment("Most of this table will be recalculated by the compiler")
|
writer.comment("Most of this table will be recalculated by the compiler")
|
||||||
writer.newline()
|
writer.newline()
|
||||||
@ -125,5 +125,5 @@ class table_G_P_K_G_(DefaultTable.DefaultTable):
|
|||||||
itemName, itemAttrs, itemContent = element
|
itemName, itemAttrs, itemContent = element
|
||||||
if itemName == "hexdata":
|
if itemName == "hexdata":
|
||||||
self.glyphlets.append(readHex(itemContent))
|
self.glyphlets.append(readHex(itemContent))
|
||||||
else:
|
else:
|
||||||
setattr(self, name, safeEval(value))
|
setattr(self, name, safeEval(value))
|
||||||
|
@ -10,7 +10,7 @@ import array
|
|||||||
# XXX back to normal eventually.
|
# XXX back to normal eventually.
|
||||||
|
|
||||||
class table_L_T_S_H_(DefaultTable.DefaultTable):
|
class table_L_T_S_H_(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
version, numGlyphs = struct.unpack(">HH", data[:4])
|
version, numGlyphs = struct.unpack(">HH", data[:4])
|
||||||
data = data[4:]
|
data = data[4:]
|
||||||
@ -23,7 +23,7 @@ class table_L_T_S_H_(DefaultTable.DefaultTable):
|
|||||||
self.yPels = {}
|
self.yPels = {}
|
||||||
for i in range(numGlyphs):
|
for i in range(numGlyphs):
|
||||||
self.yPels[ttFont.getGlyphName(i)] = yPels[i]
|
self.yPels[ttFont.getGlyphName(i)] = yPels[i]
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
version = 0
|
version = 0
|
||||||
names = list(self.yPels.keys())
|
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[ttFont.getGlyphID(name)] = self.yPels[name]
|
||||||
yPels = array.array("B", yPels)
|
yPels = array.array("B", yPels)
|
||||||
return struct.pack(">HH", version, numGlyphs) + yPels.tostring()
|
return struct.pack(">HH", version, numGlyphs) + yPels.tostring()
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
names = sorted(self.yPels.keys())
|
names = sorted(self.yPels.keys())
|
||||||
for name in names:
|
for name in names:
|
||||||
writer.simpletag("yPel", name=name, value=self.yPels[name])
|
writer.simpletag("yPel", name=name, value=self.yPels[name])
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
if not hasattr(self, "yPels"):
|
if not hasattr(self, "yPels"):
|
||||||
self.yPels = {}
|
self.yPels = {}
|
||||||
|
@ -26,19 +26,19 @@ METAGlyphRecordFormat = """
|
|||||||
nMetaEntry: H
|
nMetaEntry: H
|
||||||
"""
|
"""
|
||||||
# This record is followd by a variable data length field:
|
# 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
|
# Offset from start of META table to the beginning
|
||||||
# of this glyphs array of ns Metadata string entries.
|
# 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
|
# METAGlyphRecordFormat entries must be sorted by glyph ID
|
||||||
|
|
||||||
METAStringRecordFormat = """
|
METAStringRecordFormat = """
|
||||||
> # big endian
|
> # big endian
|
||||||
labelID: H
|
labelID: H
|
||||||
stringLen: H
|
stringLen: H
|
||||||
"""
|
"""
|
||||||
# This record is followd by a variable data length field:
|
# 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
|
# 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 entry with the same labelID
|
||||||
# There may be more than one strign with the same content.
|
# 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):
|
class table_M_E_T_A_(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
dependencies = []
|
dependencies = []
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
dummy, newData = sstruct.unpack2(METAHeaderFormat, data, self)
|
dummy, newData = sstruct.unpack2(METAHeaderFormat, data, self)
|
||||||
self.glyphRecords = []
|
self.glyphRecords = []
|
||||||
@ -97,8 +97,8 @@ class table_M_E_T_A_(DefaultTable.DefaultTable):
|
|||||||
newData = newData[4:]
|
newData = newData[4:]
|
||||||
stringRec.string = data[stringRec.offset:stringRec.offset + stringRec.stringLen]
|
stringRec.string = data[stringRec.offset:stringRec.offset + stringRec.stringLen]
|
||||||
glyphRecord.stringRecs.append(stringRec)
|
glyphRecord.stringRecs.append(stringRec)
|
||||||
self.glyphRecords.append(glyphRecord)
|
self.glyphRecords.append(glyphRecord)
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
offsetOK = 0
|
offsetOK = 0
|
||||||
self.nMetaRecs = len(self.glyphRecords)
|
self.nMetaRecs = len(self.glyphRecords)
|
||||||
@ -117,12 +117,12 @@ class table_M_E_T_A_(DefaultTable.DefaultTable):
|
|||||||
offsetOK = -1
|
offsetOK = -1
|
||||||
break
|
break
|
||||||
metaData = metaData + glyphRec.compile(self)
|
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.
|
# this will be the String Record offset for the next GlyphRecord.
|
||||||
if offsetOK == -1:
|
if offsetOK == -1:
|
||||||
offsetOK = 0
|
offsetOK = 0
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# metaData now contains the header and all of the GlyphRecords. Its length should bw
|
# metaData now contains the header and all of the GlyphRecords. Its length should bw
|
||||||
# the offset to the first StringRecord.
|
# the offset to the first StringRecord.
|
||||||
stringOffset = stringRecsOffset
|
stringOffset = stringRecsOffset
|
||||||
@ -139,7 +139,7 @@ class table_M_E_T_A_(DefaultTable.DefaultTable):
|
|||||||
if offsetOK == -1:
|
if offsetOK == -1:
|
||||||
offsetOK = 0
|
offsetOK = 0
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if ((self.metaFlags & 1) == 1) and (stringOffset < 65536):
|
if ((self.metaFlags & 1) == 1) and (stringOffset < 65536):
|
||||||
self.metaFlags = self.metaFlags - 1
|
self.metaFlags = self.metaFlags - 1
|
||||||
continue
|
continue
|
||||||
@ -152,9 +152,9 @@ class table_M_E_T_A_(DefaultTable.DefaultTable):
|
|||||||
for stringRec in glyphRec.stringRecs:
|
for stringRec in glyphRec.stringRecs:
|
||||||
assert (stringRec.offset == len(metaData)), "String offset did not compile correctly! for string:" + str(stringRec.string)
|
assert (stringRec.offset == len(metaData)), "String offset did not compile correctly! for string:" + str(stringRec.string)
|
||||||
metaData = metaData + stringRec.string
|
metaData = metaData + stringRec.string
|
||||||
|
|
||||||
return metaData
|
return metaData
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
writer.comment("Lengths and number of entries in this table will be recalculated by the compiler")
|
writer.comment("Lengths and number of entries in this table will be recalculated by the compiler")
|
||||||
writer.newline()
|
writer.newline()
|
||||||
@ -165,7 +165,7 @@ class table_M_E_T_A_(DefaultTable.DefaultTable):
|
|||||||
writer.newline()
|
writer.newline()
|
||||||
for glyphRec in self.glyphRecords:
|
for glyphRec in self.glyphRecords:
|
||||||
glyphRec.toXML(writer, ttFont)
|
glyphRec.toXML(writer, ttFont)
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
if name == "GlyphRecord":
|
if name == "GlyphRecord":
|
||||||
if not hasattr(self, "glyphRecords"):
|
if not hasattr(self, "glyphRecords"):
|
||||||
@ -179,7 +179,7 @@ class table_M_E_T_A_(DefaultTable.DefaultTable):
|
|||||||
glyphRec.fromXML(name, attrs, content, ttFont)
|
glyphRec.fromXML(name, attrs, content, ttFont)
|
||||||
glyphRec.offset = -1
|
glyphRec.offset = -1
|
||||||
glyphRec.nMetaEntry = len(glyphRec.stringRecs)
|
glyphRec.nMetaEntry = len(glyphRec.stringRecs)
|
||||||
else:
|
else:
|
||||||
setattr(self, name, safeEval(attrs["value"]))
|
setattr(self, name, safeEval(attrs["value"]))
|
||||||
|
|
||||||
|
|
||||||
@ -189,7 +189,7 @@ class GlyphRecord(object):
|
|||||||
self.nMetaEntry = -1
|
self.nMetaEntry = -1
|
||||||
self.offset = -1
|
self.offset = -1
|
||||||
self.stringRecs = []
|
self.stringRecs = []
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
writer.begintag("GlyphRecord")
|
writer.begintag("GlyphRecord")
|
||||||
writer.newline()
|
writer.newline()
|
||||||
@ -211,7 +211,7 @@ class GlyphRecord(object):
|
|||||||
continue
|
continue
|
||||||
stringRec.fromXML(name, attrs, content, ttFont)
|
stringRec.fromXML(name, attrs, content, ttFont)
|
||||||
stringRec.stringLen = len(stringRec.string)
|
stringRec.stringLen = len(stringRec.string)
|
||||||
else:
|
else:
|
||||||
setattr(self, name, safeEval(attrs["value"]))
|
setattr(self, name, safeEval(attrs["value"]))
|
||||||
|
|
||||||
def compile(self, parentTable):
|
def compile(self, parentTable):
|
||||||
@ -222,7 +222,7 @@ class GlyphRecord(object):
|
|||||||
datum = struct.pack(">L", self.offset)
|
datum = struct.pack(">L", self.offset)
|
||||||
data = data + datum
|
data = data + datum
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "GlyphRecord[ glyphID: " + str(self.glyphID) + ", nMetaEntry: " + str(self.nMetaEntry) + ", offset: " + str(self.offset) + " ]"
|
return "GlyphRecord[ glyphID: " + str(self.glyphID) + ", nMetaEntry: " + str(self.nMetaEntry) + ", offset: " + str(self.offset) + " ]"
|
||||||
|
|
||||||
@ -244,12 +244,12 @@ def mapXMLToUTF8(string):
|
|||||||
while string[i] != ";":
|
while string[i] != ";":
|
||||||
i = i+1
|
i = i+1
|
||||||
valStr = string[j:i]
|
valStr = string[j:i]
|
||||||
|
|
||||||
uString = uString + unichr(eval('0x' + valStr))
|
uString = uString + unichr(eval('0x' + valStr))
|
||||||
else:
|
else:
|
||||||
uString = uString + unichr(byteord(string[i]))
|
uString = uString + unichr(byteord(string[i]))
|
||||||
i = i +1
|
i = i +1
|
||||||
|
|
||||||
return uString.encode('utf_8')
|
return uString.encode('utf_8')
|
||||||
|
|
||||||
|
|
||||||
@ -298,7 +298,7 @@ class StringRecord(object):
|
|||||||
datum = struct.pack(">L", self.offset)
|
datum = struct.pack(">L", self.offset)
|
||||||
data = data + datum
|
data = data + datum
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "StringRecord [ labelID: " + str(self.labelID) + " aka " + getLabelString(self.labelID) \
|
return "StringRecord [ labelID: " + str(self.labelID) + " aka " + getLabelString(self.labelID) \
|
||||||
+ ", offset: " + str(self.offset) + ", length: " + str(self.stringLen) + ", string: " +self.string + " ]"
|
+ ", offset: " + str(self.offset) + ", length: " + str(self.stringLen) + ", string: " +self.string + " ]"
|
||||||
|
@ -22,13 +22,13 @@ panoseFormat = """
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
class Panose(object):
|
class Panose(object):
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
formatstring, names, fixes = sstruct.getformat(panoseFormat)
|
formatstring, names, fixes = sstruct.getformat(panoseFormat)
|
||||||
for name in names:
|
for name in names:
|
||||||
writer.simpletag(name, value=getattr(self, name))
|
writer.simpletag(name, value=getattr(self, name))
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
setattr(self, name, safeEval(attrs["value"]))
|
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):
|
class table_O_S_2f_2(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
"""the OS/2 table"""
|
"""the OS/2 table"""
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
dummy, data = sstruct.unpack2(OS2_format_0, data, self)
|
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")
|
warnings.warn("too much 'OS/2' table data")
|
||||||
|
|
||||||
self.panose = sstruct.unpack(panoseFormat, self.panose, Panose())
|
self.panose = sstruct.unpack(panoseFormat, self.panose, Panose())
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
panose = self.panose
|
panose = self.panose
|
||||||
self.panose = sstruct.pack(panoseFormat, 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)
|
raise ttLib.TTLibError("unknown format for OS/2 table: version %s" % self.version)
|
||||||
self.panose = panose
|
self.panose = panose
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
if self.version == 1:
|
if self.version == 1:
|
||||||
format = OS2_format_1
|
format = OS2_format_1
|
||||||
@ -157,7 +157,7 @@ class table_O_S_2f_2(DefaultTable.DefaultTable):
|
|||||||
writer.newline()
|
writer.newline()
|
||||||
value.toXML(writer, ttFont)
|
value.toXML(writer, ttFont)
|
||||||
writer.endtag("panose")
|
writer.endtag("panose")
|
||||||
elif name in ("ulUnicodeRange1", "ulUnicodeRange2",
|
elif name in ("ulUnicodeRange1", "ulUnicodeRange2",
|
||||||
"ulUnicodeRange3", "ulUnicodeRange4",
|
"ulUnicodeRange3", "ulUnicodeRange4",
|
||||||
"ulCodePageRange1", "ulCodePageRange2"):
|
"ulCodePageRange1", "ulCodePageRange2"):
|
||||||
writer.simpletag(name, value=num2binary(value))
|
writer.simpletag(name, value=num2binary(value))
|
||||||
@ -168,7 +168,7 @@ class table_O_S_2f_2(DefaultTable.DefaultTable):
|
|||||||
else:
|
else:
|
||||||
writer.simpletag(name, value=value)
|
writer.simpletag(name, value=value)
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
if name == "panose":
|
if name == "panose":
|
||||||
self.panose = panose = Panose()
|
self.panose = panose = Panose()
|
||||||
@ -176,7 +176,7 @@ class table_O_S_2f_2(DefaultTable.DefaultTable):
|
|||||||
if isinstance(element, tuple):
|
if isinstance(element, tuple):
|
||||||
name, attrs, content = element
|
name, attrs, content = element
|
||||||
panose.fromXML(name, attrs, content, ttFont)
|
panose.fromXML(name, attrs, content, ttFont)
|
||||||
elif name in ("ulUnicodeRange1", "ulUnicodeRange2",
|
elif name in ("ulUnicodeRange1", "ulUnicodeRange2",
|
||||||
"ulUnicodeRange3", "ulUnicodeRange4",
|
"ulUnicodeRange3", "ulUnicodeRange4",
|
||||||
"ulCodePageRange1", "ulCodePageRange2",
|
"ulCodePageRange1", "ulCodePageRange2",
|
||||||
"fsType", "fsSelection"):
|
"fsType", "fsSelection"):
|
||||||
|
@ -22,22 +22,22 @@ SINGFormat = """
|
|||||||
|
|
||||||
|
|
||||||
class table_S_I_N_G_(DefaultTable.DefaultTable):
|
class table_S_I_N_G_(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
dependencies = []
|
dependencies = []
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
dummy, rest = sstruct.unpack2(SINGFormat, data, self)
|
dummy, rest = sstruct.unpack2(SINGFormat, data, self)
|
||||||
self.uniqueName = self.decompileUniqueName(self.uniqueName)
|
self.uniqueName = self.decompileUniqueName(self.uniqueName)
|
||||||
self.nameLength = byteord(self.nameLength)
|
self.nameLength = byteord(self.nameLength)
|
||||||
assert len(rest) == self.nameLength
|
assert len(rest) == self.nameLength
|
||||||
self.baseGlyphName = tostr(rest)
|
self.baseGlyphName = tostr(rest)
|
||||||
|
|
||||||
rawMETAMD5 = self.METAMD5
|
rawMETAMD5 = self.METAMD5
|
||||||
self.METAMD5 = "[" + hex(byteord(self.METAMD5[0]))
|
self.METAMD5 = "[" + hex(byteord(self.METAMD5[0]))
|
||||||
for char in rawMETAMD5[1:]:
|
for char in rawMETAMD5[1:]:
|
||||||
self.METAMD5 = self.METAMD5 + ", " + hex(byteord(char))
|
self.METAMD5 = self.METAMD5 + ", " + hex(byteord(char))
|
||||||
self.METAMD5 = self.METAMD5 + "]"
|
self.METAMD5 = self.METAMD5 + "]"
|
||||||
|
|
||||||
def decompileUniqueName(self, data):
|
def decompileUniqueName(self, data):
|
||||||
name = ""
|
name = ""
|
||||||
for char in data:
|
for char in data:
|
||||||
@ -67,7 +67,7 @@ class table_S_I_N_G_(DefaultTable.DefaultTable):
|
|||||||
data = sstruct.pack(SINGFormat, d)
|
data = sstruct.pack(SINGFormat, d)
|
||||||
data = data + tobytes(self.baseGlyphName)
|
data = data + tobytes(self.baseGlyphName)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def compilecompileUniqueName(self, name, length):
|
def compilecompileUniqueName(self, name, length):
|
||||||
nameLen = len(name)
|
nameLen = len(name)
|
||||||
if length <= nameLen:
|
if length <= nameLen:
|
||||||
@ -86,7 +86,7 @@ class table_S_I_N_G_(DefaultTable.DefaultTable):
|
|||||||
writer.newline()
|
writer.newline()
|
||||||
writer.simpletag("baseGlyphName", value=self.baseGlyphName)
|
writer.simpletag("baseGlyphName", value=self.baseGlyphName)
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
value = attrs["value"]
|
value = attrs["value"]
|
||||||
if name in ["uniqueName", "METAMD5", "baseGlyphName"]:
|
if name in ["uniqueName", "METAMD5", "baseGlyphName"]:
|
||||||
|
@ -46,7 +46,7 @@ The XML format is:
|
|||||||
</colorPalettes>
|
</colorPalettes>
|
||||||
</SVG>
|
</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 color records in each </colorPalette> must be the same as
|
||||||
the number of <colorParamUINameID> elements.
|
the number of <colorParamUINameID> elements.
|
||||||
@ -93,13 +93,13 @@ colorRecord_format_0 = """
|
|||||||
|
|
||||||
|
|
||||||
class table_S_V_G_(DefaultTable.DefaultTable):
|
class table_S_V_G_(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
self.docList = None
|
self.docList = None
|
||||||
self.colorPalettes = None
|
self.colorPalettes = None
|
||||||
pos = 0
|
pos = 0
|
||||||
self.version = struct.unpack(">H", data[pos:pos+2])[0]
|
self.version = struct.unpack(">H", data[pos:pos+2])[0]
|
||||||
|
|
||||||
if self.version == 1:
|
if self.version == 1:
|
||||||
self.decompile_format_1(data, ttFont)
|
self.decompile_format_1(data, ttFont)
|
||||||
else:
|
else:
|
||||||
@ -355,7 +355,7 @@ class ColorPalettes(object):
|
|||||||
|
|
||||||
class ColorPalette(object):
|
class ColorPalette(object):
|
||||||
def __init__(self):
|
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
|
self.paletteColors = [] # list of ColorRecords
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
|
@ -6,13 +6,13 @@ import struct
|
|||||||
tsi0Format = '>HHl'
|
tsi0Format = '>HHl'
|
||||||
|
|
||||||
def fixlongs(glyphID, textLength, textOffset):
|
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):
|
class table_T_S_I__0(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
dependencies = ["TSI1"]
|
dependencies = ["TSI1"]
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
numGlyphs = ttFont['maxp'].numGlyphs
|
numGlyphs = ttFont['maxp'].numGlyphs
|
||||||
indices = []
|
indices = []
|
||||||
@ -25,7 +25,7 @@ class table_T_S_I__0(DefaultTable.DefaultTable):
|
|||||||
assert indices[-5] == (0XFFFE, 0, -1409540300), "bad magic number" # 0xABFC1F34
|
assert indices[-5] == (0XFFFE, 0, -1409540300), "bad magic number" # 0xABFC1F34
|
||||||
self.indices = indices[:-5]
|
self.indices = indices[:-5]
|
||||||
self.extra_indices = indices[-4:]
|
self.extra_indices = indices[-4:]
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
if not hasattr(self, "indices"):
|
if not hasattr(self, "indices"):
|
||||||
# We have no corresponding table (TSI1 or TSI3); let's return
|
# 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:
|
for index, textLength, textOffset in self.extra_indices:
|
||||||
data = data + struct.pack(tsi0Format, index, textLength, textOffset)
|
data = data + struct.pack(tsi0Format, index, textLength, textOffset)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def set(self, indices, extra_indices):
|
def set(self, indices, extra_indices):
|
||||||
# gets called by 'TSI1' or 'TSI3'
|
# gets called by 'TSI1' or 'TSI3'
|
||||||
self.indices = indices
|
self.indices = indices
|
||||||
self.extra_indices = extra_indices
|
self.extra_indices = extra_indices
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
writer.comment("This table will be calculated by the compiler")
|
writer.comment("This table will be calculated by the compiler")
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
@ -3,11 +3,11 @@ from fontTools.misc.py23 import *
|
|||||||
from . import DefaultTable
|
from . import DefaultTable
|
||||||
|
|
||||||
class table_T_S_I__1(DefaultTable.DefaultTable):
|
class table_T_S_I__1(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
extras = {0xfffa: "ppgm", 0xfffb: "cvt", 0xfffc: "reserved", 0xfffd: "fpgm"}
|
extras = {0xfffa: "ppgm", 0xfffb: "cvt", 0xfffc: "reserved", 0xfffd: "fpgm"}
|
||||||
|
|
||||||
indextable = "TSI0"
|
indextable = "TSI0"
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
indextable = ttFont[self.indextable]
|
indextable = ttFont[self.indextable]
|
||||||
self.glyphPrograms = {}
|
self.glyphPrograms = {}
|
||||||
@ -22,7 +22,7 @@ class table_T_S_I__1(DefaultTable.DefaultTable):
|
|||||||
assert len(text) == textLength
|
assert len(text) == textLength
|
||||||
if text:
|
if text:
|
||||||
self.glyphPrograms[ttFont.getGlyphName(glyphID)] = text
|
self.glyphPrograms[ttFont.getGlyphName(glyphID)] = text
|
||||||
|
|
||||||
self.extraPrograms = {}
|
self.extraPrograms = {}
|
||||||
for i in range(len(indextable.extra_indices)):
|
for i in range(len(indextable.extra_indices)):
|
||||||
extraCode, textLength, textOffset = indextable.extra_indices[i]
|
extraCode, textLength, textOffset = indextable.extra_indices[i]
|
||||||
@ -35,7 +35,7 @@ class table_T_S_I__1(DefaultTable.DefaultTable):
|
|||||||
assert len(text) == textLength
|
assert len(text) == textLength
|
||||||
if text:
|
if text:
|
||||||
self.extraPrograms[self.extras[extraCode]] = text
|
self.extraPrograms[self.extras[extraCode]] = text
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
if not hasattr(self, "glyphPrograms"):
|
if not hasattr(self, "glyphPrograms"):
|
||||||
self.glyphPrograms = {}
|
self.glyphPrograms = {}
|
||||||
@ -43,7 +43,7 @@ class table_T_S_I__1(DefaultTable.DefaultTable):
|
|||||||
data = b''
|
data = b''
|
||||||
indextable = ttFont[self.indextable]
|
indextable = ttFont[self.indextable]
|
||||||
glyphNames = ttFont.getGlyphOrder()
|
glyphNames = ttFont.getGlyphOrder()
|
||||||
|
|
||||||
indices = []
|
indices = []
|
||||||
for i in range(len(glyphNames)):
|
for i in range(len(glyphNames)):
|
||||||
if len(data) % 2:
|
if len(data) % 2:
|
||||||
@ -58,7 +58,7 @@ class table_T_S_I__1(DefaultTable.DefaultTable):
|
|||||||
textLength = 0x8000 # XXX ???
|
textLength = 0x8000 # XXX ???
|
||||||
indices.append((i, textLength, len(data)))
|
indices.append((i, textLength, len(data)))
|
||||||
data = data + text
|
data = data + text
|
||||||
|
|
||||||
extra_indices = []
|
extra_indices = []
|
||||||
codes = sorted(self.extras.items())
|
codes = sorted(self.extras.items())
|
||||||
for i in range(len(codes)):
|
for i in range(len(codes)):
|
||||||
@ -76,7 +76,7 @@ class table_T_S_I__1(DefaultTable.DefaultTable):
|
|||||||
data = data + text
|
data = data + text
|
||||||
indextable.set(indices, extra_indices)
|
indextable.set(indices, extra_indices)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
names = sorted(self.glyphPrograms.keys())
|
names = sorted(self.glyphPrograms.keys())
|
||||||
writer.newline()
|
writer.newline()
|
||||||
@ -103,7 +103,7 @@ class table_T_S_I__1(DefaultTable.DefaultTable):
|
|||||||
writer.endtag("extraProgram")
|
writer.endtag("extraProgram")
|
||||||
writer.newline()
|
writer.newline()
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
if not hasattr(self, "glyphPrograms"):
|
if not hasattr(self, "glyphPrograms"):
|
||||||
self.glyphPrograms = {}
|
self.glyphPrograms = {}
|
||||||
|
@ -5,5 +5,5 @@ from fontTools import ttLib
|
|||||||
superclass = ttLib.getTableClass("TSI0")
|
superclass = ttLib.getTableClass("TSI0")
|
||||||
|
|
||||||
class table_T_S_I__2(superclass):
|
class table_T_S_I__2(superclass):
|
||||||
|
|
||||||
dependencies = ["TSI3"]
|
dependencies = ["TSI3"]
|
||||||
|
@ -5,7 +5,7 @@ from fontTools import ttLib
|
|||||||
superclass = ttLib.getTableClass("TSI1")
|
superclass = ttLib.getTableClass("TSI1")
|
||||||
|
|
||||||
class table_T_S_I__3(superclass):
|
class table_T_S_I__3(superclass):
|
||||||
|
|
||||||
extras = {0xfffa: "reserved0", 0xfffb: "reserved1", 0xfffc: "reserved2", 0xfffd: "reserved3"}
|
extras = {0xfffa: "reserved0", 0xfffb: "reserved1", 0xfffc: "reserved2", 0xfffd: "reserved3"}
|
||||||
|
|
||||||
indextable = "TSI2"
|
indextable = "TSI2"
|
||||||
|
@ -7,7 +7,7 @@ import array
|
|||||||
|
|
||||||
|
|
||||||
class table_T_S_I__5(DefaultTable.DefaultTable):
|
class table_T_S_I__5(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
numGlyphs = ttFont['maxp'].numGlyphs
|
numGlyphs = ttFont['maxp'].numGlyphs
|
||||||
assert len(data) == 2 * numGlyphs
|
assert len(data) == 2 * numGlyphs
|
||||||
@ -18,7 +18,7 @@ class table_T_S_I__5(DefaultTable.DefaultTable):
|
|||||||
self.glyphGrouping = {}
|
self.glyphGrouping = {}
|
||||||
for i in range(numGlyphs):
|
for i in range(numGlyphs):
|
||||||
self.glyphGrouping[ttFont.getGlyphName(i)] = a[i]
|
self.glyphGrouping[ttFont.getGlyphName(i)] = a[i]
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
glyphNames = ttFont.getGlyphOrder()
|
glyphNames = ttFont.getGlyphOrder()
|
||||||
a = array.array("H")
|
a = array.array("H")
|
||||||
@ -27,13 +27,13 @@ class table_T_S_I__5(DefaultTable.DefaultTable):
|
|||||||
if sys.byteorder != "big":
|
if sys.byteorder != "big":
|
||||||
a.byteswap()
|
a.byteswap()
|
||||||
return a.tostring()
|
return a.tostring()
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
names = sorted(self.glyphGrouping.keys())
|
names = sorted(self.glyphGrouping.keys())
|
||||||
for glyphName in names:
|
for glyphName in names:
|
||||||
writer.simpletag("glyphgroup", name=glyphName, value=self.glyphGrouping[glyphName])
|
writer.simpletag("glyphgroup", name=glyphName, value=self.glyphGrouping[glyphName])
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
if not hasattr(self, "glyphGrouping"):
|
if not hasattr(self, "glyphGrouping"):
|
||||||
self.glyphGrouping = {}
|
self.glyphGrouping = {}
|
||||||
|
@ -20,7 +20,7 @@ VDMX_RatRangeFmt = """
|
|||||||
yStartRatio: B # Starting y-Ratio value
|
yStartRatio: B # Starting y-Ratio value
|
||||||
yEndRatio: B # Ending 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);
|
# VDMX Group for this ratio range (offsets will be re-calculated on compile);
|
||||||
# followed by an array of Group[numRecs] records;
|
# followed by an array of Group[numRecs] records;
|
||||||
VDMX_GroupFmt = """
|
VDMX_GroupFmt = """
|
||||||
|
@ -41,7 +41,7 @@ class table_V_O_R_G_(DefaultTable.DefaultTable):
|
|||||||
vorgs = list(self.VOriginRecords.values())
|
vorgs = list(self.VOriginRecords.values())
|
||||||
names = list(self.VOriginRecords.keys())
|
names = list(self.VOriginRecords.keys())
|
||||||
nameMap = ttFont.getReverseGlyphMap()
|
nameMap = ttFont.getReverseGlyphMap()
|
||||||
lenRecords = len(vorgs)
|
lenRecords = len(vorgs)
|
||||||
try:
|
try:
|
||||||
gids = map(operator.getitem, [nameMap]*lenRecords, names)
|
gids = map(operator.getitem, [nameMap]*lenRecords, names)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -100,7 +100,7 @@ class table_V_O_R_G_(DefaultTable.DefaultTable):
|
|||||||
|
|
||||||
if glyphSelector not in self.VOriginRecords:
|
if glyphSelector not in self.VOriginRecords:
|
||||||
return self.defaultVertOriginY
|
return self.defaultVertOriginY
|
||||||
|
|
||||||
return self.VOriginRecords[glyphSelector]
|
return self.VOriginRecords[glyphSelector]
|
||||||
|
|
||||||
def __setitem__(self, glyphSelector, value):
|
def __setitem__(self, glyphSelector, value):
|
||||||
|
@ -12,14 +12,14 @@ import operator
|
|||||||
|
|
||||||
|
|
||||||
class table__c_m_a_p(DefaultTable.DefaultTable):
|
class table__c_m_a_p(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
def getcmap(self, platformID, platEncID):
|
def getcmap(self, platformID, platEncID):
|
||||||
for subtable in self.tables:
|
for subtable in self.tables:
|
||||||
if (subtable.platformID == platformID and
|
if (subtable.platformID == platformID and
|
||||||
subtable.platEncID == platEncID):
|
subtable.platEncID == platEncID):
|
||||||
return subtable
|
return subtable
|
||||||
return None # not found
|
return None # not found
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
tableVersion, numSubTables = struct.unpack(">HH", data[:4])
|
tableVersion, numSubTables = struct.unpack(">HH", data[:4])
|
||||||
self.tableVersion = int(tableVersion)
|
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])
|
format, reserved, length = struct.unpack(">HHL", data[offset:offset+8])
|
||||||
elif format in [14]:
|
elif format in [14]:
|
||||||
format, length = struct.unpack(">HL", data[offset:offset+6])
|
format, length = struct.unpack(">HL", data[offset:offset+6])
|
||||||
|
|
||||||
if not length:
|
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))
|
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
|
continue
|
||||||
@ -53,7 +53,7 @@ class table__c_m_a_p(DefaultTable.DefaultTable):
|
|||||||
else:
|
else:
|
||||||
seenOffsets[offset] = i
|
seenOffsets[offset] = i
|
||||||
tables.append(table)
|
tables.append(table)
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
self.tables.sort() # sort according to the spec; see CmapSubtable.__lt__()
|
self.tables.sort() # sort according to the spec; see CmapSubtable.__lt__()
|
||||||
numSubTables = len(self.tables)
|
numSubTables = len(self.tables)
|
||||||
@ -74,13 +74,13 @@ class table__c_m_a_p(DefaultTable.DefaultTable):
|
|||||||
tableData = tableData + chunk
|
tableData = tableData + chunk
|
||||||
data = data + struct.pack(">HHl", table.platformID, table.platEncID, offset)
|
data = data + struct.pack(">HHl", table.platformID, table.platEncID, offset)
|
||||||
return data + tableData
|
return data + tableData
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
writer.simpletag("tableVersion", version=self.tableVersion)
|
writer.simpletag("tableVersion", version=self.tableVersion)
|
||||||
writer.newline()
|
writer.newline()
|
||||||
for table in self.tables:
|
for table in self.tables:
|
||||||
table.toXML(writer, ttFont)
|
table.toXML(writer, ttFont)
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
if name == "tableVersion":
|
if name == "tableVersion":
|
||||||
self.tableVersion = safeEval(attrs["version"])
|
self.tableVersion = safeEval(attrs["version"])
|
||||||
@ -101,7 +101,7 @@ class table__c_m_a_p(DefaultTable.DefaultTable):
|
|||||||
|
|
||||||
|
|
||||||
class CmapSubtable(object):
|
class CmapSubtable(object):
|
||||||
|
|
||||||
def __init__(self, format):
|
def __init__(self, format):
|
||||||
self.format = format
|
self.format = format
|
||||||
self.data = None
|
self.data = None
|
||||||
@ -118,7 +118,7 @@ class CmapSubtable(object):
|
|||||||
# just return the original data. Also avoids recursion when
|
# just return the original data. Also avoids recursion when
|
||||||
# called with an attribute that the cmap subtable doesn't have.
|
# called with an attribute that the cmap subtable doesn't have.
|
||||||
return getattr(self, attr)
|
return getattr(self, attr)
|
||||||
|
|
||||||
def decompileHeader(self, data, ttFont):
|
def decompileHeader(self, data, ttFont):
|
||||||
format, length, language = struct.unpack(">HHH", data[:6])
|
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)
|
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:
|
if isUnicode:
|
||||||
writer.comment(Unicode[code])
|
writer.comment(Unicode[code])
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def __lt__(self, other):
|
def __lt__(self, other):
|
||||||
if not isinstance(other, CmapSubtable):
|
if not isinstance(other, CmapSubtable):
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
@ -186,7 +186,7 @@ class CmapSubtable(object):
|
|||||||
|
|
||||||
|
|
||||||
class cmap_format_0(CmapSubtable):
|
class cmap_format_0(CmapSubtable):
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
# we usually get here indirectly from the subtable __getattr__ function, in which case both args must be None.
|
# 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.
|
# 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()
|
data = struct.pack(">HHH", 0, 262, self.language) + glyphIdArray.tostring()
|
||||||
assert len(data) == 262
|
assert len(data) == 262
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
self.language = safeEval(attrs["language"])
|
self.language = safeEval(attrs["language"])
|
||||||
if not hasattr(self, "cmap"):
|
if not hasattr(self, "cmap"):
|
||||||
@ -241,9 +241,9 @@ class SubHeader(object):
|
|||||||
self.idDelta = None
|
self.idDelta = None
|
||||||
self.idRangeOffset = None
|
self.idRangeOffset = None
|
||||||
self.glyphIndexArray = []
|
self.glyphIndexArray = []
|
||||||
|
|
||||||
class cmap_format_2(CmapSubtable):
|
class cmap_format_2(CmapSubtable):
|
||||||
|
|
||||||
def setIDDelta(self, subHeader):
|
def setIDDelta(self, subHeader):
|
||||||
subHeader.idDelta = 0
|
subHeader.idDelta = 0
|
||||||
# find the minGI which is not zero.
|
# find the minGI which is not zero.
|
||||||
@ -253,13 +253,13 @@ class cmap_format_2(CmapSubtable):
|
|||||||
minGI = gid
|
minGI = gid
|
||||||
# The lowest gid in glyphIndexArray, after subtracting idDelta, must be 1.
|
# 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.
|
# 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.
|
# 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
|
# This means that we have a problem when minGI is > 32K
|
||||||
# Since the final gi is reconstructed from the glyphArray GID by:
|
# Since the final gi is reconstructed from the glyphArray GID by:
|
||||||
# (short)finalGID = (gid + idDelta) % 0x10000),
|
# (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
|
# 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 > 1):
|
||||||
if minGI > 0x7FFF:
|
if minGI > 0x7FFF:
|
||||||
@ -269,8 +269,8 @@ class cmap_format_2(CmapSubtable):
|
|||||||
idDelta = subHeader.idDelta
|
idDelta = subHeader.idDelta
|
||||||
for i in range(subHeader.entryCount):
|
for i in range(subHeader.entryCount):
|
||||||
gid = subHeader.glyphIndexArray[i]
|
gid = subHeader.glyphIndexArray[i]
|
||||||
if gid > 0:
|
if gid > 0:
|
||||||
subHeader.glyphIndexArray[i] = gid - idDelta
|
subHeader.glyphIndexArray[i] = gid - idDelta
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
# we usually get here indirectly from the subtable __getattr__ function, in which case both args must be None.
|
# 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()
|
allKeys.byteswap()
|
||||||
subHeaderKeys = [ key//8 for key in allKeys]
|
subHeaderKeys = [ key//8 for key in allKeys]
|
||||||
maxSubHeaderindex = max(subHeaderKeys)
|
maxSubHeaderindex = max(subHeaderKeys)
|
||||||
|
|
||||||
#Load subHeaders
|
#Load subHeaders
|
||||||
subHeaderList = []
|
subHeaderList = []
|
||||||
pos = 0
|
pos = 0
|
||||||
@ -307,14 +307,14 @@ class cmap_format_2(CmapSubtable):
|
|||||||
giList.byteswap()
|
giList.byteswap()
|
||||||
subHeader.glyphIndexArray = giList
|
subHeader.glyphIndexArray = giList
|
||||||
subHeaderList.append(subHeader)
|
subHeaderList.append(subHeader)
|
||||||
# How this gets processed.
|
# How this gets processed.
|
||||||
# Charcodes may be one or two bytes.
|
# Charcodes may be one or two bytes.
|
||||||
# The first byte of a charcode is mapped through the subHeaderKeys, to select
|
# 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
|
# 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.
|
# 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.
|
# 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.
|
# 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
|
# The range in glyphIndexArray referenced by a sunheader may overlap with the range in glyphIndexArray
|
||||||
# referenced by another subheader.
|
# 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
|
# firstChar and EntryCount values. If the byte value is outside the subrange, then the glyphIndex is zero
|
||||||
# (e.g. glyph not in font).
|
# (e.g. glyph not in font).
|
||||||
# If the byte index is in the subrange, then an offset index is calculated as (byteIndex - firstChar).
|
# 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
|
# 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.
|
# glyphIndex for the index firstChar. The offset index should then be used in this array to get the glyphIndex.
|
||||||
# Example for Logocut-Medium
|
# Example for Logocut-Medium
|
||||||
@ -340,10 +340,10 @@ class cmap_format_2(CmapSubtable):
|
|||||||
# [257], [1]=2 from charcode [129, 65]
|
# [257], [1]=2 from charcode [129, 65]
|
||||||
# [258], [2]=3 from charcode [129, 66]
|
# [258], [2]=3 from charcode [129, 66]
|
||||||
# [259], [3]=4 from charcode [129, 67]
|
# [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
|
# 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!
|
# value. In this case the final glyph index = 3+ 42 -> 45 for the final glyphIndex. Whew!
|
||||||
|
|
||||||
self.data = b""
|
self.data = b""
|
||||||
self.cmap = cmap = {}
|
self.cmap = cmap = {}
|
||||||
notdefGI = 0
|
notdefGI = 0
|
||||||
@ -374,7 +374,7 @@ class cmap_format_2(CmapSubtable):
|
|||||||
continue
|
continue
|
||||||
cmap[charCode] = gi
|
cmap[charCode] = gi
|
||||||
# If not subHeader.entryCount, then all char codes with this first byte are
|
# 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.
|
# same as mapping it to .notdef.
|
||||||
# cmap values are GID's.
|
# cmap values are GID's.
|
||||||
glyphOrder = self.ttFont.getGlyphOrder()
|
glyphOrder = self.ttFont.getGlyphOrder()
|
||||||
@ -387,7 +387,7 @@ class cmap_format_2(CmapSubtable):
|
|||||||
getGlyphName = self.ttFont.getGlyphName
|
getGlyphName = self.ttFont.getGlyphName
|
||||||
names = list(map(getGlyphName, gids ))
|
names = list(map(getGlyphName, gids ))
|
||||||
list(map(operator.setitem, [cmap]*lenCmap, charCodes, names))
|
list(map(operator.setitem, [cmap]*lenCmap, charCodes, names))
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
if self.data:
|
if self.data:
|
||||||
return struct.pack(">HHH", self.format, self.length, self.language) + 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]
|
charCodes = [item[0] for item in items]
|
||||||
names = [item[1] for item in items]
|
names = [item[1] for item in items]
|
||||||
nameMap = ttFont.getReverseGlyphMap()
|
nameMap = ttFont.getReverseGlyphMap()
|
||||||
lenCharCodes = len(charCodes)
|
lenCharCodes = len(charCodes)
|
||||||
try:
|
try:
|
||||||
gids = list(map(operator.getitem, [nameMap]*lenCharCodes, names))
|
gids = list(map(operator.getitem, [nameMap]*lenCharCodes, names))
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -423,8 +423,8 @@ class cmap_format_2(CmapSubtable):
|
|||||||
gids.append(gid)
|
gids.append(gid)
|
||||||
|
|
||||||
# Process the (char code to gid) item list in char code order.
|
# Process the (char code to gid) item list in char code order.
|
||||||
# By definition, all one byte char codes map to subheader 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,
|
# 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.
|
# 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
|
# 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.
|
# same first byte are in sequential order.
|
||||||
@ -443,7 +443,7 @@ class cmap_format_2(CmapSubtable):
|
|||||||
subHeader.idDelta = 0
|
subHeader.idDelta = 0
|
||||||
subHeader.idRangeOffset = 0
|
subHeader.idRangeOffset = 0
|
||||||
subHeaderList.append(subHeader)
|
subHeaderList.append(subHeader)
|
||||||
|
|
||||||
lastFirstByte = -1
|
lastFirstByte = -1
|
||||||
items = zip(charCodes, gids)
|
items = zip(charCodes, gids)
|
||||||
for charCode, gid in items:
|
for charCode, gid in items:
|
||||||
@ -480,7 +480,7 @@ class cmap_format_2(CmapSubtable):
|
|||||||
subHeader.glyphIndexArray.append(notdefGI)
|
subHeader.glyphIndexArray.append(notdefGI)
|
||||||
subHeader.glyphIndexArray.append(gid)
|
subHeader.glyphIndexArray.append(gid)
|
||||||
subHeader.entryCount = subHeader.entryCount + codeDiff + 1
|
subHeader.entryCount = subHeader.entryCount + codeDiff + 1
|
||||||
|
|
||||||
# fix GI's and iDelta of last subheader that we we added to the subheader array.
|
# fix GI's and iDelta of last subheader that we we added to the subheader array.
|
||||||
self.setIDDelta(subHeader)
|
self.setIDDelta(subHeader)
|
||||||
|
|
||||||
@ -497,12 +497,12 @@ class cmap_format_2(CmapSubtable):
|
|||||||
subHeaderKeys[index] = emptySubheadIndex
|
subHeaderKeys[index] = emptySubheadIndex
|
||||||
# Since this is the last subheader, the GlyphIndex Array starts two bytes after the start of the
|
# 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,
|
# 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.
|
# charcode 0 and GID 0.
|
||||||
|
|
||||||
idRangeOffset = (len(subHeaderList)-1)*8 + 2 # offset to beginning of glyphIDArray from first subheader idRangeOffset.
|
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.
|
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 = subHeaderList[index]
|
||||||
subHeader.idRangeOffset = 0
|
subHeader.idRangeOffset = 0
|
||||||
for j in range(index):
|
for j in range(index):
|
||||||
@ -511,7 +511,7 @@ class cmap_format_2(CmapSubtable):
|
|||||||
subHeader.idRangeOffset = prevSubhead.idRangeOffset - (index-j)*8
|
subHeader.idRangeOffset = prevSubhead.idRangeOffset - (index-j)*8
|
||||||
subHeader.glyphIndexArray = []
|
subHeader.glyphIndexArray = []
|
||||||
break
|
break
|
||||||
if subHeader.idRangeOffset == 0: # didn't find one.
|
if subHeader.idRangeOffset == 0: # didn't find one.
|
||||||
subHeader.idRangeOffset = idRangeOffset
|
subHeader.idRangeOffset = idRangeOffset
|
||||||
idRangeOffset = (idRangeOffset - 8) + subHeader.entryCount*2 # one less subheader, one more subArray.
|
idRangeOffset = (idRangeOffset - 8) + subHeader.entryCount*2 # one less subheader, one more subArray.
|
||||||
else:
|
else:
|
||||||
@ -564,17 +564,17 @@ def splitRange(startCode, endCode, cmap):
|
|||||||
# to do well with the fonts I tested: none became bigger, many became smaller.
|
# to do well with the fonts I tested: none became bigger, many became smaller.
|
||||||
if startCode == endCode:
|
if startCode == endCode:
|
||||||
return [], [endCode]
|
return [], [endCode]
|
||||||
|
|
||||||
lastID = cmap[startCode]
|
lastID = cmap[startCode]
|
||||||
lastCode = startCode
|
lastCode = startCode
|
||||||
inOrder = None
|
inOrder = None
|
||||||
orderedBegin = None
|
orderedBegin = None
|
||||||
subRanges = []
|
subRanges = []
|
||||||
|
|
||||||
# Gather subranges in which the glyph IDs are consecutive.
|
# Gather subranges in which the glyph IDs are consecutive.
|
||||||
for code in range(startCode + 1, endCode + 1):
|
for code in range(startCode + 1, endCode + 1):
|
||||||
glyphID = cmap[code]
|
glyphID = cmap[code]
|
||||||
|
|
||||||
if glyphID - 1 == lastID:
|
if glyphID - 1 == lastID:
|
||||||
if inOrder is None or not inOrder:
|
if inOrder is None or not inOrder:
|
||||||
inOrder = 1
|
inOrder = 1
|
||||||
@ -584,14 +584,14 @@ def splitRange(startCode, endCode, cmap):
|
|||||||
inOrder = 0
|
inOrder = 0
|
||||||
subRanges.append((orderedBegin, lastCode))
|
subRanges.append((orderedBegin, lastCode))
|
||||||
orderedBegin = None
|
orderedBegin = None
|
||||||
|
|
||||||
lastID = glyphID
|
lastID = glyphID
|
||||||
lastCode = code
|
lastCode = code
|
||||||
|
|
||||||
if inOrder:
|
if inOrder:
|
||||||
subRanges.append((orderedBegin, lastCode))
|
subRanges.append((orderedBegin, lastCode))
|
||||||
assert lastCode == endCode
|
assert lastCode == endCode
|
||||||
|
|
||||||
# Now filter out those new subranges that would only make the data bigger.
|
# 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
|
# A new segment cost 8 bytes, not using a new segment costs 2 bytes per
|
||||||
# character.
|
# character.
|
||||||
@ -606,15 +606,15 @@ def splitRange(startCode, endCode, cmap):
|
|||||||
if (e - b + 1) > threshold:
|
if (e - b + 1) > threshold:
|
||||||
newRanges.append((b, e))
|
newRanges.append((b, e))
|
||||||
subRanges = newRanges
|
subRanges = newRanges
|
||||||
|
|
||||||
if not subRanges:
|
if not subRanges:
|
||||||
return [], [endCode]
|
return [], [endCode]
|
||||||
|
|
||||||
if subRanges[0][0] != startCode:
|
if subRanges[0][0] != startCode:
|
||||||
subRanges.insert(0, (startCode, subRanges[0][0] - 1))
|
subRanges.insert(0, (startCode, subRanges[0][0] - 1))
|
||||||
if subRanges[-1][1] != endCode:
|
if subRanges[-1][1] != endCode:
|
||||||
subRanges.append((subRanges[-1][1] + 1, endCode))
|
subRanges.append((subRanges[-1][1] + 1, endCode))
|
||||||
|
|
||||||
# Fill the "holes" in the segments list -- those are the segments in which
|
# Fill the "holes" in the segments list -- those are the segments in which
|
||||||
# the glyph IDs are _not_ consecutive.
|
# the glyph IDs are _not_ consecutive.
|
||||||
i = 1
|
i = 1
|
||||||
@ -623,7 +623,7 @@ def splitRange(startCode, endCode, cmap):
|
|||||||
subRanges.insert(i, (subRanges[i-1][1] + 1, subRanges[i][0] - 1))
|
subRanges.insert(i, (subRanges[i-1][1] + 1, subRanges[i][0] - 1))
|
||||||
i = i + 1
|
i = i + 1
|
||||||
i = i + 1
|
i = i + 1
|
||||||
|
|
||||||
# Transform the ranges into startCode/endCode lists.
|
# Transform the ranges into startCode/endCode lists.
|
||||||
start = []
|
start = []
|
||||||
end = []
|
end = []
|
||||||
@ -631,13 +631,13 @@ def splitRange(startCode, endCode, cmap):
|
|||||||
start.append(b)
|
start.append(b)
|
||||||
end.append(e)
|
end.append(e)
|
||||||
start.pop(0)
|
start.pop(0)
|
||||||
|
|
||||||
assert len(start) + 1 == len(end)
|
assert len(start) + 1 == len(end)
|
||||||
return start, end
|
return start, end
|
||||||
|
|
||||||
|
|
||||||
class cmap_format_4(CmapSubtable):
|
class cmap_format_4(CmapSubtable):
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
# we usually get here indirectly from the subtable __getattr__ function, in which case both args must be None.
|
# 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.
|
# 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])
|
struct.unpack(">4H", data[:8])
|
||||||
data = data[8:]
|
data = data[8:]
|
||||||
segCount = segCountX2 // 2
|
segCount = segCountX2 // 2
|
||||||
|
|
||||||
allCodes = array.array("H")
|
allCodes = array.array("H")
|
||||||
allCodes.fromstring(data)
|
allCodes.fromstring(data)
|
||||||
self.data = data = None
|
self.data = data = None
|
||||||
|
|
||||||
if sys.byteorder != "big":
|
if sys.byteorder != "big":
|
||||||
allCodes.byteswap()
|
allCodes.byteswap()
|
||||||
|
|
||||||
# divide the data
|
# divide the data
|
||||||
endCode = allCodes[:segCount]
|
endCode = allCodes[:segCount]
|
||||||
allCodes = allCodes[segCount+1:] # the +1 is skipping the reservedPad field
|
allCodes = allCodes[segCount+1:] # the +1 is skipping the reservedPad field
|
||||||
@ -707,7 +707,7 @@ class cmap_format_4(CmapSubtable):
|
|||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
if self.data:
|
if self.data:
|
||||||
return struct.pack(">HHH", self.format, self.length, self.language) + self.data
|
return struct.pack(">HHH", self.format, self.length, self.language) + self.data
|
||||||
|
|
||||||
charCodes = list(self.cmap.keys())
|
charCodes = list(self.cmap.keys())
|
||||||
lenCharCodes = len(charCodes)
|
lenCharCodes = len(charCodes)
|
||||||
if lenCharCodes == 0:
|
if lenCharCodes == 0:
|
||||||
@ -737,11 +737,11 @@ class cmap_format_4(CmapSubtable):
|
|||||||
gid = ttFont.getGlyphID(name)
|
gid = ttFont.getGlyphID(name)
|
||||||
except:
|
except:
|
||||||
raise KeyError(name)
|
raise KeyError(name)
|
||||||
|
|
||||||
gids.append(gid)
|
gids.append(gid)
|
||||||
cmap = {} # code:glyphID mapping
|
cmap = {} # code:glyphID mapping
|
||||||
list(map(operator.setitem, [cmap]*len(charCodes), charCodes, gids))
|
list(map(operator.setitem, [cmap]*len(charCodes), charCodes, gids))
|
||||||
|
|
||||||
# Build startCode and endCode lists.
|
# Build startCode and endCode lists.
|
||||||
# Split the char codes in ranges of consecutive char codes, then split
|
# Split the char codes in ranges of consecutive char codes, then split
|
||||||
# each range in more ranges of consecutive/not consecutive glyph IDs.
|
# each range in more ranges of consecutive/not consecutive glyph IDs.
|
||||||
@ -763,7 +763,7 @@ class cmap_format_4(CmapSubtable):
|
|||||||
endCode.extend(end)
|
endCode.extend(end)
|
||||||
startCode.append(0xffff)
|
startCode.append(0xffff)
|
||||||
endCode.append(0xffff)
|
endCode.append(0xffff)
|
||||||
|
|
||||||
# build up rest of cruft
|
# build up rest of cruft
|
||||||
idDelta = []
|
idDelta = []
|
||||||
idRangeOffset = []
|
idRangeOffset = []
|
||||||
@ -782,12 +782,12 @@ class cmap_format_4(CmapSubtable):
|
|||||||
glyphIndexArray.extend(indices)
|
glyphIndexArray.extend(indices)
|
||||||
idDelta.append(1) # 0xffff + 1 == (tadaa!) 0. So this end code maps to .notdef
|
idDelta.append(1) # 0xffff + 1 == (tadaa!) 0. So this end code maps to .notdef
|
||||||
idRangeOffset.append(0)
|
idRangeOffset.append(0)
|
||||||
|
|
||||||
# Insane.
|
# Insane.
|
||||||
segCount = len(endCode)
|
segCount = len(endCode)
|
||||||
segCountX2 = segCount * 2
|
segCountX2 = segCount * 2
|
||||||
searchRange, entrySelector, rangeShift = getSearchRange(segCount, 2)
|
searchRange, entrySelector, rangeShift = getSearchRange(segCount, 2)
|
||||||
|
|
||||||
charCodeArray = array.array("H", endCode + [0] + startCode)
|
charCodeArray = array.array("H", endCode + [0] + startCode)
|
||||||
idDeltaArray = array.array("H", idDelta)
|
idDeltaArray = array.array("H", idDelta)
|
||||||
restArray = array.array("H", idRangeOffset + glyphIndexArray)
|
restArray = array.array("H", idRangeOffset + glyphIndexArray)
|
||||||
@ -798,10 +798,10 @@ class cmap_format_4(CmapSubtable):
|
|||||||
data = charCodeArray.tostring() + idDeltaArray.tostring() + restArray.tostring()
|
data = charCodeArray.tostring() + idDeltaArray.tostring() + restArray.tostring()
|
||||||
|
|
||||||
length = struct.calcsize(cmap_format_4_format) + len(data)
|
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)
|
segCountX2, searchRange, entrySelector, rangeShift)
|
||||||
return header + data
|
return header + data
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
self.language = safeEval(attrs["language"])
|
self.language = safeEval(attrs["language"])
|
||||||
if not hasattr(self, "cmap"):
|
if not hasattr(self, "cmap"):
|
||||||
@ -818,7 +818,7 @@ class cmap_format_4(CmapSubtable):
|
|||||||
|
|
||||||
|
|
||||||
class cmap_format_6(CmapSubtable):
|
class cmap_format_6(CmapSubtable):
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
# we usually get here indirectly from the subtable __getattr__ function, in which case both args must be None.
|
# 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.
|
# 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
|
getGlyphName = self.ttFont.getGlyphName
|
||||||
names = list(map(getGlyphName, glyphIndexArray ))
|
names = list(map(getGlyphName, glyphIndexArray ))
|
||||||
list(map(operator.setitem, [cmap]*lenArray, charCodes, names))
|
list(map(operator.setitem, [cmap]*lenArray, charCodes, names))
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
if self.data:
|
if self.data:
|
||||||
return struct.pack(">HHH", self.format, self.length, self.language) + self.data
|
return struct.pack(">HHH", self.format, self.length, self.language) + self.data
|
||||||
@ -867,10 +867,10 @@ class cmap_format_6(CmapSubtable):
|
|||||||
else:
|
else:
|
||||||
data = b""
|
data = b""
|
||||||
firstCode = 0
|
firstCode = 0
|
||||||
header = struct.pack(">HHHHH",
|
header = struct.pack(">HHHHH",
|
||||||
6, len(data) + 10, self.language, firstCode, len(codes))
|
6, len(data) + 10, self.language, firstCode, len(codes))
|
||||||
return header + data
|
return header + data
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
self.language = safeEval(attrs["language"])
|
self.language = safeEval(attrs["language"])
|
||||||
if not hasattr(self, "cmap"):
|
if not hasattr(self, "cmap"):
|
||||||
@ -887,7 +887,7 @@ class cmap_format_6(CmapSubtable):
|
|||||||
|
|
||||||
|
|
||||||
class cmap_format_12_or_13(CmapSubtable):
|
class cmap_format_12_or_13(CmapSubtable):
|
||||||
|
|
||||||
def __init__(self, format):
|
def __init__(self, format):
|
||||||
self.format = format
|
self.format = format
|
||||||
self.reserved = 0
|
self.reserved = 0
|
||||||
@ -933,12 +933,12 @@ class cmap_format_12_or_13(CmapSubtable):
|
|||||||
getGlyphName = self.ttFont.getGlyphName
|
getGlyphName = self.ttFont.getGlyphName
|
||||||
names = list(map(getGlyphName, gids ))
|
names = list(map(getGlyphName, gids ))
|
||||||
list(map(operator.setitem, [cmap]*lenCmap, charCodes, names))
|
list(map(operator.setitem, [cmap]*lenCmap, charCodes, names))
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
if self.data:
|
if self.data:
|
||||||
return struct.pack(">HHLLL", self.format, self.reserved, self.length, self.language, self.nGroups) + self.data
|
return struct.pack(">HHLLL", self.format, self.reserved, self.length, self.language, self.nGroups) + self.data
|
||||||
charCodes = list(self.cmap.keys())
|
charCodes = list(self.cmap.keys())
|
||||||
lenCharCodes = len(charCodes)
|
lenCharCodes = len(charCodes)
|
||||||
names = list(self.cmap.values())
|
names = list(self.cmap.values())
|
||||||
nameMap = ttFont.getReverseGlyphMap()
|
nameMap = ttFont.getReverseGlyphMap()
|
||||||
try:
|
try:
|
||||||
@ -963,7 +963,7 @@ class cmap_format_12_or_13(CmapSubtable):
|
|||||||
raise KeyError(name)
|
raise KeyError(name)
|
||||||
|
|
||||||
gids.append(gid)
|
gids.append(gid)
|
||||||
|
|
||||||
cmap = {} # code:glyphID mapping
|
cmap = {} # code:glyphID mapping
|
||||||
list(map(operator.setitem, [cmap]*len(charCodes), charCodes, gids))
|
list(map(operator.setitem, [cmap]*len(charCodes), charCodes, gids))
|
||||||
|
|
||||||
@ -992,7 +992,7 @@ class cmap_format_12_or_13(CmapSubtable):
|
|||||||
lengthSubtable = len(data) +16
|
lengthSubtable = len(data) +16
|
||||||
assert len(data) == (nGroups*12) == (lengthSubtable-16)
|
assert len(data) == (nGroups*12) == (lengthSubtable-16)
|
||||||
return struct.pack(">HHLLL", self.format, self.reserved, lengthSubtable, self.language, nGroups) + data
|
return struct.pack(">HHLLL", self.format, self.reserved, lengthSubtable, self.language, nGroups) + data
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
writer.begintag(self.__class__.__name__, [
|
writer.begintag(self.__class__.__name__, [
|
||||||
("platformID", self.platformID),
|
("platformID", self.platformID),
|
||||||
@ -1008,7 +1008,7 @@ class cmap_format_12_or_13(CmapSubtable):
|
|||||||
self._writeCodes(codes, writer)
|
self._writeCodes(codes, writer)
|
||||||
writer.endtag(self.__class__.__name__)
|
writer.endtag(self.__class__.__name__)
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
self.format = safeEval(attrs["format"])
|
self.format = safeEval(attrs["format"])
|
||||||
self.reserved = safeEval(attrs["reserved"])
|
self.reserved = safeEval(attrs["reserved"])
|
||||||
@ -1079,12 +1079,12 @@ class cmap_format_14(CmapSubtable):
|
|||||||
else:
|
else:
|
||||||
assert (data is None and ttFont is None), "Need both data and ttFont arguments"
|
assert (data is None and ttFont is None), "Need both data and ttFont arguments"
|
||||||
data = self.data
|
data = self.data
|
||||||
|
|
||||||
self.cmap = {} # so that clients that expect this to exist in a cmap table won't fail.
|
self.cmap = {} # so that clients that expect this to exist in a cmap table won't fail.
|
||||||
uvsDict = {}
|
uvsDict = {}
|
||||||
recOffset = 0
|
recOffset = 0
|
||||||
for n in range(self.numVarSelectorRecords):
|
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
|
recOffset += 11
|
||||||
varUVS = cvtToUVS(uvs)
|
varUVS = cvtToUVS(uvs)
|
||||||
if defOVSOffset:
|
if defOVSOffset:
|
||||||
@ -1103,7 +1103,7 @@ class cmap_format_14(CmapSubtable):
|
|||||||
uvsDict[varUVS].extend(localUVList)
|
uvsDict[varUVS].extend(localUVList)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
uvsDict[varUVS] = list(localUVList)
|
uvsDict[varUVS] = list(localUVList)
|
||||||
|
|
||||||
if nonDefUVSOffset:
|
if nonDefUVSOffset:
|
||||||
startOffset = nonDefUVSOffset - 10
|
startOffset = nonDefUVSOffset - 10
|
||||||
numRecs, = struct.unpack(">L", data[startOffset:startOffset+4])
|
numRecs, = struct.unpack(">L", data[startOffset:startOffset+4])
|
||||||
@ -1119,9 +1119,9 @@ class cmap_format_14(CmapSubtable):
|
|||||||
uvsDict[varUVS].extend(localUVList)
|
uvsDict[varUVS].extend(localUVList)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
uvsDict[varUVS] = localUVList
|
uvsDict[varUVS] = localUVList
|
||||||
|
|
||||||
self.uvsDict = uvsDict
|
self.uvsDict = uvsDict
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
writer.begintag(self.__class__.__name__, [
|
writer.begintag(self.__class__.__name__, [
|
||||||
("platformID", self.platformID),
|
("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.
|
self.cmap = {} # so that clients that expect this to exist in a cmap table won't fail.
|
||||||
if not hasattr(self, "uvsDict"):
|
if not hasattr(self, "uvsDict"):
|
||||||
self.uvsDict = {}
|
self.uvsDict = {}
|
||||||
uvsDict = self.uvsDict
|
uvsDict = self.uvsDict
|
||||||
|
|
||||||
for element in content:
|
for element in content:
|
||||||
if not isinstance(element, tuple):
|
if not isinstance(element, tuple):
|
||||||
@ -1201,7 +1201,7 @@ class cmap_format_14(CmapSubtable):
|
|||||||
lastUV = defEntry
|
lastUV = defEntry
|
||||||
defRecs.append(rec)
|
defRecs.append(rec)
|
||||||
cnt = 0
|
cnt = 0
|
||||||
|
|
||||||
rec = struct.pack(">3sB", cvtFromUVS(lastUV), cnt)
|
rec = struct.pack(">3sB", cvtFromUVS(lastUV), cnt)
|
||||||
defRecs.append(rec)
|
defRecs.append(rec)
|
||||||
|
|
||||||
@ -1226,20 +1226,20 @@ class cmap_format_14(CmapSubtable):
|
|||||||
data.append(ndrec)
|
data.append(ndrec)
|
||||||
else:
|
else:
|
||||||
nonDefUVSOffset = 0
|
nonDefUVSOffset = 0
|
||||||
|
|
||||||
vrec = struct.pack(">3sLL", cvtFromUVS(uvs), defOVSOffset, nonDefUVSOffset)
|
vrec = struct.pack(">3sLL", cvtFromUVS(uvs), defOVSOffset, nonDefUVSOffset)
|
||||||
varSelectorRecords.append(vrec)
|
varSelectorRecords.append(vrec)
|
||||||
|
|
||||||
data = bytesjoin(varSelectorRecords) + bytesjoin(data)
|
data = bytesjoin(varSelectorRecords) + bytesjoin(data)
|
||||||
self.length = 10 + len(data)
|
self.length = 10 + len(data)
|
||||||
headerdata = struct.pack(">HLL", self.format, self.length, self.numVarSelectorRecords)
|
headerdata = struct.pack(">HLL", self.format, self.length, self.numVarSelectorRecords)
|
||||||
self.data = headerdata + data
|
self.data = headerdata + data
|
||||||
|
|
||||||
return self.data
|
return self.data
|
||||||
|
|
||||||
|
|
||||||
class cmap_format_unknown(CmapSubtable):
|
class cmap_format_unknown(CmapSubtable):
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
cmapName = self.__class__.__name__[:12] + str(self.format)
|
cmapName = self.__class__.__name__[:12] + str(self.format)
|
||||||
writer.begintag(cmapName, [
|
writer.begintag(cmapName, [
|
||||||
@ -1250,15 +1250,15 @@ class cmap_format_unknown(CmapSubtable):
|
|||||||
writer.dumphex(self.data)
|
writer.dumphex(self.data)
|
||||||
writer.endtag(cmapName)
|
writer.endtag(cmapName)
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
self.data = readHex(content)
|
self.data = readHex(content)
|
||||||
self.cmap = {}
|
self.cmap = {}
|
||||||
|
|
||||||
def decompileHeader(self, data, ttFont):
|
def decompileHeader(self, data, ttFont):
|
||||||
self.language = 0 # dummy value
|
self.language = 0 # dummy value
|
||||||
self.data = data
|
self.data = data
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
# we usually get here indirectly from the subtable __getattr__ function, in which case both args must be None.
|
# 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.
|
# If not, someone is calling the subtable decompile() directly, and must provide both args.
|
||||||
|
@ -6,26 +6,26 @@ import sys
|
|||||||
import array
|
import array
|
||||||
|
|
||||||
class table__c_v_t(DefaultTable.DefaultTable):
|
class table__c_v_t(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
values = array.array("h")
|
values = array.array("h")
|
||||||
values.fromstring(data)
|
values.fromstring(data)
|
||||||
if sys.byteorder != "big":
|
if sys.byteorder != "big":
|
||||||
values.byteswap()
|
values.byteswap()
|
||||||
self.values = values
|
self.values = values
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
values = self.values[:]
|
values = self.values[:]
|
||||||
if sys.byteorder != "big":
|
if sys.byteorder != "big":
|
||||||
values.byteswap()
|
values.byteswap()
|
||||||
return values.tostring()
|
return values.tostring()
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
for i in range(len(self.values)):
|
for i in range(len(self.values)):
|
||||||
value = self.values[i]
|
value = self.values[i]
|
||||||
writer.simpletag("cv", value=value, index=i)
|
writer.simpletag("cv", value=value, index=i)
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
if not hasattr(self, "values"):
|
if not hasattr(self, "values"):
|
||||||
self.values = array.array("h")
|
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)):
|
for i in range(1 + index - len(self.values)):
|
||||||
self.values.append(0)
|
self.values.append(0)
|
||||||
self.values[index] = value
|
self.values[index] = value
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self.values)
|
return len(self.values)
|
||||||
|
|
||||||
def __getitem__(self, index):
|
def __getitem__(self, index):
|
||||||
return self.values[index]
|
return self.values[index]
|
||||||
|
|
||||||
def __setitem__(self, index, value):
|
def __setitem__(self, index, value):
|
||||||
self.values[index] = value
|
self.values[index] = value
|
||||||
|
|
||||||
def __delitem__(self, index):
|
def __delitem__(self, index):
|
||||||
del self.values[index]
|
del self.values[index]
|
||||||
|
@ -4,23 +4,23 @@ from . import DefaultTable
|
|||||||
from . import ttProgram
|
from . import ttProgram
|
||||||
|
|
||||||
class table__f_p_g_m(DefaultTable.DefaultTable):
|
class table__f_p_g_m(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
program = ttProgram.Program()
|
program = ttProgram.Program()
|
||||||
program.fromBytecode(data)
|
program.fromBytecode(data)
|
||||||
self.program = program
|
self.program = program
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
return self.program.getBytecode()
|
return self.program.getBytecode()
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
self.program.toXML(writer, ttFont)
|
self.program.toXML(writer, ttFont)
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
program = ttProgram.Program()
|
program = ttProgram.Program()
|
||||||
program.fromXML(name, attrs, content, ttFont)
|
program.fromXML(name, attrs, content, ttFont)
|
||||||
self.program = program
|
self.program = program
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self.program)
|
return len(self.program)
|
||||||
|
@ -11,7 +11,7 @@ GASP_DOGRAY = 0x0002
|
|||||||
GASP_GRIDFIT = 0x0001
|
GASP_GRIDFIT = 0x0001
|
||||||
|
|
||||||
class table__g_a_s_p(DefaultTable.DefaultTable):
|
class table__g_a_s_p(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
self.version, numRanges = struct.unpack(">HH", data[:4])
|
self.version, numRanges = struct.unpack(">HH", data[:4])
|
||||||
assert 0 <= self.version <= 1, "unknown 'gasp' format: %s" % self.version
|
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)
|
self.gaspRange[int(rangeMaxPPEM)] = int(rangeGaspBehavior)
|
||||||
data = data[4:]
|
data = data[4:]
|
||||||
assert not data, "too much data"
|
assert not data, "too much data"
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
version = 0 # ignore self.version
|
version = 0 # ignore self.version
|
||||||
numRanges = len(self.gaspRange)
|
numRanges = len(self.gaspRange)
|
||||||
@ -34,7 +34,7 @@ class table__g_a_s_p(DefaultTable.DefaultTable):
|
|||||||
version = 1
|
version = 1
|
||||||
data = struct.pack(">HH", version, numRanges) + data
|
data = struct.pack(">HH", version, numRanges) + data
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
items = sorted(self.gaspRange.items())
|
items = sorted(self.gaspRange.items())
|
||||||
for rangeMaxPPEM, rangeGaspBehavior in items:
|
for rangeMaxPPEM, rangeGaspBehavior in items:
|
||||||
@ -42,7 +42,7 @@ class table__g_a_s_p(DefaultTable.DefaultTable):
|
|||||||
("rangeMaxPPEM", rangeMaxPPEM),
|
("rangeMaxPPEM", rangeMaxPPEM),
|
||||||
("rangeGaspBehavior", rangeGaspBehavior)])
|
("rangeGaspBehavior", rangeGaspBehavior)])
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
if name != "gaspRange":
|
if name != "gaspRange":
|
||||||
return
|
return
|
||||||
|
@ -16,20 +16,20 @@ import array
|
|||||||
import warnings
|
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
|
# scaled composite components: one does scale first and then translate
|
||||||
# and the other does it vice versa. MS defined some flags to indicate
|
# and the other does it vice versa. MS defined some flags to indicate
|
||||||
# the difference, but it seems nobody actually _sets_ those flags.
|
# the difference, but it seems nobody actually _sets_ those flags.
|
||||||
#
|
#
|
||||||
# Funny thing: Apple seems to _only_ do their thing in the
|
# 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)...
|
# (eg. Charcoal)...
|
||||||
#
|
#
|
||||||
SCALE_COMPONENT_OFFSET_DEFAULT = 0 # 0 == MS, 1 == Apple
|
SCALE_COMPONENT_OFFSET_DEFAULT = 0 # 0 == MS, 1 == Apple
|
||||||
|
|
||||||
|
|
||||||
class table__g_l_y_f(DefaultTable.DefaultTable):
|
class table__g_l_y_f(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
loca = ttFont['loca']
|
loca = ttFont['loca']
|
||||||
last = int(loca[0])
|
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
|
if ttFont.lazy is False: # Be lazy for None and True
|
||||||
for glyph in self.glyphs.values():
|
for glyph in self.glyphs.values():
|
||||||
glyph.expand(self)
|
glyph.expand(self)
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
if not hasattr(self, "glyphOrder"):
|
if not hasattr(self, "glyphOrder"):
|
||||||
self.glyphOrder = ttFont.getGlyphOrder()
|
self.glyphOrder = ttFont.getGlyphOrder()
|
||||||
@ -92,7 +92,7 @@ class table__g_l_y_f(DefaultTable.DefaultTable):
|
|||||||
ttFont['loca'].set(locations)
|
ttFont['loca'].set(locations)
|
||||||
ttFont['maxp'].numGlyphs = len(self.glyphs)
|
ttFont['maxp'].numGlyphs = len(self.glyphs)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def toXML(self, writer, ttFont, progress=None):
|
def toXML(self, writer, ttFont, progress=None):
|
||||||
writer.newline()
|
writer.newline()
|
||||||
glyphNames = ttFont.getGlyphNames()
|
glyphNames = ttFont.getGlyphNames()
|
||||||
@ -125,7 +125,7 @@ class table__g_l_y_f(DefaultTable.DefaultTable):
|
|||||||
writer.comment("contains no outline data")
|
writer.comment("contains no outline data")
|
||||||
writer.newline()
|
writer.newline()
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
if name != "TTGlyph":
|
if name != "TTGlyph":
|
||||||
return
|
return
|
||||||
@ -147,39 +147,39 @@ class table__g_l_y_f(DefaultTable.DefaultTable):
|
|||||||
glyph.fromXML(name, attrs, content, ttFont)
|
glyph.fromXML(name, attrs, content, ttFont)
|
||||||
if not ttFont.recalcBBoxes:
|
if not ttFont.recalcBBoxes:
|
||||||
glyph.compact(self, 0)
|
glyph.compact(self, 0)
|
||||||
|
|
||||||
def setGlyphOrder(self, glyphOrder):
|
def setGlyphOrder(self, glyphOrder):
|
||||||
self.glyphOrder = glyphOrder
|
self.glyphOrder = glyphOrder
|
||||||
|
|
||||||
def getGlyphName(self, glyphID):
|
def getGlyphName(self, glyphID):
|
||||||
return self.glyphOrder[glyphID]
|
return self.glyphOrder[glyphID]
|
||||||
|
|
||||||
def getGlyphID(self, glyphName):
|
def getGlyphID(self, glyphName):
|
||||||
# XXX optimize with reverse dict!!!
|
# XXX optimize with reverse dict!!!
|
||||||
return self.glyphOrder.index(glyphName)
|
return self.glyphOrder.index(glyphName)
|
||||||
|
|
||||||
def keys(self):
|
def keys(self):
|
||||||
return self.glyphs.keys()
|
return self.glyphs.keys()
|
||||||
|
|
||||||
def has_key(self, glyphName):
|
def has_key(self, glyphName):
|
||||||
return glyphName in self.glyphs
|
return glyphName in self.glyphs
|
||||||
|
|
||||||
__contains__ = has_key
|
__contains__ = has_key
|
||||||
|
|
||||||
def __getitem__(self, glyphName):
|
def __getitem__(self, glyphName):
|
||||||
glyph = self.glyphs[glyphName]
|
glyph = self.glyphs[glyphName]
|
||||||
glyph.expand(self)
|
glyph.expand(self)
|
||||||
return glyph
|
return glyph
|
||||||
|
|
||||||
def __setitem__(self, glyphName, glyph):
|
def __setitem__(self, glyphName, glyph):
|
||||||
self.glyphs[glyphName] = glyph
|
self.glyphs[glyphName] = glyph
|
||||||
if glyphName not in self.glyphOrder:
|
if glyphName not in self.glyphOrder:
|
||||||
self.glyphOrder.append(glyphName)
|
self.glyphOrder.append(glyphName)
|
||||||
|
|
||||||
def __delitem__(self, glyphName):
|
def __delitem__(self, glyphName):
|
||||||
del self.glyphs[glyphName]
|
del self.glyphs[glyphName]
|
||||||
self.glyphOrder.remove(glyphName)
|
self.glyphOrder.remove(glyphName)
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
assert len(self.glyphOrder) == len(self.glyphs)
|
assert len(self.glyphOrder) == len(self.glyphs)
|
||||||
return len(self.glyphs)
|
return len(self.glyphs)
|
||||||
@ -267,35 +267,35 @@ def flagEncodeCoords(flag, x, y, xBytes, yBytes):
|
|||||||
flagEncodeCoord(flag, flagYsame|flagYShort, y, yBytes)
|
flagEncodeCoord(flag, flagYsame|flagYShort, y, yBytes)
|
||||||
|
|
||||||
|
|
||||||
ARG_1_AND_2_ARE_WORDS = 0x0001 # if set args are words otherwise they are bytes
|
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
|
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
|
ROUND_XY_TO_GRID = 0x0004 # for the xy values if above is true
|
||||||
WE_HAVE_A_SCALE = 0x0008 # Sx = Sy, otherwise scale == 1.0
|
WE_HAVE_A_SCALE = 0x0008 # Sx = Sy, otherwise scale == 1.0
|
||||||
NON_OVERLAPPING = 0x0010 # set to same value for all components (obsolete!)
|
NON_OVERLAPPING = 0x0010 # set to same value for all components (obsolete!)
|
||||||
MORE_COMPONENTS = 0x0020 # indicates at least one more glyph after this one
|
MORE_COMPONENTS = 0x0020 # indicates at least one more glyph after this one
|
||||||
WE_HAVE_AN_X_AND_Y_SCALE = 0x0040 # Sx, Sy
|
WE_HAVE_AN_X_AND_Y_SCALE = 0x0040 # Sx, Sy
|
||||||
WE_HAVE_A_TWO_BY_TWO = 0x0080 # t00, t01, t10, t11
|
WE_HAVE_A_TWO_BY_TWO = 0x0080 # t00, t01, t10, t11
|
||||||
WE_HAVE_INSTRUCTIONS = 0x0100 # instructions follow
|
WE_HAVE_INSTRUCTIONS = 0x0100 # instructions follow
|
||||||
USE_MY_METRICS = 0x0200 # apply these metrics to parent glyph
|
USE_MY_METRICS = 0x0200 # apply these metrics to parent glyph
|
||||||
OVERLAP_COMPOUND = 0x0400 # used by Apple in GX fonts
|
OVERLAP_COMPOUND = 0x0400 # used by Apple in GX fonts
|
||||||
SCALED_COMPONENT_OFFSET = 0x0800 # composite designed to have the component offset scaled (designed for Apple)
|
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)
|
UNSCALED_COMPONENT_OFFSET = 0x1000 # composite designed not to have the component offset scaled (designed for MS)
|
||||||
|
|
||||||
|
|
||||||
class Glyph(object):
|
class Glyph(object):
|
||||||
|
|
||||||
def __init__(self, data=""):
|
def __init__(self, data=""):
|
||||||
if not data:
|
if not data:
|
||||||
# empty char
|
# empty char
|
||||||
self.numberOfContours = 0
|
self.numberOfContours = 0
|
||||||
return
|
return
|
||||||
self.data = data
|
self.data = data
|
||||||
|
|
||||||
def compact(self, glyfTable, recalcBBoxes=True):
|
def compact(self, glyfTable, recalcBBoxes=True):
|
||||||
data = self.compile(glyfTable, recalcBBoxes)
|
data = self.compile(glyfTable, recalcBBoxes)
|
||||||
self.__dict__.clear()
|
self.__dict__.clear()
|
||||||
self.data = data
|
self.data = data
|
||||||
|
|
||||||
def expand(self, glyfTable):
|
def expand(self, glyfTable):
|
||||||
if not hasattr(self, "data"):
|
if not hasattr(self, "data"):
|
||||||
# already unpacked
|
# already unpacked
|
||||||
@ -310,7 +310,7 @@ class Glyph(object):
|
|||||||
self.decompileComponents(data, glyfTable)
|
self.decompileComponents(data, glyfTable)
|
||||||
else:
|
else:
|
||||||
self.decompileCoordinates(data)
|
self.decompileCoordinates(data)
|
||||||
|
|
||||||
def compile(self, glyfTable, recalcBBoxes=True):
|
def compile(self, glyfTable, recalcBBoxes=True):
|
||||||
if hasattr(self, "data"):
|
if hasattr(self, "data"):
|
||||||
return self.data
|
return self.data
|
||||||
@ -324,7 +324,7 @@ class Glyph(object):
|
|||||||
else:
|
else:
|
||||||
data = data + self.compileCoordinates()
|
data = data + self.compileCoordinates()
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
if self.isComposite():
|
if self.isComposite():
|
||||||
for compo in self.components:
|
for compo in self.components:
|
||||||
@ -341,7 +341,7 @@ class Glyph(object):
|
|||||||
writer.newline()
|
writer.newline()
|
||||||
for j in range(last, self.endPtsOfContours[i] + 1):
|
for j in range(last, self.endPtsOfContours[i] + 1):
|
||||||
writer.simpletag("pt", [
|
writer.simpletag("pt", [
|
||||||
("x", self.coordinates[j][0]),
|
("x", self.coordinates[j][0]),
|
||||||
("y", self.coordinates[j][1]),
|
("y", self.coordinates[j][1]),
|
||||||
("on", self.flags[j] & flagOnCurve)])
|
("on", self.flags[j] & flagOnCurve)])
|
||||||
writer.newline()
|
writer.newline()
|
||||||
@ -353,7 +353,7 @@ class Glyph(object):
|
|||||||
self.program.toXML(writer, ttFont)
|
self.program.toXML(writer, ttFont)
|
||||||
writer.endtag("instructions")
|
writer.endtag("instructions")
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
if name == "contour":
|
if name == "contour":
|
||||||
if self.numberOfContours < 0:
|
if self.numberOfContours < 0:
|
||||||
@ -394,7 +394,7 @@ class Glyph(object):
|
|||||||
continue
|
continue
|
||||||
name, attrs, content = element
|
name, attrs, content = element
|
||||||
self.program.fromXML(name, attrs, content, ttFont)
|
self.program.fromXML(name, attrs, content, ttFont)
|
||||||
|
|
||||||
def getCompositeMaxpValues(self, glyfTable, maxComponentDepth=1):
|
def getCompositeMaxpValues(self, glyfTable, maxComponentDepth=1):
|
||||||
assert self.isComposite()
|
assert self.isComposite()
|
||||||
nContours = 0
|
nContours = 0
|
||||||
@ -411,11 +411,11 @@ class Glyph(object):
|
|||||||
nPoints = nPoints + nP
|
nPoints = nPoints + nP
|
||||||
nContours = nContours + nC
|
nContours = nContours + nC
|
||||||
return nPoints, nContours, maxComponentDepth
|
return nPoints, nContours, maxComponentDepth
|
||||||
|
|
||||||
def getMaxpValues(self):
|
def getMaxpValues(self):
|
||||||
assert self.numberOfContours > 0
|
assert self.numberOfContours > 0
|
||||||
return len(self.coordinates), len(self.endPtsOfContours)
|
return len(self.coordinates), len(self.endPtsOfContours)
|
||||||
|
|
||||||
def decompileComponents(self, data, glyfTable):
|
def decompileComponents(self, data, glyfTable):
|
||||||
self.components = []
|
self.components = []
|
||||||
more = 1
|
more = 1
|
||||||
@ -433,16 +433,16 @@ class Glyph(object):
|
|||||||
data = data[numInstructions:]
|
data = data[numInstructions:]
|
||||||
if len(data) >= 4:
|
if len(data) >= 4:
|
||||||
warnings.warn("too much glyph data at the end of composite glyph: %d excess bytes" % len(data))
|
warnings.warn("too much glyph data at the end of composite glyph: %d excess bytes" % len(data))
|
||||||
|
|
||||||
def decompileCoordinates(self, data):
|
def decompileCoordinates(self, data):
|
||||||
endPtsOfContours = array.array("h")
|
endPtsOfContours = array.array("h")
|
||||||
endPtsOfContours.fromstring(data[:2*self.numberOfContours])
|
endPtsOfContours.fromstring(data[:2*self.numberOfContours])
|
||||||
if sys.byteorder != "big":
|
if sys.byteorder != "big":
|
||||||
endPtsOfContours.byteswap()
|
endPtsOfContours.byteswap()
|
||||||
self.endPtsOfContours = endPtsOfContours.tolist()
|
self.endPtsOfContours = endPtsOfContours.tolist()
|
||||||
|
|
||||||
data = data[2*self.numberOfContours:]
|
data = data[2*self.numberOfContours:]
|
||||||
|
|
||||||
instructionLength, = struct.unpack(">h", data[:2])
|
instructionLength, = struct.unpack(">h", data[:2])
|
||||||
data = data[2:]
|
data = data[2:]
|
||||||
self.program = ttProgram.Program()
|
self.program = ttProgram.Program()
|
||||||
@ -451,7 +451,7 @@ class Glyph(object):
|
|||||||
nCoordinates = self.endPtsOfContours[-1] + 1
|
nCoordinates = self.endPtsOfContours[-1] + 1
|
||||||
flags, xCoordinates, yCoordinates = \
|
flags, xCoordinates, yCoordinates = \
|
||||||
self.decompileCoordinatesRaw(nCoordinates, data)
|
self.decompileCoordinatesRaw(nCoordinates, data)
|
||||||
|
|
||||||
# fill in repetitions and apply signs
|
# fill in repetitions and apply signs
|
||||||
self.coordinates = coordinates = GlyphCoordinates.zeros(nCoordinates)
|
self.coordinates = coordinates = GlyphCoordinates.zeros(nCoordinates)
|
||||||
xIndex = 0
|
xIndex = 0
|
||||||
@ -528,7 +528,7 @@ class Glyph(object):
|
|||||||
xCoordinates = struct.unpack(xFormat, data[:xDataLen])
|
xCoordinates = struct.unpack(xFormat, data[:xDataLen])
|
||||||
yCoordinates = struct.unpack(yFormat, data[xDataLen:xDataLen+yDataLen])
|
yCoordinates = struct.unpack(yFormat, data[xDataLen:xDataLen+yDataLen])
|
||||||
return flags, xCoordinates, yCoordinates
|
return flags, xCoordinates, yCoordinates
|
||||||
|
|
||||||
def compileComponents(self, glyfTable):
|
def compileComponents(self, glyfTable):
|
||||||
data = b""
|
data = b""
|
||||||
lastcomponent = len(self.components) - 1
|
lastcomponent = len(self.components) - 1
|
||||||
@ -544,7 +544,7 @@ class Glyph(object):
|
|||||||
instructions = self.program.getBytecode()
|
instructions = self.program.getBytecode()
|
||||||
data = data + struct.pack(">h", len(instructions)) + instructions
|
data = data + struct.pack(">h", len(instructions)) + instructions
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def compileCoordinates(self):
|
def compileCoordinates(self):
|
||||||
assert len(self.coordinates) == len(self.flags)
|
assert len(self.coordinates) == len(self.flags)
|
||||||
data = []
|
data = []
|
||||||
@ -676,7 +676,7 @@ class Glyph(object):
|
|||||||
compressedYs = compressedYs.tostring()
|
compressedYs = compressedYs.tostring()
|
||||||
|
|
||||||
return (compressedFlags, compressedXs, compressedYs)
|
return (compressedFlags, compressedXs, compressedYs)
|
||||||
|
|
||||||
def recalcBounds(self, glyfTable):
|
def recalcBounds(self, glyfTable):
|
||||||
coords, endPts, flags = self.getCoordinates(glyfTable)
|
coords, endPts, flags = self.getCoordinates(glyfTable)
|
||||||
if len(coords) > 0:
|
if len(coords) > 0:
|
||||||
@ -734,19 +734,19 @@ class Glyph(object):
|
|||||||
self.xMin, self.yMin, self.xMax, self.yMax = calcIntBounds(coords)
|
self.xMin, self.yMin, self.xMax, self.yMax = calcIntBounds(coords)
|
||||||
else:
|
else:
|
||||||
self.xMin, self.yMin, self.xMax, self.yMax = (0, 0, 0, 0)
|
self.xMin, self.yMin, self.xMax, self.yMax = (0, 0, 0, 0)
|
||||||
|
|
||||||
def isComposite(self):
|
def isComposite(self):
|
||||||
"""Can be called on compact or expanded glyph."""
|
"""Can be called on compact or expanded glyph."""
|
||||||
if hasattr(self, "data") and self.data:
|
if hasattr(self, "data") and self.data:
|
||||||
return struct.unpack(">h", self.data[:2])[0] == -1
|
return struct.unpack(">h", self.data[:2])[0] == -1
|
||||||
else:
|
else:
|
||||||
return self.numberOfContours == -1
|
return self.numberOfContours == -1
|
||||||
|
|
||||||
def __getitem__(self, componentIndex):
|
def __getitem__(self, componentIndex):
|
||||||
if not self.isComposite():
|
if not self.isComposite():
|
||||||
raise ttLib.TTLibError("can't use glyph as sequence")
|
raise ttLib.TTLibError("can't use glyph as sequence")
|
||||||
return self.components[componentIndex]
|
return self.components[componentIndex]
|
||||||
|
|
||||||
def getCoordinates(self, glyfTable):
|
def getCoordinates(self, glyfTable):
|
||||||
if self.numberOfContours > 0:
|
if self.numberOfContours > 0:
|
||||||
return self.coordinates, self.endPtsOfContours, self.flags
|
return self.coordinates, self.endPtsOfContours, self.flags
|
||||||
@ -765,7 +765,7 @@ class Glyph(object):
|
|||||||
move = x1-x2, y1-y2
|
move = x1-x2, y1-y2
|
||||||
else:
|
else:
|
||||||
move = compo.x, compo.y
|
move = compo.x, compo.y
|
||||||
|
|
||||||
coordinates = GlyphCoordinates(coordinates)
|
coordinates = GlyphCoordinates(coordinates)
|
||||||
if not hasattr(compo, "transform"):
|
if not hasattr(compo, "transform"):
|
||||||
coordinates.translate(move)
|
coordinates.translate(move)
|
||||||
@ -962,14 +962,14 @@ class Glyph(object):
|
|||||||
|
|
||||||
|
|
||||||
class GlyphComponent(object):
|
class GlyphComponent(object):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def getComponentInfo(self):
|
def getComponentInfo(self):
|
||||||
"""Return the base glyph name and a transform."""
|
"""Return the base glyph name and a transform."""
|
||||||
# XXX Ignoring self.firstPt & self.lastpt for now: I need to implement
|
# 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).
|
# convert it to an absolute offset, since it is valuable information).
|
||||||
# This method will now raise "AttributeError: x" on glyphs that use
|
# This method will now raise "AttributeError: x" on glyphs that use
|
||||||
# this TT feature.
|
# this TT feature.
|
||||||
@ -979,7 +979,7 @@ class GlyphComponent(object):
|
|||||||
else:
|
else:
|
||||||
trans = (1, 0, 0, 1, self.x, self.y)
|
trans = (1, 0, 0, 1, self.x, self.y)
|
||||||
return self.glyphName, trans
|
return self.glyphName, trans
|
||||||
|
|
||||||
def decompile(self, data, glyfTable):
|
def decompile(self, data, glyfTable):
|
||||||
flags, glyphID = struct.unpack(">HH", data[:4])
|
flags, glyphID = struct.unpack(">HH", data[:4])
|
||||||
self.flags = int(flags)
|
self.flags = int(flags)
|
||||||
@ -987,7 +987,7 @@ class GlyphComponent(object):
|
|||||||
self.glyphName = glyfTable.getGlyphName(int(glyphID))
|
self.glyphName = glyfTable.getGlyphName(int(glyphID))
|
||||||
#print ">>", reprflag(self.flags)
|
#print ">>", reprflag(self.flags)
|
||||||
data = data[4:]
|
data = data[4:]
|
||||||
|
|
||||||
if self.flags & ARG_1_AND_2_ARE_WORDS:
|
if self.flags & ARG_1_AND_2_ARE_WORDS:
|
||||||
if self.flags & ARGS_ARE_XY_VALUES:
|
if self.flags & ARGS_ARE_XY_VALUES:
|
||||||
self.x, self.y = struct.unpack(">hh", data[:4])
|
self.x, self.y = struct.unpack(">hh", data[:4])
|
||||||
@ -1002,7 +1002,7 @@ class GlyphComponent(object):
|
|||||||
x, y = struct.unpack(">BB", data[:2])
|
x, y = struct.unpack(">BB", data[:2])
|
||||||
self.firstPt, self.secondPt = int(x), int(y)
|
self.firstPt, self.secondPt = int(x), int(y)
|
||||||
data = data[2:]
|
data = data[2:]
|
||||||
|
|
||||||
if self.flags & WE_HAVE_A_SCALE:
|
if self.flags & WE_HAVE_A_SCALE:
|
||||||
scale, = struct.unpack(">h", data[:2])
|
scale, = struct.unpack(">h", data[:2])
|
||||||
self.transform = [[fi2fl(scale,14), 0], [0, fi2fl(scale,14)]] # fixed 2.14
|
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
|
self.transform = [[fi2fl(xscale,14), 0], [0, fi2fl(yscale,14)]] # fixed 2.14
|
||||||
data = data[4:]
|
data = data[4:]
|
||||||
elif self.flags & WE_HAVE_A_TWO_BY_TWO:
|
elif self.flags & WE_HAVE_A_TWO_BY_TWO:
|
||||||
(xscale, scale01,
|
(xscale, scale01,
|
||||||
scale10, yscale) = struct.unpack(">hhhh", data[:8])
|
scale10, yscale) = struct.unpack(">hhhh", data[:8])
|
||||||
self.transform = [[fi2fl(xscale,14), fi2fl(scale01,14)],
|
self.transform = [[fi2fl(xscale,14), fi2fl(scale01,14)],
|
||||||
[fi2fl(scale10,14), fi2fl(yscale,14)]] # fixed 2.14
|
[fi2fl(scale10,14), fi2fl(yscale,14)]] # fixed 2.14
|
||||||
data = data[8:]
|
data = data[8:]
|
||||||
more = self.flags & MORE_COMPONENTS
|
more = self.flags & MORE_COMPONENTS
|
||||||
haveInstructions = self.flags & WE_HAVE_INSTRUCTIONS
|
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 |
|
SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET |
|
||||||
NON_OVERLAPPING)
|
NON_OVERLAPPING)
|
||||||
return more, haveInstructions, data
|
return more, haveInstructions, data
|
||||||
|
|
||||||
def compile(self, more, haveInstructions, glyfTable):
|
def compile(self, more, haveInstructions, glyfTable):
|
||||||
data = b""
|
data = b""
|
||||||
|
|
||||||
# reset all flags we will calculate ourselves
|
# 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 |
|
SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET |
|
||||||
NON_OVERLAPPING)
|
NON_OVERLAPPING)
|
||||||
if more:
|
if more:
|
||||||
flags = flags | MORE_COMPONENTS
|
flags = flags | MORE_COMPONENTS
|
||||||
if haveInstructions:
|
if haveInstructions:
|
||||||
flags = flags | WE_HAVE_INSTRUCTIONS
|
flags = flags | WE_HAVE_INSTRUCTIONS
|
||||||
|
|
||||||
if hasattr(self, "firstPt"):
|
if hasattr(self, "firstPt"):
|
||||||
if (0 <= self.firstPt <= 255) and (0 <= self.secondPt <= 255):
|
if (0 <= self.firstPt <= 255) and (0 <= self.secondPt <= 255):
|
||||||
data = data + struct.pack(">BB", self.firstPt, self.secondPt)
|
data = data + struct.pack(">BB", self.firstPt, self.secondPt)
|
||||||
@ -1049,33 +1049,33 @@ class GlyphComponent(object):
|
|||||||
else:
|
else:
|
||||||
data = data + struct.pack(">hh", self.x, self.y)
|
data = data + struct.pack(">hh", self.x, self.y)
|
||||||
flags = flags | ARG_1_AND_2_ARE_WORDS
|
flags = flags | ARG_1_AND_2_ARE_WORDS
|
||||||
|
|
||||||
if hasattr(self, "transform"):
|
if hasattr(self, "transform"):
|
||||||
transform = [[fl2fi(x,14) for x in row] for row in self.transform]
|
transform = [[fl2fi(x,14) for x in row] for row in self.transform]
|
||||||
if transform[0][1] or transform[1][0]:
|
if transform[0][1] or transform[1][0]:
|
||||||
flags = flags | WE_HAVE_A_TWO_BY_TWO
|
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[0][0], transform[0][1],
|
||||||
transform[1][0], transform[1][1])
|
transform[1][0], transform[1][1])
|
||||||
elif transform[0][0] != transform[1][1]:
|
elif transform[0][0] != transform[1][1]:
|
||||||
flags = flags | WE_HAVE_AN_X_AND_Y_SCALE
|
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])
|
transform[0][0], transform[1][1])
|
||||||
else:
|
else:
|
||||||
flags = flags | WE_HAVE_A_SCALE
|
flags = flags | WE_HAVE_A_SCALE
|
||||||
data = data + struct.pack(">h",
|
data = data + struct.pack(">h",
|
||||||
transform[0][0])
|
transform[0][0])
|
||||||
|
|
||||||
glyphID = glyfTable.getGlyphID(self.glyphName)
|
glyphID = glyfTable.getGlyphID(self.glyphName)
|
||||||
return struct.pack(">HH", flags, glyphID) + data
|
return struct.pack(">HH", flags, glyphID) + data
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
attrs = [("glyphName", self.glyphName)]
|
attrs = [("glyphName", self.glyphName)]
|
||||||
if not hasattr(self, "firstPt"):
|
if not hasattr(self, "firstPt"):
|
||||||
attrs = attrs + [("x", self.x), ("y", self.y)]
|
attrs = attrs + [("x", self.x), ("y", self.y)]
|
||||||
else:
|
else:
|
||||||
attrs = attrs + [("firstPt", self.firstPt), ("secondPt", self.secondPt)]
|
attrs = attrs + [("firstPt", self.firstPt), ("secondPt", self.secondPt)]
|
||||||
|
|
||||||
if hasattr(self, "transform"):
|
if hasattr(self, "transform"):
|
||||||
transform = self.transform
|
transform = self.transform
|
||||||
if transform[0][1] or transform[1][0]:
|
if transform[0][1] or transform[1][0]:
|
||||||
@ -1092,7 +1092,7 @@ class GlyphComponent(object):
|
|||||||
attrs = attrs + [("flags", hex(self.flags))]
|
attrs = attrs + [("flags", hex(self.flags))]
|
||||||
writer.simpletag("component", attrs)
|
writer.simpletag("component", attrs)
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
self.glyphName = attrs["glyphName"]
|
self.glyphName = attrs["glyphName"]
|
||||||
if "firstPt" in attrs:
|
if "firstPt" in attrs:
|
||||||
@ -1115,7 +1115,7 @@ class GlyphComponent(object):
|
|||||||
scale = safeEval(attrs["scale"])
|
scale = safeEval(attrs["scale"])
|
||||||
self.transform = [[scale, 0], [0, scale]]
|
self.transform = [[scale, 0], [0, scale]]
|
||||||
self.flags = safeEval(attrs["flags"])
|
self.flags = safeEval(attrs["flags"])
|
||||||
|
|
||||||
def __ne__(self, other):
|
def __ne__(self, other):
|
||||||
return not self.__eq__(other)
|
return not self.__eq__(other)
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
|
@ -11,7 +11,7 @@ hdmxHeaderFormat = """
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
class table__h_d_m_x(DefaultTable.DefaultTable):
|
class table__h_d_m_x(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
numGlyphs = ttFont['maxp'].numGlyphs
|
numGlyphs = ttFont['maxp'].numGlyphs
|
||||||
glyphOrder = ttFont.getGlyphOrder()
|
glyphOrder = ttFont.getGlyphOrder()
|
||||||
@ -26,7 +26,7 @@ class table__h_d_m_x(DefaultTable.DefaultTable):
|
|||||||
self.hdmx[ppem] = widths
|
self.hdmx[ppem] = widths
|
||||||
data = data[self.recordSize:]
|
data = data[self.recordSize:]
|
||||||
assert len(data) == 0, "too much hdmx data"
|
assert len(data) == 0, "too much hdmx data"
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
self.version = 0
|
self.version = 0
|
||||||
numGlyphs = ttFont['maxp'].numGlyphs
|
numGlyphs = ttFont['maxp'].numGlyphs
|
||||||
@ -43,7 +43,7 @@ class table__h_d_m_x(DefaultTable.DefaultTable):
|
|||||||
data = data + bytechr(width)
|
data = data + bytechr(width)
|
||||||
data = data + pad
|
data = data + pad
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
writer.begintag("hdmxData")
|
writer.begintag("hdmxData")
|
||||||
writer.newline()
|
writer.newline()
|
||||||
@ -72,7 +72,7 @@ class table__h_d_m_x(DefaultTable.DefaultTable):
|
|||||||
writer.newline()
|
writer.newline()
|
||||||
writer.endtag("hdmxData")
|
writer.endtag("hdmxData")
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
if name != "hdmxData":
|
if name != "hdmxData":
|
||||||
return
|
return
|
||||||
|
@ -30,9 +30,9 @@ headFormat = """
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
class table__h_e_a_d(DefaultTable.DefaultTable):
|
class table__h_e_a_d(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
dependencies = ['maxp', 'loca']
|
dependencies = ['maxp', 'loca']
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
dummy, rest = sstruct.unpack2(headFormat, data, self)
|
dummy, rest = sstruct.unpack2(headFormat, data, self)
|
||||||
if rest:
|
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)
|
warnings.warn("'%s' timestamp seems very low; regarding as unix timestamp" % stamp)
|
||||||
value += 0x7C259DC0
|
value += 0x7C259DC0
|
||||||
setattr(self, stamp, value)
|
setattr(self, stamp, value)
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
if ttFont.recalcTimestamp:
|
if ttFont.recalcTimestamp:
|
||||||
self.modified = timestampNow()
|
self.modified = timestampNow()
|
||||||
data = sstruct.pack(headFormat, self)
|
data = sstruct.pack(headFormat, self)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
writer.comment("Most of this table will be recalculated by the compiler")
|
writer.comment("Most of this table will be recalculated by the compiler")
|
||||||
writer.newline()
|
writer.newline()
|
||||||
@ -80,7 +80,7 @@ class table__h_e_a_d(DefaultTable.DefaultTable):
|
|||||||
value = num2binary(value, 16)
|
value = num2binary(value, 16)
|
||||||
writer.simpletag(name, value=value)
|
writer.simpletag(name, value=value)
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
value = attrs["value"]
|
value = attrs["value"]
|
||||||
if name in ("created", "modified"):
|
if name in ("created", "modified"):
|
||||||
|
@ -31,15 +31,15 @@ class table__h_h_e_a(DefaultTable.DefaultTable):
|
|||||||
# Note: Keep in sync with table__v_h_e_a
|
# Note: Keep in sync with table__v_h_e_a
|
||||||
|
|
||||||
dependencies = ['hmtx', 'glyf']
|
dependencies = ['hmtx', 'glyf']
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
sstruct.unpack(hheaFormat, data, self)
|
sstruct.unpack(hheaFormat, data, self)
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
if ttFont.isLoaded('glyf') and ttFont.recalcBBoxes:
|
if ttFont.isLoaded('glyf') and ttFont.recalcBBoxes:
|
||||||
self.recalc(ttFont)
|
self.recalc(ttFont)
|
||||||
return sstruct.pack(hheaFormat, self)
|
return sstruct.pack(hheaFormat, self)
|
||||||
|
|
||||||
def recalc(self, ttFont):
|
def recalc(self, ttFont):
|
||||||
hmtxTable = ttFont['hmtx']
|
hmtxTable = ttFont['hmtx']
|
||||||
if 'glyf' in ttFont:
|
if 'glyf' in ttFont:
|
||||||
@ -79,13 +79,13 @@ class table__h_h_e_a(DefaultTable.DefaultTable):
|
|||||||
else:
|
else:
|
||||||
# XXX CFF recalc...
|
# XXX CFF recalc...
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
formatstring, names, fixes = sstruct.getformat(hheaFormat)
|
formatstring, names, fixes = sstruct.getformat(hheaFormat)
|
||||||
for name in names:
|
for name in names:
|
||||||
value = getattr(self, name)
|
value = getattr(self, name)
|
||||||
writer.simpletag(name, value=value)
|
writer.simpletag(name, value=value)
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
setattr(self, name, safeEval(attrs["value"]))
|
setattr(self, name, safeEval(attrs["value"]))
|
||||||
|
@ -8,12 +8,12 @@ import warnings
|
|||||||
|
|
||||||
|
|
||||||
class table__h_m_t_x(DefaultTable.DefaultTable):
|
class table__h_m_t_x(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
headerTag = 'hhea'
|
headerTag = 'hhea'
|
||||||
advanceName = 'width'
|
advanceName = 'width'
|
||||||
sideBearingName = 'lsb'
|
sideBearingName = 'lsb'
|
||||||
numberOfMetricsName = 'numberOfHMetrics'
|
numberOfMetricsName = 'numberOfHMetrics'
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
numGlyphs = ttFont['maxp'].numGlyphs
|
numGlyphs = ttFont['maxp'].numGlyphs
|
||||||
numberOfMetrics = int(getattr(ttFont[self.headerTag], self.numberOfMetricsName))
|
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):
|
for i in range(numberOfSideBearings):
|
||||||
glyphName = glyphOrder[i + numberOfMetrics]
|
glyphName = glyphOrder[i + numberOfMetrics]
|
||||||
self.metrics[glyphName] = [lastAdvance, sideBearings[i]]
|
self.metrics[glyphName] = [lastAdvance, sideBearings[i]]
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
metrics = []
|
metrics = []
|
||||||
for glyphName in ttFont.getGlyphOrder():
|
for glyphName in ttFont.getGlyphOrder():
|
||||||
@ -58,7 +58,7 @@ class table__h_m_t_x(DefaultTable.DefaultTable):
|
|||||||
additionalMetrics = [sb for advance, sb in additionalMetrics]
|
additionalMetrics = [sb for advance, sb in additionalMetrics]
|
||||||
metrics = metrics[:lastIndex]
|
metrics = metrics[:lastIndex]
|
||||||
setattr(ttFont[self.headerTag], self.numberOfMetricsName, len(metrics))
|
setattr(ttFont[self.headerTag], self.numberOfMetricsName, len(metrics))
|
||||||
|
|
||||||
allMetrics = []
|
allMetrics = []
|
||||||
for item in metrics:
|
for item in metrics:
|
||||||
allMetrics.extend(item)
|
allMetrics.extend(item)
|
||||||
@ -66,36 +66,36 @@ class table__h_m_t_x(DefaultTable.DefaultTable):
|
|||||||
if sys.byteorder != "big":
|
if sys.byteorder != "big":
|
||||||
allMetrics.byteswap()
|
allMetrics.byteswap()
|
||||||
data = allMetrics.tostring()
|
data = allMetrics.tostring()
|
||||||
|
|
||||||
additionalMetrics = array.array("h", additionalMetrics)
|
additionalMetrics = array.array("h", additionalMetrics)
|
||||||
if sys.byteorder != "big":
|
if sys.byteorder != "big":
|
||||||
additionalMetrics.byteswap()
|
additionalMetrics.byteswap()
|
||||||
data = data + additionalMetrics.tostring()
|
data = data + additionalMetrics.tostring()
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
names = sorted(self.metrics.keys())
|
names = sorted(self.metrics.keys())
|
||||||
for glyphName in names:
|
for glyphName in names:
|
||||||
advance, sb = self.metrics[glyphName]
|
advance, sb = self.metrics[glyphName]
|
||||||
writer.simpletag("mtx", [
|
writer.simpletag("mtx", [
|
||||||
("name", glyphName),
|
("name", glyphName),
|
||||||
(self.advanceName, advance),
|
(self.advanceName, advance),
|
||||||
(self.sideBearingName, sb),
|
(self.sideBearingName, sb),
|
||||||
])
|
])
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
if not hasattr(self, "metrics"):
|
if not hasattr(self, "metrics"):
|
||||||
self.metrics = {}
|
self.metrics = {}
|
||||||
if name == "mtx":
|
if name == "mtx":
|
||||||
self.metrics[attrs["name"]] = [safeEval(attrs[self.advanceName]),
|
self.metrics[attrs["name"]] = [safeEval(attrs[self.advanceName]),
|
||||||
safeEval(attrs[self.sideBearingName])]
|
safeEval(attrs[self.sideBearingName])]
|
||||||
|
|
||||||
def __delitem__(self, glyphName):
|
def __delitem__(self, glyphName):
|
||||||
del self.metrics[glyphName]
|
del self.metrics[glyphName]
|
||||||
|
|
||||||
def __getitem__(self, glyphName):
|
def __getitem__(self, glyphName):
|
||||||
return self.metrics[glyphName]
|
return self.metrics[glyphName]
|
||||||
|
|
||||||
def __setitem__(self, glyphName, advance_sb_pair):
|
def __setitem__(self, glyphName, advance_sb_pair):
|
||||||
self.metrics[glyphName] = tuple(advance_sb_pair)
|
self.metrics[glyphName] = tuple(advance_sb_pair)
|
||||||
|
@ -9,13 +9,13 @@ import warnings
|
|||||||
|
|
||||||
|
|
||||||
class table__k_e_r_n(DefaultTable.DefaultTable):
|
class table__k_e_r_n(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
def getkern(self, format):
|
def getkern(self, format):
|
||||||
for subtable in self.kernTables:
|
for subtable in self.kernTables:
|
||||||
if subtable.version == format:
|
if subtable.version == format:
|
||||||
return subtable
|
return subtable
|
||||||
return None # not found
|
return None # not found
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
version, nTables = struct.unpack(">HH", data[:4])
|
version, nTables = struct.unpack(">HH", data[:4])
|
||||||
apple = False
|
apple = False
|
||||||
@ -46,7 +46,7 @@ class table__k_e_r_n(DefaultTable.DefaultTable):
|
|||||||
subtable.decompile(data[:length], ttFont)
|
subtable.decompile(data[:length], ttFont)
|
||||||
self.kernTables.append(subtable)
|
self.kernTables.append(subtable)
|
||||||
data = data[length:]
|
data = data[length:]
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
if hasattr(self, "kernTables"):
|
if hasattr(self, "kernTables"):
|
||||||
nTables = len(self.kernTables)
|
nTables = len(self.kernTables)
|
||||||
@ -61,13 +61,13 @@ class table__k_e_r_n(DefaultTable.DefaultTable):
|
|||||||
for subtable in self.kernTables:
|
for subtable in self.kernTables:
|
||||||
data = data + subtable.compile(ttFont)
|
data = data + subtable.compile(ttFont)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
writer.simpletag("version", value=self.version)
|
writer.simpletag("version", value=self.version)
|
||||||
writer.newline()
|
writer.newline()
|
||||||
for subtable in self.kernTables:
|
for subtable in self.kernTables:
|
||||||
subtable.toXML(writer, ttFont)
|
subtable.toXML(writer, ttFont)
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
if name == "version":
|
if name == "version":
|
||||||
self.version = safeEval(attrs["value"])
|
self.version = safeEval(attrs["value"])
|
||||||
@ -86,7 +86,7 @@ class table__k_e_r_n(DefaultTable.DefaultTable):
|
|||||||
|
|
||||||
|
|
||||||
class KernTable_format_0(object):
|
class KernTable_format_0(object):
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
version, length, coverage = (0,0,0)
|
version, length, coverage = (0,0,0)
|
||||||
if not self.apple:
|
if not self.apple:
|
||||||
@ -96,12 +96,12 @@ class KernTable_format_0(object):
|
|||||||
version, length, coverage = struct.unpack(">LHH", data[:8])
|
version, length, coverage = struct.unpack(">LHH", data[:8])
|
||||||
data = data[8:]
|
data = data[8:]
|
||||||
self.version, self.coverage = int(version), int(coverage)
|
self.version, self.coverage = int(version), int(coverage)
|
||||||
|
|
||||||
self.kernTable = kernTable = {}
|
self.kernTable = kernTable = {}
|
||||||
|
|
||||||
nPairs, searchRange, entrySelector, rangeShift = struct.unpack(">HHHH", data[:8])
|
nPairs, searchRange, entrySelector, rangeShift = struct.unpack(">HHHH", data[:8])
|
||||||
data = data[8:]
|
data = data[8:]
|
||||||
|
|
||||||
for k in range(nPairs):
|
for k in range(nPairs):
|
||||||
if len(data) < 6:
|
if len(data) < 6:
|
||||||
# buggy kern table
|
# buggy kern table
|
||||||
@ -113,19 +113,19 @@ class KernTable_format_0(object):
|
|||||||
kernTable[(ttFont.getGlyphName(left), ttFont.getGlyphName(right))] = value
|
kernTable[(ttFont.getGlyphName(left), ttFont.getGlyphName(right))] = value
|
||||||
if len(data):
|
if len(data):
|
||||||
warnings.warn("excess data in 'kern' subtable: %d bytes" % len(data))
|
warnings.warn("excess data in 'kern' subtable: %d bytes" % len(data))
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
nPairs = len(self.kernTable)
|
nPairs = len(self.kernTable)
|
||||||
searchRange, entrySelector, rangeShift = getSearchRange(nPairs, 6)
|
searchRange, entrySelector, rangeShift = getSearchRange(nPairs, 6)
|
||||||
data = struct.pack(">HHHH", nPairs, searchRange, entrySelector, rangeShift)
|
data = struct.pack(">HHHH", nPairs, searchRange, entrySelector, rangeShift)
|
||||||
|
|
||||||
# yeehee! (I mean, turn names into indices)
|
# yeehee! (I mean, turn names into indices)
|
||||||
getGlyphID = ttFont.getGlyphID
|
getGlyphID = ttFont.getGlyphID
|
||||||
kernTable = sorted((getGlyphID(left), getGlyphID(right), value) for ((left,right),value) in self.kernTable.items())
|
kernTable = sorted((getGlyphID(left), getGlyphID(right), value) for ((left,right),value) in self.kernTable.items())
|
||||||
for left, right, value in kernTable:
|
for left, right, value in kernTable:
|
||||||
data = data + struct.pack(">HHh", left, right, value)
|
data = data + struct.pack(">HHh", left, right, value)
|
||||||
return struct.pack(">HHH", self.version, len(data) + 6, self.coverage) + data
|
return struct.pack(">HHH", self.version, len(data) + 6, self.coverage) + data
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
writer.begintag("kernsubtable", coverage=self.coverage, format=0)
|
writer.begintag("kernsubtable", coverage=self.coverage, format=0)
|
||||||
writer.newline()
|
writer.newline()
|
||||||
@ -139,7 +139,7 @@ class KernTable_format_0(object):
|
|||||||
writer.newline()
|
writer.newline()
|
||||||
writer.endtag("kernsubtable")
|
writer.endtag("kernsubtable")
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
self.coverage = safeEval(attrs["coverage"])
|
self.coverage = safeEval(attrs["coverage"])
|
||||||
self.version = safeEval(attrs["format"])
|
self.version = safeEval(attrs["format"])
|
||||||
@ -150,28 +150,28 @@ class KernTable_format_0(object):
|
|||||||
continue
|
continue
|
||||||
name, attrs, content = element
|
name, attrs, content = element
|
||||||
self.kernTable[(attrs["l"], attrs["r"])] = safeEval(attrs["v"])
|
self.kernTable[(attrs["l"], attrs["r"])] = safeEval(attrs["v"])
|
||||||
|
|
||||||
def __getitem__(self, pair):
|
def __getitem__(self, pair):
|
||||||
return self.kernTable[pair]
|
return self.kernTable[pair]
|
||||||
|
|
||||||
def __setitem__(self, pair, value):
|
def __setitem__(self, pair, value):
|
||||||
self.kernTable[pair] = value
|
self.kernTable[pair] = value
|
||||||
|
|
||||||
def __delitem__(self, pair):
|
def __delitem__(self, pair):
|
||||||
del self.kernTable[pair]
|
del self.kernTable[pair]
|
||||||
|
|
||||||
|
|
||||||
class KernTable_format_unkown(object):
|
class KernTable_format_unkown(object):
|
||||||
|
|
||||||
def __init__(self, format):
|
def __init__(self, format):
|
||||||
self.format = format
|
self.format = format
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
self.data = data
|
self.data = data
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
return self.data
|
return self.data
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
writer.begintag("kernsubtable", format=self.format)
|
writer.begintag("kernsubtable", format=self.format)
|
||||||
writer.newline()
|
writer.newline()
|
||||||
@ -180,7 +180,7 @@ class KernTable_format_unkown(object):
|
|||||||
writer.dumphex(self.data)
|
writer.dumphex(self.data)
|
||||||
writer.endtag("kernsubtable")
|
writer.endtag("kernsubtable")
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
self.decompile(readHex(content), ttFont)
|
self.decompile(readHex(content), ttFont)
|
||||||
|
|
||||||
|
@ -6,9 +6,9 @@ import array
|
|||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
class table__l_o_c_a(DefaultTable.DefaultTable):
|
class table__l_o_c_a(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
dependencies = ['glyf']
|
dependencies = ['glyf']
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
longFormat = ttFont['head'].indexToLocFormat
|
longFormat = ttFont['head'].indexToLocFormat
|
||||||
if longFormat:
|
if longFormat:
|
||||||
@ -27,7 +27,7 @@ class table__l_o_c_a(DefaultTable.DefaultTable):
|
|||||||
if len(locations) < (ttFont['maxp'].numGlyphs + 1):
|
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))
|
warnings.warn("corrupt 'loca' table, or wrong numGlyphs in 'maxp': %d %d" % (len(locations) - 1, ttFont['maxp'].numGlyphs))
|
||||||
self.locations = locations
|
self.locations = locations
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
try:
|
try:
|
||||||
max_location = max(self.locations)
|
max_location = max(self.locations)
|
||||||
@ -45,16 +45,16 @@ class table__l_o_c_a(DefaultTable.DefaultTable):
|
|||||||
if sys.byteorder != "big":
|
if sys.byteorder != "big":
|
||||||
locations.byteswap()
|
locations.byteswap()
|
||||||
return locations.tostring()
|
return locations.tostring()
|
||||||
|
|
||||||
def set(self, locations):
|
def set(self, locations):
|
||||||
self.locations = array.array("I", locations)
|
self.locations = array.array("I", locations)
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
writer.comment("The 'loca' table will be calculated by the compiler")
|
writer.comment("The 'loca' table will be calculated by the compiler")
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def __getitem__(self, index):
|
def __getitem__(self, index):
|
||||||
return self.locations[index]
|
return self.locations[index]
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self.locations)
|
return len(self.locations)
|
||||||
|
@ -29,16 +29,16 @@ maxpFormat_1_0_add = """
|
|||||||
|
|
||||||
|
|
||||||
class table__m_a_x_p(DefaultTable.DefaultTable):
|
class table__m_a_x_p(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
dependencies = ['glyf']
|
dependencies = ['glyf']
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
dummy, data = sstruct.unpack2(maxpFormat_0_5, data, self)
|
dummy, data = sstruct.unpack2(maxpFormat_0_5, data, self)
|
||||||
self.numGlyphs = int(self.numGlyphs)
|
self.numGlyphs = int(self.numGlyphs)
|
||||||
if self.tableVersion != 0x00005000:
|
if self.tableVersion != 0x00005000:
|
||||||
dummy, data = sstruct.unpack2(maxpFormat_1_0_add, data, self)
|
dummy, data = sstruct.unpack2(maxpFormat_1_0_add, data, self)
|
||||||
assert len(data) == 0
|
assert len(data) == 0
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
if 'glyf' in ttFont:
|
if 'glyf' in ttFont:
|
||||||
if ttFont.isLoaded('glyf') and ttFont.recalcBBoxes:
|
if ttFont.isLoaded('glyf') and ttFont.recalcBBoxes:
|
||||||
@ -52,7 +52,7 @@ class table__m_a_x_p(DefaultTable.DefaultTable):
|
|||||||
if self.tableVersion == 0x00010000:
|
if self.tableVersion == 0x00010000:
|
||||||
data = data + sstruct.pack(maxpFormat_1_0_add, self)
|
data = data + sstruct.pack(maxpFormat_1_0_add, self)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def recalc(self, ttFont):
|
def recalc(self, ttFont):
|
||||||
"""Recalculate the font bounding box, and most other maxp values except
|
"""Recalculate the font bounding box, and most other maxp values except
|
||||||
for the TT instructions values. Also recalculate the value of bit 1
|
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
|
headTable.flags = headTable.flags | 0x2
|
||||||
else:
|
else:
|
||||||
headTable.flags = headTable.flags & ~0x2
|
headTable.flags = headTable.flags & ~0x2
|
||||||
|
|
||||||
def testrepr(self):
|
def testrepr(self):
|
||||||
items = sorted(self.__dict__.items())
|
items = sorted(self.__dict__.items())
|
||||||
print(". . . . . . . . .")
|
print(". . . . . . . . .")
|
||||||
for combo in items:
|
for combo in items:
|
||||||
print(" %s: %s" % combo)
|
print(" %s: %s" % combo)
|
||||||
print(". . . . . . . . .")
|
print(". . . . . . . . .")
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
if self.tableVersion != 0x00005000:
|
if self.tableVersion != 0x00005000:
|
||||||
writer.comment("Most of this table will be recalculated by the compiler")
|
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)
|
value = hex(value)
|
||||||
writer.simpletag(name, value=value)
|
writer.simpletag(name, value=value)
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
setattr(self, name, safeEval(attrs["value"]))
|
setattr(self, name, safeEval(attrs["value"]))
|
||||||
|
@ -20,7 +20,7 @@ nameRecordSize = sstruct.calcsize(nameRecordFormat)
|
|||||||
|
|
||||||
|
|
||||||
class table__n_a_m_e(DefaultTable.DefaultTable):
|
class table__n_a_m_e(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
format, n, stringOffset = struct.unpack(">HHH", data[:6])
|
format, n, stringOffset = struct.unpack(">HHH", data[:6])
|
||||||
expectedStringOffset = 6 + n * nameRecordSize
|
expectedStringOffset = 6 + n * nameRecordSize
|
||||||
@ -43,7 +43,7 @@ class table__n_a_m_e(DefaultTable.DefaultTable):
|
|||||||
# print name.__dict__
|
# print name.__dict__
|
||||||
del name.offset, name.length
|
del name.offset, name.length
|
||||||
self.names.append(name)
|
self.names.append(name)
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
if not hasattr(self, "names"):
|
if not hasattr(self, "names"):
|
||||||
# only happens when there are NO name table entries read
|
# 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])
|
stringData = bytesjoin([stringData, string])
|
||||||
data = data + sstruct.pack(nameRecordFormat, name)
|
data = data + sstruct.pack(nameRecordFormat, name)
|
||||||
return data + stringData
|
return data + stringData
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
for name in self.names:
|
for name in self.names:
|
||||||
name.toXML(writer, ttFont)
|
name.toXML(writer, ttFont)
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
if name != "namerecord":
|
if name != "namerecord":
|
||||||
return # ignore unknown tags
|
return # ignore unknown tags
|
||||||
@ -80,11 +80,11 @@ class table__n_a_m_e(DefaultTable.DefaultTable):
|
|||||||
name = NameRecord()
|
name = NameRecord()
|
||||||
self.names.append(name)
|
self.names.append(name)
|
||||||
name.fromXML(name, attrs, content, ttFont)
|
name.fromXML(name, attrs, content, ttFont)
|
||||||
|
|
||||||
def getName(self, nameID, platformID, platEncID, langID=None):
|
def getName(self, nameID, platformID, platEncID, langID=None):
|
||||||
for namerecord in self.names:
|
for namerecord in self.names:
|
||||||
if ( namerecord.nameID == nameID and
|
if ( namerecord.nameID == nameID and
|
||||||
namerecord.platformID == platformID and
|
namerecord.platformID == platformID and
|
||||||
namerecord.platEncID == platEncID):
|
namerecord.platEncID == platEncID):
|
||||||
if langID is None or namerecord.langID == langID:
|
if langID is None or namerecord.langID == langID:
|
||||||
return namerecord
|
return namerecord
|
||||||
@ -202,7 +202,7 @@ class NameRecord(object):
|
|||||||
writer.newline()
|
writer.newline()
|
||||||
writer.endtag("namerecord")
|
writer.endtag("namerecord")
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
self.nameID = safeEval(attrs["nameID"])
|
self.nameID = safeEval(attrs["nameID"])
|
||||||
self.platformID = safeEval(attrs["platformID"])
|
self.platformID = safeEval(attrs["platformID"])
|
||||||
@ -215,7 +215,7 @@ class NameRecord(object):
|
|||||||
else:
|
else:
|
||||||
# This is the inverse of write8bit...
|
# This is the inverse of write8bit...
|
||||||
self.string = s.encode("latin1")
|
self.string = s.encode("latin1")
|
||||||
|
|
||||||
def __lt__(self, other):
|
def __lt__(self, other):
|
||||||
if type(self) != type(other):
|
if type(self) != type(other):
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
@ -236,7 +236,7 @@ class NameRecord(object):
|
|||||||
getattr(other, "string", None),
|
getattr(other, "string", None),
|
||||||
)
|
)
|
||||||
return selfTuple < otherTuple
|
return selfTuple < otherTuple
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "<NameRecord NameID=%d; PlatformID=%d; LanguageID=%d>" % (
|
return "<NameRecord NameID=%d; PlatformID=%d; LanguageID=%d>" % (
|
||||||
self.nameID, self.platformID, self.langID)
|
self.nameID, self.platformID, self.langID)
|
||||||
|
@ -13,7 +13,7 @@ import array
|
|||||||
postFormat = """
|
postFormat = """
|
||||||
>
|
>
|
||||||
formatType: 16.16F
|
formatType: 16.16F
|
||||||
italicAngle: 16.16F # italic angle in degrees
|
italicAngle: 16.16F # italic angle in degrees
|
||||||
underlinePosition: h
|
underlinePosition: h
|
||||||
underlineThickness: h
|
underlineThickness: h
|
||||||
isFixedPitch: L
|
isFixedPitch: L
|
||||||
@ -27,7 +27,7 @@ postFormatSize = sstruct.calcsize(postFormat)
|
|||||||
|
|
||||||
|
|
||||||
class table__p_o_s_t(DefaultTable.DefaultTable):
|
class table__p_o_s_t(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
sstruct.unpack(postFormat, data[:postFormatSize], self)
|
sstruct.unpack(postFormat, data[:postFormatSize], self)
|
||||||
data = data[postFormatSize:]
|
data = data[postFormatSize:]
|
||||||
@ -42,7 +42,7 @@ class table__p_o_s_t(DefaultTable.DefaultTable):
|
|||||||
else:
|
else:
|
||||||
# supported format
|
# supported format
|
||||||
raise ttLib.TTLibError("'post' table format %f not supported" % self.formatType)
|
raise ttLib.TTLibError("'post' table format %f not supported" % self.formatType)
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
data = sstruct.pack(postFormat, self)
|
data = sstruct.pack(postFormat, self)
|
||||||
if self.formatType == 1.0:
|
if self.formatType == 1.0:
|
||||||
@ -57,7 +57,7 @@ class table__p_o_s_t(DefaultTable.DefaultTable):
|
|||||||
# supported format
|
# supported format
|
||||||
raise ttLib.TTLibError("'post' table format %f not supported" % self.formatType)
|
raise ttLib.TTLibError("'post' table format %f not supported" % self.formatType)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def getGlyphOrder(self):
|
def getGlyphOrder(self):
|
||||||
"""This function will get called by a ttLib.TTFont instance.
|
"""This function will get called by a ttLib.TTFont instance.
|
||||||
Do not call this function yourself, use TTFont().getGlyphOrder()
|
Do not call this function yourself, use TTFont().getGlyphOrder()
|
||||||
@ -68,10 +68,10 @@ class table__p_o_s_t(DefaultTable.DefaultTable):
|
|||||||
glyphOrder = self.glyphOrder
|
glyphOrder = self.glyphOrder
|
||||||
del self.glyphOrder
|
del self.glyphOrder
|
||||||
return glyphOrder
|
return glyphOrder
|
||||||
|
|
||||||
def decode_format_1_0(self, data, ttFont):
|
def decode_format_1_0(self, data, ttFont):
|
||||||
self.glyphOrder = standardGlyphOrder[:ttFont["maxp"].numGlyphs]
|
self.glyphOrder = standardGlyphOrder[:ttFont["maxp"].numGlyphs]
|
||||||
|
|
||||||
def decode_format_2_0(self, data, ttFont):
|
def decode_format_2_0(self, data, ttFont):
|
||||||
numGlyphs, = struct.unpack(">H", data[:2])
|
numGlyphs, = struct.unpack(">H", data[:2])
|
||||||
numGlyphs = int(numGlyphs)
|
numGlyphs = int(numGlyphs)
|
||||||
@ -103,7 +103,7 @@ class table__p_o_s_t(DefaultTable.DefaultTable):
|
|||||||
name = standardGlyphOrder[index]
|
name = standardGlyphOrder[index]
|
||||||
glyphOrder[glyphID] = name
|
glyphOrder[glyphID] = name
|
||||||
self.build_psNameMapping(ttFont)
|
self.build_psNameMapping(ttFont)
|
||||||
|
|
||||||
def build_psNameMapping(self, ttFont):
|
def build_psNameMapping(self, ttFont):
|
||||||
mapping = {}
|
mapping = {}
|
||||||
allNames = {}
|
allNames = {}
|
||||||
@ -125,12 +125,12 @@ class table__p_o_s_t(DefaultTable.DefaultTable):
|
|||||||
mapping[glyphName] = psName
|
mapping[glyphName] = psName
|
||||||
|
|
||||||
self.mapping = mapping
|
self.mapping = mapping
|
||||||
|
|
||||||
def decode_format_3_0(self, data, ttFont):
|
def decode_format_3_0(self, data, ttFont):
|
||||||
# Setting self.glyphOrder to None will cause the TTFont object
|
# Setting self.glyphOrder to None will cause the TTFont object
|
||||||
# try and construct glyph names from a Unicode cmap table.
|
# try and construct glyph names from a Unicode cmap table.
|
||||||
self.glyphOrder = None
|
self.glyphOrder = None
|
||||||
|
|
||||||
def decode_format_4_0(self, data, ttFont):
|
def decode_format_4_0(self, data, ttFont):
|
||||||
from fontTools import agl
|
from fontTools import agl
|
||||||
numGlyphs = ttFont['maxp'].numGlyphs
|
numGlyphs = ttFont['maxp'].numGlyphs
|
||||||
@ -178,7 +178,7 @@ class table__p_o_s_t(DefaultTable.DefaultTable):
|
|||||||
if sys.byteorder != "big":
|
if sys.byteorder != "big":
|
||||||
indices.byteswap()
|
indices.byteswap()
|
||||||
return struct.pack(">H", numGlyphs) + indices.tostring() + packPStrings(extraNames)
|
return struct.pack(">H", numGlyphs) + indices.tostring() + packPStrings(extraNames)
|
||||||
|
|
||||||
def encode_format_4_0(self, ttFont):
|
def encode_format_4_0(self, ttFont):
|
||||||
from fontTools import agl
|
from fontTools import agl
|
||||||
numGlyphs = ttFont['maxp'].numGlyphs
|
numGlyphs = ttFont['maxp'].numGlyphs
|
||||||
@ -235,7 +235,7 @@ class table__p_o_s_t(DefaultTable.DefaultTable):
|
|||||||
writer.dumphex(self.data)
|
writer.dumphex(self.data)
|
||||||
writer.endtag("hexdata")
|
writer.endtag("hexdata")
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
if name not in ("psNames", "extraNames", "hexdata"):
|
if name not in ("psNames", "extraNames", "hexdata"):
|
||||||
setattr(self, name, safeEval(attrs["value"]))
|
setattr(self, name, safeEval(attrs["value"]))
|
||||||
|
@ -30,14 +30,14 @@ class table__v_h_e_a(DefaultTable.DefaultTable):
|
|||||||
# Note: Keep in sync with table__h_h_e_a
|
# Note: Keep in sync with table__h_h_e_a
|
||||||
|
|
||||||
dependencies = ['vmtx', 'glyf']
|
dependencies = ['vmtx', 'glyf']
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
sstruct.unpack(vheaFormat, data, self)
|
sstruct.unpack(vheaFormat, data, self)
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
self.recalc(ttFont)
|
self.recalc(ttFont)
|
||||||
return sstruct.pack(vheaFormat, self)
|
return sstruct.pack(vheaFormat, self)
|
||||||
|
|
||||||
def recalc(self, ttFont):
|
def recalc(self, ttFont):
|
||||||
vtmxTable = ttFont['vmtx']
|
vtmxTable = ttFont['vmtx']
|
||||||
if 'glyf' in ttFont:
|
if 'glyf' in ttFont:
|
||||||
@ -77,13 +77,13 @@ class table__v_h_e_a(DefaultTable.DefaultTable):
|
|||||||
else:
|
else:
|
||||||
# XXX CFF recalc...
|
# XXX CFF recalc...
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
formatstring, names, fixes = sstruct.getformat(vheaFormat)
|
formatstring, names, fixes = sstruct.getformat(vheaFormat)
|
||||||
for name in names:
|
for name in names:
|
||||||
value = getattr(self, name)
|
value = getattr(self, name)
|
||||||
writer.simpletag(name, value=value)
|
writer.simpletag(name, value=value)
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
setattr(self, name, safeEval(attrs["value"]))
|
setattr(self, name, safeEval(attrs["value"]))
|
||||||
|
@ -5,7 +5,7 @@ from fontTools import ttLib
|
|||||||
superclass = ttLib.getTableClass("hmtx")
|
superclass = ttLib.getTableClass("hmtx")
|
||||||
|
|
||||||
class table__v_m_t_x(superclass):
|
class table__v_m_t_x(superclass):
|
||||||
|
|
||||||
headerTag = 'vhea'
|
headerTag = 'vhea'
|
||||||
advanceName = 'height'
|
advanceName = 'height'
|
||||||
sideBearingName = 'tsb'
|
sideBearingName = 'tsb'
|
||||||
|
@ -4,7 +4,7 @@ from . import DefaultTable
|
|||||||
|
|
||||||
|
|
||||||
class asciiTable(DefaultTable.DefaultTable):
|
class asciiTable(DefaultTable.DefaultTable):
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
data = tostr(self.data)
|
data = tostr(self.data)
|
||||||
# removing null bytes. XXX needed??
|
# removing null bytes. XXX needed??
|
||||||
@ -16,7 +16,7 @@ class asciiTable(DefaultTable.DefaultTable):
|
|||||||
writer.newline()
|
writer.newline()
|
||||||
writer.endtag("source")
|
writer.endtag("source")
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
lines = strjoin(content).replace("\r", "\n").split("\n")
|
lines = strjoin(content).replace("\r", "\n").split("\n")
|
||||||
self.data = tobytes("\r".join(lines[1:-1]))
|
self.data = tobytes("\r".join(lines[1:-1]))
|
||||||
|
@ -23,12 +23,12 @@ class OTLOffsetOverflowError(Exception):
|
|||||||
|
|
||||||
|
|
||||||
class BaseTTXConverter(DefaultTable):
|
class BaseTTXConverter(DefaultTable):
|
||||||
|
|
||||||
"""Generic base class for TTX table converters. It functions as an
|
"""Generic base class for TTX table converters. It functions as an
|
||||||
adapter between the TTX (ttLib actually) table model and the model
|
adapter between the TTX (ttLib actually) table model and the model
|
||||||
we use for OpenType tables, which is necessarily subtly different.
|
we use for OpenType tables, which is necessarily subtly different.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def decompile(self, data, font):
|
def decompile(self, data, font):
|
||||||
from . import otTables
|
from . import otTables
|
||||||
cachingStats = None if True else {}
|
cachingStats = None if True else {}
|
||||||
@ -51,15 +51,15 @@ class BaseTTXConverter(DefaultTable):
|
|||||||
break
|
break
|
||||||
print(v, k)
|
print(v, k)
|
||||||
print("---", len(stats))
|
print("---", len(stats))
|
||||||
|
|
||||||
def compile(self, font):
|
def compile(self, font):
|
||||||
""" Create a top-level OTFWriter for the GPOS/GSUB table.
|
""" Create a top-level OTFWriter for the GPOS/GSUB table.
|
||||||
Call the compile method for the the table
|
Call the compile method for the the table
|
||||||
for each 'converter' record in the table converter list
|
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
|
- For simple items, the write method adds a string to the
|
||||||
writer's self.items list.
|
writer's self.items list.
|
||||||
- For Struct/Table/Subtable items, it add first adds new writer to the
|
- 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.
|
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
|
This creates a tree of writers, rooted at the GUSB/GPOS writer, with
|
||||||
each writer representing a table, and the writer.items list containing
|
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
|
Traverse the flat list of tables again, calling getData each get the data in the table, now that
|
||||||
pos's and offset are known.
|
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):
|
class GlobalState(object):
|
||||||
def __init__(self, tableType):
|
def __init__(self, tableType):
|
||||||
@ -106,7 +106,7 @@ class BaseTTXConverter(DefaultTable):
|
|||||||
|
|
||||||
def toXML(self, writer, font):
|
def toXML(self, writer, font):
|
||||||
self.table.toXML2(writer, font)
|
self.table.toXML2(writer, font)
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, font):
|
def fromXML(self, name, attrs, content, font):
|
||||||
from . import otTables
|
from . import otTables
|
||||||
if not hasattr(self, "table"):
|
if not hasattr(self, "table"):
|
||||||
@ -169,7 +169,7 @@ class OTTableReader(object):
|
|||||||
value, = struct.unpack(">L", self.data[pos:newpos])
|
value, = struct.unpack(">L", self.data[pos:newpos])
|
||||||
self.pos = newpos
|
self.pos = newpos
|
||||||
return value
|
return value
|
||||||
|
|
||||||
def readTag(self):
|
def readTag(self):
|
||||||
pos = self.pos
|
pos = self.pos
|
||||||
newpos = pos + 4
|
newpos = pos + 4
|
||||||
@ -188,9 +188,9 @@ class OTTableReader(object):
|
|||||||
|
|
||||||
|
|
||||||
class OTTableWriter(object):
|
class OTTableWriter(object):
|
||||||
|
|
||||||
"""Helper class to gather and assemble data for OpenType tables."""
|
"""Helper class to gather and assemble data for OpenType tables."""
|
||||||
|
|
||||||
def __init__(self, globalState, localState=None):
|
def __init__(self, globalState, localState=None):
|
||||||
self.items = []
|
self.items = []
|
||||||
self.pos = None
|
self.pos = None
|
||||||
@ -207,7 +207,7 @@ class OTTableWriter(object):
|
|||||||
return self.localState[name]
|
return self.localState[name]
|
||||||
|
|
||||||
# assembler interface
|
# assembler interface
|
||||||
|
|
||||||
def getAllData(self):
|
def getAllData(self):
|
||||||
"""Assemble all data, including all subtables."""
|
"""Assemble all data, including all subtables."""
|
||||||
self._doneWriting()
|
self._doneWriting()
|
||||||
@ -235,7 +235,7 @@ class OTTableWriter(object):
|
|||||||
data.append(tableData)
|
data.append(tableData)
|
||||||
|
|
||||||
return bytesjoin(data)
|
return bytesjoin(data)
|
||||||
|
|
||||||
def getDataLength(self):
|
def getDataLength(self):
|
||||||
"""Return the length of this table in bytes, without subtables."""
|
"""Return the length of this table in bytes, without subtables."""
|
||||||
l = 0
|
l = 0
|
||||||
@ -248,7 +248,7 @@ class OTTableWriter(object):
|
|||||||
else:
|
else:
|
||||||
l = l + len(item)
|
l = l + len(item)
|
||||||
return l
|
return l
|
||||||
|
|
||||||
def getData(self):
|
def getData(self):
|
||||||
"""Assemble the data for this writer/table, without subtables."""
|
"""Assemble the data for this writer/table, without subtables."""
|
||||||
items = list(self.items) # make a shallow copy
|
items = list(self.items) # make a shallow copy
|
||||||
@ -256,7 +256,7 @@ class OTTableWriter(object):
|
|||||||
numItems = len(items)
|
numItems = len(items)
|
||||||
for i in range(numItems):
|
for i in range(numItems):
|
||||||
item = items[i]
|
item = items[i]
|
||||||
|
|
||||||
if hasattr(item, "getData"):
|
if hasattr(item, "getData"):
|
||||||
if item.longOffset:
|
if item.longOffset:
|
||||||
items[i] = packULong(item.pos - pos)
|
items[i] = packULong(item.pos - pos)
|
||||||
@ -271,7 +271,7 @@ class OTTableWriter(object):
|
|||||||
# overflow is within a subTable. Life is more complicated.
|
# 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.
|
# 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;
|
# 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.
|
# Get worst case by adding up all the item lengths, depth first traversal.
|
||||||
# and then report the first item that overflows a short.
|
# and then report the first item that overflows a short.
|
||||||
def getDeepItemLength(table):
|
def getDeepItemLength(table):
|
||||||
@ -282,36 +282,36 @@ class OTTableWriter(object):
|
|||||||
else:
|
else:
|
||||||
length = len(table)
|
length = len(table)
|
||||||
return length
|
return length
|
||||||
|
|
||||||
length = self.getDataLength()
|
length = self.getDataLength()
|
||||||
if hasattr(self, "sortCoverageLast") and item.name == "Coverage":
|
if hasattr(self, "sortCoverageLast") and item.name == "Coverage":
|
||||||
# Coverage is first in the item list, but last in the table list,
|
# 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.
|
# table in the following test.
|
||||||
items = items[i+1:]
|
items = items[i+1:]
|
||||||
|
|
||||||
for j in range(len(items)):
|
for j in range(len(items)):
|
||||||
item = items[j]
|
item = items[j]
|
||||||
length = length + getDeepItemLength(item)
|
length = length + getDeepItemLength(item)
|
||||||
if length > 65535:
|
if length > 65535:
|
||||||
break
|
break
|
||||||
overflowErrorRecord = self.getOverflowErrorRecord(item)
|
overflowErrorRecord = self.getOverflowErrorRecord(item)
|
||||||
|
|
||||||
raise OTLOffsetOverflowError(overflowErrorRecord)
|
raise OTLOffsetOverflowError(overflowErrorRecord)
|
||||||
|
|
||||||
return bytesjoin(items)
|
return bytesjoin(items)
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
# only works after self._doneWriting() has been called
|
# only works after self._doneWriting() has been called
|
||||||
return hash(self.items)
|
return hash(self.items)
|
||||||
|
|
||||||
def __ne__(self, other):
|
def __ne__(self, other):
|
||||||
return not self.__eq__(other)
|
return not self.__eq__(other)
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
if type(self) != type(other):
|
if type(self) != type(other):
|
||||||
return NotImplemented
|
return NotImplemented
|
||||||
return self.items == other.items
|
return self.items == other.items
|
||||||
|
|
||||||
def _doneWriting(self, internedTables=None):
|
def _doneWriting(self, internedTables=None):
|
||||||
# Convert CountData references to data string items
|
# Convert CountData references to data string items
|
||||||
# collapse duplicate table references to a unique entry
|
# collapse duplicate table references to a unique entry
|
||||||
@ -324,7 +324,7 @@ class OTTableWriter(object):
|
|||||||
internedTables = {}
|
internedTables = {}
|
||||||
items = self.items
|
items = self.items
|
||||||
iRange = list(range(len(items)))
|
iRange = list(range(len(items)))
|
||||||
|
|
||||||
if hasattr(self, "Extension"):
|
if hasattr(self, "Extension"):
|
||||||
newTree = 1
|
newTree = 1
|
||||||
else:
|
else:
|
||||||
@ -344,12 +344,12 @@ class OTTableWriter(object):
|
|||||||
else:
|
else:
|
||||||
internedTables[item] = item
|
internedTables[item] = item
|
||||||
self.items = tuple(items)
|
self.items = tuple(items)
|
||||||
|
|
||||||
def _gatherTables(self, tables=None, extTables=None, done=None):
|
def _gatherTables(self, tables=None, extTables=None, done=None):
|
||||||
# Convert table references in self.items tree to a flat
|
# Convert table references in self.items tree to a flat
|
||||||
# list of tables in depth-first traversal order.
|
# list of tables in depth-first traversal order.
|
||||||
# "tables" are OTTableWriter objects.
|
# "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.
|
# resolve duplicate references to be the last reference in the list of tables.
|
||||||
# For extension lookups, duplicate references can be merged only within the
|
# For extension lookups, duplicate references can be merged only within the
|
||||||
# writer tree under the extension lookup.
|
# writer tree under the extension lookup.
|
||||||
@ -406,9 +406,9 @@ class OTTableWriter(object):
|
|||||||
|
|
||||||
tables.append(self)
|
tables.append(self)
|
||||||
return tables, extTables
|
return tables, extTables
|
||||||
|
|
||||||
# interface for gathering data, as used by table.compile()
|
# interface for gathering data, as used by table.compile()
|
||||||
|
|
||||||
def getSubWriter(self):
|
def getSubWriter(self):
|
||||||
subwriter = self.__class__(self.globalState, self.localState)
|
subwriter = self.__class__(self.globalState, self.localState)
|
||||||
subwriter.parent = self # because some subtables have idential values, we discard
|
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.
|
# subtable writers can have more than one parent writer.
|
||||||
# But we just care about first one right now.
|
# But we just care about first one right now.
|
||||||
return subwriter
|
return subwriter
|
||||||
|
|
||||||
def writeUShort(self, value):
|
def writeUShort(self, value):
|
||||||
assert 0 <= value < 0x10000
|
assert 0 <= value < 0x10000
|
||||||
self.items.append(struct.pack(">H", value))
|
self.items.append(struct.pack(">H", value))
|
||||||
|
|
||||||
def writeShort(self, value):
|
def writeShort(self, value):
|
||||||
self.items.append(struct.pack(">h", value))
|
self.items.append(struct.pack(">h", value))
|
||||||
|
|
||||||
@ -428,30 +428,30 @@ class OTTableWriter(object):
|
|||||||
assert 0 <= value < 0x1000000
|
assert 0 <= value < 0x1000000
|
||||||
b = struct.pack(">L", value)
|
b = struct.pack(">L", value)
|
||||||
self.items.append(b[1:])
|
self.items.append(b[1:])
|
||||||
|
|
||||||
def writeLong(self, value):
|
def writeLong(self, value):
|
||||||
self.items.append(struct.pack(">l", value))
|
self.items.append(struct.pack(">l", value))
|
||||||
|
|
||||||
def writeULong(self, value):
|
def writeULong(self, value):
|
||||||
self.items.append(struct.pack(">L", value))
|
self.items.append(struct.pack(">L", value))
|
||||||
|
|
||||||
def writeTag(self, tag):
|
def writeTag(self, tag):
|
||||||
tag = Tag(tag).tobytes()
|
tag = Tag(tag).tobytes()
|
||||||
assert len(tag) == 4
|
assert len(tag) == 4
|
||||||
self.items.append(tag)
|
self.items.append(tag)
|
||||||
|
|
||||||
def writeSubTable(self, subWriter):
|
def writeSubTable(self, subWriter):
|
||||||
self.items.append(subWriter)
|
self.items.append(subWriter)
|
||||||
|
|
||||||
def writeCountReference(self, table, name):
|
def writeCountReference(self, table, name):
|
||||||
ref = CountReference(table, name)
|
ref = CountReference(table, name)
|
||||||
self.items.append(ref)
|
self.items.append(ref)
|
||||||
return ref
|
return ref
|
||||||
|
|
||||||
def writeStruct(self, format, values):
|
def writeStruct(self, format, values):
|
||||||
data = struct.pack(*(format,) + values)
|
data = struct.pack(*(format,) + values)
|
||||||
self.items.append(data)
|
self.items.append(data)
|
||||||
|
|
||||||
def writeData(self, data):
|
def writeData(self, data):
|
||||||
self.items.append(data)
|
self.items.append(data)
|
||||||
|
|
||||||
@ -528,13 +528,13 @@ class BaseTable(object):
|
|||||||
raise AttributeError(attr)
|
raise AttributeError(attr)
|
||||||
|
|
||||||
"""Generic base class for all OpenType (sub)tables."""
|
"""Generic base class for all OpenType (sub)tables."""
|
||||||
|
|
||||||
def getConverters(self):
|
def getConverters(self):
|
||||||
return self.converters
|
return self.converters
|
||||||
|
|
||||||
def getConverterByName(self, name):
|
def getConverterByName(self, name):
|
||||||
return self.convertersByName[name]
|
return self.convertersByName[name]
|
||||||
|
|
||||||
def decompile(self, reader, font):
|
def decompile(self, reader, font):
|
||||||
self.readFormat(reader)
|
self.readFormat(reader)
|
||||||
table = {}
|
table = {}
|
||||||
@ -624,19 +624,19 @@ class BaseTable(object):
|
|||||||
conv.write(writer, font, table, value)
|
conv.write(writer, font, table, value)
|
||||||
if conv.isPropagated:
|
if conv.isPropagated:
|
||||||
writer[conv.name] = value
|
writer[conv.name] = value
|
||||||
|
|
||||||
def readFormat(self, reader):
|
def readFormat(self, reader):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def writeFormat(self, writer):
|
def writeFormat(self, writer):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def postRead(self, table, font):
|
def postRead(self, table, font):
|
||||||
self.__dict__.update(table)
|
self.__dict__.update(table)
|
||||||
|
|
||||||
def preWrite(self, font):
|
def preWrite(self, font):
|
||||||
return self.__dict__.copy()
|
return self.__dict__.copy()
|
||||||
|
|
||||||
def toXML(self, xmlWriter, font, attrs=None, name=None):
|
def toXML(self, xmlWriter, font, attrs=None, name=None):
|
||||||
tableName = name if name else self.__class__.__name__
|
tableName = name if name else self.__class__.__name__
|
||||||
if attrs is None:
|
if attrs is None:
|
||||||
@ -648,7 +648,7 @@ class BaseTable(object):
|
|||||||
self.toXML2(xmlWriter, font)
|
self.toXML2(xmlWriter, font)
|
||||||
xmlWriter.endtag(tableName)
|
xmlWriter.endtag(tableName)
|
||||||
xmlWriter.newline()
|
xmlWriter.newline()
|
||||||
|
|
||||||
def toXML2(self, xmlWriter, font):
|
def toXML2(self, xmlWriter, font):
|
||||||
# Simpler variant of toXML, *only* for the top level tables (like GPOS, GSUB).
|
# 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
|
# This is because in TTX our parent writes our main tag, and in otBase.py we
|
||||||
@ -665,7 +665,7 @@ class BaseTable(object):
|
|||||||
continue
|
continue
|
||||||
value = getattr(self, conv.name)
|
value = getattr(self, conv.name)
|
||||||
conv.xmlWrite(xmlWriter, font, value, conv.name, [])
|
conv.xmlWrite(xmlWriter, font, value, conv.name, [])
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, font):
|
def fromXML(self, name, attrs, content, font):
|
||||||
try:
|
try:
|
||||||
conv = self.getConverterByName(name)
|
conv = self.getConverterByName(name)
|
||||||
@ -680,7 +680,7 @@ class BaseTable(object):
|
|||||||
seq.append(value)
|
seq.append(value)
|
||||||
else:
|
else:
|
||||||
setattr(self, conv.name, value)
|
setattr(self, conv.name, value)
|
||||||
|
|
||||||
def __ne__(self, other):
|
def __ne__(self, other):
|
||||||
return not self.__eq__(other)
|
return not self.__eq__(other)
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
@ -694,20 +694,20 @@ class BaseTable(object):
|
|||||||
|
|
||||||
|
|
||||||
class FormatSwitchingBaseTable(BaseTable):
|
class FormatSwitchingBaseTable(BaseTable):
|
||||||
|
|
||||||
"""Minor specialization of BaseTable, for tables that have multiple
|
"""Minor specialization of BaseTable, for tables that have multiple
|
||||||
formats, eg. CoverageFormat1 vs. CoverageFormat2."""
|
formats, eg. CoverageFormat1 vs. CoverageFormat2."""
|
||||||
|
|
||||||
def getConverters(self):
|
def getConverters(self):
|
||||||
return self.converters[self.Format]
|
return self.converters[self.Format]
|
||||||
|
|
||||||
def getConverterByName(self, name):
|
def getConverterByName(self, name):
|
||||||
return self.convertersByName[self.Format][name]
|
return self.convertersByName[self.Format][name]
|
||||||
|
|
||||||
def readFormat(self, reader):
|
def readFormat(self, reader):
|
||||||
self.Format = reader.readUShort()
|
self.Format = reader.readUShort()
|
||||||
assert self.Format != 0, (self, reader.pos, len(reader.data))
|
assert self.Format != 0, (self, reader.pos, len(reader.data))
|
||||||
|
|
||||||
def writeFormat(self, writer):
|
def writeFormat(self, writer):
|
||||||
writer.writeUShort(self.Format)
|
writer.writeUShort(self.Format)
|
||||||
|
|
||||||
@ -754,7 +754,7 @@ valueRecordFormatDict = _buildDict()
|
|||||||
|
|
||||||
|
|
||||||
class ValueRecordFactory(object):
|
class ValueRecordFactory(object):
|
||||||
|
|
||||||
"""Given a format code, this object convert ValueRecords."""
|
"""Given a format code, this object convert ValueRecords."""
|
||||||
|
|
||||||
def __init__(self, valueFormat):
|
def __init__(self, valueFormat):
|
||||||
@ -763,7 +763,7 @@ class ValueRecordFactory(object):
|
|||||||
if valueFormat & mask:
|
if valueFormat & mask:
|
||||||
format.append((name, isDevice, signed))
|
format.append((name, isDevice, signed))
|
||||||
self.format = format
|
self.format = format
|
||||||
|
|
||||||
def readValueRecord(self, reader, font):
|
def readValueRecord(self, reader, font):
|
||||||
format = self.format
|
format = self.format
|
||||||
if not format:
|
if not format:
|
||||||
@ -784,7 +784,7 @@ class ValueRecordFactory(object):
|
|||||||
value = None
|
value = None
|
||||||
setattr(valueRecord, name, value)
|
setattr(valueRecord, name, value)
|
||||||
return valueRecord
|
return valueRecord
|
||||||
|
|
||||||
def writeValueRecord(self, writer, font, valueRecord):
|
def writeValueRecord(self, writer, font, valueRecord):
|
||||||
for name, isDevice, signed in self.format:
|
for name, isDevice, signed in self.format:
|
||||||
value = getattr(valueRecord, name, 0)
|
value = getattr(valueRecord, name, 0)
|
||||||
@ -802,15 +802,15 @@ class ValueRecordFactory(object):
|
|||||||
|
|
||||||
|
|
||||||
class ValueRecord(object):
|
class ValueRecord(object):
|
||||||
|
|
||||||
# see ValueRecordFactory
|
# see ValueRecordFactory
|
||||||
|
|
||||||
def getFormat(self):
|
def getFormat(self):
|
||||||
format = 0
|
format = 0
|
||||||
for name in self.__dict__.keys():
|
for name in self.__dict__.keys():
|
||||||
format = format | valueRecordFormatDict[name][0]
|
format = format | valueRecordFormatDict[name][0]
|
||||||
return format
|
return format
|
||||||
|
|
||||||
def toXML(self, xmlWriter, font, valueName, attrs=None):
|
def toXML(self, xmlWriter, font, valueName, attrs=None):
|
||||||
if attrs is None:
|
if attrs is None:
|
||||||
simpleItems = []
|
simpleItems = []
|
||||||
@ -836,7 +836,7 @@ class ValueRecord(object):
|
|||||||
else:
|
else:
|
||||||
xmlWriter.simpletag(valueName, simpleItems)
|
xmlWriter.simpletag(valueName, simpleItems)
|
||||||
xmlWriter.newline()
|
xmlWriter.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, font):
|
def fromXML(self, name, attrs, content, font):
|
||||||
from . import otTables
|
from . import otTables
|
||||||
for k, v in attrs.items():
|
for k, v in attrs.items():
|
||||||
@ -852,7 +852,7 @@ class ValueRecord(object):
|
|||||||
name2, attrs2, content2 = elem2
|
name2, attrs2, content2 = elem2
|
||||||
value.fromXML(name2, attrs2, content2, font)
|
value.fromXML(name2, attrs2, content2, font)
|
||||||
setattr(self, name, value)
|
setattr(self, name, value)
|
||||||
|
|
||||||
def __ne__(self, other):
|
def __ne__(self, other):
|
||||||
return not self.__eq__(other)
|
return not self.__eq__(other)
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
|
@ -51,10 +51,10 @@ def buildConverters(tableSpec, tableNamespace):
|
|||||||
|
|
||||||
|
|
||||||
class BaseConverter(object):
|
class BaseConverter(object):
|
||||||
|
|
||||||
"""Base class for converter objects. Apart from the constructor, this
|
"""Base class for converter objects. Apart from the constructor, this
|
||||||
is an abstract class."""
|
is an abstract class."""
|
||||||
|
|
||||||
def __init__(self, name, repeat, aux, tableClass):
|
def __init__(self, name, repeat, aux, tableClass):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.repeat = repeat
|
self.repeat = repeat
|
||||||
@ -63,19 +63,19 @@ class BaseConverter(object):
|
|||||||
self.isCount = name.endswith("Count")
|
self.isCount = name.endswith("Count")
|
||||||
self.isLookupType = name.endswith("LookupType")
|
self.isLookupType = name.endswith("LookupType")
|
||||||
self.isPropagated = name in ["ClassCount", "Class2Count", "FeatureTag", "SettingsCount", "AxisCount"]
|
self.isPropagated = name in ["ClassCount", "Class2Count", "FeatureTag", "SettingsCount", "AxisCount"]
|
||||||
|
|
||||||
def read(self, reader, font, tableDict):
|
def read(self, reader, font, tableDict):
|
||||||
"""Read a value from the reader."""
|
"""Read a value from the reader."""
|
||||||
raise NotImplementedError(self)
|
raise NotImplementedError(self)
|
||||||
|
|
||||||
def write(self, writer, font, tableDict, value, repeatIndex=None):
|
def write(self, writer, font, tableDict, value, repeatIndex=None):
|
||||||
"""Write a value to the writer."""
|
"""Write a value to the writer."""
|
||||||
raise NotImplementedError(self)
|
raise NotImplementedError(self)
|
||||||
|
|
||||||
def xmlRead(self, attrs, content, font):
|
def xmlRead(self, attrs, content, font):
|
||||||
"""Read a value from XML."""
|
"""Read a value from XML."""
|
||||||
raise NotImplementedError(self)
|
raise NotImplementedError(self)
|
||||||
|
|
||||||
def xmlWrite(self, xmlWriter, font, value, name, attrs):
|
def xmlWrite(self, xmlWriter, font, value, name, attrs):
|
||||||
"""Write a value to XML."""
|
"""Write a value to XML."""
|
||||||
raise NotImplementedError(self)
|
raise NotImplementedError(self)
|
||||||
@ -191,15 +191,15 @@ class Version(BaseConverter):
|
|||||||
|
|
||||||
|
|
||||||
class Struct(BaseConverter):
|
class Struct(BaseConverter):
|
||||||
|
|
||||||
def read(self, reader, font, tableDict):
|
def read(self, reader, font, tableDict):
|
||||||
table = self.tableClass()
|
table = self.tableClass()
|
||||||
table.decompile(reader, font)
|
table.decompile(reader, font)
|
||||||
return table
|
return table
|
||||||
|
|
||||||
def write(self, writer, font, tableDict, value, repeatIndex=None):
|
def write(self, writer, font, tableDict, value, repeatIndex=None):
|
||||||
value.compile(writer, font)
|
value.compile(writer, font)
|
||||||
|
|
||||||
def xmlWrite(self, xmlWriter, font, value, name, attrs):
|
def xmlWrite(self, xmlWriter, font, value, name, attrs):
|
||||||
if value is None:
|
if value is None:
|
||||||
if attrs:
|
if attrs:
|
||||||
@ -212,7 +212,7 @@ class Struct(BaseConverter):
|
|||||||
pass # NULL table, ignore
|
pass # NULL table, ignore
|
||||||
else:
|
else:
|
||||||
value.toXML(xmlWriter, font, attrs, name=name)
|
value.toXML(xmlWriter, font, attrs, name=name)
|
||||||
|
|
||||||
def xmlRead(self, attrs, content, font):
|
def xmlRead(self, attrs, content, font):
|
||||||
if "empty" in attrs and safeEval(attrs["empty"]):
|
if "empty" in attrs and safeEval(attrs["empty"]):
|
||||||
return None
|
return None
|
||||||
@ -241,7 +241,7 @@ class Table(Struct):
|
|||||||
writer.writeULong(0)
|
writer.writeULong(0)
|
||||||
else:
|
else:
|
||||||
writer.writeUShort(0)
|
writer.writeUShort(0)
|
||||||
|
|
||||||
def read(self, reader, font, tableDict):
|
def read(self, reader, font, tableDict):
|
||||||
offset = self.readOffset(reader)
|
offset = self.readOffset(reader)
|
||||||
if offset == 0:
|
if offset == 0:
|
||||||
@ -259,7 +259,7 @@ class Table(Struct):
|
|||||||
else:
|
else:
|
||||||
table.decompile(reader, font)
|
table.decompile(reader, font)
|
||||||
return table
|
return table
|
||||||
|
|
||||||
def write(self, writer, font, tableDict, value, repeatIndex=None):
|
def write(self, writer, font, tableDict, value, repeatIndex=None):
|
||||||
if value is None:
|
if value is None:
|
||||||
self.writeNullOffset(writer)
|
self.writeNullOffset(writer)
|
||||||
@ -287,7 +287,7 @@ class SubTable(Table):
|
|||||||
|
|
||||||
|
|
||||||
class ExtSubTable(LTable, SubTable):
|
class ExtSubTable(LTable, SubTable):
|
||||||
|
|
||||||
def write(self, writer, font, tableDict, value, repeatIndex=None):
|
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.
|
writer.Extension = 1 # actually, mere presence of the field flags it as an Ext Subtable writer.
|
||||||
Table.write(self, writer, font, tableDict, value, repeatIndex)
|
Table.write(self, writer, font, tableDict, value, repeatIndex)
|
||||||
@ -329,7 +329,7 @@ class ValueRecord(ValueFormat):
|
|||||||
|
|
||||||
|
|
||||||
class DeltaValue(BaseConverter):
|
class DeltaValue(BaseConverter):
|
||||||
|
|
||||||
def read(self, reader, font, tableDict):
|
def read(self, reader, font, tableDict):
|
||||||
StartSize = tableDict["StartSize"]
|
StartSize = tableDict["StartSize"]
|
||||||
EndSize = tableDict["EndSize"]
|
EndSize = tableDict["EndSize"]
|
||||||
@ -340,7 +340,7 @@ class DeltaValue(BaseConverter):
|
|||||||
minusOffset = 1 << nBits
|
minusOffset = 1 << nBits
|
||||||
mask = (1 << nBits) - 1
|
mask = (1 << nBits) - 1
|
||||||
signMask = 1 << (nBits - 1)
|
signMask = 1 << (nBits - 1)
|
||||||
|
|
||||||
DeltaValue = []
|
DeltaValue = []
|
||||||
tmp, shift = 0, 0
|
tmp, shift = 0, 0
|
||||||
for i in range(nItems):
|
for i in range(nItems):
|
||||||
@ -352,7 +352,7 @@ class DeltaValue(BaseConverter):
|
|||||||
value = value - minusOffset
|
value = value - minusOffset
|
||||||
DeltaValue.append(value)
|
DeltaValue.append(value)
|
||||||
return DeltaValue
|
return DeltaValue
|
||||||
|
|
||||||
def write(self, writer, font, tableDict, value, repeatIndex=None):
|
def write(self, writer, font, tableDict, value, repeatIndex=None):
|
||||||
StartSize = tableDict["StartSize"]
|
StartSize = tableDict["StartSize"]
|
||||||
EndSize = tableDict["EndSize"]
|
EndSize = tableDict["EndSize"]
|
||||||
@ -363,7 +363,7 @@ class DeltaValue(BaseConverter):
|
|||||||
nBits = 1 << DeltaFormat
|
nBits = 1 << DeltaFormat
|
||||||
assert len(DeltaValue) == nItems
|
assert len(DeltaValue) == nItems
|
||||||
mask = (1 << nBits) - 1
|
mask = (1 << nBits) - 1
|
||||||
|
|
||||||
tmp, shift = 0, 16
|
tmp, shift = 0, 16
|
||||||
for value in DeltaValue:
|
for value in DeltaValue:
|
||||||
shift = shift - nBits
|
shift = shift - nBits
|
||||||
@ -373,11 +373,11 @@ class DeltaValue(BaseConverter):
|
|||||||
tmp, shift = 0, 16
|
tmp, shift = 0, 16
|
||||||
if shift != 16:
|
if shift != 16:
|
||||||
writer.writeUShort(tmp)
|
writer.writeUShort(tmp)
|
||||||
|
|
||||||
def xmlWrite(self, xmlWriter, font, value, name, attrs):
|
def xmlWrite(self, xmlWriter, font, value, name, attrs):
|
||||||
xmlWriter.simpletag(name, attrs + [("value", value)])
|
xmlWriter.simpletag(name, attrs + [("value", value)])
|
||||||
xmlWriter.newline()
|
xmlWriter.newline()
|
||||||
|
|
||||||
def xmlRead(self, attrs, content, font):
|
def xmlRead(self, attrs, content, font):
|
||||||
return safeEval(attrs["value"])
|
return safeEval(attrs["value"])
|
||||||
|
|
||||||
|
@ -33,9 +33,9 @@ class FeatureParamsCharacterVariants(FeatureParams):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
class Coverage(FormatSwitchingBaseTable):
|
class Coverage(FormatSwitchingBaseTable):
|
||||||
|
|
||||||
# manual implementation to get rid of glyphID dependencies
|
# manual implementation to get rid of glyphID dependencies
|
||||||
|
|
||||||
def postRead(self, rawTable, font):
|
def postRead(self, rawTable, font):
|
||||||
if self.Format == 1:
|
if self.Format == 1:
|
||||||
# TODO only allow glyphs that are valid?
|
# TODO only allow glyphs that are valid?
|
||||||
@ -75,7 +75,7 @@ class Coverage(FormatSwitchingBaseTable):
|
|||||||
else:
|
else:
|
||||||
assert 0, "unknown format: %s" % self.Format
|
assert 0, "unknown format: %s" % self.Format
|
||||||
del self.Format # Don't need this anymore
|
del self.Format # Don't need this anymore
|
||||||
|
|
||||||
def preWrite(self, font):
|
def preWrite(self, font):
|
||||||
glyphs = getattr(self, "glyphs", None)
|
glyphs = getattr(self, "glyphs", None)
|
||||||
if glyphs is None:
|
if glyphs is None:
|
||||||
@ -87,7 +87,7 @@ class Coverage(FormatSwitchingBaseTable):
|
|||||||
# find out whether Format 2 is more compact or not
|
# find out whether Format 2 is more compact or not
|
||||||
glyphIDs = [getGlyphID(glyphName) for glyphName in glyphs ]
|
glyphIDs = [getGlyphID(glyphName) for glyphName in glyphs ]
|
||||||
brokenOrder = sorted(glyphIDs) != glyphIDs
|
brokenOrder = sorted(glyphIDs) != glyphIDs
|
||||||
|
|
||||||
last = glyphIDs[0]
|
last = glyphIDs[0]
|
||||||
ranges = [[last]]
|
ranges = [[last]]
|
||||||
for glyphID in glyphIDs[1:]:
|
for glyphID in glyphIDs[1:]:
|
||||||
@ -96,7 +96,7 @@ class Coverage(FormatSwitchingBaseTable):
|
|||||||
ranges.append([glyphID])
|
ranges.append([glyphID])
|
||||||
last = glyphID
|
last = glyphID
|
||||||
ranges[-1].append(last)
|
ranges[-1].append(last)
|
||||||
|
|
||||||
if brokenOrder or len(ranges) * 3 < len(glyphs): # 3 words vs. 1 word
|
if brokenOrder or len(ranges) * 3 < len(glyphs): # 3 words vs. 1 word
|
||||||
# Format 2 is more compact
|
# Format 2 is more compact
|
||||||
index = 0
|
index = 0
|
||||||
@ -120,12 +120,12 @@ class Coverage(FormatSwitchingBaseTable):
|
|||||||
# fallthrough; Format 1 is more compact
|
# fallthrough; Format 1 is more compact
|
||||||
self.Format = format
|
self.Format = format
|
||||||
return rawTable
|
return rawTable
|
||||||
|
|
||||||
def toXML2(self, xmlWriter, font):
|
def toXML2(self, xmlWriter, font):
|
||||||
for glyphName in getattr(self, "glyphs", []):
|
for glyphName in getattr(self, "glyphs", []):
|
||||||
xmlWriter.simpletag("Glyph", value=glyphName)
|
xmlWriter.simpletag("Glyph", value=glyphName)
|
||||||
xmlWriter.newline()
|
xmlWriter.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, font):
|
def fromXML(self, name, attrs, content, font):
|
||||||
glyphs = getattr(self, "glyphs", None)
|
glyphs = getattr(self, "glyphs", None)
|
||||||
if glyphs is None:
|
if glyphs is None:
|
||||||
@ -161,7 +161,7 @@ class SingleSubst(FormatSwitchingBaseTable):
|
|||||||
assert 0, "unknown format: %s" % self.Format
|
assert 0, "unknown format: %s" % self.Format
|
||||||
self.mapping = mapping
|
self.mapping = mapping
|
||||||
del self.Format # Don't need this anymore
|
del self.Format # Don't need this anymore
|
||||||
|
|
||||||
def preWrite(self, font):
|
def preWrite(self, font):
|
||||||
mapping = getattr(self, "mapping", None)
|
mapping = getattr(self, "mapping", None)
|
||||||
if mapping is None:
|
if mapping is None:
|
||||||
@ -200,14 +200,14 @@ class SingleSubst(FormatSwitchingBaseTable):
|
|||||||
else:
|
else:
|
||||||
rawTable["Substitute"] = subst
|
rawTable["Substitute"] = subst
|
||||||
return rawTable
|
return rawTable
|
||||||
|
|
||||||
def toXML2(self, xmlWriter, font):
|
def toXML2(self, xmlWriter, font):
|
||||||
items = sorted(self.mapping.items())
|
items = sorted(self.mapping.items())
|
||||||
for inGlyph, outGlyph in items:
|
for inGlyph, outGlyph in items:
|
||||||
xmlWriter.simpletag("Substitution",
|
xmlWriter.simpletag("Substitution",
|
||||||
[("in", inGlyph), ("out", outGlyph)])
|
[("in", inGlyph), ("out", outGlyph)])
|
||||||
xmlWriter.newline()
|
xmlWriter.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, font):
|
def fromXML(self, name, attrs, content, font):
|
||||||
mapping = getattr(self, "mapping", None)
|
mapping = getattr(self, "mapping", None)
|
||||||
if mapping is None:
|
if mapping is None:
|
||||||
@ -217,7 +217,7 @@ class SingleSubst(FormatSwitchingBaseTable):
|
|||||||
|
|
||||||
|
|
||||||
class ClassDef(FormatSwitchingBaseTable):
|
class ClassDef(FormatSwitchingBaseTable):
|
||||||
|
|
||||||
def postRead(self, rawTable, font):
|
def postRead(self, rawTable, font):
|
||||||
classDefs = {}
|
classDefs = {}
|
||||||
glyphOrder = font.getGlyphOrder()
|
glyphOrder = font.getGlyphOrder()
|
||||||
@ -266,7 +266,7 @@ class ClassDef(FormatSwitchingBaseTable):
|
|||||||
assert 0, "unknown format: %s" % self.Format
|
assert 0, "unknown format: %s" % self.Format
|
||||||
self.classDefs = classDefs
|
self.classDefs = classDefs
|
||||||
del self.Format # Don't need this anymore
|
del self.Format # Don't need this anymore
|
||||||
|
|
||||||
def preWrite(self, font):
|
def preWrite(self, font):
|
||||||
classDefs = getattr(self, "classDefs", None)
|
classDefs = getattr(self, "classDefs", None)
|
||||||
if classDefs is None:
|
if classDefs is None:
|
||||||
@ -316,13 +316,13 @@ class ClassDef(FormatSwitchingBaseTable):
|
|||||||
rawTable = {"StartGlyph": startGlyphName, "ClassValueArray": classes}
|
rawTable = {"StartGlyph": startGlyphName, "ClassValueArray": classes}
|
||||||
self.Format = format
|
self.Format = format
|
||||||
return rawTable
|
return rawTable
|
||||||
|
|
||||||
def toXML2(self, xmlWriter, font):
|
def toXML2(self, xmlWriter, font):
|
||||||
items = sorted(self.classDefs.items())
|
items = sorted(self.classDefs.items())
|
||||||
for glyphName, cls in items:
|
for glyphName, cls in items:
|
||||||
xmlWriter.simpletag("ClassDef", [("glyph", glyphName), ("class", cls)])
|
xmlWriter.simpletag("ClassDef", [("glyph", glyphName), ("class", cls)])
|
||||||
xmlWriter.newline()
|
xmlWriter.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, font):
|
def fromXML(self, name, attrs, content, font):
|
||||||
classDefs = getattr(self, "classDefs", None)
|
classDefs = getattr(self, "classDefs", None)
|
||||||
if classDefs is None:
|
if classDefs is None:
|
||||||
@ -332,7 +332,7 @@ class ClassDef(FormatSwitchingBaseTable):
|
|||||||
|
|
||||||
|
|
||||||
class AlternateSubst(FormatSwitchingBaseTable):
|
class AlternateSubst(FormatSwitchingBaseTable):
|
||||||
|
|
||||||
def postRead(self, rawTable, font):
|
def postRead(self, rawTable, font):
|
||||||
alternates = {}
|
alternates = {}
|
||||||
if self.Format == 1:
|
if self.Format == 1:
|
||||||
@ -346,7 +346,7 @@ class AlternateSubst(FormatSwitchingBaseTable):
|
|||||||
assert 0, "unknown format: %s" % self.Format
|
assert 0, "unknown format: %s" % self.Format
|
||||||
self.alternates = alternates
|
self.alternates = alternates
|
||||||
del self.Format # Don't need this anymore
|
del self.Format # Don't need this anymore
|
||||||
|
|
||||||
def preWrite(self, font):
|
def preWrite(self, font):
|
||||||
self.Format = 1
|
self.Format = 1
|
||||||
alternates = getattr(self, "alternates", None)
|
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
|
# 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.
|
# 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.
|
# Allows packing more rules in subtable.
|
||||||
self.sortCoverageLast = 1
|
self.sortCoverageLast = 1
|
||||||
return {"Coverage": cov, "AlternateSet": alternates}
|
return {"Coverage": cov, "AlternateSet": alternates}
|
||||||
|
|
||||||
def toXML2(self, xmlWriter, font):
|
def toXML2(self, xmlWriter, font):
|
||||||
items = sorted(self.alternates.items())
|
items = sorted(self.alternates.items())
|
||||||
for glyphName, alternates in items:
|
for glyphName, alternates in items:
|
||||||
@ -383,7 +383,7 @@ class AlternateSubst(FormatSwitchingBaseTable):
|
|||||||
xmlWriter.newline()
|
xmlWriter.newline()
|
||||||
xmlWriter.endtag("AlternateSet")
|
xmlWriter.endtag("AlternateSet")
|
||||||
xmlWriter.newline()
|
xmlWriter.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, font):
|
def fromXML(self, name, attrs, content, font):
|
||||||
alternates = getattr(self, "alternates", None)
|
alternates = getattr(self, "alternates", None)
|
||||||
if alternates is None:
|
if alternates is None:
|
||||||
@ -400,7 +400,7 @@ class AlternateSubst(FormatSwitchingBaseTable):
|
|||||||
|
|
||||||
|
|
||||||
class LigatureSubst(FormatSwitchingBaseTable):
|
class LigatureSubst(FormatSwitchingBaseTable):
|
||||||
|
|
||||||
def postRead(self, rawTable, font):
|
def postRead(self, rawTable, font):
|
||||||
ligatures = {}
|
ligatures = {}
|
||||||
if self.Format == 1:
|
if self.Format == 1:
|
||||||
@ -413,7 +413,7 @@ class LigatureSubst(FormatSwitchingBaseTable):
|
|||||||
assert 0, "unknown format: %s" % self.Format
|
assert 0, "unknown format: %s" % self.Format
|
||||||
self.ligatures = ligatures
|
self.ligatures = ligatures
|
||||||
del self.Format # Don't need this anymore
|
del self.Format # Don't need this anymore
|
||||||
|
|
||||||
def preWrite(self, font):
|
def preWrite(self, font):
|
||||||
self.Format = 1
|
self.Format = 1
|
||||||
ligatures = getattr(self, "ligatures", None)
|
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
|
# 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.
|
# I don't need to calculate the change in subtabl offset due to the coverage table size.
|
||||||
# Allows packing more rules in subtable.
|
# Allows packing more rules in subtable.
|
||||||
self.sortCoverageLast = 1
|
self.sortCoverageLast = 1
|
||||||
return {"Coverage": cov, "LigatureSet": ligSets}
|
return {"Coverage": cov, "LigatureSet": ligSets}
|
||||||
|
|
||||||
def toXML2(self, xmlWriter, font):
|
def toXML2(self, xmlWriter, font):
|
||||||
items = sorted(self.ligatures.items())
|
items = sorted(self.ligatures.items())
|
||||||
for glyphName, ligSets in items:
|
for glyphName, ligSets in items:
|
||||||
@ -452,7 +452,7 @@ class LigatureSubst(FormatSwitchingBaseTable):
|
|||||||
xmlWriter.newline()
|
xmlWriter.newline()
|
||||||
xmlWriter.endtag("LigatureSet")
|
xmlWriter.endtag("LigatureSet")
|
||||||
xmlWriter.newline()
|
xmlWriter.newline()
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, font):
|
def fromXML(self, name, attrs, content, font):
|
||||||
ligatures = getattr(self, "ligatures", None)
|
ligatures = getattr(self, "ligatures", None)
|
||||||
if ligatures is None:
|
if ligatures is None:
|
||||||
@ -513,7 +513,7 @@ _equivalents = {
|
|||||||
|
|
||||||
def fixLookupOverFlows(ttf, overflowRecord):
|
def fixLookupOverFlows(ttf, overflowRecord):
|
||||||
""" Either the offset from the LookupList to a lookup overflowed, or
|
""" 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:
|
The table layout is:
|
||||||
GPSO/GUSB
|
GPSO/GUSB
|
||||||
Script List
|
Script List
|
||||||
@ -532,7 +532,7 @@ def fixLookupOverFlows(ttf, overflowRecord):
|
|||||||
SubTable[n] and contents
|
SubTable[n] and contents
|
||||||
If the offset to a lookup overflowed (SubTableIndex is None)
|
If the offset to a lookup overflowed (SubTableIndex is None)
|
||||||
we must promote the *previous* lookup to an Extension type.
|
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.
|
to an Extension Lookup type.
|
||||||
"""
|
"""
|
||||||
ok = 0
|
ok = 0
|
||||||
@ -554,7 +554,7 @@ def fixLookupOverFlows(ttf, overflowRecord):
|
|||||||
if lookupIndex < 0:
|
if lookupIndex < 0:
|
||||||
return ok
|
return ok
|
||||||
lookup = lookups[lookupIndex]
|
lookup = lookups[lookupIndex]
|
||||||
|
|
||||||
for si in range(len(lookup.SubTable)):
|
for si in range(len(lookup.SubTable)):
|
||||||
subTable = lookup.SubTable[si]
|
subTable = lookup.SubTable[si]
|
||||||
extSubTableClass = lookupTypes[overflowRecord.tableType][extType]
|
extSubTableClass = lookupTypes[overflowRecord.tableType][extType]
|
||||||
@ -570,7 +570,7 @@ def splitAlternateSubst(oldSubTable, newSubTable, overflowRecord):
|
|||||||
newSubTable.Format = oldSubTable.Format
|
newSubTable.Format = oldSubTable.Format
|
||||||
if hasattr(oldSubTable, 'sortCoverageLast'):
|
if hasattr(oldSubTable, 'sortCoverageLast'):
|
||||||
newSubTable.sortCoverageLast = oldSubTable.sortCoverageLast
|
newSubTable.sortCoverageLast = oldSubTable.sortCoverageLast
|
||||||
|
|
||||||
oldAlts = sorted(oldSubTable.alternates.items())
|
oldAlts = sorted(oldSubTable.alternates.items())
|
||||||
oldLen = len(oldAlts)
|
oldLen = len(oldAlts)
|
||||||
|
|
||||||
@ -580,7 +580,7 @@ def splitAlternateSubst(oldSubTable, newSubTable, overflowRecord):
|
|||||||
newLen = oldLen//2
|
newLen = oldLen//2
|
||||||
|
|
||||||
elif overflowRecord.itemName == 'AlternateSet':
|
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
|
# from the overflowed AlternateSet index to make sure the offset
|
||||||
# to the Coverage table doesn't overflow.
|
# to the Coverage table doesn't overflow.
|
||||||
newLen = overflowRecord.itemIndex - 1
|
newLen = overflowRecord.itemIndex - 1
|
||||||
@ -607,7 +607,7 @@ def splitLigatureSubst(oldSubTable, newSubTable, overflowRecord):
|
|||||||
newLen = oldLen//2
|
newLen = oldLen//2
|
||||||
|
|
||||||
elif overflowRecord.itemName == 'LigatureSet':
|
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
|
# from the overflowed AlternateSet index to make sure the offset
|
||||||
# to the Coverage table doesn't overflow.
|
# to the Coverage table doesn't overflow.
|
||||||
newLen = overflowRecord.itemIndex - 1
|
newLen = overflowRecord.itemIndex - 1
|
||||||
@ -647,7 +647,7 @@ splitTable = { 'GSUB': {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def fixSubTableOverFlows(ttf, overflowRecord):
|
def fixSubTableOverFlows(ttf, overflowRecord):
|
||||||
"""
|
"""
|
||||||
An offset has overflowed within a sub-table. We need to divide this subtable into smaller parts.
|
An offset has overflowed within a sub-table. We need to divide this subtable into smaller parts.
|
||||||
"""
|
"""
|
||||||
ok = 0
|
ok = 0
|
||||||
@ -694,10 +694,10 @@ def fixSubTableOverFlows(ttf, overflowRecord):
|
|||||||
def _buildClasses():
|
def _buildClasses():
|
||||||
import re
|
import re
|
||||||
from .otData import otData
|
from .otData import otData
|
||||||
|
|
||||||
formatPat = re.compile("([A-Za-z0-9]+)Format(\d+)$")
|
formatPat = re.compile("([A-Za-z0-9]+)Format(\d+)$")
|
||||||
namespace = globals()
|
namespace = globals()
|
||||||
|
|
||||||
# populate module with classes
|
# populate module with classes
|
||||||
for name, table in otData:
|
for name, table in otData:
|
||||||
baseClass = BaseTable
|
baseClass = BaseTable
|
||||||
@ -710,12 +710,12 @@ def _buildClasses():
|
|||||||
# the class doesn't exist yet, so the base implementation is used.
|
# the class doesn't exist yet, so the base implementation is used.
|
||||||
cls = type(name, (baseClass,), {})
|
cls = type(name, (baseClass,), {})
|
||||||
namespace[name] = cls
|
namespace[name] = cls
|
||||||
|
|
||||||
for base, alts in _equivalents.items():
|
for base, alts in _equivalents.items():
|
||||||
base = namespace[base]
|
base = namespace[base]
|
||||||
for alt in alts:
|
for alt in alts:
|
||||||
namespace[alt] = type(alt, (base,), {})
|
namespace[alt] = type(alt, (base,), {})
|
||||||
|
|
||||||
global lookupTypes
|
global lookupTypes
|
||||||
lookupTypes = {
|
lookupTypes = {
|
||||||
'GSUB': {
|
'GSUB': {
|
||||||
@ -753,7 +753,7 @@ def _buildClasses():
|
|||||||
featureParamTypes['ss%02d' % i] = FeatureParamsStylisticSet
|
featureParamTypes['ss%02d' % i] = FeatureParamsStylisticSet
|
||||||
for i in range(1, 99+1):
|
for i in range(1, 99+1):
|
||||||
featureParamTypes['cv%02d' % i] = FeatureParamsCharacterVariants
|
featureParamTypes['cv%02d' % i] = FeatureParamsCharacterVariants
|
||||||
|
|
||||||
# add converters to classes
|
# add converters to classes
|
||||||
from .otConverters import buildConverters
|
from .otConverters import buildConverters
|
||||||
for name, table in otData:
|
for name, table in otData:
|
||||||
|
@ -31,7 +31,7 @@ class Glyph(object):
|
|||||||
self.rawdata = rawdata
|
self.rawdata = rawdata
|
||||||
self.graphicType = graphicType
|
self.graphicType = graphicType
|
||||||
self.imageData = imageData
|
self.imageData = imageData
|
||||||
|
|
||||||
# fix self.graphicType if it is null terminated or too short
|
# fix self.graphicType if it is null terminated or too short
|
||||||
if self.graphicType is not None:
|
if self.graphicType is not None:
|
||||||
if self.graphicType[-1] == "\0":
|
if self.graphicType[-1] == "\0":
|
||||||
|
@ -199,30 +199,30 @@ def _skipWhite(data, pos):
|
|||||||
|
|
||||||
|
|
||||||
class Program(object):
|
class Program(object):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def fromBytecode(self, bytecode):
|
def fromBytecode(self, bytecode):
|
||||||
self.bytecode = array.array("B", bytecode)
|
self.bytecode = array.array("B", bytecode)
|
||||||
if hasattr(self, "assembly"):
|
if hasattr(self, "assembly"):
|
||||||
del self.assembly
|
del self.assembly
|
||||||
|
|
||||||
def fromAssembly(self, assembly):
|
def fromAssembly(self, assembly):
|
||||||
self.assembly = assembly
|
self.assembly = assembly
|
||||||
if hasattr(self, "bytecode"):
|
if hasattr(self, "bytecode"):
|
||||||
del self.bytecode
|
del self.bytecode
|
||||||
|
|
||||||
def getBytecode(self):
|
def getBytecode(self):
|
||||||
if not hasattr(self, "bytecode"):
|
if not hasattr(self, "bytecode"):
|
||||||
self._assemble()
|
self._assemble()
|
||||||
return self.bytecode.tostring()
|
return self.bytecode.tostring()
|
||||||
|
|
||||||
def getAssembly(self, preserve=False):
|
def getAssembly(self, preserve=False):
|
||||||
if not hasattr(self, "assembly"):
|
if not hasattr(self, "assembly"):
|
||||||
self._disassemble(preserve=preserve)
|
self._disassemble(preserve=preserve)
|
||||||
return self.assembly
|
return self.assembly
|
||||||
|
|
||||||
def toXML(self, writer, ttFont):
|
def toXML(self, writer, ttFont):
|
||||||
if not hasattr (ttFont, "disassembleInstructions") or ttFont.disassembleInstructions:
|
if not hasattr (ttFont, "disassembleInstructions") or ttFont.disassembleInstructions:
|
||||||
assembly = self.getAssembly()
|
assembly = self.getAssembly()
|
||||||
@ -255,7 +255,7 @@ class Program(object):
|
|||||||
writer.newline()
|
writer.newline()
|
||||||
writer.dumphex(self.getBytecode())
|
writer.dumphex(self.getBytecode())
|
||||||
writer.endtag("bytecode")
|
writer.endtag("bytecode")
|
||||||
|
|
||||||
def fromXML(self, name, attrs, content, ttFont):
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
if name == "assembly":
|
if name == "assembly":
|
||||||
self.fromAssembly(strjoin(content))
|
self.fromAssembly(strjoin(content))
|
||||||
@ -264,7 +264,7 @@ class Program(object):
|
|||||||
else:
|
else:
|
||||||
assert name == "bytecode"
|
assert name == "bytecode"
|
||||||
self.fromBytecode(readHex(content))
|
self.fromBytecode(readHex(content))
|
||||||
|
|
||||||
def _assemble(self):
|
def _assemble(self):
|
||||||
assembly = self.assembly
|
assembly = self.assembly
|
||||||
if isinstance(assembly, type([])):
|
if isinstance(assembly, type([])):
|
||||||
@ -282,7 +282,7 @@ class Program(object):
|
|||||||
if comment:
|
if comment:
|
||||||
pos = _skipWhite(assembly, pos)
|
pos = _skipWhite(assembly, pos)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
arg = arg.strip()
|
arg = arg.strip()
|
||||||
if mnemonic.startswith("INSTR"):
|
if mnemonic.startswith("INSTR"):
|
||||||
# Unknown instruction
|
# Unknown instruction
|
||||||
@ -383,11 +383,11 @@ class Program(object):
|
|||||||
push(value)
|
push(value)
|
||||||
|
|
||||||
pos = _skipWhite(assembly, pos)
|
pos = _skipWhite(assembly, pos)
|
||||||
|
|
||||||
if bytecode:
|
if bytecode:
|
||||||
assert max(bytecode) < 256 and min(bytecode) >= 0
|
assert max(bytecode) < 256 and min(bytecode) >= 0
|
||||||
self.bytecode = array.array("B", bytecode)
|
self.bytecode = array.array("B", bytecode)
|
||||||
|
|
||||||
def _disassemble(self, preserve=False):
|
def _disassemble(self, preserve=False):
|
||||||
assembly = []
|
assembly = []
|
||||||
i = 0
|
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/-"""
|
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 = Program()
|
||||||
p.fromBytecode(bc)
|
p.fromBytecode(bc)
|
||||||
asm = p.getAssembly(preserve=True)
|
asm = p.getAssembly(preserve=True)
|
||||||
|
@ -82,7 +82,7 @@ def usage():
|
|||||||
print(__doc__ % version)
|
print(__doc__ % version)
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
|
|
||||||
numberAddedRE = re.compile("#\d+$")
|
numberAddedRE = re.compile("#\d+$")
|
||||||
opentypeheaderRE = re.compile('''sfntVersion=['"]OTTO["']''')
|
opentypeheaderRE = re.compile('''sfntVersion=['"]OTTO["']''')
|
||||||
|
|
||||||
@ -262,13 +262,13 @@ def parseOptions(args):
|
|||||||
rawOptions, files = getopt.getopt(args, "ld:o:fvqht:x:sim:z:baey:")
|
rawOptions, files = getopt.getopt(args, "ld:o:fvqht:x:sim:z:baey:")
|
||||||
except getopt.GetoptError:
|
except getopt.GetoptError:
|
||||||
usage()
|
usage()
|
||||||
|
|
||||||
if not files:
|
if not files:
|
||||||
usage()
|
usage()
|
||||||
|
|
||||||
options = Options(rawOptions, len(files))
|
options = Options(rawOptions, len(files))
|
||||||
jobs = []
|
jobs = []
|
||||||
|
|
||||||
for input in files:
|
for input in files:
|
||||||
tp = guessFileType(input)
|
tp = guessFileType(input)
|
||||||
if tp in ("OTF", "TTF", "TTC", "WOFF"):
|
if tp in ("OTF", "TTF", "TTC", "WOFF"):
|
||||||
@ -286,7 +286,7 @@ def parseOptions(args):
|
|||||||
else:
|
else:
|
||||||
print('Unknown file type: "%s"' % input)
|
print('Unknown file type: "%s"' % input)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if options.outputFile:
|
if options.outputFile:
|
||||||
output = options.outputFile
|
output = options.outputFile
|
||||||
else:
|
else:
|
||||||
@ -329,7 +329,7 @@ def main(args):
|
|||||||
waitForKeyPress()
|
waitForKeyPress()
|
||||||
else:
|
else:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main(sys.argv[1:])
|
main(sys.argv[1:])
|
||||||
|
Loading…
x
Reference in New Issue
Block a user