CFF/T2 <-> XML roundtripping has begun!

git-svn-id: svn://svn.code.sf.net/p/fonttools/code/trunk@254 4cde692c-a291-49d1-8350-778aa11640f8
This commit is contained in:
jvr 2002-05-24 09:58:04 +00:00
parent f2cf9c5d6d
commit 4e5af60930
4 changed files with 284 additions and 101 deletions

View File

@ -1,13 +1,14 @@
"""cffLib.py -- read/write tools for Adobe CFF fonts.""" """cffLib.py -- read/write tools for Adobe CFF fonts."""
# #
# $Id: cffLib.py,v 1.21 2002-05-23 21:50:36 jvr Exp $ # $Id: cffLib.py,v 1.22 2002-05-24 09:58:03 jvr Exp $
# #
import struct, sstruct import struct, sstruct
import string import string
from types import FloatType, ListType, TupleType from types import FloatType, ListType, StringType, TupleType
from fontTools.misc import psCharStrings from fontTools.misc import psCharStrings
from fontTools.misc.textTools import safeEval
DEBUG = 0 DEBUG = 0
@ -25,16 +26,16 @@ class CFFFontSet:
def __init__(self): def __init__(self):
pass pass
def decompile(self, file): 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, "fontNames")) self.fontNames = list(Index(file))
self.topDictIndex = TopDictIndex(file) self.topDictIndex = TopDictIndex(file)
self.strings = IndexedStrings(file) self.strings = IndexedStrings(file)
self.GlobalSubrs = GlobalSubrsIndex(file, name="GlobalSubrsIndex") self.GlobalSubrs = GlobalSubrsIndex(file)
self.topDictIndex.strings = self.strings self.topDictIndex.strings = self.strings
self.topDictIndex.GlobalSubrs = self.GlobalSubrs self.topDictIndex.GlobalSubrs = self.GlobalSubrs
@ -54,7 +55,7 @@ class CFFFontSet:
raise KeyError, name raise KeyError, name
return self.topDictIndex[index] return self.topDictIndex[index]
def compile(self, file): def compile(self, file, otFont):
strings = IndexedStrings() strings = IndexedStrings()
writer = CFFWriter() writer = CFFWriter()
writer.add(sstruct.pack(cffHeaderFormat, self)) writer.add(sstruct.pack(cffHeaderFormat, self))
@ -67,11 +68,14 @@ class CFFFontSet:
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:
if not hasattr(topDict, "charset") or topDict.charset is None:
charset = otFont.getGlyphOrder()
topDict.charset = charset
for child in topCompiler.getChildren(strings): for child in topCompiler.getChildren(strings):
writer.add(child) writer.add(child)
print writer.data
writer.toFile(file) writer.toFile(file)
def toXML(self, xmlWriter, progress=None): def toXML(self, xmlWriter, progress=None):
@ -92,7 +96,33 @@ class CFFFontSet:
xmlWriter.newline() xmlWriter.newline()
def fromXML(self, (name, attrs, content)): def fromXML(self, (name, attrs, content)):
xxx if not hasattr(self, "GlobalSubrs"):
self.GlobalSubrs = GlobalSubrsIndex()
self.major = 1
self.minor = 0
self.hdrSize = 4
self.offSize = 4 # XXX ??
if name == "CFFFont":
if not hasattr(self, "fontNames"):
self.fontNames = []
self.topDictIndex = TopDictIndex()
fontName = attrs["name"]
topDict = TopDict(GlobalSubrs=self.GlobalSubrs)
topDict.charset = None # gets filled in later
self.fontNames.append(fontName)
self.topDictIndex.append(topDict)
for element in content:
if isinstance(element, StringType):
continue
topDict.fromXML(element)
elif name == "GlobalSubrs":
for element in content:
if isinstance(element, StringType):
continue
name, attrs, content = element
subr = psCharStrings.T2CharString(None, subrs=None, globalSubrs=None)
subr.fromXML((name, attrs, content))
self.GlobalSubrs.append(subr)
class CFFWriter: class CFFWriter:
@ -107,21 +137,25 @@ class CFFWriter:
lastPosList = None lastPosList = None
count = 1 count = 1
while 1: while 1:
print "XXX iteration", count if DEBUG:
count += 1 print "CFFWriter.toFile() iteration:", count
count = count + 1
pos = 0 pos = 0
posList = [pos] posList = [pos]
for item in self.data: for item in self.data:
if hasattr(item, "setPos"):
item.setPos(pos)
if hasattr(item, "getDataLength"): if hasattr(item, "getDataLength"):
pos = pos + item.getDataLength() endPos = pos + item.getDataLength()
else: else:
pos = pos + len(item) endPos = pos + len(item)
if hasattr(item, "setPos"):
item.setPos(pos, endPos)
pos = endPos
posList.append(pos) posList.append(pos)
if posList == lastPosList: if posList == lastPosList:
break break
lastPosList = posList lastPosList = posList
if DEBUG:
print "CFFWriter.toFile() writing to file."
begin = file.tell() begin = file.tell()
posList = [0] posList = [0]
for item in self.data: for item in self.data:
@ -130,10 +164,6 @@ class CFFWriter:
else: else:
file.write(item) file.write(item)
posList.append(file.tell() - begin) posList.append(file.tell() - begin)
if posList != lastPosList:
print "++++"
print posList
print lastPosList
assert posList == lastPosList assert posList == lastPosList
@ -181,8 +211,6 @@ class IndexCompiler:
return dataLength return dataLength
def toFile(self, file): def toFile(self, file):
size = self.getDataLength()
start = file.tell()
offsets = self.getOffsets() offsets = self.getOffsets()
writeCard16(file, len(self.items)) writeCard16(file, len(self.items))
offSize = calcOffSize(offsets[-1]) offSize = calcOffSize(offsets[-1])
@ -198,7 +226,6 @@ class IndexCompiler:
item.toFile(file) item.toFile(file)
else: else:
file.write(item) file.write(item)
assert start + size == file.tell()
class IndexedStringsCompiler(IndexCompiler): class IndexedStringsCompiler(IndexCompiler):
@ -231,12 +258,12 @@ class GlobalSubrsCompiler(IndexCompiler):
return out return out
class SubrsCompiler(GlobalSubrsCompiler): class SubrsCompiler(GlobalSubrsCompiler):
def setPos(self, pos): def setPos(self, pos, endPos):
offset = pos - self.parent.pos offset = pos - self.parent.pos
self.parent.rawDict["Subrs"] = offset self.parent.rawDict["Subrs"] = offset
class CharStringsCompiler(GlobalSubrsCompiler): class CharStringsCompiler(GlobalSubrsCompiler):
def setPos(self, pos): def setPos(self, pos, endPos):
self.parent.rawDict["CharStrings"] = pos self.parent.rawDict["CharStrings"] = pos
@ -246,8 +273,7 @@ class Index:
compilerClass = IndexCompiler compilerClass = IndexCompiler
def __init__(self, file=None, name=None): def __init__(self, file=None):
if name is None:
name = self.__class__.__name__ name = self.__class__.__name__
if file is None: if file is None:
self.items = [] self.items = []
@ -308,9 +334,8 @@ 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):
name=None): Index.__init__(self, file)
Index.__init__(self, file, name)
self.globalSubrs = globalSubrs self.globalSubrs = globalSubrs
self.private = private self.private = private
self.fdSelect = fdSelect self.fdSelect = fdSelect
@ -331,6 +356,9 @@ class GlobalSubrsIndex(Index):
def toXML(self, xmlWriter, progress): def toXML(self, xmlWriter, progress):
fdSelect = self.fdSelect fdSelect = self.fdSelect
xmlWriter.comment("The 'index' attribute is only for humans; "
"it is ignored when parsed.")
xmlWriter.newline()
for i in range(len(self)): for i in range(len(self)):
xmlWriter.begintag("CharString", index=i) xmlWriter.begintag("CharString", index=i)
xmlWriter.newline() xmlWriter.newline()
@ -338,6 +366,13 @@ class GlobalSubrsIndex(Index):
xmlWriter.endtag("CharString") xmlWriter.endtag("CharString")
xmlWriter.newline() xmlWriter.newline()
def fromXML(self, (name, attrs, content)):
if name <> "CharString":
return
subr = psCharStrings.T2CharString(None, subrs=None, globalSubrs=None)
subr.fromXML((name, attrs, content))
self.append(subr)
def getItemAndSelector(self, index): def getItemAndSelector(self, index):
fdSelect = self.fdSelect fdSelect = self.fdSelect
if fdSelect is None: if fdSelect is None:
@ -371,30 +406,55 @@ class TopDictIndex(Index):
class CharStrings: class CharStrings:
def __init__(self, file, charset, globalSubrs, private, fdSelect, fdArray): def __init__(self, file, charset, globalSubrs, private, fdSelect, fdArray):
if file is not None:
self.charStringsIndex = SubrsIndex(file, globalSubrs, private, fdSelect, fdArray) self.charStringsIndex = SubrsIndex(file, globalSubrs, private, fdSelect, fdArray)
self.nameToIndex = nameToIndex = {} self.charStrings = charStrings = {}
for i in range(len(charset)): for i in range(len(charset)):
nameToIndex[charset[i]] = i charStrings[charset[i]] = i
self.charStringsAreIndexed = 1
else:
self.charStrings = {}
self.charStringsAreIndexed = 0
self.globalSubrs = globalSubrs
self.private = private
self.fdSelect = fdSelect
self.fdArray = fdArray
def keys(self): def keys(self):
return self.nameToIndex.keys() return self.charStrings.keys()
def values(self): def values(self):
if self.charStringsAreIndexed:
return self.charStringsIndex return self.charStringsIndex
else:
return self.charStrings.values()
def has_key(self, name): def has_key(self, name):
return self.nameToIndex.has_key(name) return self.charStrings.has_key(name)
def __len__(self): def __len__(self):
return len(self.charStringsIndex) return len(self.charStrings)
def __getitem__(self, name): def __getitem__(self, name):
index = self.nameToIndex[name] charString = self.charStrings[name]
return self.charStringsIndex[index] if self.charStringsAreIndexed:
charString = self.charStringsIndex[charString]
return charString
def __setitem__(self, name, charString):
if self.charStringsAreIndexed:
index = self.charStrings[name]
self.charStringsIndex[index] = charString
else:
self.charStrings[name] = charString
def getItemAndSelector(self, name): def getItemAndSelector(self, name):
index = self.nameToIndex[name] if self.charStringsAreIndexed:
index = self.charStrings[name]
return self.charStringsIndex.getItemAndSelector(index) return self.charStringsIndex.getItemAndSelector(index)
else:
# XXX needs work for CID fonts
return self.charStrings[name], None
def toXML(self, xmlWriter, progress): def toXML(self, xmlWriter, progress):
names = self.keys() names = self.keys()
@ -411,6 +471,23 @@ class CharStrings:
xmlWriter.endtag("CharString") xmlWriter.endtag("CharString")
xmlWriter.newline() xmlWriter.newline()
def fromXML(self, (name, attrs, content)):
for element in content:
if isinstance(element, StringType):
continue
name, attrs, content = element
if name <> "CharString":
continue
glyphName = attrs["name"]
if hasattr(self.private, "Subrs"):
subrs = self.private.Subrs
else:
subrs = []
globalSubrs = self.globalSubrs
charString = psCharStrings.T2CharString(None, subrs=subrs, globalSubrs=globalSubrs)
charString.fromXML((name, attrs, content))
self[glyphName] = charString
def readCard8(file): def readCard8(file):
return ord(file.read(1)) return ord(file.read(1))
@ -467,40 +544,78 @@ def buildConverters(table):
return d return d
class BaseConverter: class SimpleConverter:
def read(self, parent, value): def read(self, parent, value):
return value return value
def write(self, parent, value): def write(self, parent, value):
return value return value
def xmlWrite(self, xmlWriter, name, value):
xmlWriter.simpletag(name, value=value)
xmlWriter.newline()
def xmlRead(self, (name, attrs, content), parent):
return attrs["value"]
def parseNum(s):
try:
value = int(s)
except:
value = float(s)
return value
class NumberConverter(SimpleConverter):
def xmlRead(self, (name, attrs, content), parent):
return parseNum(attrs["value"])
class ArrayConverter(SimpleConverter):
def xmlWrite(self, xmlWriter, name, value):
value = map(str, value)
xmlWriter.simpletag(name, value=" ".join(value))
xmlWriter.newline()
def xmlRead(self, (name, attrs, content), parent):
values = attrs["value"].split()
return map(parseNum, values)
class TableConverter(SimpleConverter):
def xmlWrite(self, xmlWriter, name, value): def xmlWrite(self, xmlWriter, name, value):
xmlWriter.begintag(name) xmlWriter.begintag(name)
xmlWriter.newline() xmlWriter.newline()
value.toXML(xmlWriter, None) value.toXML(xmlWriter, None)
xmlWriter.endtag(name) xmlWriter.endtag(name)
xmlWriter.newline() xmlWriter.newline()
def xmlRead(self, (name, attrs, content), parent):
ob = self.getClass()()
for element in content:
if isinstance(element, StringType):
continue
ob.fromXML(element)
return ob
class PrivateDictConverter(BaseConverter): class PrivateDictConverter(TableConverter):
def getClass(self):
return PrivateDict
def read(self, parent, value): def read(self, parent, value):
size, offset = value size, offset = value
file = parent.file file = parent.file
pr = PrivateDict(parent.strings, file, offset) priv = PrivateDict(parent.strings, file, offset)
file.seek(offset) file.seek(offset)
data = file.read(size) data = file.read(size)
len(data) == size len(data) == size
pr.decompile(data) priv.decompile(data)
return pr return priv
def write(self, parent, value): def write(self, parent, value):
return (0, 0) # dummy value return (0, 0) # dummy value
class SubrsConverter(BaseConverter): class SubrsConverter(TableConverter):
def getClass(self):
return SubrsIndex
def read(self, parent, value): def read(self, parent, value):
file = parent.file file = parent.file
file.seek(parent.offset + value) # Offset(self) file.seek(parent.offset + value) # Offset(self)
return SubrsIndex(file, name="SubrsIndex") return SubrsIndex(file)
def write(self, parent, value): def write(self, parent, value):
return 0 # dummy value return 0 # dummy value
class CharStringsConverter(BaseConverter): class CharStringsConverter(TableConverter):
def read(self, parent, value): def read(self, parent, value):
file = parent.file file = parent.file
charset = parent.charset charset = parent.charset
@ -515,6 +630,12 @@ class CharStringsConverter(BaseConverter):
return CharStrings(file, charset, globalSubrs, private, fdSelect, fdArray) return CharStrings(file, charset, globalSubrs, private, fdSelect, fdArray)
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):
# XXX needs work for CID fonts
fdSelect, fdArray = None, None
charStrings = CharStrings(None, None, parent.GlobalSubrs, parent.Private, fdSelect, fdArray)
charStrings.fromXML((name, attrs, content))
return charStrings
class CharsetConverter: class CharsetConverter:
def read(self, parent, value): def read(self, parent, value):
@ -554,9 +675,14 @@ class CharsetConverter:
def write(self, parent, value): def write(self, parent, value):
return 0 # dummy value return 0 # dummy value
def xmlWrite(self, xmlWriter, name, value): def xmlWrite(self, xmlWriter, name, value):
# XXX GlyphOrder needs to be stored *somewhere*, but not here... # XXX only write charset when not in OT/TTX context, where we
xmlWriter.simpletag("charset", value=value) # dump charset as a separate "GlyphOrder" table.
##xmlWriter.simpletag("charset")
xmlWriter.comment("charset is dumped separately as the 'GlyphOrder' element")
xmlWriter.newline() xmlWriter.newline()
def xmlRead(self, (name, attrs, content), parent):
if 0:
return safeEval(attrs["value"])
class CharsetCompiler: class CharsetCompiler:
@ -570,7 +696,7 @@ class CharsetCompiler:
self.data = "".join(data) self.data = "".join(data)
self.parent = parent self.parent = parent
def setPos(self, pos): def setPos(self, pos, endPos):
self.parent.rawDict["charset"] = pos self.parent.rawDict["charset"] = pos
def getDataLength(self): def getDataLength(self):
@ -607,7 +733,7 @@ def parseCharset(numGlyphs, file, strings, isCID, format):
return charset return charset
class FDArrayConverter(BaseConverter): 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)
@ -648,7 +774,7 @@ class FDSelectConverter:
pass pass
class ROSConverter(BaseConverter): class ROSConverter(SimpleConverter):
def xmlWrite(self, xmlWriter, name, value): def xmlWrite(self, xmlWriter, name, value):
registry, order, supplement = value registry, order, supplement = value
xmlWriter.simpletag(name, [('Registry', registry), ('Order', order), xmlWriter.simpletag(name, [('Registry', registry), ('Order', order),
@ -718,6 +844,24 @@ privateDictOperators = [
(19, 'Subrs', 'number', None, SubrsConverter()), (19, 'Subrs', 'number', None, SubrsConverter()),
] ]
def addConverters(table):
for i in range(len(table)):
op, name, arg, default, conv = table[i]
if conv is not None:
continue
if arg in ("delta", "array"):
conv = ArrayConverter()
elif arg == "number":
conv = NumberConverter()
elif arg == "SID":
conv = SimpleConverter()
else:
assert 0
table[i] = op, name, arg, default, conv
addConverters(privateDictOperators)
addConverters(topDictOperators)
class TopDictDecompiler(psCharStrings.DictDecompiler): class TopDictDecompiler(psCharStrings.DictDecompiler):
operators = buildOperatorDict(topDictOperators) operators = buildOperatorDict(topDictOperators)
@ -740,20 +884,21 @@ class DictCompiler:
if value is None: if value is None:
continue continue
conv = dictObj.converters[name] conv = dictObj.converters[name]
if conv:
value = conv.write(dictObj, value) value = conv.write(dictObj, value)
if value == dictObj.defaults.get(name): if value == dictObj.defaults.get(name):
continue continue
rawDict[name] = value rawDict[name] = value
self.rawDict = rawDict self.rawDict = rawDict
def setPos(self, pos): def setPos(self, pos, endPos):
pass pass
def getDataLength(self): def getDataLength(self):
return len(self.compile()) return len(self.compile("getDataLength"))
def compile(self): def compile(self, reason):
if DEBUG:
print "-- compiling %s for %s" % (self.__class__.__name__, reason)
rawDict = self.rawDict rawDict = self.rawDict
data = [] data = []
for name in self.dictObj.order: for name in self.dictObj.order:
@ -776,7 +921,7 @@ class DictCompiler:
return "".join(data) return "".join(data)
def toFile(self, file): def toFile(self, file):
file.write(self.compile()) file.write(self.compile("toFile"))
def arg_number(self, num): def arg_number(self, num):
return encodeNumber(num) return encodeNumber(num)
@ -832,8 +977,8 @@ class PrivateDictCompiler(DictCompiler):
opcodes = buildOpcodeDict(privateDictOperators) opcodes = buildOpcodeDict(privateDictOperators)
def setPos(self, pos): def setPos(self, pos, endPos):
size = len(self.compile()) size = endPos - pos
self.parent.rawDict["Private"] = size, pos self.parent.rawDict["Private"] = size, pos
self.pos = pos self.pos = pos
@ -846,7 +991,7 @@ class PrivateDictCompiler(DictCompiler):
class BaseDict: class BaseDict:
def __init__(self, strings, file, offset): def __init__(self, strings=None, file=None, offset=None):
self.rawDict = {} self.rawDict = {}
if DEBUG: if DEBUG:
print "loading %s at %s" % (self.__class__.__name__, offset) print "loading %s at %s" % (self.__class__.__name__, offset)
@ -876,7 +1021,6 @@ class BaseDict:
if value is None: if value is None:
raise AttributeError, name raise AttributeError, name
conv = self.converters[name] conv = self.converters[name]
if conv is not None:
value = conv.read(self, value) value = conv.read(self, value)
setattr(self, name, value) setattr(self, name, value)
return value return value
@ -888,14 +1032,13 @@ class BaseDict:
value = getattr(self, name, None) value = getattr(self, name, None)
if value is None: if value is None:
continue continue
conv = self.converters.get(name) conv = self.converters[name]
if conv is not None:
conv.xmlWrite(xmlWriter, name, value) conv.xmlWrite(xmlWriter, name, value)
else:
if isinstance(value, ListType): def fromXML(self, (name, attrs, content)):
value = " ".join(map(str, value)) conv = self.converters[name]
xmlWriter.simpletag(name, value=value) value = conv.xmlRead((name, attrs, content), self)
xmlWriter.newline() setattr(self, name, value)
class TopDict(BaseDict): class TopDict(BaseDict):
@ -906,7 +1049,7 @@ class TopDict(BaseDict):
decompilerClass = TopDictDecompiler decompilerClass = TopDictDecompiler
compilerClass = TopDictCompiler compilerClass = TopDictCompiler
def __init__(self, strings, file, offset, GlobalSubrs): 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
@ -932,6 +1075,7 @@ class TopDict(BaseDict):
BaseDict.toXML(self, xmlWriter, progress) BaseDict.toXML(self, xmlWriter, progress)
def decompileAllCharStrings(self): def decompileAllCharStrings(self):
# XXX only when doing ttdump -i?
for charString in self.CharStrings.values(): for charString in self.CharStrings.values():
charString.decompile() charString.decompile()
@ -952,7 +1096,7 @@ class IndexedStrings:
if file is None: if file is None:
strings = [] strings = []
else: else:
strings = list(Index(file, "IndexedStrings")) strings = list(Index(file))
self.strings = strings self.strings = strings
def getCompiler(self): def getCompiler(self):

View File

@ -200,6 +200,9 @@ def encodeFloat(f):
return d return d
class CharStringCompileError(Exception): pass
class T2CharString(ByteCodeBase): class T2CharString(ByteCodeBase):
operandEncoding = t2OperandEncoding operandEncoding = t2OperandEncoding
@ -229,20 +232,35 @@ class T2CharString(ByteCodeBase):
def compile(self): def compile(self):
if self.bytecode is not None: if self.bytecode is not None:
return return
if self.program[-1] not in ("endchar", "return", "callsubr", "callgsubr", "seac"):
print "XXX", self.program
assert 0, "illegal CharString"
bytecode = [] bytecode = []
opcodes = self.opcodes opcodes = self.opcodes
for token in self.program: program = self.program
i = 0
end = len(program)
while i < end:
token = program[i]
i = i + 1
tp = type(token) tp = type(token)
if tp == types.StringType: if tp == types.StringType:
if opcodes.has_key(token): try:
bytecode.extend(map(chr, opcodes[token])) bytecode.extend(map(chr, opcodes[token]))
else: except KeyError:
bytecode.append(token) # hint mask raise CharStringCompileError, "illegal operator: %s" % token
if token in ('hintmask', 'cntrmask'):
bytecode.append(program[i]) # hint mask
i = i + 1
elif tp == types.IntType: elif tp == types.IntType:
bytecode.append(encodeIntT2(token)) bytecode.append(encodeIntT2(token))
else: else:
assert 0, "unsupported type: %s" % tp assert 0, "unsupported type: %s" % tp
try:
bytecode = "".join(bytecode) bytecode = "".join(bytecode)
except TypeError:
print bytecode
raise
self.setBytecode(bytecode) self.setBytecode(bytecode)
def needsDecompilation(self): def needsDecompilation(self):
@ -322,6 +340,31 @@ class T2CharString(ByteCodeBase):
else: else:
args.append(token) args.append(token)
def fromXML(self, (name, attrs, content)):
from fontTools.misc.textTools import binary2num
content = "".join(content)
content = content.split()
program = []
end = len(content)
i = 0
while i < end:
token = content[i]
i = i + 1
try:
token = int(token)
except ValueError:
program.append(token)
if token in ('hintmask', 'cntrmask'):
mask = content[i]
maskBytes = ""
for j in range(0, len(mask), 8):
maskBytes = maskBytes + chr(binary2num(mask[j:j+8]))
program.append(maskBytes)
i = i + 1
else:
program.append(token)
self.setProgram(program)
t1Operators = [ t1Operators = [
# opcode name # opcode name
@ -414,6 +457,8 @@ class SimpleT2Decompiler:
pushToStack(token) pushToStack(token)
if needsDecompilation: if needsDecompilation:
charString.setProgram(program) charString.setProgram(program)
if program[-1] not in ("endchar", "return", "callsubr", "callgsubr", "seac"):
print "XXX", program
assert program[-1] in ("endchar", "return", "callsubr", "callgsubr", "seac") assert program[-1] in ("endchar", "return", "callsubr", "callgsubr", "seac")
del self.callingStack[-1] del self.callingStack[-1]

View File

@ -42,7 +42,7 @@ Dumping 'prep' table...
""" """
# #
# $Id: __init__.py,v 1.30 2002-05-23 09:42:45 jvr Exp $ # $Id: __init__.py,v 1.31 2002-05-24 09:58:04 jvr Exp $
# #
import os import os
@ -534,8 +534,8 @@ class GlyphOrder:
def toXML(self, writer, ttFont): def toXML(self, writer, ttFont):
glyphOrder = ttFont.getGlyphOrder() glyphOrder = ttFont.getGlyphOrder()
writer.comment("The 'id' attribute is merely a reading aid; " writer.comment("The 'id' attribute is only for humans; "
"it is ignored when read.") "it is ignored when parsed.")
writer.newline() writer.newline()
for i in range(len(glyphOrder)): for i in range(len(glyphOrder)):
glyphName = glyphOrder[i] glyphName = glyphOrder[i]

View File

@ -2,12 +2,6 @@ import DefaultTable
from fontTools import cffLib from fontTools import cffLib
# temporary switch:
# - if true use possibly incomplete compile/decompile/toXML/fromXML implementation
# - if false use DefaultTable, ie. dump as hex.
TESTING_CFF = 0
class table_C_F_F_(DefaultTable.DefaultTable): class table_C_F_F_(DefaultTable.DefaultTable):
def __init__(self, tag): def __init__(self, tag):
@ -17,12 +11,14 @@ class table_C_F_F_(DefaultTable.DefaultTable):
def decompile(self, data, otFont): def decompile(self, data, otFont):
from cStringIO import StringIO from cStringIO import StringIO
self.data = data # XXX while work is in progress... self.cff.decompile(StringIO(data), otFont)
self.cff.decompile(StringIO(data))
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):
# xxx from cStringIO import StringIO
f = StringIO()
self.cff.compile(f, otFont)
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"):
@ -43,12 +39,10 @@ class table_C_F_F_(DefaultTable.DefaultTable):
#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):
if TESTING_CFF:
self.cff.toXML(writer, progress) self.cff.toXML(writer, progress)
else:
# dump as hex as long as we can't compile
DefaultTable.DefaultTable.toXML(self, writer, otFont)
#def fromXML(self, (name, attrs, content), otFont): def fromXML(self, (name, attrs, content), otFont):
# xxx if not hasattr(self, "cff"):
self.cff = cffLib.CFFFontSet()
self.cff.fromXML((name, attrs, content))