Lots of CID work by rroberts.
git-svn-id: svn://svn.code.sf.net/p/fonttools/code/trunk@407 4cde692c-a291-49d1-8350-778aa11640f8
This commit is contained in:
parent
700df03131
commit
ed10151701
@ -1,7 +1,7 @@
|
|||||||
"""cffLib.py -- read/write tools for Adobe CFF fonts."""
|
"""cffLib.py -- read/write tools for Adobe CFF fonts."""
|
||||||
|
|
||||||
#
|
#
|
||||||
# $Id: cffLib.py,v 1.28 2003-01-03 20:56:01 jvr Exp $
|
# $Id: cffLib.py,v 1.29 2003-08-22 19:53:32 jvr Exp $
|
||||||
#
|
#
|
||||||
|
|
||||||
import struct, sstruct
|
import struct, sstruct
|
||||||
@ -10,7 +10,6 @@ from types import FloatType, ListType, StringType, TupleType
|
|||||||
from fontTools.misc import psCharStrings
|
from fontTools.misc import psCharStrings
|
||||||
from fontTools.misc.textTools import safeEval
|
from fontTools.misc.textTools import safeEval
|
||||||
|
|
||||||
|
|
||||||
DEBUG = 0
|
DEBUG = 0
|
||||||
|
|
||||||
|
|
||||||
@ -249,6 +248,44 @@ class TopDictIndexCompiler(IndexCompiler):
|
|||||||
return children
|
return children
|
||||||
|
|
||||||
|
|
||||||
|
class FDArrayIndexCompiler(IndexCompiler):
|
||||||
|
|
||||||
|
def getItems(self, items, strings):
|
||||||
|
out = []
|
||||||
|
for item in items:
|
||||||
|
out.append(item.getCompiler(strings, self))
|
||||||
|
return out
|
||||||
|
|
||||||
|
def getChildren(self, strings):
|
||||||
|
children = []
|
||||||
|
for fontDict in self.items:
|
||||||
|
children.extend(fontDict.getChildren(strings))
|
||||||
|
return children
|
||||||
|
|
||||||
|
|
||||||
|
def toFile(self, file):
|
||||||
|
offsets = self.getOffsets()
|
||||||
|
writeCard16(file, len(self.items))
|
||||||
|
offSize = calcOffSize(offsets[-1])
|
||||||
|
writeCard8(file, offSize)
|
||||||
|
offSize = -offSize
|
||||||
|
pack = struct.pack
|
||||||
|
for offset in offsets:
|
||||||
|
binOffset = pack(">l", offset)[offSize:]
|
||||||
|
assert len(binOffset) == -offSize
|
||||||
|
file.write(binOffset)
|
||||||
|
for item in self.items:
|
||||||
|
if hasattr(item, "toFile"):
|
||||||
|
item.toFile(file)
|
||||||
|
else:
|
||||||
|
file.write(item)
|
||||||
|
|
||||||
|
def setPos(self, pos, endPos):
|
||||||
|
self.parent.rawDict["FDArray"] = pos
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class GlobalSubrsCompiler(IndexCompiler):
|
class GlobalSubrsCompiler(IndexCompiler):
|
||||||
def getItems(self, items, strings):
|
def getItems(self, items, strings):
|
||||||
out = []
|
out = []
|
||||||
@ -338,13 +375,15 @@ class GlobalSubrsIndex(Index):
|
|||||||
Index.__init__(self, file)
|
Index.__init__(self, file)
|
||||||
self.globalSubrs = globalSubrs
|
self.globalSubrs = globalSubrs
|
||||||
self.private = private
|
self.private = private
|
||||||
self.fdSelect = fdSelect
|
if fdSelect:
|
||||||
self.fdArray = fdArray
|
self.fdSelect = fdSelect
|
||||||
|
if 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
|
||||||
elif self.fdArray is not None:
|
elif hasattr(self, 'fdArray') and self.fdArray is not None:
|
||||||
private = self.fdArray[self.fdSelect[index]].Private
|
private = self.fdArray[self.fdSelect[index]].Private
|
||||||
else:
|
else:
|
||||||
private = None
|
private = None
|
||||||
@ -355,9 +394,7 @@ class GlobalSubrsIndex(Index):
|
|||||||
return psCharStrings.T2CharString(data, subrs=subrs, globalSubrs=self.globalSubrs)
|
return psCharStrings.T2CharString(data, subrs=subrs, globalSubrs=self.globalSubrs)
|
||||||
|
|
||||||
def toXML(self, xmlWriter, progress):
|
def toXML(self, xmlWriter, progress):
|
||||||
fdSelect = self.fdSelect
|
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()
|
||||||
for i in range(len(self)):
|
for i in range(len(self)):
|
||||||
subr = self[i]
|
subr = self[i]
|
||||||
@ -378,11 +415,9 @@ class GlobalSubrsIndex(Index):
|
|||||||
self.append(subr)
|
self.append(subr)
|
||||||
|
|
||||||
def getItemAndSelector(self, index):
|
def getItemAndSelector(self, index):
|
||||||
fdSelect = self.fdSelect
|
sel = None
|
||||||
if fdSelect is None:
|
if hasattr(self, 'fdSelect'):
|
||||||
sel = None
|
sel = self.fdSelect[index]
|
||||||
else:
|
|
||||||
sel = fdSelect[index]
|
|
||||||
return self[index], sel
|
return self[index], sel
|
||||||
|
|
||||||
|
|
||||||
@ -408,6 +443,67 @@ class TopDictIndex(Index):
|
|||||||
xmlWriter.newline()
|
xmlWriter.newline()
|
||||||
|
|
||||||
|
|
||||||
|
class FDArrayIndex(TopDictIndex):
|
||||||
|
|
||||||
|
compilerClass = FDArrayIndexCompiler
|
||||||
|
|
||||||
|
def fromXML(self, (name, attrs, content)):
|
||||||
|
if name <> "FontDict":
|
||||||
|
return
|
||||||
|
fontDict = FontDict()
|
||||||
|
for element in content:
|
||||||
|
if isinstance(element, StringType):
|
||||||
|
continue
|
||||||
|
fontDict.fromXML(element)
|
||||||
|
self.append(fontDict)
|
||||||
|
|
||||||
|
|
||||||
|
class FDSelect:
|
||||||
|
def __init__(self, file = None, numGlyphs = None, format=None):
|
||||||
|
if file:
|
||||||
|
# read data in from file
|
||||||
|
self.format = readCard8(file)
|
||||||
|
if self.format == 0:
|
||||||
|
from array import array
|
||||||
|
self.gidArray = array("B", file.read(numGlyphs)).tolist()
|
||||||
|
elif self.format == 3:
|
||||||
|
gidArray = [None] * numGlyphs
|
||||||
|
nRanges = readCard16(file)
|
||||||
|
prev = None
|
||||||
|
for i in range(nRanges):
|
||||||
|
first = readCard16(file)
|
||||||
|
if prev is not None:
|
||||||
|
for glyphID in range(prev, first):
|
||||||
|
gidArray[glyphID] = fd
|
||||||
|
prev = first
|
||||||
|
fd = readCard8(file)
|
||||||
|
if prev is not None:
|
||||||
|
first = readCard16(file)
|
||||||
|
for glyphID in range(prev, first):
|
||||||
|
gidArray[glyphID] = fd
|
||||||
|
self.gidArray = gidArray
|
||||||
|
else:
|
||||||
|
assert 0, "unsupported FDSelect format: %s" % format
|
||||||
|
else:
|
||||||
|
# reading from XML. Make empty gidArray,, and leave format as passed in.
|
||||||
|
# format == None will result in the smallest representation being used.
|
||||||
|
self.format = format
|
||||||
|
self.gidArray = []
|
||||||
|
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.gidArray)
|
||||||
|
|
||||||
|
def __getitem__(self, index):
|
||||||
|
return self.gidArray[index]
|
||||||
|
|
||||||
|
def __setitem__(self, index, fdSelectValue):
|
||||||
|
self.gidArray[index] = fdSelectValue
|
||||||
|
|
||||||
|
def append(self, fdSelectValue):
|
||||||
|
self.gidArray.append(fdSelectValue)
|
||||||
|
|
||||||
|
|
||||||
class CharStrings:
|
class CharStrings:
|
||||||
|
|
||||||
def __init__(self, file, charset, globalSubrs, private, fdSelect, fdArray):
|
def __init__(self, file, charset, globalSubrs, private, fdSelect, fdArray):
|
||||||
@ -422,8 +518,10 @@ class CharStrings:
|
|||||||
self.charStringsAreIndexed = 0
|
self.charStringsAreIndexed = 0
|
||||||
self.globalSubrs = globalSubrs
|
self.globalSubrs = globalSubrs
|
||||||
self.private = private
|
self.private = private
|
||||||
self.fdSelect = fdSelect
|
if fdSelect != None:
|
||||||
self.fdArray = fdArray
|
self.fdSelect = fdSelect
|
||||||
|
if fdArray!= None:
|
||||||
|
self.fdArray = fdArray
|
||||||
|
|
||||||
def keys(self):
|
def keys(self):
|
||||||
return self.charStrings.keys()
|
return self.charStrings.keys()
|
||||||
@ -458,8 +556,11 @@ class CharStrings:
|
|||||||
index = self.charStrings[name]
|
index = self.charStrings[name]
|
||||||
return self.charStringsIndex.getItemAndSelector(index)
|
return self.charStringsIndex.getItemAndSelector(index)
|
||||||
else:
|
else:
|
||||||
# XXX needs work for CID fonts
|
if hasattr(self, 'fdSelect'):
|
||||||
return self.charStrings[name], None
|
sel = self.fdSelect[index]
|
||||||
|
else:
|
||||||
|
raise KeyError("fdSelect array not yet defined.")
|
||||||
|
return self.charStrings[name], sel
|
||||||
|
|
||||||
def toXML(self, xmlWriter, progress):
|
def toXML(self, xmlWriter, progress):
|
||||||
names = self.keys()
|
names = self.keys()
|
||||||
@ -468,16 +569,16 @@ class CharStrings:
|
|||||||
step = 10
|
step = 10
|
||||||
numGlyphs = len(names)
|
numGlyphs = len(names)
|
||||||
for name in names:
|
for name in names:
|
||||||
charStr, fdSelect = self.getItemAndSelector(name)
|
charStr, fdSelectIndex = self.getItemAndSelector(name)
|
||||||
if charStr.needsDecompilation():
|
if charStr.needsDecompilation():
|
||||||
raw = [("raw", 1)]
|
raw = [("raw", 1)]
|
||||||
else:
|
else:
|
||||||
raw = []
|
raw = []
|
||||||
if fdSelect is None:
|
if fdSelectIndex is None:
|
||||||
xmlWriter.begintag("CharString", [('name', name)] + raw)
|
xmlWriter.begintag("CharString", [('name', name)] + raw)
|
||||||
else:
|
else:
|
||||||
xmlWriter.begintag("CharString",
|
xmlWriter.begintag("CharString",
|
||||||
[('name', name), ('fdSelect', fdSelect)] + raw)
|
[('name', name), ('fdSelectIndex', fdSelectIndex)] + raw)
|
||||||
xmlWriter.newline()
|
xmlWriter.newline()
|
||||||
charStr.toXML(xmlWriter)
|
charStr.toXML(xmlWriter)
|
||||||
xmlWriter.endtag("CharString")
|
xmlWriter.endtag("CharString")
|
||||||
@ -494,14 +595,23 @@ class CharStrings:
|
|||||||
name, attrs, content = element
|
name, attrs, content = element
|
||||||
if name <> "CharString":
|
if name <> "CharString":
|
||||||
continue
|
continue
|
||||||
|
fdID = -1
|
||||||
|
if hasattr(self, "fdArray"):
|
||||||
|
fdID = safeEval(attrs["fdSelectIndex"])
|
||||||
|
private = self.fdArray[fdID].Private
|
||||||
|
else:
|
||||||
|
private = self.private
|
||||||
|
|
||||||
glyphName = attrs["name"]
|
glyphName = attrs["name"]
|
||||||
if hasattr(self.private, "Subrs"):
|
if hasattr(private, "Subrs"):
|
||||||
subrs = self.private.Subrs
|
subrs = private.Subrs
|
||||||
else:
|
else:
|
||||||
subrs = []
|
subrs = []
|
||||||
globalSubrs = self.globalSubrs
|
globalSubrs = self.globalSubrs
|
||||||
charString = psCharStrings.T2CharString(None, subrs=subrs, globalSubrs=globalSubrs)
|
charString = psCharStrings.T2CharString(None, subrs=subrs, globalSubrs=globalSubrs)
|
||||||
charString.fromXML((name, attrs, content))
|
charString.fromXML((name, attrs, content))
|
||||||
|
if fdID >= 0:
|
||||||
|
charString.fdSelectIndex = fdID
|
||||||
self[glyphName] = charString
|
self[glyphName] = charString
|
||||||
|
|
||||||
|
|
||||||
@ -653,9 +763,13 @@ class CharStringsConverter(TableConverter):
|
|||||||
def write(self, parent, value):
|
def write(self, parent, value):
|
||||||
return 0 # dummy value
|
return 0 # dummy value
|
||||||
def xmlRead(self, (name, attrs, content), parent):
|
def xmlRead(self, (name, attrs, content), parent):
|
||||||
# XXX needs work for CID fonts
|
if hasattr(parent, "ROS"):
|
||||||
fdSelect, fdArray = None, None
|
# if it is a CID-keyed font, then the private Dict is extracted from the parent.FDArray
|
||||||
charStrings = CharStrings(None, None, parent.GlobalSubrs, parent.Private, fdSelect, fdArray)
|
private, fdSelect, fdArray = None, parent.FDSelect, parent.FDArray
|
||||||
|
else:
|
||||||
|
# if it is a name-keyed font, then the private dict is in the top dict, and there is no fdArray.
|
||||||
|
private, fdSelect, fdArray = parent.Private, None, None
|
||||||
|
charStrings = CharStrings(None, None, parent.GlobalSubrs, private, fdSelect, fdArray)
|
||||||
charStrings.fromXML((name, attrs, content))
|
charStrings.fromXML((name, attrs, content))
|
||||||
return charStrings
|
return charStrings
|
||||||
|
|
||||||
@ -711,8 +825,9 @@ class CharsetCompiler:
|
|||||||
|
|
||||||
def __init__(self, strings, charset, parent):
|
def __init__(self, strings, charset, parent):
|
||||||
assert charset[0] == '.notdef'
|
assert charset[0] == '.notdef'
|
||||||
data0 = packCharset0(charset, strings)
|
isCID = hasattr(parent.dictObj, "ROS")
|
||||||
data = packCharset(charset, strings)
|
data0 = packCharset0(charset, isCID, strings)
|
||||||
|
data = packCharset(charset, isCID, strings)
|
||||||
if len(data) < len(data0):
|
if len(data) < len(data0):
|
||||||
self.data = data
|
self.data = data
|
||||||
else:
|
else:
|
||||||
@ -729,20 +844,37 @@ class CharsetCompiler:
|
|||||||
file.write(self.data)
|
file.write(self.data)
|
||||||
|
|
||||||
|
|
||||||
def packCharset0(charset, strings):
|
def getCIDfromName(name, strings):
|
||||||
|
return int(name[3:])
|
||||||
|
|
||||||
|
def getSIDfromName(name, strings):
|
||||||
|
return strings.getSID(name)
|
||||||
|
|
||||||
|
def packCharset0(charset, isCID, strings):
|
||||||
format = 0
|
format = 0
|
||||||
data = [packCard8(format)]
|
data = [packCard8(format)]
|
||||||
|
if isCID:
|
||||||
|
getNameID = getCIDfromName
|
||||||
|
else:
|
||||||
|
getNameID = getSIDfromName
|
||||||
|
|
||||||
for name in charset[1:]:
|
for name in charset[1:]:
|
||||||
data.append(packCard16(strings.getSID(name)))
|
data.append(packCard16(getNameID(name,strings)))
|
||||||
return "".join(data)
|
return "".join(data)
|
||||||
|
|
||||||
def packCharset(charset, strings):
|
|
||||||
|
def packCharset(charset, isCID, strings):
|
||||||
format = 1
|
format = 1
|
||||||
ranges = []
|
ranges = []
|
||||||
first = None
|
first = None
|
||||||
end = 0
|
end = 0
|
||||||
|
if isCID:
|
||||||
|
getNameID = getCIDfromName
|
||||||
|
else:
|
||||||
|
getNameID = getSIDfromName
|
||||||
|
|
||||||
for name in charset[1:]:
|
for name in charset[1:]:
|
||||||
SID = strings.getSID(name)
|
SID = getNameID(name, strings)
|
||||||
if first is None:
|
if first is None:
|
||||||
first = SID
|
first = SID
|
||||||
elif end + 1 <> SID:
|
elif end + 1 <> SID:
|
||||||
@ -785,7 +917,7 @@ def parseCharset(numGlyphs, file, strings, isCID, format):
|
|||||||
nLeft = nLeftFunc(file)
|
nLeft = nLeftFunc(file)
|
||||||
if isCID:
|
if isCID:
|
||||||
for CID in range(first, first+nLeft+1):
|
for CID in range(first, first+nLeft+1):
|
||||||
charset.append(CID)
|
charset.append("cid" + str(CID) )
|
||||||
else:
|
else:
|
||||||
for SID in range(first, first+nLeft+1):
|
for SID in range(first, first+nLeft+1):
|
||||||
charset.append(strings[SID])
|
charset.append(strings[SID])
|
||||||
@ -956,53 +1088,127 @@ def packEncoding1(charset, encoding, strings):
|
|||||||
|
|
||||||
|
|
||||||
class FDArrayConverter(TableConverter):
|
class FDArrayConverter(TableConverter):
|
||||||
|
|
||||||
def read(self, parent, value):
|
def read(self, parent, value):
|
||||||
file = parent.file
|
file = parent.file
|
||||||
file.seek(value)
|
file.seek(value)
|
||||||
fdArray = TopDictIndex(file)
|
fdArray = FDArrayIndex(file)
|
||||||
fdArray.strings = parent.strings
|
fdArray.strings = parent.strings
|
||||||
fdArray.GlobalSubrs = parent.GlobalSubrs
|
fdArray.GlobalSubrs = parent.GlobalSubrs
|
||||||
return fdArray
|
return fdArray
|
||||||
|
|
||||||
|
def write(self, parent, value):
|
||||||
|
return 0 # dummy value
|
||||||
|
|
||||||
|
def xmlRead(self, (name, attrs, content), parent):
|
||||||
|
fdArray = FDArrayIndex()
|
||||||
|
for element in content:
|
||||||
|
if isinstance(element, StringType):
|
||||||
|
continue
|
||||||
|
fdArray.fromXML(element)
|
||||||
|
return fdArray
|
||||||
|
|
||||||
|
|
||||||
class FDSelectConverter:
|
class FDSelectConverter:
|
||||||
|
|
||||||
def read(self, parent, value):
|
def read(self, parent, value):
|
||||||
file = parent.file
|
file = parent.file
|
||||||
file.seek(value)
|
file.seek(value)
|
||||||
format = readCard8(file)
|
fdSelect = FDSelect(file, parent.numGlyphs)
|
||||||
numGlyphs = parent.numGlyphs
|
return fdSelect
|
||||||
if format == 0:
|
|
||||||
from array import array
|
def write(self, parent, value):
|
||||||
fdSelect = array("B", file.read(numGlyphs)).tolist()
|
return 0 # dummy value
|
||||||
elif format == 3:
|
|
||||||
fdSelect = [None] * numGlyphs
|
# The FDSelect glyph data is written out to XML in the charstring keys,
|
||||||
nRanges = readCard16(file)
|
# so we write out only the format selector
|
||||||
prev = None
|
|
||||||
for i in range(nRanges):
|
|
||||||
first = readCard16(file)
|
|
||||||
if prev is not None:
|
|
||||||
for glyphID in range(prev, first):
|
|
||||||
fdSelect[glyphID] = fd
|
|
||||||
prev = first
|
|
||||||
fd = readCard8(file)
|
|
||||||
if prev is not None:
|
|
||||||
first = readCard16(file)
|
|
||||||
for glyphID in range(prev, first):
|
|
||||||
fdSelect[glyphID] = fd
|
|
||||||
else:
|
|
||||||
assert 0, "unsupported FDSelect format: %s" % format
|
|
||||||
return fdSelect
|
|
||||||
def xmlWrite(self, xmlWriter, name, value, progress):
|
def xmlWrite(self, xmlWriter, name, value, progress):
|
||||||
pass
|
xmlWriter.simpletag(name, [('format', value.format)])
|
||||||
|
xmlWriter.newline()
|
||||||
|
|
||||||
|
def xmlRead(self, (name, attrs, content), parent):
|
||||||
|
format = safeEval(attrs["format"])
|
||||||
|
file = None
|
||||||
|
numGlyphs = None
|
||||||
|
fdSelect = FDSelect(file, numGlyphs, format)
|
||||||
|
return fdSelect
|
||||||
|
|
||||||
|
|
||||||
|
def packFDSelect0(fdSelectArray):
|
||||||
|
format = 0
|
||||||
|
data = [packCard8(format)]
|
||||||
|
for index in fdSelectArray:
|
||||||
|
data.append(packCard8(index))
|
||||||
|
return "".join(data)
|
||||||
|
|
||||||
|
|
||||||
|
def packFDSelect3(fdSelectArray):
|
||||||
|
format = 3
|
||||||
|
fdRanges = []
|
||||||
|
first = None
|
||||||
|
end = 0
|
||||||
|
lenArray = len(fdSelectArray)
|
||||||
|
lastFDIndex = -1
|
||||||
|
for i in range(lenArray):
|
||||||
|
fdIndex = fdSelectArray[i]
|
||||||
|
if lastFDIndex != fdIndex:
|
||||||
|
fdRanges.append([i, fdIndex])
|
||||||
|
lastFDIndex = fdIndex
|
||||||
|
sentinelGID = i + 1
|
||||||
|
|
||||||
|
data = [packCard8(format)]
|
||||||
|
data.append(packCard16( len(fdRanges) ))
|
||||||
|
for fdRange in fdRanges:
|
||||||
|
data.append(packCard16(fdRange[0]))
|
||||||
|
data.append(packCard8(fdRange[1]))
|
||||||
|
data.append(packCard16(sentinelGID))
|
||||||
|
return "".join(data)
|
||||||
|
|
||||||
|
|
||||||
|
class FDSelectCompiler:
|
||||||
|
|
||||||
|
def __init__(self, fdSelect, parent):
|
||||||
|
format = fdSelect.format
|
||||||
|
fdSelectArray = fdSelect.gidArray
|
||||||
|
if format == 0:
|
||||||
|
self.data = packFDSelect0(fdSelectArray)
|
||||||
|
elif format == 3:
|
||||||
|
self.data = packFDSelect3(fdSelectArray)
|
||||||
|
else:
|
||||||
|
# choose smaller of the two formats
|
||||||
|
data0 = packFDSelect0(fdSelectArray)
|
||||||
|
data3 = packFDSelect3(fdSelectArray)
|
||||||
|
if len(data0) < len(data3):
|
||||||
|
self.data = data0
|
||||||
|
fdSelect.format = 0
|
||||||
|
else:
|
||||||
|
self.data = data3
|
||||||
|
fdSelect.format = 3
|
||||||
|
|
||||||
|
self.parent = parent
|
||||||
|
|
||||||
|
def setPos(self, pos, endPos):
|
||||||
|
self.parent.rawDict["FDSelect"] = pos
|
||||||
|
|
||||||
|
def getDataLength(self):
|
||||||
|
return len(self.data)
|
||||||
|
|
||||||
|
def toFile(self, file):
|
||||||
|
file.write(self.data)
|
||||||
|
|
||||||
|
|
||||||
class ROSConverter(SimpleConverter):
|
class ROSConverter(SimpleConverter):
|
||||||
|
|
||||||
def xmlWrite(self, xmlWriter, name, value, progress):
|
def xmlWrite(self, xmlWriter, name, value, progress):
|
||||||
registry, order, supplement = value
|
registry, order, supplement = value
|
||||||
xmlWriter.simpletag(name, [('Registry', registry), ('Order', order),
|
xmlWriter.simpletag(name, [('Registry', registry), ('Order', order),
|
||||||
('Supplement', supplement)])
|
('Supplement', supplement)])
|
||||||
xmlWriter.newline()
|
xmlWriter.newline()
|
||||||
|
|
||||||
|
def xmlRead(self, (name, attrs, content), parent):
|
||||||
|
return (attrs['Registry'], attrs['Order'], safeEval(attrs['Supplement']))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
topDictOperators = [
|
topDictOperators = [
|
||||||
# opcode name argument type default converter
|
# opcode name argument type default converter
|
||||||
@ -1026,7 +1232,6 @@ topDictOperators = [
|
|||||||
(5, 'FontBBox', 'array', [0,0,0,0], None),
|
(5, 'FontBBox', 'array', [0,0,0,0], None),
|
||||||
((12, 8), 'StrokeWidth', 'number', 0, None),
|
((12, 8), 'StrokeWidth', 'number', 0, None),
|
||||||
(14, 'XUID', 'array', None, None),
|
(14, 'XUID', 'array', None, None),
|
||||||
(15, 'charset', 'number', 0, CharsetConverter()),
|
|
||||||
((12, 21), 'PostScript', 'SID', None, None),
|
((12, 21), 'PostScript', 'SID', None, None),
|
||||||
((12, 22), 'BaseFontName', 'SID', None, None),
|
((12, 22), 'BaseFontName', 'SID', None, None),
|
||||||
((12, 23), 'BaseFontBlend', 'delta', None, None),
|
((12, 23), 'BaseFontBlend', 'delta', None, None),
|
||||||
@ -1034,14 +1239,19 @@ topDictOperators = [
|
|||||||
((12, 32), 'CIDFontRevision', 'number', 0, None),
|
((12, 32), 'CIDFontRevision', 'number', 0, None),
|
||||||
((12, 33), 'CIDFontType', 'number', 0, None),
|
((12, 33), 'CIDFontType', 'number', 0, None),
|
||||||
((12, 34), 'CIDCount', 'number', 8720, None),
|
((12, 34), 'CIDCount', 'number', 8720, None),
|
||||||
|
(15, 'charset', 'number', 0, CharsetConverter()),
|
||||||
((12, 35), 'UIDBase', 'number', None, None),
|
((12, 35), 'UIDBase', 'number', None, None),
|
||||||
(16, 'Encoding', 'number', 0, EncodingConverter()),
|
(16, 'Encoding', 'number', 0, EncodingConverter()),
|
||||||
((12, 36), 'FDArray', 'number', None, FDArrayConverter()),
|
|
||||||
((12, 37), 'FDSelect', 'number', None, FDSelectConverter()),
|
|
||||||
(18, 'Private', ('number','number'), None, PrivateDictConverter()),
|
(18, 'Private', ('number','number'), None, PrivateDictConverter()),
|
||||||
|
((12, 37), 'FDSelect', 'number', None, FDSelectConverter()),
|
||||||
|
((12, 36), 'FDArray', 'number', None, FDArrayConverter()),
|
||||||
(17, 'CharStrings', 'number', None, CharStringsConverter()),
|
(17, 'CharStrings', 'number', None, CharStringsConverter()),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Note! FDSelect and FDArray must both preceed CharStrings in the output XML build order,
|
||||||
|
# in order for the font to compile back from xml.
|
||||||
|
|
||||||
|
|
||||||
privateDictOperators = [
|
privateDictOperators = [
|
||||||
# opcode name argument type default converter
|
# opcode name argument type default converter
|
||||||
(6, 'BlueValues', 'delta', None, None),
|
(6, 'BlueValues', 'delta', None, None),
|
||||||
@ -1121,6 +1331,7 @@ class DictCompiler:
|
|||||||
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)
|
||||||
|
print "in baseDict: ", self
|
||||||
rawDict = self.rawDict
|
rawDict = self.rawDict
|
||||||
data = []
|
data = []
|
||||||
for name in self.dictObj.order:
|
for name in self.dictObj.order:
|
||||||
@ -1132,7 +1343,10 @@ class DictCompiler:
|
|||||||
l = len(argType)
|
l = len(argType)
|
||||||
assert len(value) == l, "value doesn't match arg type"
|
assert len(value) == l, "value doesn't match arg type"
|
||||||
for i in range(l):
|
for i in range(l):
|
||||||
arg = argType[l - i - 1]
|
# why was this here? arg = argType[l - i - 1]
|
||||||
|
# In the case of the ROS, it assigns exactly the
|
||||||
|
# wrong handler types
|
||||||
|
arg = argType[i]
|
||||||
v = value[i]
|
v = value[i]
|
||||||
arghandler = getattr(self, "arg_" + arg)
|
arghandler = getattr(self, "arg_" + arg)
|
||||||
data.append(arghandler(v))
|
data.append(arghandler(v))
|
||||||
@ -1179,12 +1393,25 @@ class TopDictCompiler(DictCompiler):
|
|||||||
|
|
||||||
def getChildren(self, strings):
|
def getChildren(self, strings):
|
||||||
children = []
|
children = []
|
||||||
if hasattr(self.dictObj, "charset"):
|
if hasattr(self.dictObj, "charset") and self.dictObj.charset:
|
||||||
children.append(CharsetCompiler(strings, self.dictObj.charset, self))
|
children.append(CharsetCompiler(strings, self.dictObj.charset, self))
|
||||||
if hasattr(self.dictObj, "Encoding"):
|
if hasattr(self.dictObj, "Encoding"):
|
||||||
encoding = self.dictObj.Encoding
|
encoding = self.dictObj.Encoding
|
||||||
if not isinstance(encoding, StringType):
|
if not isinstance(encoding, StringType):
|
||||||
children.append(EncodingCompiler(strings, encoding, self))
|
children.append(EncodingCompiler(strings, encoding, self))
|
||||||
|
if hasattr(self.dictObj, "FDSelect"):
|
||||||
|
# I have not yet supported merging a ttx CFF-CID font, as there are interesting
|
||||||
|
# issues about merging the FDArrays. Here I assume that
|
||||||
|
# either the font was read from XML, and teh FDSelect indices are all
|
||||||
|
# in the charstring data, or the FDSelect array is already fully defined.
|
||||||
|
fdSelect = self.dictObj.FDSelect
|
||||||
|
if len(fdSelect) == 0: # probably read in from XML; assume fdIndex in CharString data
|
||||||
|
charStrings = self.dictObj.CharStrings
|
||||||
|
for name in self.dictObj.charset:
|
||||||
|
charstring = charStrings[name]
|
||||||
|
fdSelect.append(charStrings[name].fdSelectIndex)
|
||||||
|
fdSelectComp = FDSelectCompiler(fdSelect, self)
|
||||||
|
children.append(fdSelectComp)
|
||||||
if hasattr(self.dictObj, "CharStrings"):
|
if hasattr(self.dictObj, "CharStrings"):
|
||||||
items = []
|
items = []
|
||||||
charStrings = self.dictObj.CharStrings
|
charStrings = self.dictObj.CharStrings
|
||||||
@ -1192,6 +1419,26 @@ class TopDictCompiler(DictCompiler):
|
|||||||
items.append(charStrings[name])
|
items.append(charStrings[name])
|
||||||
charStringsComp = CharStringsCompiler(items, strings, self)
|
charStringsComp = CharStringsCompiler(items, strings, self)
|
||||||
children.append(charStringsComp)
|
children.append(charStringsComp)
|
||||||
|
if hasattr(self.dictObj, "FDArray"):
|
||||||
|
# I have not yet supported merging a ttx CFF-CID font, as there are interesting
|
||||||
|
# issues about merging the FDArrays. Here I assume that the FDArray info is correct
|
||||||
|
# and complete.
|
||||||
|
fdArrayIndexComp = self.dictObj.FDArray.getCompiler(strings, self)
|
||||||
|
children.append(fdArrayIndexComp)
|
||||||
|
children.extend(fdArrayIndexComp.getChildren(strings))
|
||||||
|
if hasattr(self.dictObj, "Private"):
|
||||||
|
privComp = self.dictObj.Private.getCompiler(strings, self)
|
||||||
|
children.append(privComp)
|
||||||
|
children.extend(privComp.getChildren(strings))
|
||||||
|
return children
|
||||||
|
|
||||||
|
|
||||||
|
class FontDictCompiler(DictCompiler):
|
||||||
|
|
||||||
|
opcodes = buildOpcodeDict(topDictOperators)
|
||||||
|
|
||||||
|
def getChildren(self, strings):
|
||||||
|
children = []
|
||||||
if hasattr(self.dictObj, "Private"):
|
if hasattr(self.dictObj, "Private"):
|
||||||
privComp = self.dictObj.Private.getCompiler(strings, self)
|
privComp = self.dictObj.Private.getCompiler(strings, self)
|
||||||
children.append(privComp)
|
children.append(privComp)
|
||||||
@ -1293,6 +1540,8 @@ class TopDict(BaseDict):
|
|||||||
def toXML(self, xmlWriter, progress):
|
def toXML(self, xmlWriter, progress):
|
||||||
if hasattr(self, "CharStrings"):
|
if hasattr(self, "CharStrings"):
|
||||||
self.decompileAllCharStrings(progress)
|
self.decompileAllCharStrings(progress)
|
||||||
|
if hasattr(self, "ROS"):
|
||||||
|
self.skipNames = ['Encoding']
|
||||||
if not hasattr(self, "ROS") or not hasattr(self, "CharStrings"):
|
if not hasattr(self, "ROS") or not hasattr(self, "CharStrings"):
|
||||||
# these values have default values, but I only want them to show up
|
# these values have default values, but I only want them to show up
|
||||||
# in CID fonts.
|
# in CID fonts.
|
||||||
@ -1304,12 +1553,39 @@ class TopDict(BaseDict):
|
|||||||
# XXX only when doing ttdump -i?
|
# XXX only when doing ttdump -i?
|
||||||
i = 0
|
i = 0
|
||||||
for charString in self.CharStrings.values():
|
for charString in self.CharStrings.values():
|
||||||
charString.decompile()
|
try:
|
||||||
|
charString.decompile()
|
||||||
|
except:
|
||||||
|
print "Error in charstring ", i
|
||||||
|
import sys
|
||||||
|
type, value = sys. exc_info()[0:2]
|
||||||
|
raise type(value)
|
||||||
if not i % 30 and progress:
|
if not i % 30 and progress:
|
||||||
progress.increment(0) # update
|
progress.increment(0) # update
|
||||||
i = i + 1
|
i = i + 1
|
||||||
|
|
||||||
|
|
||||||
|
class FontDict(BaseDict):
|
||||||
|
|
||||||
|
defaults = buildDefaults(topDictOperators)
|
||||||
|
converters = buildConverters(topDictOperators)
|
||||||
|
order = buildOrder(topDictOperators)
|
||||||
|
decompilerClass = None
|
||||||
|
compilerClass = FontDictCompiler
|
||||||
|
|
||||||
|
def __init__(self, strings=None, file=None, offset=None, GlobalSubrs=None):
|
||||||
|
BaseDict.__init__(self, strings, file, offset)
|
||||||
|
self.GlobalSubrs = GlobalSubrs
|
||||||
|
|
||||||
|
def getGlyphOrder(self):
|
||||||
|
return self.charset
|
||||||
|
|
||||||
|
def toXML(self, xmlWriter, progress):
|
||||||
|
self.skipNames = ['Encoding']
|
||||||
|
BaseDict.toXML(self, xmlWriter, progress)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PrivateDict(BaseDict):
|
class PrivateDict(BaseDict):
|
||||||
defaults = buildDefaults(privateDictOperators)
|
defaults = buildDefaults(privateDictOperators)
|
||||||
converters = buildConverters(privateDictOperators)
|
converters = buildConverters(privateDictOperators)
|
||||||
@ -1437,4 +1713,3 @@ assert len(cffStandardStrings) == cffStandardStringCount
|
|||||||
cffStandardStringMapping = {}
|
cffStandardStringMapping = {}
|
||||||
for _i in range(cffStandardStringCount):
|
for _i in range(cffStandardStringCount):
|
||||||
cffStandardStringMapping[cffStandardStrings[_i]] = _i
|
cffStandardStringMapping[cffStandardStrings[_i]] = _i
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user