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