psCharStrings.py revision e56bc902cf6a707349ae6ddfe8a83a1bd7b155b9
1a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard"""psCharStrings.py -- module implementing various kinds of CharStrings:
2a245d15da5d295af21ead9a01583c64796a31ad7Jean ChalardCFF dictionary data and Type1/Type2 CharStrings.
3a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard"""
4a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard
5a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalardimport types
6a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalardimport struct
7a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalardimport string
8a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard
9a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard
10a245d15da5d295af21ead9a01583c64796a31ad7Jean ChalardDEBUG = 0
11a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard
12a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard
13a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalardt1OperandEncoding = [None] * 256
14a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalardt1OperandEncoding[0:32] = (32) * ["do_operator"]
15a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalardt1OperandEncoding[32:247] = (247 - 32) * ["read_byte"]
16a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalardt1OperandEncoding[247:251] = (251 - 247) * ["read_smallInt1"]
17a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalardt1OperandEncoding[251:255] = (255 - 251) * ["read_smallInt2"]
189e51c6c0c62b78eaf14f92890981f9d35702b2c9Keisuke Kuroyanagit1OperandEncoding[255] = "read_longInt"
19a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalardassert len(t1OperandEncoding) == 256
20a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard
21a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalardt2OperandEncoding = t1OperandEncoding[:]
22a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalardt2OperandEncoding[28] = "read_shortInt"
2388bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagit2OperandEncoding[255] = "read_fixed1616"
2488bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi
2588bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke KuroyanagicffDictOperandEncoding = t2OperandEncoding[:]
2688bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke KuroyanagicffDictOperandEncoding[29] = "read_longInt"
2788bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke KuroyanagicffDictOperandEncoding[30] = "read_realNumber"
2888bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke KuroyanagicffDictOperandEncoding[255] = "reserved"
296e4b674f83e0c287e00bfe6546db2a1f93daf5f0Keisuke Kuroyanagi
30a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard
31a245d15da5d295af21ead9a01583c64796a31ad7Jean ChalardrealNibbles = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
32a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard		'.', 'E', 'E-', None, '-']
33a245d15da5d295af21ead9a01583c64796a31ad7Jean ChalardrealNibblesDict = {}
348dac7ce2e2b56c77e289507625b7695449b2e41aKeisuke Kuroyanagifor _i in range(len(realNibbles)):
356e4b674f83e0c287e00bfe6546db2a1f93daf5f0Keisuke Kuroyanagi	realNibblesDict[realNibbles[_i]] = _i
36f87bb77a9183d126847d5925c2b03bec45fabd6dKeisuke Kuroyanagi
3788bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi
38a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalardclass ByteCodeBase:
39be6117058840492c2862f8ae9f7dc95c29f3a8f3Keisuke Kuroyanagi
40be6117058840492c2862f8ae9f7dc95c29f3a8f3Keisuke Kuroyanagi	def read_byte(self, b0, data, index):
4188bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi		return b0 - 139, index
42a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard
43a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard	def read_smallInt1(self, b0, data, index):
44a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard		b1 = ord(data[index])
45a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard		return (b0-247)*256 + b1 + 108, index+1
46a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard
47a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard	def read_smallInt2(self, b0, data, index):
481d6afa179cd31010efe28f1c3e17698d6be79cabKeisuke Kuroyanagi		b1 = ord(data[index])
491d6afa179cd31010efe28f1c3e17698d6be79cabKeisuke Kuroyanagi		return -(b0-251)*256 - b1 - 108, index+1
5088bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi
51660b00477c980d74be48529b9de70d9725ffc72bKeisuke Kuroyanagi	def read_shortInt(self, b0, data, index):
52c4696b2eb6b25eea4d5c869683104ab99aec0421Keisuke Kuroyanagi		bin = data[index] + data[index+1]
536b0561f9d26215209e8e8895f5c35982af5158f0Keisuke Kuroyanagi		value, = struct.unpack(">h", bin)
54a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard		return value, index+2
55a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard
56a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard	def read_longInt(self, b0, data, index):
5788bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi		bin = data[index] + data[index+1] + data[index+2] + data[index+3]
58a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard		value, = struct.unpack(">l", bin)
59a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard		return value, index+4
60a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard
61a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard	def read_fixed1616(self, b0, data, index):
62a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard		bin = data[index] + data[index+1] + data[index+2] + data[index+3]
63a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard		value, = struct.unpack(">l", bin)
64a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard		return value / 65536.0, index+4
6588bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi
660a9c3f30b61ca50bb09c5cfc9ec3196c16efc656Keisuke Kuroyanagi	def read_realNumber(self, b0, data, index):
67de3121dead395d32760379c03938faef6eac2f98Keisuke Kuroyanagi		number = ''
68de3121dead395d32760379c03938faef6eac2f98Keisuke Kuroyanagi		while 1:
6988bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi			b = ord(data[index])
7088bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi			index = index + 1
7188bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi			nibble0 = (b & 0xf0) >> 4
7288bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi			nibble1 = b & 0x0f
7388bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi			if nibble0 == 0xf:
7488bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi				break
7588bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi			number = number + realNibbles[nibble0]
7688bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi			if nibble1 == 0xf:
7788bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi				break
7888bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi			number = number + realNibbles[nibble1]
7988bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi		return float(number), index
8088bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi
8188bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi
8288bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagidef buildOperatorDict(operatorList):
8388bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi	oper = {}
8488bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi	opc = {}
8588bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi	for item in operatorList:
8688bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi		if len(item) == 2:
8788bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi			oper[item[0]] = item[1]
8888bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi		else:
8988bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi			oper[item[0]] = item[1:]
90a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard		if type(item[0]) == types.TupleType:
91a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard			opc[item[1]] = item[0]
92a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard		else:
93a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard			opc[item[1]] = (item[0],)
94a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard	return oper, opc
95a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard
96a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard
97a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalardt2Operators = [
98a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard#	opcode     name
99a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard	(1,        'hstem'),
100e9121a68a67b8723477668130a16d4c72d98f6feKeisuke Kuroyanagi	(3,        'vstem'),
101a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard	(4,        'vmoveto'),
102a245d15da5d295af21ead9a01583c64796a31ad7Jean Chalard	(5,        'rlineto'),
103c72652cb00eb0a02c46bfcd95202deec068ba5e0Yohei Yukawa	(6,        'hlineto'),
10407e14126318f7661f76fdce421d723d64e7ea8deKeisuke Kuroyanagi	(7,        'vlineto'),
10588bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi	(8,        'rrcurveto'),
1066bf268132d60061fd26bd8cba63a12b56b22056eKeisuke Kuroyanagi	(10,       'callsubr'),
1076bf268132d60061fd26bd8cba63a12b56b22056eKeisuke Kuroyanagi	(11,       'return'),
1086bf268132d60061fd26bd8cba63a12b56b22056eKeisuke Kuroyanagi	(14,       'endchar'),
1096bf268132d60061fd26bd8cba63a12b56b22056eKeisuke Kuroyanagi	(16,       'blend'),
1106bf268132d60061fd26bd8cba63a12b56b22056eKeisuke Kuroyanagi	(18,       'hstemhm'),
1116bf268132d60061fd26bd8cba63a12b56b22056eKeisuke Kuroyanagi	(19,       'hintmask'),
1126bf268132d60061fd26bd8cba63a12b56b22056eKeisuke Kuroyanagi	(20,       'cntrmask'),
1136bf268132d60061fd26bd8cba63a12b56b22056eKeisuke Kuroyanagi	(21,       'rmoveto'),
11488bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi	(22,       'hmoveto'),
1156bf268132d60061fd26bd8cba63a12b56b22056eKeisuke Kuroyanagi	(23,       'vstemhm'),
1166bf268132d60061fd26bd8cba63a12b56b22056eKeisuke Kuroyanagi	(24,       'rcurveline'),
1176bf268132d60061fd26bd8cba63a12b56b22056eKeisuke Kuroyanagi	(25,       'rlinecurve'),
1186bf268132d60061fd26bd8cba63a12b56b22056eKeisuke Kuroyanagi	(26,       'vvcurveto'),
1196bf268132d60061fd26bd8cba63a12b56b22056eKeisuke Kuroyanagi	(27,       'hhcurveto'),
12088bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi#	(28,       'shortint'),  # not really an operator
1216bf268132d60061fd26bd8cba63a12b56b22056eKeisuke Kuroyanagi	(29,       'callgsubr'),
1226bf268132d60061fd26bd8cba63a12b56b22056eKeisuke Kuroyanagi	(30,       'vhcurveto'),
12307e14126318f7661f76fdce421d723d64e7ea8deKeisuke Kuroyanagi	(31,       'hvcurveto'),
1246bf268132d60061fd26bd8cba63a12b56b22056eKeisuke Kuroyanagi	((12, 0),  'ignore'),  # dotsection. Yes, there a few very early OTF/CFF
125c72652cb00eb0a02c46bfcd95202deec068ba5e0Yohei Yukawa	                   # fonts with this deprecated operator. Just ignore it.
126b417d7d69f72f3f8224887f63b6d569dc1b19b02Yohei Yukawa	((12, 3),  'and'),
12788bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi	((12, 4),  'or'),
12888bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi	((12, 5),  'not'),
12988bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi	((12, 8),  'store'),
13088bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi	((12, 9),  'abs'),
13188bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi	((12, 10), 'add'),
13288bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi	((12, 11), 'sub'),
13388bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi	((12, 12), 'div'),
13488bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi	((12, 13), 'load'),
13588bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi	((12, 14), 'neg'),
13688bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi	((12, 15), 'eq'),
13788bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi	((12, 18), 'drop'),
13888bc312ad34321fb3e81be2dc939a889d065f4a7Keisuke Kuroyanagi	((12, 20), 'put'),
13940b6d6cbd11f4cdcff2ffbb756e8a4e3fb148ab7Keisuke Kuroyanagi	((12, 21), 'get'),
140985b2c2e91485a0cb293bff35a80877b2be71eaeKeisuke Kuroyanagi	((12, 22), 'ifelse'),
14140b6d6cbd11f4cdcff2ffbb756e8a4e3fb148ab7Keisuke Kuroyanagi	((12, 23), 'random'),
14269732169cca572c9b3f0a48e434e4abcbb4c95baKeisuke Kuroyanagi	((12, 24), 'mul'),
14375d8c20d03f8300946c5e4a4832117530110910bKeisuke Kuroyanagi	((12, 26), 'sqrt'),
14429dcf97e7472bde94d591c743c5311b641fd8238Keisuke Kuroyanagi	((12, 27), 'dup'),
14578aea9f133f00706fd6281e093b99a07edf5b81dKeisuke Kuroyanagi	((12, 28), 'exch'),
14678aea9f133f00706fd6281e093b99a07edf5b81dKeisuke Kuroyanagi	((12, 29), 'index'),
147	((12, 30), 'roll'),
148	((12, 34), 'hflex'),
149	((12, 35), 'flex'),
150	((12, 36), 'hflex1'),
151	((12, 37), 'flex1'),
152]
153
154
155def getIntEncoder(format):
156	if format == "cff":
157		fourByteOp = chr(29)
158	elif format == "t1":
159		fourByteOp = chr(255)
160	else:
161		assert format == "t2"
162		fourByteOp = None
163
164	def encodeInt(value, fourByteOp=fourByteOp, chr=chr,
165			pack=struct.pack, unpack=struct.unpack):
166		if -107 <= value <= 107:
167			code = chr(value + 139)
168		elif 108 <= value <= 1131:
169			value = value - 108
170			code = chr((value >> 8) + 247) + chr(value & 0xFF)
171		elif -1131 <= value <= -108:
172			value = -value - 108
173			code = chr((value >> 8) + 251) + chr(value & 0xFF)
174		elif fourByteOp is None:
175			# T2 only supports 2 byte ints
176			if -32768 <= value <= 32767:
177				code = chr(28) + pack(">h", value)
178			else:
179				# Backwards compatible hack: due to a previous bug in FontTools,
180				# 16.16 fixed numbers were written out as 4-byte ints. When
181				# these numbers were small, they were wrongly written back as
182				# small ints instead of 4-byte ints, breaking round-tripping.
183				# This here workaround doesn't do it any better, since we can't
184				# distinguish anymore between small ints that were supposed to
185				# be small fixed numbers and small ints that were just small
186				# ints. Hence the warning.
187				import sys
188				sys.stderr.write("Warning: 4-byte T2 number got passed to the "
189					"IntType handler. This should happen only when reading in "
190					"old XML files.\n")
191				code = chr(255) + pack(">l", value)
192		else:
193			code = fourByteOp + pack(">l", value)
194		return code
195
196	return encodeInt
197
198
199encodeIntCFF = getIntEncoder("cff")
200encodeIntT1 = getIntEncoder("t1")
201encodeIntT2 = getIntEncoder("t2")
202
203def encodeFixed(f, pack=struct.pack):
204	# For T2 only
205	return "\xff" + pack(">l", int(round(f * 65536)))
206
207def encodeFloat(f):
208	# For CFF only, used in cffLib
209	s = str(f).upper()
210	if s[:2] == "0.":
211		s = s[1:]
212	elif s[:3] == "-0.":
213		s = "-" + s[2:]
214	nibbles = []
215	while s:
216		c = s[0]
217		s = s[1:]
218		if c == "E" and s[:1] == "-":
219			s = s[1:]
220			c = "E-"
221		nibbles.append(realNibblesDict[c])
222	nibbles.append(0xf)
223	if len(nibbles) % 2:
224		nibbles.append(0xf)
225	d = chr(30)
226	for i in range(0, len(nibbles), 2):
227		d = d + chr(nibbles[i] << 4 | nibbles[i+1])
228	return d
229
230
231class CharStringCompileError(Exception): pass
232
233
234class T2CharString(ByteCodeBase):
235
236	operandEncoding = t2OperandEncoding
237	operators, opcodes = buildOperatorDict(t2Operators)
238
239	def __init__(self, bytecode=None, program=None, private=None, globalSubrs=None):
240		if program is None:
241			program = []
242		self.bytecode = bytecode
243		self.program = program
244		self.private = private
245		self.globalSubrs = globalSubrs
246
247	def __repr__(self):
248		if self.bytecode is None:
249			return "<%s (source) at %x>" % (self.__class__.__name__, id(self))
250		else:
251			return "<%s (bytecode) at %x>" % (self.__class__.__name__, id(self))
252
253	def getIntEncoder(self):
254		return encodeIntT2
255
256	def getFixedEncoder(self):
257		return encodeFixed
258
259	def decompile(self):
260		if not self.needsDecompilation():
261			return
262		subrs = getattr(self.private, "Subrs", [])
263		decompiler = SimpleT2Decompiler(subrs, self.globalSubrs)
264		decompiler.execute(self)
265
266	def draw(self, pen):
267		subrs = getattr(self.private, "Subrs", [])
268		extractor = T2OutlineExtractor(pen, subrs, self.globalSubrs,
269				self.private.nominalWidthX, self.private.defaultWidthX)
270		extractor.execute(self)
271		self.width = extractor.width
272
273	def compile(self):
274		if self.bytecode is not None:
275			return
276		assert self.program, "illegal CharString: decompiled to empty program"
277		assert self.program[-1] in ("endchar", "return", "callsubr", "callgsubr",
278				"seac"), "illegal CharString"
279		bytecode = []
280		opcodes = self.opcodes
281		program = self.program
282		encodeInt = self.getIntEncoder()
283		encodeFixed = self.getFixedEncoder()
284		i = 0
285		end = len(program)
286		while i < end:
287			token = program[i]
288			i = i + 1
289			tp = type(token)
290			if tp == types.StringType:
291				try:
292					bytecode.extend(map(chr, opcodes[token]))
293				except KeyError:
294					raise CharStringCompileError, "illegal operator: %s" % token
295				if token in ('hintmask', 'cntrmask'):
296					bytecode.append(program[i])  # hint mask
297					i = i + 1
298			elif tp == types.IntType:
299				bytecode.append(encodeInt(token))
300			elif tp == types.FloatType:
301				bytecode.append(encodeFixed(token))
302			else:
303				assert 0, "unsupported type: %s" % tp
304		try:
305			bytecode = "".join(bytecode)
306		except TypeError:
307			print bytecode
308			raise
309		self.setBytecode(bytecode)
310
311	def needsDecompilation(self):
312		return self.bytecode is not None
313
314	def setProgram(self, program):
315		self.program = program
316		self.bytecode = None
317
318	def setBytecode(self, bytecode):
319		self.bytecode = bytecode
320		self.program = None
321
322	def getToken(self, index,
323			len=len, ord=ord, getattr=getattr, type=type, StringType=types.StringType):
324		if self.bytecode is not None:
325			if index >= len(self.bytecode):
326				return None, 0, 0
327			b0 = ord(self.bytecode[index])
328			index = index + 1
329			code = self.operandEncoding[b0]
330			handler = getattr(self, code)
331			token, index = handler(b0, self.bytecode, index)
332		else:
333			if index >= len(self.program):
334				return None, 0, 0
335			token = self.program[index]
336			index = index + 1
337		isOperator = type(token) == StringType
338		return token, isOperator, index
339
340	def getBytes(self, index, nBytes):
341		if self.bytecode is not None:
342			newIndex = index + nBytes
343			bytes = self.bytecode[index:newIndex]
344			index = newIndex
345		else:
346			bytes = self.program[index]
347			index = index + 1
348		assert len(bytes) == nBytes
349		return bytes, index
350
351	def do_operator(self, b0, data, index):
352		if b0 == 12:
353			op = (b0, ord(data[index]))
354			index = index+1
355		else:
356			op = b0
357		operator = self.operators[op]
358		return operator, index
359
360	def toXML(self, xmlWriter):
361		from fontTools.misc.textTools import num2binary
362		if self.bytecode is not None:
363			xmlWriter.dumphex(self.bytecode)
364		else:
365			index = 0
366			args = []
367			while 1:
368				token, isOperator, index = self.getToken(index)
369				if token is None:
370					break
371				if isOperator:
372					args = map(str, args)
373					if token in ('hintmask', 'cntrmask'):
374						hintMask, isOperator, index = self.getToken(index)
375						bits = []
376						for byte in hintMask:
377							bits.append(num2binary(ord(byte), 8))
378						hintMask = string.join(bits, "")
379						line = string.join(args + [token, hintMask], " ")
380					else:
381						line = string.join(args + [token], " ")
382					xmlWriter.write(line)
383					xmlWriter.newline()
384					args = []
385				else:
386					args.append(token)
387
388	def fromXML(self, (name, attrs, content)):
389		from fontTools.misc.textTools import binary2num, readHex
390		if attrs.get("raw"):
391			self.setBytecode(readHex(content))
392			return
393		content = "".join(content)
394		content = content.split()
395		program = []
396		end = len(content)
397		i = 0
398		while i < end:
399			token = content[i]
400			i = i + 1
401			try:
402				token = int(token)
403			except ValueError:
404				try:
405					token = float(token)
406				except ValueError:
407					program.append(token)
408					if token in ('hintmask', 'cntrmask'):
409						mask = content[i]
410						maskBytes = ""
411						for j in range(0, len(mask), 8):
412							maskBytes = maskBytes + chr(binary2num(mask[j:j+8]))
413						program.append(maskBytes)
414						i = i + 1
415				else:
416					program.append(token)
417			else:
418				program.append(token)
419		self.setProgram(program)
420
421
422t1Operators = [
423#	opcode     name
424	(1,        'hstem'),
425	(3,        'vstem'),
426	(4,        'vmoveto'),
427	(5,        'rlineto'),
428	(6,        'hlineto'),
429	(7,        'vlineto'),
430	(8,        'rrcurveto'),
431	(9,        'closepath'),
432	(10,       'callsubr'),
433	(11,       'return'),
434	(13,       'hsbw'),
435	(14,       'endchar'),
436	(21,       'rmoveto'),
437	(22,       'hmoveto'),
438	(30,       'vhcurveto'),
439	(31,       'hvcurveto'),
440	((12, 0),  'dotsection'),
441	((12, 1),  'vstem3'),
442	((12, 2),  'hstem3'),
443	((12, 6),  'seac'),
444	((12, 7),  'sbw'),
445	((12, 12), 'div'),
446	((12, 16), 'callothersubr'),
447	((12, 17), 'pop'),
448	((12, 33), 'setcurrentpoint'),
449]
450
451class T1CharString(T2CharString):
452
453	operandEncoding = t1OperandEncoding
454	operators, opcodes = buildOperatorDict(t1Operators)
455
456	def __init__(self, bytecode=None, program=None, subrs=None):
457		if program is None:
458			program = []
459		self.bytecode = bytecode
460		self.program = program
461		self.subrs = subrs
462
463	def getIntEncoder(self):
464		return encodeIntT1
465
466	def getFixedEncoder(self):
467		def encodeFixed(value):
468			raise TypeError("Type 1 charstrings don't support floating point operands")
469
470	def decompile(self):
471		if self.program is not None:
472			return
473		program = []
474		index = 0
475		while 1:
476			token, isOperator, index = self.getToken(index)
477			if token is None:
478				break
479			program.append(token)
480		self.setProgram(program)
481
482	def draw(self, pen):
483		extractor = T1OutlineExtractor(pen, self.subrs)
484		extractor.execute(self)
485		self.width = extractor.width
486
487
488class SimpleT2Decompiler:
489
490	def __init__(self, localSubrs, globalSubrs):
491		self.localSubrs = localSubrs
492		self.localBias = calcSubrBias(localSubrs)
493		self.globalSubrs = globalSubrs
494		self.globalBias = calcSubrBias(globalSubrs)
495		self.reset()
496
497	def reset(self):
498		self.callingStack = []
499		self.operandStack = []
500		self.hintCount = 0
501		self.hintMaskBytes = 0
502
503	def execute(self, charString):
504		self.callingStack.append(charString)
505		needsDecompilation = charString.needsDecompilation()
506		if needsDecompilation:
507			program = []
508			pushToProgram = program.append
509		else:
510			pushToProgram = lambda x: None
511		pushToStack = self.operandStack.append
512		index = 0
513		while 1:
514			token, isOperator, index = charString.getToken(index)
515			if token is None:
516				break  # we're done!
517			pushToProgram(token)
518			if isOperator:
519				handlerName = "op_" + token
520				if hasattr(self, handlerName):
521					handler = getattr(self, handlerName)
522					rv = handler(index)
523					if rv:
524						hintMaskBytes, index = rv
525						pushToProgram(hintMaskBytes)
526				else:
527					self.popall()
528			else:
529				pushToStack(token)
530		if needsDecompilation:
531			assert program, "illegal CharString: decompiled to empty program"
532			assert program[-1] in ("endchar", "return", "callsubr", "callgsubr",
533					"seac"), "illegal CharString"
534			charString.setProgram(program)
535		del self.callingStack[-1]
536
537	def pop(self):
538		value = self.operandStack[-1]
539		del self.operandStack[-1]
540		return value
541
542	def popall(self):
543		stack = self.operandStack[:]
544		self.operandStack[:] = []
545		return stack
546
547	def push(self, value):
548		self.operandStack.append(value)
549
550	def op_return(self, index):
551		if self.operandStack:
552			pass
553
554	def op_endchar(self, index):
555		pass
556
557	def op_ignore(self, index):
558		pass
559
560	def op_callsubr(self, index):
561		subrIndex = self.pop()
562		subr = self.localSubrs[subrIndex+self.localBias]
563		self.execute(subr)
564
565	def op_callgsubr(self, index):
566		subrIndex = self.pop()
567		subr = self.globalSubrs[subrIndex+self.globalBias]
568		self.execute(subr)
569
570	def op_hstem(self, index):
571		self.countHints()
572	def op_vstem(self, index):
573		self.countHints()
574	def op_hstemhm(self, index):
575		self.countHints()
576	def op_vstemhm(self, index):
577		self.countHints()
578
579	def op_hintmask(self, index):
580		if not self.hintMaskBytes:
581			self.countHints()
582			self.hintMaskBytes = (self.hintCount + 7) / 8
583		hintMaskBytes, index = self.callingStack[-1].getBytes(index, self.hintMaskBytes)
584		return hintMaskBytes, index
585
586	op_cntrmask = op_hintmask
587
588	def countHints(self):
589		args = self.popall()
590		self.hintCount = self.hintCount + len(args) / 2
591
592
593class T2OutlineExtractor(SimpleT2Decompiler):
594
595	def __init__(self, pen, localSubrs, globalSubrs, nominalWidthX, defaultWidthX):
596		SimpleT2Decompiler.__init__(self, localSubrs, globalSubrs)
597		self.pen = pen
598		self.nominalWidthX = nominalWidthX
599		self.defaultWidthX = defaultWidthX
600
601	def reset(self):
602		SimpleT2Decompiler.reset(self)
603		self.hints = []
604		self.gotWidth = 0
605		self.width = 0
606		self.currentPoint = (0, 0)
607		self.sawMoveTo = 0
608
609	def _nextPoint(self, point):
610		x, y = self.currentPoint
611		point = x + point[0], y + point[1]
612		self.currentPoint = point
613		return point
614
615	def rMoveTo(self, point):
616		self.pen.moveTo(self._nextPoint(point))
617		self.sawMoveTo = 1
618
619	def rLineTo(self, point):
620		if not self.sawMoveTo:
621			self.rMoveTo((0, 0))
622		self.pen.lineTo(self._nextPoint(point))
623
624	def rCurveTo(self, pt1, pt2, pt3):
625		if not self.sawMoveTo:
626			self.rMoveTo((0, 0))
627		nextPoint = self._nextPoint
628		self.pen.curveTo(nextPoint(pt1), nextPoint(pt2), nextPoint(pt3))
629
630	def closePath(self):
631		if self.sawMoveTo:
632			self.pen.closePath()
633		self.sawMoveTo = 0
634
635	def endPath(self):
636		# In T2 there are no open paths, so always do a closePath when
637		# finishing a sub path.
638		self.closePath()
639
640	def popallWidth(self, evenOdd=0):
641		args = self.popall()
642		if not self.gotWidth:
643			if evenOdd ^ (len(args) % 2):
644				self.width = self.nominalWidthX + args[0]
645				args = args[1:]
646			else:
647				self.width = self.defaultWidthX
648			self.gotWidth = 1
649		return args
650
651	def countHints(self):
652		args = self.popallWidth()
653		self.hintCount = self.hintCount + len(args) / 2
654
655	#
656	# hint operators
657	#
658	#def op_hstem(self, index):
659	#	self.countHints()
660	#def op_vstem(self, index):
661	#	self.countHints()
662	#def op_hstemhm(self, index):
663	#	self.countHints()
664	#def op_vstemhm(self, index):
665	#	self.countHints()
666	#def op_hintmask(self, index):
667	#	self.countHints()
668	#def op_cntrmask(self, index):
669	#	self.countHints()
670
671	#
672	# path constructors, moveto
673	#
674	def op_rmoveto(self, index):
675		self.endPath()
676		self.rMoveTo(self.popallWidth())
677	def op_hmoveto(self, index):
678		self.endPath()
679		self.rMoveTo((self.popallWidth(1)[0], 0))
680	def op_vmoveto(self, index):
681		self.endPath()
682		self.rMoveTo((0, self.popallWidth(1)[0]))
683	def op_endchar(self, index):
684		self.endPath()
685		args = self.popallWidth()
686		if args:
687			from fontTools.encodings.StandardEncoding import StandardEncoding
688			# endchar can do seac accent bulding; The T2 spec says it's deprecated,
689			# but recent software that shall remain nameless does output it.
690			adx, ady, bchar, achar = args
691			baseGlyph = StandardEncoding[bchar]
692			self.pen.addComponent(baseGlyph, (1, 0, 0, 1, 0, 0))
693			accentGlyph = StandardEncoding[achar]
694			self.pen.addComponent(accentGlyph, (1, 0, 0, 1, adx, ady))
695
696	#
697	# path constructors, lines
698	#
699	def op_rlineto(self, index):
700		args = self.popall()
701		for i in range(0, len(args), 2):
702			point = args[i:i+2]
703			self.rLineTo(point)
704
705	def op_hlineto(self, index):
706		self.alternatingLineto(1)
707	def op_vlineto(self, index):
708		self.alternatingLineto(0)
709
710	#
711	# path constructors, curves
712	#
713	def op_rrcurveto(self, index):
714		"""{dxa dya dxb dyb dxc dyc}+ rrcurveto"""
715		args = self.popall()
716		for i in range(0, len(args), 6):
717			dxa, dya, dxb, dyb, dxc, dyc, = args[i:i+6]
718			self.rCurveTo((dxa, dya), (dxb, dyb), (dxc, dyc))
719
720	def op_rcurveline(self, index):
721		"""{dxa dya dxb dyb dxc dyc}+ dxd dyd rcurveline"""
722		args = self.popall()
723		for i in range(0, len(args)-2, 6):
724			dxb, dyb, dxc, dyc, dxd, dyd = args[i:i+6]
725			self.rCurveTo((dxb, dyb), (dxc, dyc), (dxd, dyd))
726		self.rLineTo(args[-2:])
727
728	def op_rlinecurve(self, index):
729		"""{dxa dya}+ dxb dyb dxc dyc dxd dyd rlinecurve"""
730		args = self.popall()
731		lineArgs = args[:-6]
732		for i in range(0, len(lineArgs), 2):
733			self.rLineTo(lineArgs[i:i+2])
734		dxb, dyb, dxc, dyc, dxd, dyd = args[-6:]
735		self.rCurveTo((dxb, dyb), (dxc, dyc), (dxd, dyd))
736
737	def op_vvcurveto(self, index):
738		"dx1? {dya dxb dyb dyc}+ vvcurveto"
739		args = self.popall()
740		if len(args) % 2:
741			dx1 = args[0]
742			args = args[1:]
743		else:
744			dx1 = 0
745		for i in range(0, len(args), 4):
746			dya, dxb, dyb, dyc = args[i:i+4]
747			self.rCurveTo((dx1, dya), (dxb, dyb), (0, dyc))
748			dx1 = 0
749
750	def op_hhcurveto(self, index):
751		"""dy1? {dxa dxb dyb dxc}+ hhcurveto"""
752		args = self.popall()
753		if len(args) % 2:
754			dy1 = args[0]
755			args = args[1:]
756		else:
757			dy1 = 0
758		for i in range(0, len(args), 4):
759			dxa, dxb, dyb, dxc = args[i:i+4]
760			self.rCurveTo((dxa, dy1), (dxb, dyb), (dxc, 0))
761			dy1 = 0
762
763	def op_vhcurveto(self, index):
764		"""dy1 dx2 dy2 dx3 {dxa dxb dyb dyc dyd dxe dye dxf}* dyf? vhcurveto (30)
765		{dya dxb dyb dxc dxd dxe dye dyf}+ dxf? vhcurveto
766		"""
767		args = self.popall()
768		while args:
769			args = self.vcurveto(args)
770			if args:
771				args = self.hcurveto(args)
772
773	def op_hvcurveto(self, index):
774		"""dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* dxf?
775		{dxa dxb dyb dyc dyd dxe dye dxf}+ dyf?
776		"""
777		args = self.popall()
778		while args:
779			args = self.hcurveto(args)
780			if args:
781				args = self.vcurveto(args)
782
783	#
784	# path constructors, flex
785	#
786	def op_hflex(self, index):
787		dx1, dx2, dy2, dx3, dx4, dx5, dx6 = self.popall()
788		dy1 = dy3 = dy4 = dy6 = 0
789		dy5 = -dy2
790		self.rCurveTo((dx1, dy1), (dx2, dy2), (dx3, dy3))
791		self.rCurveTo((dx4, dy4), (dx5, dy5), (dx6, dy6))
792	def op_flex(self, index):
793		dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4, dx5, dy5, dx6, dy6, fd = self.popall()
794		self.rCurveTo((dx1, dy1), (dx2, dy2), (dx3, dy3))
795		self.rCurveTo((dx4, dy4), (dx5, dy5), (dx6, dy6))
796	def op_hflex1(self, index):
797		dx1, dy1, dx2, dy2, dx3, dx4, dx5, dy5, dx6 = self.popall()
798		dy3 = dy4 = 0
799		dy6 = -(dy1 + dy2 + dy3 + dy4 + dy5)
800
801		self.rCurveTo((dx1, dy1), (dx2, dy2), (dx3, dy3))
802		self.rCurveTo((dx4, dy4), (dx5, dy5), (dx6, dy6))
803	def op_flex1(self, index):
804		dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4, dx5, dy5, d6 = self.popall()
805		dx = dx1 + dx2 + dx3 + dx4 + dx5
806		dy = dy1 + dy2 + dy3 + dy4 + dy5
807		if abs(dx) > abs(dy):
808			dx6 = d6
809			dy6 = -dy
810		else:
811			dx6 = -dx
812			dy6 = d6
813		self.rCurveTo((dx1, dy1), (dx2, dy2), (dx3, dy3))
814		self.rCurveTo((dx4, dy4), (dx5, dy5), (dx6, dy6))
815
816	#
817	# MultipleMaster. Well...
818	#
819	def op_blend(self, index):
820		args = self.popall()
821
822	# misc
823	def op_and(self, index):
824		raise NotImplementedError
825	def op_or(self, index):
826		raise NotImplementedError
827	def op_not(self, index):
828		raise NotImplementedError
829	def op_store(self, index):
830		raise NotImplementedError
831	def op_abs(self, index):
832		raise NotImplementedError
833	def op_add(self, index):
834		raise NotImplementedError
835	def op_sub(self, index):
836		raise NotImplementedError
837	def op_div(self, index):
838		num2 = self.pop()
839		num1 = self.pop()
840		d1 = num1/num2
841		d2 = float(num1)/num2
842		if d1 == d2:
843			self.push(d1)
844		else:
845			self.push(d2)
846	def op_load(self, index):
847		raise NotImplementedError
848	def op_neg(self, index):
849		raise NotImplementedError
850	def op_eq(self, index):
851		raise NotImplementedError
852	def op_drop(self, index):
853		raise NotImplementedError
854	def op_put(self, index):
855		raise NotImplementedError
856	def op_get(self, index):
857		raise NotImplementedError
858	def op_ifelse(self, index):
859		raise NotImplementedError
860	def op_random(self, index):
861		raise NotImplementedError
862	def op_mul(self, index):
863		raise NotImplementedError
864	def op_sqrt(self, index):
865		raise NotImplementedError
866	def op_dup(self, index):
867		raise NotImplementedError
868	def op_exch(self, index):
869		raise NotImplementedError
870	def op_index(self, index):
871		raise NotImplementedError
872	def op_roll(self, index):
873		raise NotImplementedError
874
875	#
876	# miscelaneous helpers
877	#
878	def alternatingLineto(self, isHorizontal):
879		args = self.popall()
880		for arg in args:
881			if isHorizontal:
882				point = (arg, 0)
883			else:
884				point = (0, arg)
885			self.rLineTo(point)
886			isHorizontal = not isHorizontal
887
888	def vcurveto(self, args):
889		dya, dxb, dyb, dxc = args[:4]
890		args = args[4:]
891		if len(args) == 1:
892			dyc = args[0]
893			args = []
894		else:
895			dyc = 0
896		self.rCurveTo((0, dya), (dxb, dyb), (dxc, dyc))
897		return args
898
899	def hcurveto(self, args):
900		dxa, dxb, dyb, dyc = args[:4]
901		args = args[4:]
902		if len(args) == 1:
903			dxc = args[0]
904			args = []
905		else:
906			dxc = 0
907		self.rCurveTo((dxa, 0), (dxb, dyb), (dxc, dyc))
908		return args
909
910
911class T1OutlineExtractor(T2OutlineExtractor):
912
913	def __init__(self, pen, subrs):
914		self.pen = pen
915		self.subrs = subrs
916		self.reset()
917
918	def reset(self):
919		self.flexing = 0
920		self.width = 0
921		self.sbx = 0
922		T2OutlineExtractor.reset(self)
923
924	def endPath(self):
925		if self.sawMoveTo:
926			self.pen.endPath()
927		self.sawMoveTo = 0
928
929	def popallWidth(self, evenOdd=0):
930		return self.popall()
931
932	def exch(self):
933		stack = self.operandStack
934		stack[-1], stack[-2] = stack[-2], stack[-1]
935
936	#
937	# path constructors
938	#
939	def op_rmoveto(self, index):
940		if self.flexing:
941			return
942		self.endPath()
943		self.rMoveTo(self.popall())
944	def op_hmoveto(self, index):
945		if self.flexing:
946			# We must add a parameter to the stack if we are flexing
947			self.push(0)
948			return
949		self.endPath()
950		self.rMoveTo((self.popall()[0], 0))
951	def op_vmoveto(self, index):
952		if self.flexing:
953			# We must add a parameter to the stack if we are flexing
954			self.push(0)
955			self.exch()
956			return
957		self.endPath()
958		self.rMoveTo((0, self.popall()[0]))
959	def op_closepath(self, index):
960		self.closePath()
961	def op_setcurrentpoint(self, index):
962		args = self.popall()
963		x, y = args
964		self.currentPoint = x, y
965
966	def op_endchar(self, index):
967		self.endPath()
968
969	def op_hsbw(self, index):
970		sbx, wx = self.popall()
971		self.width = wx
972		self.sbx = sbx
973		self.currentPoint = sbx, self.currentPoint[1]
974	def op_sbw(self, index):
975		self.popall()  # XXX
976
977	#
978	def op_callsubr(self, index):
979		subrIndex = self.pop()
980		subr = self.subrs[subrIndex]
981		self.execute(subr)
982	def op_callothersubr(self, index):
983		subrIndex = self.pop()
984		nArgs = self.pop()
985		#print nArgs, subrIndex, "callothersubr"
986		if subrIndex == 0 and nArgs == 3:
987			self.doFlex()
988			self.flexing = 0
989		elif subrIndex == 1 and nArgs == 0:
990			self.flexing = 1
991		# ignore...
992	def op_pop(self, index):
993		pass  # ignore...
994
995	def doFlex(self):
996		finaly = self.pop()
997		finalx = self.pop()
998		self.pop()	# flex height is unused
999
1000		p3y = self.pop()
1001		p3x = self.pop()
1002		bcp4y = self.pop()
1003		bcp4x = self.pop()
1004		bcp3y = self.pop()
1005		bcp3x = self.pop()
1006		p2y = self.pop()
1007		p2x = self.pop()
1008		bcp2y = self.pop()
1009		bcp2x = self.pop()
1010		bcp1y = self.pop()
1011		bcp1x = self.pop()
1012		rpy = self.pop()
1013		rpx = self.pop()
1014
1015		# call rrcurveto
1016		self.push(bcp1x+rpx)
1017		self.push(bcp1y+rpy)
1018		self.push(bcp2x)
1019		self.push(bcp2y)
1020		self.push(p2x)
1021		self.push(p2y)
1022		self.op_rrcurveto(None)
1023
1024		# call rrcurveto
1025		self.push(bcp3x)
1026		self.push(bcp3y)
1027		self.push(bcp4x)
1028		self.push(bcp4y)
1029		self.push(p3x)
1030		self.push(p3y)
1031		self.op_rrcurveto(None)
1032
1033		# Push back final coords so subr 0 can find them
1034		self.push(finalx)
1035		self.push(finaly)
1036
1037	def op_dotsection(self, index):
1038		self.popall()  # XXX
1039	def op_hstem3(self, index):
1040		self.popall()  # XXX
1041	def op_seac(self, index):
1042		"asb adx ady bchar achar seac"
1043		from fontTools.encodings.StandardEncoding import StandardEncoding
1044		asb, adx, ady, bchar, achar = self.popall()
1045		baseGlyph = StandardEncoding[bchar]
1046		self.pen.addComponent(baseGlyph, (1, 0, 0, 1, 0, 0))
1047		accentGlyph = StandardEncoding[achar]
1048		adx = adx + self.sbx - asb  # seac weirdness
1049		self.pen.addComponent(accentGlyph, (1, 0, 0, 1, adx, ady))
1050	def op_vstem3(self, index):
1051		self.popall()  # XXX
1052
1053
1054class DictDecompiler(ByteCodeBase):
1055
1056	operandEncoding = cffDictOperandEncoding
1057
1058	def __init__(self, strings):
1059		self.stack = []
1060		self.strings = strings
1061		self.dict = {}
1062
1063	def getDict(self):
1064		assert len(self.stack) == 0, "non-empty stack"
1065		return self.dict
1066
1067	def decompile(self, data):
1068		index = 0
1069		lenData = len(data)
1070		push = self.stack.append
1071		while index < lenData:
1072			b0 = ord(data[index])
1073			index = index + 1
1074			code = self.operandEncoding[b0]
1075			handler = getattr(self, code)
1076			value, index = handler(b0, data, index)
1077			if value is not None:
1078				push(value)
1079
1080	def pop(self):
1081		value = self.stack[-1]
1082		del self.stack[-1]
1083		return value
1084
1085	def popall(self):
1086		all = self.stack[:]
1087		del self.stack[:]
1088		return all
1089
1090	def do_operator(self, b0, data, index):
1091		if b0 == 12:
1092			op = (b0, ord(data[index]))
1093			index = index+1
1094		else:
1095			op = b0
1096		operator, argType = self.operators[op]
1097		self.handle_operator(operator, argType)
1098		return None, index
1099
1100	def handle_operator(self, operator, argType):
1101		if type(argType) == type(()):
1102			value = ()
1103			for i in range(len(argType)-1, -1, -1):
1104				arg = argType[i]
1105				arghandler = getattr(self, "arg_" + arg)
1106				value = (arghandler(operator),) + value
1107		else:
1108			arghandler = getattr(self, "arg_" + argType)
1109			value = arghandler(operator)
1110		self.dict[operator] = value
1111
1112	def arg_number(self, name):
1113		return self.pop()
1114	def arg_SID(self, name):
1115		return self.strings[self.pop()]
1116	def arg_array(self, name):
1117		return self.popall()
1118	def arg_delta(self, name):
1119		out = []
1120		current = 0
1121		for v in self.popall():
1122			current = current + v
1123			out.append(current)
1124		return out
1125
1126
1127def calcSubrBias(subrs):
1128	nSubrs = len(subrs)
1129	if nSubrs < 1240:
1130		bias = 107
1131	elif nSubrs < 33900:
1132		bias = 1131
1133	else:
1134		bias = 32768
1135	return bias
1136