17842e56b97ce677b83bdab09cda48bc2d89ac75aJust"""psCharStrings.py -- module implementing various kinds of CharStrings:
27842e56b97ce677b83bdab09cda48bc2d89ac75aJustCFF dictionary data and Type1/Type2 CharStrings.
37842e56b97ce677b83bdab09cda48bc2d89ac75aJust"""
47842e56b97ce677b83bdab09cda48bc2d89ac75aJust
51ae29591efbb29492ce05378909ccf4028d7c1eeBehdad Esfahbodfrom __future__ import print_function, division, absolute_import
630e691edd056ba22fa8970280e986747817bec3dBehdad Esfahbodfrom fontTools.misc.py23 import *
77842e56b97ce677b83bdab09cda48bc2d89ac75aJustimport struct
87842e56b97ce677b83bdab09cda48bc2d89ac75aJust
97842e56b97ce677b83bdab09cda48bc2d89ac75aJust
10455af6592bffbd6f2fc9f56fbfe083022a8353d4jvrDEBUG = 0
11455af6592bffbd6f2fc9f56fbfe083022a8353d4jvr
12455af6592bffbd6f2fc9f56fbfe083022a8353d4jvr
137842e56b97ce677b83bdab09cda48bc2d89ac75aJustt1OperandEncoding = [None] * 256
147842e56b97ce677b83bdab09cda48bc2d89ac75aJustt1OperandEncoding[0:32] = (32) * ["do_operator"]
157842e56b97ce677b83bdab09cda48bc2d89ac75aJustt1OperandEncoding[32:247] = (247 - 32) * ["read_byte"]
167842e56b97ce677b83bdab09cda48bc2d89ac75aJustt1OperandEncoding[247:251] = (251 - 247) * ["read_smallInt1"]
177842e56b97ce677b83bdab09cda48bc2d89ac75aJustt1OperandEncoding[251:255] = (255 - 251) * ["read_smallInt2"]
187842e56b97ce677b83bdab09cda48bc2d89ac75aJustt1OperandEncoding[255] = "read_longInt"
197842e56b97ce677b83bdab09cda48bc2d89ac75aJustassert len(t1OperandEncoding) == 256
207842e56b97ce677b83bdab09cda48bc2d89ac75aJust
217842e56b97ce677b83bdab09cda48bc2d89ac75aJustt2OperandEncoding = t1OperandEncoding[:]
227842e56b97ce677b83bdab09cda48bc2d89ac75aJustt2OperandEncoding[28] = "read_shortInt"
2395c9e9fc11dc028bd1747788f2b417f3936fc59bjvrt2OperandEncoding[255] = "read_fixed1616"
247842e56b97ce677b83bdab09cda48bc2d89ac75aJust
257842e56b97ce677b83bdab09cda48bc2d89ac75aJustcffDictOperandEncoding = t2OperandEncoding[:]
267842e56b97ce677b83bdab09cda48bc2d89ac75aJustcffDictOperandEncoding[29] = "read_longInt"
277842e56b97ce677b83bdab09cda48bc2d89ac75aJustcffDictOperandEncoding[30] = "read_realNumber"
287842e56b97ce677b83bdab09cda48bc2d89ac75aJustcffDictOperandEncoding[255] = "reserved"
297842e56b97ce677b83bdab09cda48bc2d89ac75aJust
307842e56b97ce677b83bdab09cda48bc2d89ac75aJust
317842e56b97ce677b83bdab09cda48bc2d89ac75aJustrealNibbles = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
327842e56b97ce677b83bdab09cda48bc2d89ac75aJust		'.', 'E', 'E-', None, '-']
33f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrrealNibblesDict = {}
34f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrfor _i in range(len(realNibbles)):
35f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	realNibblesDict[realNibbles[_i]] = _i
367842e56b97ce677b83bdab09cda48bc2d89ac75aJust
377842e56b97ce677b83bdab09cda48bc2d89ac75aJust
38e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass ByteCodeBase(object):
397842e56b97ce677b83bdab09cda48bc2d89ac75aJust
407842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def read_byte(self, b0, data, index):
417842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return b0 - 139, index
427842e56b97ce677b83bdab09cda48bc2d89ac75aJust
437842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def read_smallInt1(self, b0, data, index):
44319c5fd10e2ea84304bd299b7483e05b5b0d5480Behdad Esfahbod		b1 = byteord(data[index])
457842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return (b0-247)*256 + b1 + 108, index+1
467842e56b97ce677b83bdab09cda48bc2d89ac75aJust
477842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def read_smallInt2(self, b0, data, index):
48319c5fd10e2ea84304bd299b7483e05b5b0d5480Behdad Esfahbod		b1 = byteord(data[index])
497842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return -(b0-251)*256 - b1 - 108, index+1
507842e56b97ce677b83bdab09cda48bc2d89ac75aJust
517842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def read_shortInt(self, b0, data, index):
5218316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod		value, = struct.unpack(">h", data[index:index+2])
537842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return value, index+2
547842e56b97ce677b83bdab09cda48bc2d89ac75aJust
557842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def read_longInt(self, b0, data, index):
5618316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod		value, = struct.unpack(">l", data[index:index+4])
577842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return value, index+4
587842e56b97ce677b83bdab09cda48bc2d89ac75aJust
5995c9e9fc11dc028bd1747788f2b417f3936fc59bjvr	def read_fixed1616(self, b0, data, index):
6018316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod		value, = struct.unpack(">l", data[index:index+4])
6132c10eecffb4923e0721c395e4b80fb732543f18Behdad Esfahbod		return value / 65536, index+4
6295c9e9fc11dc028bd1747788f2b417f3936fc59bjvr
637842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def read_realNumber(self, b0, data, index):
647842e56b97ce677b83bdab09cda48bc2d89ac75aJust		number = ''
65ac1b4359467ca3deab03186a15eae1d55eb35567Behdad Esfahbod		while True:
66319c5fd10e2ea84304bd299b7483e05b5b0d5480Behdad Esfahbod			b = byteord(data[index])
677842e56b97ce677b83bdab09cda48bc2d89ac75aJust			index = index + 1
687842e56b97ce677b83bdab09cda48bc2d89ac75aJust			nibble0 = (b & 0xf0) >> 4
697842e56b97ce677b83bdab09cda48bc2d89ac75aJust			nibble1 = b & 0x0f
707842e56b97ce677b83bdab09cda48bc2d89ac75aJust			if nibble0 == 0xf:
717842e56b97ce677b83bdab09cda48bc2d89ac75aJust				break
727842e56b97ce677b83bdab09cda48bc2d89ac75aJust			number = number + realNibbles[nibble0]
737842e56b97ce677b83bdab09cda48bc2d89ac75aJust			if nibble1 == 0xf:
747842e56b97ce677b83bdab09cda48bc2d89ac75aJust				break
757842e56b97ce677b83bdab09cda48bc2d89ac75aJust			number = number + realNibbles[nibble1]
76455af6592bffbd6f2fc9f56fbfe083022a8353d4jvr		return float(number), index
777842e56b97ce677b83bdab09cda48bc2d89ac75aJust
787842e56b97ce677b83bdab09cda48bc2d89ac75aJust
79dbc2c173b35360386c907a3c70cb931ae4c3fac9jvrdef buildOperatorDict(operatorList):
80455af6592bffbd6f2fc9f56fbfe083022a8353d4jvr	oper = {}
81455af6592bffbd6f2fc9f56fbfe083022a8353d4jvr	opc = {}
827842e56b97ce677b83bdab09cda48bc2d89ac75aJust	for item in operatorList:
837842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if len(item) == 2:
84455af6592bffbd6f2fc9f56fbfe083022a8353d4jvr			oper[item[0]] = item[1]
85455af6592bffbd6f2fc9f56fbfe083022a8353d4jvr		else:
86455af6592bffbd6f2fc9f56fbfe083022a8353d4jvr			oper[item[0]] = item[1:]
87002c32fd0d869e280783777ec57916a9267aaea5Behdad Esfahbod		if isinstance(item[0], tuple):
88455af6592bffbd6f2fc9f56fbfe083022a8353d4jvr			opc[item[1]] = item[0]
897842e56b97ce677b83bdab09cda48bc2d89ac75aJust		else:
90455af6592bffbd6f2fc9f56fbfe083022a8353d4jvr			opc[item[1]] = (item[0],)
91455af6592bffbd6f2fc9f56fbfe083022a8353d4jvr	return oper, opc
927842e56b97ce677b83bdab09cda48bc2d89ac75aJust
937842e56b97ce677b83bdab09cda48bc2d89ac75aJust
947842e56b97ce677b83bdab09cda48bc2d89ac75aJustt2Operators = [
957842e56b97ce677b83bdab09cda48bc2d89ac75aJust#	opcode     name
967842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(1,        'hstem'),
977842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(3,        'vstem'),
987842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(4,        'vmoveto'),
997842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(5,        'rlineto'),
1007842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(6,        'hlineto'),
1017842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(7,        'vlineto'),
1027842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(8,        'rrcurveto'),
1037842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(10,       'callsubr'),
1047842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(11,       'return'),
1057842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(14,       'endchar'),
1067842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(16,       'blend'),
1077842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(18,       'hstemhm'),
1087842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(19,       'hintmask'),
1097842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(20,       'cntrmask'),
1107842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(21,       'rmoveto'),
1117842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(22,       'hmoveto'),
1127842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(23,       'vstemhm'),
1137842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(24,       'rcurveline'),
1147842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(25,       'rlinecurve'),
1157842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(26,       'vvcurveto'),
1167842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(27,       'hhcurveto'),
1177842e56b97ce677b83bdab09cda48bc2d89ac75aJust#	(28,       'shortint'),  # not really an operator
1187842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(29,       'callgsubr'),
1197842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(30,       'vhcurveto'),
1207842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(31,       'hvcurveto'),
1217099f4c0f9fbaf1a5c811113fdfd2404dee04361jvr	((12, 0),  'ignore'),  # dotsection. Yes, there a few very early OTF/CFF
1227099f4c0f9fbaf1a5c811113fdfd2404dee04361jvr	                   # fonts with this deprecated operator. Just ignore it.
1237842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 3),  'and'),
1247842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 4),  'or'),
1257842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 5),  'not'),
1267842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 8),  'store'),
1277842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 9),  'abs'),
1287842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 10), 'add'),
1297842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 11), 'sub'),
1307842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 12), 'div'),
1317842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 13), 'load'),
1327842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 14), 'neg'),
1337842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 15), 'eq'),
1347842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 18), 'drop'),
1357842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 20), 'put'),
1367842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 21), 'get'),
1377842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 22), 'ifelse'),
1387842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 23), 'random'),
1397842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 24), 'mul'),
1407842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 26), 'sqrt'),
1417842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 27), 'dup'),
1427842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 28), 'exch'),
1437842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 29), 'index'),
1447842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 30), 'roll'),
1457842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 34), 'hflex'),
1467842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 35), 'flex'),
1477842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 36), 'hflex1'),
1487842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 37), 'flex1'),
1497842e56b97ce677b83bdab09cda48bc2d89ac75aJust]
1507842e56b97ce677b83bdab09cda48bc2d89ac75aJust
151f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
152f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrdef getIntEncoder(format):
153f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	if format == "cff":
154b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod		fourByteOp = bytechr(29)
155f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	elif format == "t1":
156b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod		fourByteOp = bytechr(255)
157f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	else:
158f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		assert format == "t2"
15995c9e9fc11dc028bd1747788f2b417f3936fc59bjvr		fourByteOp = None
160f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
161b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod	def encodeInt(value, fourByteOp=fourByteOp, bytechr=bytechr,
16295c9e9fc11dc028bd1747788f2b417f3936fc59bjvr			pack=struct.pack, unpack=struct.unpack):
163f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		if -107 <= value <= 107:
164b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod			code = bytechr(value + 139)
165f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		elif 108 <= value <= 1131:
166f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			value = value - 108
167b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod			code = bytechr((value >> 8) + 247) + bytechr(value & 0xFF)
168f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		elif -1131 <= value <= -108:
169f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			value = -value - 108
170b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod			code = bytechr((value >> 8) + 251) + bytechr(value & 0xFF)
17195c9e9fc11dc028bd1747788f2b417f3936fc59bjvr		elif fourByteOp is None:
17295c9e9fc11dc028bd1747788f2b417f3936fc59bjvr			# T2 only supports 2 byte ints
17395c9e9fc11dc028bd1747788f2b417f3936fc59bjvr			if -32768 <= value <= 32767:
174b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod				code = bytechr(28) + pack(">h", value)
17595c9e9fc11dc028bd1747788f2b417f3936fc59bjvr			else:
17695c9e9fc11dc028bd1747788f2b417f3936fc59bjvr				# Backwards compatible hack: due to a previous bug in FontTools,
17795c9e9fc11dc028bd1747788f2b417f3936fc59bjvr				# 16.16 fixed numbers were written out as 4-byte ints. When
17895c9e9fc11dc028bd1747788f2b417f3936fc59bjvr				# these numbers were small, they were wrongly written back as
17995c9e9fc11dc028bd1747788f2b417f3936fc59bjvr				# small ints instead of 4-byte ints, breaking round-tripping.
18095c9e9fc11dc028bd1747788f2b417f3936fc59bjvr				# This here workaround doesn't do it any better, since we can't
18195c9e9fc11dc028bd1747788f2b417f3936fc59bjvr				# distinguish anymore between small ints that were supposed to
18295c9e9fc11dc028bd1747788f2b417f3936fc59bjvr				# be small fixed numbers and small ints that were just small
18395c9e9fc11dc028bd1747788f2b417f3936fc59bjvr				# ints. Hence the warning.
18495c9e9fc11dc028bd1747788f2b417f3936fc59bjvr				import sys
18595c9e9fc11dc028bd1747788f2b417f3936fc59bjvr				sys.stderr.write("Warning: 4-byte T2 number got passed to the "
18695c9e9fc11dc028bd1747788f2b417f3936fc59bjvr					"IntType handler. This should happen only when reading in "
18795c9e9fc11dc028bd1747788f2b417f3936fc59bjvr					"old XML files.\n")
188b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod				code = bytechr(255) + pack(">l", value)
189f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		else:
190f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			code = fourByteOp + pack(">l", value)
191f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		return code
192f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
193f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	return encodeInt
194f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
195f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
196f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrencodeIntCFF = getIntEncoder("cff")
197f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrencodeIntT1 = getIntEncoder("t1")
198f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrencodeIntT2 = getIntEncoder("t2")
199f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
20095c9e9fc11dc028bd1747788f2b417f3936fc59bjvrdef encodeFixed(f, pack=struct.pack):
20195c9e9fc11dc028bd1747788f2b417f3936fc59bjvr	# For T2 only
20218316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod	return b"\xff" + pack(">l", int(round(f * 65536)))
20395c9e9fc11dc028bd1747788f2b417f3936fc59bjvr
204f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrdef encodeFloat(f):
20595c9e9fc11dc028bd1747788f2b417f3936fc59bjvr	# For CFF only, used in cffLib
206f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	s = str(f).upper()
207f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	if s[:2] == "0.":
208f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		s = s[1:]
209f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	elif s[:3] == "-0.":
210f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		s = "-" + s[2:]
211f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	nibbles = []
212f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	while s:
213f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		c = s[0]
214f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		s = s[1:]
215f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		if c == "E" and s[:1] == "-":
216f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			s = s[1:]
217f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr			c = "E-"
218f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		nibbles.append(realNibblesDict[c])
219f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	nibbles.append(0xf)
220f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	if len(nibbles) % 2:
221f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		nibbles.append(0xf)
222b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod	d = bytechr(30)
223f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	for i in range(0, len(nibbles), 2):
224b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod		d = d + bytechr(nibbles[i] << 4 | nibbles[i+1])
225f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	return d
226f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
227f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
2284e5af60930726d06a58a30bae45bb27ae50aea77jvrclass CharStringCompileError(Exception): pass
2294e5af60930726d06a58a30bae45bb27ae50aea77jvr
2304e5af60930726d06a58a30bae45bb27ae50aea77jvr
231f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrclass T2CharString(ByteCodeBase):
2327842e56b97ce677b83bdab09cda48bc2d89ac75aJust
2337842e56b97ce677b83bdab09cda48bc2d89ac75aJust	operandEncoding = t2OperandEncoding
234455af6592bffbd6f2fc9f56fbfe083022a8353d4jvr	operators, opcodes = buildOperatorDict(t2Operators)
2357842e56b97ce677b83bdab09cda48bc2d89ac75aJust
236489d76a340845361def6af9ab7d9152f8e66f417jvr	def __init__(self, bytecode=None, program=None, private=None, globalSubrs=None):
2377842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if program is None:
2387842e56b97ce677b83bdab09cda48bc2d89ac75aJust			program = []
2397842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.bytecode = bytecode
2407842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.program = program
241489d76a340845361def6af9ab7d9152f8e66f417jvr		self.private = private
242846d09e380215f8c7fdb4bbb9f083f8e68722cdaBehdad Esfahbod		self.globalSubrs = globalSubrs if globalSubrs is not None else []
2437842e56b97ce677b83bdab09cda48bc2d89ac75aJust
2447842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def __repr__(self):
2457842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if self.bytecode is None:
2467842e56b97ce677b83bdab09cda48bc2d89ac75aJust			return "<%s (source) at %x>" % (self.__class__.__name__, id(self))
2477842e56b97ce677b83bdab09cda48bc2d89ac75aJust		else:
2487842e56b97ce677b83bdab09cda48bc2d89ac75aJust			return "<%s (bytecode) at %x>" % (self.__class__.__name__, id(self))
2497842e56b97ce677b83bdab09cda48bc2d89ac75aJust
25095c9e9fc11dc028bd1747788f2b417f3936fc59bjvr	def getIntEncoder(self):
25195c9e9fc11dc028bd1747788f2b417f3936fc59bjvr		return encodeIntT2
25295c9e9fc11dc028bd1747788f2b417f3936fc59bjvr
25395c9e9fc11dc028bd1747788f2b417f3936fc59bjvr	def getFixedEncoder(self):
25495c9e9fc11dc028bd1747788f2b417f3936fc59bjvr		return encodeFixed
25595c9e9fc11dc028bd1747788f2b417f3936fc59bjvr
256586345b7c1c0aa97b06f1597b67c3bb4c4e97be1jvr	def decompile(self):
257586345b7c1c0aa97b06f1597b67c3bb4c4e97be1jvr		if not self.needsDecompilation():
258586345b7c1c0aa97b06f1597b67c3bb4c4e97be1jvr			return
259489d76a340845361def6af9ab7d9152f8e66f417jvr		subrs = getattr(self.private, "Subrs", [])
260489d76a340845361def6af9ab7d9152f8e66f417jvr		decompiler = SimpleT2Decompiler(subrs, self.globalSubrs)
261586345b7c1c0aa97b06f1597b67c3bb4c4e97be1jvr		decompiler.execute(self)
262586345b7c1c0aa97b06f1597b67c3bb4c4e97be1jvr
263489d76a340845361def6af9ab7d9152f8e66f417jvr	def draw(self, pen):
264489d76a340845361def6af9ab7d9152f8e66f417jvr		subrs = getattr(self.private, "Subrs", [])
265489d76a340845361def6af9ab7d9152f8e66f417jvr		extractor = T2OutlineExtractor(pen, subrs, self.globalSubrs,
266489d76a340845361def6af9ab7d9152f8e66f417jvr				self.private.nominalWidthX, self.private.defaultWidthX)
267489d76a340845361def6af9ab7d9152f8e66f417jvr		extractor.execute(self)
268489d76a340845361def6af9ab7d9152f8e66f417jvr		self.width = extractor.width
269489d76a340845361def6af9ab7d9152f8e66f417jvr
270455af6592bffbd6f2fc9f56fbfe083022a8353d4jvr	def compile(self):
271455af6592bffbd6f2fc9f56fbfe083022a8353d4jvr		if self.bytecode is not None:
272455af6592bffbd6f2fc9f56fbfe083022a8353d4jvr			return
2739920ad5286b6e61d67f07f908107d65f7fa817acjvr		assert self.program, "illegal CharString: decompiled to empty program"
2749920ad5286b6e61d67f07f908107d65f7fa817acjvr		assert self.program[-1] in ("endchar", "return", "callsubr", "callgsubr",
2759920ad5286b6e61d67f07f908107d65f7fa817acjvr				"seac"), "illegal CharString"
276455af6592bffbd6f2fc9f56fbfe083022a8353d4jvr		bytecode = []
277455af6592bffbd6f2fc9f56fbfe083022a8353d4jvr		opcodes = self.opcodes
2784e5af60930726d06a58a30bae45bb27ae50aea77jvr		program = self.program
27995c9e9fc11dc028bd1747788f2b417f3936fc59bjvr		encodeInt = self.getIntEncoder()
28095c9e9fc11dc028bd1747788f2b417f3936fc59bjvr		encodeFixed = self.getFixedEncoder()
2814e5af60930726d06a58a30bae45bb27ae50aea77jvr		i = 0
2824e5af60930726d06a58a30bae45bb27ae50aea77jvr		end = len(program)
2834e5af60930726d06a58a30bae45bb27ae50aea77jvr		while i < end:
2844e5af60930726d06a58a30bae45bb27ae50aea77jvr			token = program[i]
2854e5af60930726d06a58a30bae45bb27ae50aea77jvr			i = i + 1
286455af6592bffbd6f2fc9f56fbfe083022a8353d4jvr			tp = type(token)
287278c88c0afa33fcd1a267f2741d2f95983006e4dBehdad Esfahbod			if issubclass(tp, basestring):
2884e5af60930726d06a58a30bae45bb27ae50aea77jvr				try:
289b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod					bytecode.extend(bytechr(b) for b in opcodes[token])
2904e5af60930726d06a58a30bae45bb27ae50aea77jvr				except KeyError:
291cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod					raise CharStringCompileError("illegal operator: %s" % token)
2924e5af60930726d06a58a30bae45bb27ae50aea77jvr				if token in ('hintmask', 'cntrmask'):
2934e5af60930726d06a58a30bae45bb27ae50aea77jvr					bytecode.append(program[i])  # hint mask
2944e5af60930726d06a58a30bae45bb27ae50aea77jvr					i = i + 1
295002c32fd0d869e280783777ec57916a9267aaea5Behdad Esfahbod			elif tp == int:
29695c9e9fc11dc028bd1747788f2b417f3936fc59bjvr				bytecode.append(encodeInt(token))
297002c32fd0d869e280783777ec57916a9267aaea5Behdad Esfahbod			elif tp == float:
29895c9e9fc11dc028bd1747788f2b417f3936fc59bjvr				bytecode.append(encodeFixed(token))
299455af6592bffbd6f2fc9f56fbfe083022a8353d4jvr			else:
300f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr				assert 0, "unsupported type: %s" % tp
3014e5af60930726d06a58a30bae45bb27ae50aea77jvr		try:
30218316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod			bytecode = bytesjoin(bytecode)
3034e5af60930726d06a58a30bae45bb27ae50aea77jvr		except TypeError:
3043ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod			print(bytecode)
3054e5af60930726d06a58a30bae45bb27ae50aea77jvr			raise
306f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		self.setBytecode(bytecode)
307f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
3087842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def needsDecompilation(self):
3097842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return self.bytecode is not None
3107842e56b97ce677b83bdab09cda48bc2d89ac75aJust
3117842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def setProgram(self, program):
3127842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.program = program
3137842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.bytecode = None
3147842e56b97ce677b83bdab09cda48bc2d89ac75aJust
315f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr	def setBytecode(self, bytecode):
316f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		self.bytecode = bytecode
317f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr		self.program = None
318f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvr
3197842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def getToken(self, index,
320319c5fd10e2ea84304bd299b7483e05b5b0d5480Behdad Esfahbod			len=len, byteord=byteord, getattr=getattr, type=type, StringType=str):
3217842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if self.bytecode is not None:
3227842e56b97ce677b83bdab09cda48bc2d89ac75aJust			if index >= len(self.bytecode):
3237842e56b97ce677b83bdab09cda48bc2d89ac75aJust				return None, 0, 0
324319c5fd10e2ea84304bd299b7483e05b5b0d5480Behdad Esfahbod			b0 = byteord(self.bytecode[index])
3257842e56b97ce677b83bdab09cda48bc2d89ac75aJust			index = index + 1
3267842e56b97ce677b83bdab09cda48bc2d89ac75aJust			code = self.operandEncoding[b0]
3277842e56b97ce677b83bdab09cda48bc2d89ac75aJust			handler = getattr(self, code)
3287842e56b97ce677b83bdab09cda48bc2d89ac75aJust			token, index = handler(b0, self.bytecode, index)
3297842e56b97ce677b83bdab09cda48bc2d89ac75aJust		else:
3307842e56b97ce677b83bdab09cda48bc2d89ac75aJust			if index >= len(self.program):
3317842e56b97ce677b83bdab09cda48bc2d89ac75aJust				return None, 0, 0
3327842e56b97ce677b83bdab09cda48bc2d89ac75aJust			token = self.program[index]
3337842e56b97ce677b83bdab09cda48bc2d89ac75aJust			index = index + 1
334ac1b4359467ca3deab03186a15eae1d55eb35567Behdad Esfahbod		isOperator = isinstance(token, StringType)
3357842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return token, isOperator, index
3367842e56b97ce677b83bdab09cda48bc2d89ac75aJust
3377842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def getBytes(self, index, nBytes):
3387842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if self.bytecode is not None:
3397842e56b97ce677b83bdab09cda48bc2d89ac75aJust			newIndex = index + nBytes
3407842e56b97ce677b83bdab09cda48bc2d89ac75aJust			bytes = self.bytecode[index:newIndex]
3417842e56b97ce677b83bdab09cda48bc2d89ac75aJust			index = newIndex
3427842e56b97ce677b83bdab09cda48bc2d89ac75aJust		else:
3437842e56b97ce677b83bdab09cda48bc2d89ac75aJust			bytes = self.program[index]
3447842e56b97ce677b83bdab09cda48bc2d89ac75aJust			index = index + 1
3457842e56b97ce677b83bdab09cda48bc2d89ac75aJust		assert len(bytes) == nBytes
3467842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return bytes, index
3477842e56b97ce677b83bdab09cda48bc2d89ac75aJust
3487842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def do_operator(self, b0, data, index):
3497842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if b0 == 12:
350319c5fd10e2ea84304bd299b7483e05b5b0d5480Behdad Esfahbod			op = (b0, byteord(data[index]))
3517842e56b97ce677b83bdab09cda48bc2d89ac75aJust			index = index+1
3527842e56b97ce677b83bdab09cda48bc2d89ac75aJust		else:
3537842e56b97ce677b83bdab09cda48bc2d89ac75aJust			op = b0
3547842e56b97ce677b83bdab09cda48bc2d89ac75aJust		operator = self.operators[op]
3557842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return operator, index
3567842e56b97ce677b83bdab09cda48bc2d89ac75aJust
3577842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def toXML(self, xmlWriter):
358dab433233bd4024ede9ad27c6c61ea0072c2edafJust		from fontTools.misc.textTools import num2binary
3597842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if self.bytecode is not None:
3607842e56b97ce677b83bdab09cda48bc2d89ac75aJust			xmlWriter.dumphex(self.bytecode)
3617842e56b97ce677b83bdab09cda48bc2d89ac75aJust		else:
3627842e56b97ce677b83bdab09cda48bc2d89ac75aJust			index = 0
3637842e56b97ce677b83bdab09cda48bc2d89ac75aJust			args = []
364ac1b4359467ca3deab03186a15eae1d55eb35567Behdad Esfahbod			while True:
3657842e56b97ce677b83bdab09cda48bc2d89ac75aJust				token, isOperator, index = self.getToken(index)
3667842e56b97ce677b83bdab09cda48bc2d89ac75aJust				if token is None:
3677842e56b97ce677b83bdab09cda48bc2d89ac75aJust					break
3687842e56b97ce677b83bdab09cda48bc2d89ac75aJust				if isOperator:
369e5ca79699d00fdf7ac6eaceaed372aea8d6bc1fdBehdad Esfahbod					args = [str(arg) for arg in args]
3707842e56b97ce677b83bdab09cda48bc2d89ac75aJust					if token in ('hintmask', 'cntrmask'):
3717842e56b97ce677b83bdab09cda48bc2d89ac75aJust						hintMask, isOperator, index = self.getToken(index)
3727842e56b97ce677b83bdab09cda48bc2d89ac75aJust						bits = []
3737842e56b97ce677b83bdab09cda48bc2d89ac75aJust						for byte in hintMask:
374319c5fd10e2ea84304bd299b7483e05b5b0d5480Behdad Esfahbod							bits.append(num2binary(byteord(byte), 8))
37518316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod						hintMask = strjoin(bits)
37614fb031125b773f0a15eb19be4f02ed8540b2db6Behdad Esfahbod						line = ' '.join(args + [token, hintMask])
3777842e56b97ce677b83bdab09cda48bc2d89ac75aJust					else:
37814fb031125b773f0a15eb19be4f02ed8540b2db6Behdad Esfahbod						line = ' '.join(args + [token])
3797842e56b97ce677b83bdab09cda48bc2d89ac75aJust					xmlWriter.write(line)
3807842e56b97ce677b83bdab09cda48bc2d89ac75aJust					xmlWriter.newline()
3817842e56b97ce677b83bdab09cda48bc2d89ac75aJust					args = []
3827842e56b97ce677b83bdab09cda48bc2d89ac75aJust				else:
3837842e56b97ce677b83bdab09cda48bc2d89ac75aJust					args.append(token)
3844e5af60930726d06a58a30bae45bb27ae50aea77jvr
3853a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod	def fromXML(self, name, attrs, content):
386b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr		from fontTools.misc.textTools import binary2num, readHex
387b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr		if attrs.get("raw"):
388b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr			self.setBytecode(readHex(content))
389b58176e5ac4d1e0b0e6a6c71c3020f5e85bd4dfejvr			return
39018316aa769566eeb6f3f4a6ed2685fa8f8e861c2Behdad Esfahbod		content = strjoin(content)
3914e5af60930726d06a58a30bae45bb27ae50aea77jvr		content = content.split()
3924e5af60930726d06a58a30bae45bb27ae50aea77jvr		program = []
3934e5af60930726d06a58a30bae45bb27ae50aea77jvr		end = len(content)
3944e5af60930726d06a58a30bae45bb27ae50aea77jvr		i = 0
3954e5af60930726d06a58a30bae45bb27ae50aea77jvr		while i < end:
3964e5af60930726d06a58a30bae45bb27ae50aea77jvr			token = content[i]
3974e5af60930726d06a58a30bae45bb27ae50aea77jvr			i = i + 1
3984e5af60930726d06a58a30bae45bb27ae50aea77jvr			try:
3994e5af60930726d06a58a30bae45bb27ae50aea77jvr				token = int(token)
4004e5af60930726d06a58a30bae45bb27ae50aea77jvr			except ValueError:
40195c9e9fc11dc028bd1747788f2b417f3936fc59bjvr				try:
40295c9e9fc11dc028bd1747788f2b417f3936fc59bjvr					token = float(token)
40395c9e9fc11dc028bd1747788f2b417f3936fc59bjvr				except ValueError:
40495c9e9fc11dc028bd1747788f2b417f3936fc59bjvr					program.append(token)
40595c9e9fc11dc028bd1747788f2b417f3936fc59bjvr					if token in ('hintmask', 'cntrmask'):
40695c9e9fc11dc028bd1747788f2b417f3936fc59bjvr						mask = content[i]
407278c88c0afa33fcd1a267f2741d2f95983006e4dBehdad Esfahbod						maskBytes = b""
40895c9e9fc11dc028bd1747788f2b417f3936fc59bjvr						for j in range(0, len(mask), 8):
409b7a2d797a40fb658d1e6dca6c08c9d2e1d83e78aBehdad Esfahbod							maskBytes = maskBytes + bytechr(binary2num(mask[j:j+8]))
41095c9e9fc11dc028bd1747788f2b417f3936fc59bjvr						program.append(maskBytes)
41195c9e9fc11dc028bd1747788f2b417f3936fc59bjvr						i = i + 1
41295c9e9fc11dc028bd1747788f2b417f3936fc59bjvr				else:
41395c9e9fc11dc028bd1747788f2b417f3936fc59bjvr					program.append(token)
4144e5af60930726d06a58a30bae45bb27ae50aea77jvr			else:
4154e5af60930726d06a58a30bae45bb27ae50aea77jvr				program.append(token)
4164e5af60930726d06a58a30bae45bb27ae50aea77jvr		self.setProgram(program)
4177842e56b97ce677b83bdab09cda48bc2d89ac75aJust
4187842e56b97ce677b83bdab09cda48bc2d89ac75aJust
4197842e56b97ce677b83bdab09cda48bc2d89ac75aJustt1Operators = [
4207842e56b97ce677b83bdab09cda48bc2d89ac75aJust#	opcode     name
4217842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(1,        'hstem'),
4227842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(3,        'vstem'),
4237842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(4,        'vmoveto'),
4247842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(5,        'rlineto'),
4257842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(6,        'hlineto'),
4267842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(7,        'vlineto'),
4277842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(8,        'rrcurveto'),
4287842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(9,        'closepath'),
4297842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(10,       'callsubr'),
4307842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(11,       'return'),
4317842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(13,       'hsbw'),
4327842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(14,       'endchar'),
4337842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(21,       'rmoveto'),
4347842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(22,       'hmoveto'),
4357842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(30,       'vhcurveto'),
4367842e56b97ce677b83bdab09cda48bc2d89ac75aJust	(31,       'hvcurveto'),
4377842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 0),  'dotsection'),
4387842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 1),  'vstem3'),
4397842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 2),  'hstem3'),
4407842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 6),  'seac'),
4417842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 7),  'sbw'),
4427842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 12), 'div'),
4437842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 16), 'callothersubr'),
4447842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 17), 'pop'),
4457842e56b97ce677b83bdab09cda48bc2d89ac75aJust	((12, 33), 'setcurrentpoint'),
4467842e56b97ce677b83bdab09cda48bc2d89ac75aJust]
4477842e56b97ce677b83bdab09cda48bc2d89ac75aJust
4487842e56b97ce677b83bdab09cda48bc2d89ac75aJustclass T1CharString(T2CharString):
4497842e56b97ce677b83bdab09cda48bc2d89ac75aJust
4507842e56b97ce677b83bdab09cda48bc2d89ac75aJust	operandEncoding = t1OperandEncoding
451455af6592bffbd6f2fc9f56fbfe083022a8353d4jvr	operators, opcodes = buildOperatorDict(t1Operators)
4527842e56b97ce677b83bdab09cda48bc2d89ac75aJust
453489d76a340845361def6af9ab7d9152f8e66f417jvr	def __init__(self, bytecode=None, program=None, subrs=None):
454489d76a340845361def6af9ab7d9152f8e66f417jvr		if program is None:
455489d76a340845361def6af9ab7d9152f8e66f417jvr			program = []
456489d76a340845361def6af9ab7d9152f8e66f417jvr		self.bytecode = bytecode
457489d76a340845361def6af9ab7d9152f8e66f417jvr		self.program = program
458489d76a340845361def6af9ab7d9152f8e66f417jvr		self.subrs = subrs
459489d76a340845361def6af9ab7d9152f8e66f417jvr
46095c9e9fc11dc028bd1747788f2b417f3936fc59bjvr	def getIntEncoder(self):
46195c9e9fc11dc028bd1747788f2b417f3936fc59bjvr		return encodeIntT1
46295c9e9fc11dc028bd1747788f2b417f3936fc59bjvr
46395c9e9fc11dc028bd1747788f2b417f3936fc59bjvr	def getFixedEncoder(self):
46495c9e9fc11dc028bd1747788f2b417f3936fc59bjvr		def encodeFixed(value):
46595c9e9fc11dc028bd1747788f2b417f3936fc59bjvr			raise TypeError("Type 1 charstrings don't support floating point operands")
46695c9e9fc11dc028bd1747788f2b417f3936fc59bjvr
4677842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def decompile(self):
46878c02b6af38ce255eda220b69e23dad3102129e5Behdad Esfahbod		if self.bytecode is None:
4697842e56b97ce677b83bdab09cda48bc2d89ac75aJust			return
4707842e56b97ce677b83bdab09cda48bc2d89ac75aJust		program = []
4717842e56b97ce677b83bdab09cda48bc2d89ac75aJust		index = 0
472ac1b4359467ca3deab03186a15eae1d55eb35567Behdad Esfahbod		while True:
4737842e56b97ce677b83bdab09cda48bc2d89ac75aJust			token, isOperator, index = self.getToken(index)
4747842e56b97ce677b83bdab09cda48bc2d89ac75aJust			if token is None:
4757842e56b97ce677b83bdab09cda48bc2d89ac75aJust				break
4767842e56b97ce677b83bdab09cda48bc2d89ac75aJust			program.append(token)
4777842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.setProgram(program)
4787842e56b97ce677b83bdab09cda48bc2d89ac75aJust
479489d76a340845361def6af9ab7d9152f8e66f417jvr	def draw(self, pen):
480489d76a340845361def6af9ab7d9152f8e66f417jvr		extractor = T1OutlineExtractor(pen, self.subrs)
481489d76a340845361def6af9ab7d9152f8e66f417jvr		extractor.execute(self)
482489d76a340845361def6af9ab7d9152f8e66f417jvr		self.width = extractor.width
483489d76a340845361def6af9ab7d9152f8e66f417jvr
4847842e56b97ce677b83bdab09cda48bc2d89ac75aJust
485e388db566b9ba42669c7e353db4293cf27bc2a5bBehdad Esfahbodclass SimpleT2Decompiler(object):
4867842e56b97ce677b83bdab09cda48bc2d89ac75aJust
4877842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def __init__(self, localSubrs, globalSubrs):
4887842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.localSubrs = localSubrs
4897842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.localBias = calcSubrBias(localSubrs)
4907842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.globalSubrs = globalSubrs
4917842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.globalBias = calcSubrBias(globalSubrs)
4927842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.reset()
4937842e56b97ce677b83bdab09cda48bc2d89ac75aJust
4947842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def reset(self):
4957842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.callingStack = []
4967842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.operandStack = []
4977842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.hintCount = 0
4987842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.hintMaskBytes = 0
4997842e56b97ce677b83bdab09cda48bc2d89ac75aJust
5007842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def execute(self, charString):
5017842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.callingStack.append(charString)
5027842e56b97ce677b83bdab09cda48bc2d89ac75aJust		needsDecompilation = charString.needsDecompilation()
5037842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if needsDecompilation:
5047842e56b97ce677b83bdab09cda48bc2d89ac75aJust			program = []
5057842e56b97ce677b83bdab09cda48bc2d89ac75aJust			pushToProgram = program.append
5067842e56b97ce677b83bdab09cda48bc2d89ac75aJust		else:
5077842e56b97ce677b83bdab09cda48bc2d89ac75aJust			pushToProgram = lambda x: None
5087842e56b97ce677b83bdab09cda48bc2d89ac75aJust		pushToStack = self.operandStack.append
5097842e56b97ce677b83bdab09cda48bc2d89ac75aJust		index = 0
510ac1b4359467ca3deab03186a15eae1d55eb35567Behdad Esfahbod		while True:
5117842e56b97ce677b83bdab09cda48bc2d89ac75aJust			token, isOperator, index = charString.getToken(index)
5127842e56b97ce677b83bdab09cda48bc2d89ac75aJust			if token is None:
5137842e56b97ce677b83bdab09cda48bc2d89ac75aJust				break  # we're done!
5147842e56b97ce677b83bdab09cda48bc2d89ac75aJust			pushToProgram(token)
5157842e56b97ce677b83bdab09cda48bc2d89ac75aJust			if isOperator:
5167842e56b97ce677b83bdab09cda48bc2d89ac75aJust				handlerName = "op_" + token
5177842e56b97ce677b83bdab09cda48bc2d89ac75aJust				if hasattr(self, handlerName):
5187842e56b97ce677b83bdab09cda48bc2d89ac75aJust					handler = getattr(self, handlerName)
5197842e56b97ce677b83bdab09cda48bc2d89ac75aJust					rv = handler(index)
5207842e56b97ce677b83bdab09cda48bc2d89ac75aJust					if rv:
5217842e56b97ce677b83bdab09cda48bc2d89ac75aJust						hintMaskBytes, index = rv
5227842e56b97ce677b83bdab09cda48bc2d89ac75aJust						pushToProgram(hintMaskBytes)
5237842e56b97ce677b83bdab09cda48bc2d89ac75aJust				else:
5247842e56b97ce677b83bdab09cda48bc2d89ac75aJust					self.popall()
5257842e56b97ce677b83bdab09cda48bc2d89ac75aJust			else:
5267842e56b97ce677b83bdab09cda48bc2d89ac75aJust				pushToStack(token)
5277842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if needsDecompilation:
5289920ad5286b6e61d67f07f908107d65f7fa817acjvr			assert program, "illegal CharString: decompiled to empty program"
5299920ad5286b6e61d67f07f908107d65f7fa817acjvr			assert program[-1] in ("endchar", "return", "callsubr", "callgsubr",
5309920ad5286b6e61d67f07f908107d65f7fa817acjvr					"seac"), "illegal CharString"
5317842e56b97ce677b83bdab09cda48bc2d89ac75aJust			charString.setProgram(program)
5327842e56b97ce677b83bdab09cda48bc2d89ac75aJust		del self.callingStack[-1]
5337842e56b97ce677b83bdab09cda48bc2d89ac75aJust
5347842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def pop(self):
5357842e56b97ce677b83bdab09cda48bc2d89ac75aJust		value = self.operandStack[-1]
5367842e56b97ce677b83bdab09cda48bc2d89ac75aJust		del self.operandStack[-1]
5377842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return value
5387842e56b97ce677b83bdab09cda48bc2d89ac75aJust
5397842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def popall(self):
5407842e56b97ce677b83bdab09cda48bc2d89ac75aJust		stack = self.operandStack[:]
5417842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.operandStack[:] = []
5427842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return stack
5437842e56b97ce677b83bdab09cda48bc2d89ac75aJust
5447842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def push(self, value):
5457842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.operandStack.append(value)
5467842e56b97ce677b83bdab09cda48bc2d89ac75aJust
5477842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_return(self, index):
5487842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if self.operandStack:
5497842e56b97ce677b83bdab09cda48bc2d89ac75aJust			pass
5507842e56b97ce677b83bdab09cda48bc2d89ac75aJust
5517842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_endchar(self, index):
5527842e56b97ce677b83bdab09cda48bc2d89ac75aJust		pass
5537099f4c0f9fbaf1a5c811113fdfd2404dee04361jvr
5547099f4c0f9fbaf1a5c811113fdfd2404dee04361jvr	def op_ignore(self, index):
5557099f4c0f9fbaf1a5c811113fdfd2404dee04361jvr		pass
5567099f4c0f9fbaf1a5c811113fdfd2404dee04361jvr
5577842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_callsubr(self, index):
5587842e56b97ce677b83bdab09cda48bc2d89ac75aJust		subrIndex = self.pop()
5597842e56b97ce677b83bdab09cda48bc2d89ac75aJust		subr = self.localSubrs[subrIndex+self.localBias]
5607842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.execute(subr)
5617842e56b97ce677b83bdab09cda48bc2d89ac75aJust
5627842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_callgsubr(self, index):
5637842e56b97ce677b83bdab09cda48bc2d89ac75aJust		subrIndex = self.pop()
5647842e56b97ce677b83bdab09cda48bc2d89ac75aJust		subr = self.globalSubrs[subrIndex+self.globalBias]
5657842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.execute(subr)
5667842e56b97ce677b83bdab09cda48bc2d89ac75aJust
567586345b7c1c0aa97b06f1597b67c3bb4c4e97be1jvr	def op_hstem(self, index):
568586345b7c1c0aa97b06f1597b67c3bb4c4e97be1jvr		self.countHints()
569586345b7c1c0aa97b06f1597b67c3bb4c4e97be1jvr	def op_vstem(self, index):
570586345b7c1c0aa97b06f1597b67c3bb4c4e97be1jvr		self.countHints()
5717842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_hstemhm(self, index):
5727842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.countHints()
573586345b7c1c0aa97b06f1597b67c3bb4c4e97be1jvr	def op_vstemhm(self, index):
574586345b7c1c0aa97b06f1597b67c3bb4c4e97be1jvr		self.countHints()
5757842e56b97ce677b83bdab09cda48bc2d89ac75aJust
5767842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_hintmask(self, index):
5777842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if not self.hintMaskBytes:
5787842e56b97ce677b83bdab09cda48bc2d89ac75aJust			self.countHints()
57932c10eecffb4923e0721c395e4b80fb732543f18Behdad Esfahbod			self.hintMaskBytes = (self.hintCount + 7) // 8
5807842e56b97ce677b83bdab09cda48bc2d89ac75aJust		hintMaskBytes, index = self.callingStack[-1].getBytes(index, self.hintMaskBytes)
5817842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return hintMaskBytes, index
5827842e56b97ce677b83bdab09cda48bc2d89ac75aJust
5837842e56b97ce677b83bdab09cda48bc2d89ac75aJust	op_cntrmask = op_hintmask
5847842e56b97ce677b83bdab09cda48bc2d89ac75aJust
5857842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def countHints(self):
5867842e56b97ce677b83bdab09cda48bc2d89ac75aJust		args = self.popall()
58732c10eecffb4923e0721c395e4b80fb732543f18Behdad Esfahbod		self.hintCount = self.hintCount + len(args) // 2
5887842e56b97ce677b83bdab09cda48bc2d89ac75aJust
589f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod	# misc
590f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod	def op_and(self, index):
591f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod		raise NotImplementedError
592f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod	def op_or(self, index):
593f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod		raise NotImplementedError
594f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod	def op_not(self, index):
595f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod		raise NotImplementedError
596f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod	def op_store(self, index):
597f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod		raise NotImplementedError
598f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod	def op_abs(self, index):
599f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod		raise NotImplementedError
600f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod	def op_add(self, index):
601f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod		raise NotImplementedError
602f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod	def op_sub(self, index):
603f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod		raise NotImplementedError
604f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod	def op_div(self, index):
605f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod		raise NotImplementedError
606f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod	def op_load(self, index):
607f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod		raise NotImplementedError
608f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod	def op_neg(self, index):
609f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod		raise NotImplementedError
610f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod	def op_eq(self, index):
611f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod		raise NotImplementedError
612f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod	def op_drop(self, index):
613f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod		raise NotImplementedError
614f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod	def op_put(self, index):
615f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod		raise NotImplementedError
616f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod	def op_get(self, index):
617f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod		raise NotImplementedError
618f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod	def op_ifelse(self, index):
619f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod		raise NotImplementedError
620f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod	def op_random(self, index):
621f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod		raise NotImplementedError
622f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod	def op_mul(self, index):
623f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod		raise NotImplementedError
624f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod	def op_sqrt(self, index):
625f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod		raise NotImplementedError
626f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod	def op_dup(self, index):
627f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod		raise NotImplementedError
628f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod	def op_exch(self, index):
629f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod		raise NotImplementedError
630f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod	def op_index(self, index):
631f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod		raise NotImplementedError
632f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod	def op_roll(self, index):
633f09f1d406446d1e249ab89b5c345d0a86e8392e3Behdad Esfahbod		raise NotImplementedError
6347842e56b97ce677b83bdab09cda48bc2d89ac75aJust
6357842e56b97ce677b83bdab09cda48bc2d89ac75aJustclass T2OutlineExtractor(SimpleT2Decompiler):
6367842e56b97ce677b83bdab09cda48bc2d89ac75aJust
637489d76a340845361def6af9ab7d9152f8e66f417jvr	def __init__(self, pen, localSubrs, globalSubrs, nominalWidthX, defaultWidthX):
6387842e56b97ce677b83bdab09cda48bc2d89ac75aJust		SimpleT2Decompiler.__init__(self, localSubrs, globalSubrs)
639489d76a340845361def6af9ab7d9152f8e66f417jvr		self.pen = pen
6407842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.nominalWidthX = nominalWidthX
6417842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.defaultWidthX = defaultWidthX
6427842e56b97ce677b83bdab09cda48bc2d89ac75aJust
6437842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def reset(self):
6447842e56b97ce677b83bdab09cda48bc2d89ac75aJust		SimpleT2Decompiler.reset(self)
6457842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.hints = []
6467842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.gotWidth = 0
6477842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.width = 0
648489d76a340845361def6af9ab7d9152f8e66f417jvr		self.currentPoint = (0, 0)
649489d76a340845361def6af9ab7d9152f8e66f417jvr		self.sawMoveTo = 0
6507842e56b97ce677b83bdab09cda48bc2d89ac75aJust
651489d76a340845361def6af9ab7d9152f8e66f417jvr	def _nextPoint(self, point):
652489d76a340845361def6af9ab7d9152f8e66f417jvr		x, y = self.currentPoint
653489d76a340845361def6af9ab7d9152f8e66f417jvr		point = x + point[0], y + point[1]
654489d76a340845361def6af9ab7d9152f8e66f417jvr		self.currentPoint = point
655489d76a340845361def6af9ab7d9152f8e66f417jvr		return point
6567842e56b97ce677b83bdab09cda48bc2d89ac75aJust
657489d76a340845361def6af9ab7d9152f8e66f417jvr	def rMoveTo(self, point):
658489d76a340845361def6af9ab7d9152f8e66f417jvr		self.pen.moveTo(self._nextPoint(point))
659489d76a340845361def6af9ab7d9152f8e66f417jvr		self.sawMoveTo = 1
660489d76a340845361def6af9ab7d9152f8e66f417jvr
661489d76a340845361def6af9ab7d9152f8e66f417jvr	def rLineTo(self, point):
662489d76a340845361def6af9ab7d9152f8e66f417jvr		if not self.sawMoveTo:
663489d76a340845361def6af9ab7d9152f8e66f417jvr			self.rMoveTo((0, 0))
664489d76a340845361def6af9ab7d9152f8e66f417jvr		self.pen.lineTo(self._nextPoint(point))
665489d76a340845361def6af9ab7d9152f8e66f417jvr
666489d76a340845361def6af9ab7d9152f8e66f417jvr	def rCurveTo(self, pt1, pt2, pt3):
667489d76a340845361def6af9ab7d9152f8e66f417jvr		if not self.sawMoveTo:
668489d76a340845361def6af9ab7d9152f8e66f417jvr			self.rMoveTo((0, 0))
669489d76a340845361def6af9ab7d9152f8e66f417jvr		nextPoint = self._nextPoint
670489d76a340845361def6af9ab7d9152f8e66f417jvr		self.pen.curveTo(nextPoint(pt1), nextPoint(pt2), nextPoint(pt3))
6717842e56b97ce677b83bdab09cda48bc2d89ac75aJust
6727842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def closePath(self):
673489d76a340845361def6af9ab7d9152f8e66f417jvr		if self.sawMoveTo:
674489d76a340845361def6af9ab7d9152f8e66f417jvr			self.pen.closePath()
675489d76a340845361def6af9ab7d9152f8e66f417jvr		self.sawMoveTo = 0
6767842e56b97ce677b83bdab09cda48bc2d89ac75aJust
677d3ee2d4319742ec61cb299665ccba66c139e4834jvr	def endPath(self):
678d3ee2d4319742ec61cb299665ccba66c139e4834jvr		# In T2 there are no open paths, so always do a closePath when
679d3ee2d4319742ec61cb299665ccba66c139e4834jvr		# finishing a sub path.
680d3ee2d4319742ec61cb299665ccba66c139e4834jvr		self.closePath()
681d3ee2d4319742ec61cb299665ccba66c139e4834jvr
6827842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def popallWidth(self, evenOdd=0):
6837842e56b97ce677b83bdab09cda48bc2d89ac75aJust		args = self.popall()
6847842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if not self.gotWidth:
6857842e56b97ce677b83bdab09cda48bc2d89ac75aJust			if evenOdd ^ (len(args) % 2):
6867842e56b97ce677b83bdab09cda48bc2d89ac75aJust				self.width = self.nominalWidthX + args[0]
6877842e56b97ce677b83bdab09cda48bc2d89ac75aJust				args = args[1:]
6887842e56b97ce677b83bdab09cda48bc2d89ac75aJust			else:
6897842e56b97ce677b83bdab09cda48bc2d89ac75aJust				self.width = self.defaultWidthX
6907842e56b97ce677b83bdab09cda48bc2d89ac75aJust			self.gotWidth = 1
6917842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return args
6927842e56b97ce677b83bdab09cda48bc2d89ac75aJust
6937842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def countHints(self):
6947842e56b97ce677b83bdab09cda48bc2d89ac75aJust		args = self.popallWidth()
69532c10eecffb4923e0721c395e4b80fb732543f18Behdad Esfahbod		self.hintCount = self.hintCount + len(args) // 2
6967842e56b97ce677b83bdab09cda48bc2d89ac75aJust
6977842e56b97ce677b83bdab09cda48bc2d89ac75aJust	#
6987842e56b97ce677b83bdab09cda48bc2d89ac75aJust	# hint operators
6997842e56b97ce677b83bdab09cda48bc2d89ac75aJust	#
700586345b7c1c0aa97b06f1597b67c3bb4c4e97be1jvr	#def op_hstem(self, index):
701586345b7c1c0aa97b06f1597b67c3bb4c4e97be1jvr	#	self.countHints()
702586345b7c1c0aa97b06f1597b67c3bb4c4e97be1jvr	#def op_vstem(self, index):
703586345b7c1c0aa97b06f1597b67c3bb4c4e97be1jvr	#	self.countHints()
704586345b7c1c0aa97b06f1597b67c3bb4c4e97be1jvr	#def op_hstemhm(self, index):
705586345b7c1c0aa97b06f1597b67c3bb4c4e97be1jvr	#	self.countHints()
706586345b7c1c0aa97b06f1597b67c3bb4c4e97be1jvr	#def op_vstemhm(self, index):
707586345b7c1c0aa97b06f1597b67c3bb4c4e97be1jvr	#	self.countHints()
7087842e56b97ce677b83bdab09cda48bc2d89ac75aJust	#def op_hintmask(self, index):
7097842e56b97ce677b83bdab09cda48bc2d89ac75aJust	#	self.countHints()
7107842e56b97ce677b83bdab09cda48bc2d89ac75aJust	#def op_cntrmask(self, index):
7117842e56b97ce677b83bdab09cda48bc2d89ac75aJust	#	self.countHints()
7127842e56b97ce677b83bdab09cda48bc2d89ac75aJust
7137842e56b97ce677b83bdab09cda48bc2d89ac75aJust	#
7147842e56b97ce677b83bdab09cda48bc2d89ac75aJust	# path constructors, moveto
7157842e56b97ce677b83bdab09cda48bc2d89ac75aJust	#
7167842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_rmoveto(self, index):
717d3ee2d4319742ec61cb299665ccba66c139e4834jvr		self.endPath()
718489d76a340845361def6af9ab7d9152f8e66f417jvr		self.rMoveTo(self.popallWidth())
7197842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_hmoveto(self, index):
720d3ee2d4319742ec61cb299665ccba66c139e4834jvr		self.endPath()
721489d76a340845361def6af9ab7d9152f8e66f417jvr		self.rMoveTo((self.popallWidth(1)[0], 0))
7227842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_vmoveto(self, index):
723d3ee2d4319742ec61cb299665ccba66c139e4834jvr		self.endPath()
724489d76a340845361def6af9ab7d9152f8e66f417jvr		self.rMoveTo((0, self.popallWidth(1)[0]))
7257842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_endchar(self, index):
726d3ee2d4319742ec61cb299665ccba66c139e4834jvr		self.endPath()
727382df6c42a7a6aecb690e07c6338e19f038f0543jvr		args = self.popallWidth()
728382df6c42a7a6aecb690e07c6338e19f038f0543jvr		if args:
729382df6c42a7a6aecb690e07c6338e19f038f0543jvr			from fontTools.encodings.StandardEncoding import StandardEncoding
730382df6c42a7a6aecb690e07c6338e19f038f0543jvr			# endchar can do seac accent bulding; The T2 spec says it's deprecated,
731382df6c42a7a6aecb690e07c6338e19f038f0543jvr			# but recent software that shall remain nameless does output it.
732382df6c42a7a6aecb690e07c6338e19f038f0543jvr			adx, ady, bchar, achar = args
733382df6c42a7a6aecb690e07c6338e19f038f0543jvr			baseGlyph = StandardEncoding[bchar]
734382df6c42a7a6aecb690e07c6338e19f038f0543jvr			self.pen.addComponent(baseGlyph, (1, 0, 0, 1, 0, 0))
735382df6c42a7a6aecb690e07c6338e19f038f0543jvr			accentGlyph = StandardEncoding[achar]
736382df6c42a7a6aecb690e07c6338e19f038f0543jvr			self.pen.addComponent(accentGlyph, (1, 0, 0, 1, adx, ady))
7377842e56b97ce677b83bdab09cda48bc2d89ac75aJust
7387842e56b97ce677b83bdab09cda48bc2d89ac75aJust	#
7397842e56b97ce677b83bdab09cda48bc2d89ac75aJust	# path constructors, lines
7407842e56b97ce677b83bdab09cda48bc2d89ac75aJust	#
7417842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_rlineto(self, index):
7427842e56b97ce677b83bdab09cda48bc2d89ac75aJust		args = self.popall()
7437842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for i in range(0, len(args), 2):
7447842e56b97ce677b83bdab09cda48bc2d89ac75aJust			point = args[i:i+2]
745489d76a340845361def6af9ab7d9152f8e66f417jvr			self.rLineTo(point)
7467842e56b97ce677b83bdab09cda48bc2d89ac75aJust
7477842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_hlineto(self, index):
7487842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.alternatingLineto(1)
7497842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_vlineto(self, index):
7507842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.alternatingLineto(0)
7517842e56b97ce677b83bdab09cda48bc2d89ac75aJust
7527842e56b97ce677b83bdab09cda48bc2d89ac75aJust	#
7537842e56b97ce677b83bdab09cda48bc2d89ac75aJust	# path constructors, curves
7547842e56b97ce677b83bdab09cda48bc2d89ac75aJust	#
7557842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_rrcurveto(self, index):
7567842e56b97ce677b83bdab09cda48bc2d89ac75aJust		"""{dxa dya dxb dyb dxc dyc}+ rrcurveto"""
7577842e56b97ce677b83bdab09cda48bc2d89ac75aJust		args = self.popall()
7587842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for i in range(0, len(args), 6):
7597842e56b97ce677b83bdab09cda48bc2d89ac75aJust			dxa, dya, dxb, dyb, dxc, dyc, = args[i:i+6]
760489d76a340845361def6af9ab7d9152f8e66f417jvr			self.rCurveTo((dxa, dya), (dxb, dyb), (dxc, dyc))
7617842e56b97ce677b83bdab09cda48bc2d89ac75aJust
7627842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_rcurveline(self, index):
7637842e56b97ce677b83bdab09cda48bc2d89ac75aJust		"""{dxa dya dxb dyb dxc dyc}+ dxd dyd rcurveline"""
7647842e56b97ce677b83bdab09cda48bc2d89ac75aJust		args = self.popall()
7657842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for i in range(0, len(args)-2, 6):
7667842e56b97ce677b83bdab09cda48bc2d89ac75aJust			dxb, dyb, dxc, dyc, dxd, dyd = args[i:i+6]
767489d76a340845361def6af9ab7d9152f8e66f417jvr			self.rCurveTo((dxb, dyb), (dxc, dyc), (dxd, dyd))
768489d76a340845361def6af9ab7d9152f8e66f417jvr		self.rLineTo(args[-2:])
7697842e56b97ce677b83bdab09cda48bc2d89ac75aJust
7707842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_rlinecurve(self, index):
7717842e56b97ce677b83bdab09cda48bc2d89ac75aJust		"""{dxa dya}+ dxb dyb dxc dyc dxd dyd rlinecurve"""
7727842e56b97ce677b83bdab09cda48bc2d89ac75aJust		args = self.popall()
7737842e56b97ce677b83bdab09cda48bc2d89ac75aJust		lineArgs = args[:-6]
7747842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for i in range(0, len(lineArgs), 2):
775489d76a340845361def6af9ab7d9152f8e66f417jvr			self.rLineTo(lineArgs[i:i+2])
7767842e56b97ce677b83bdab09cda48bc2d89ac75aJust		dxb, dyb, dxc, dyc, dxd, dyd = args[-6:]
777489d76a340845361def6af9ab7d9152f8e66f417jvr		self.rCurveTo((dxb, dyb), (dxc, dyc), (dxd, dyd))
7787842e56b97ce677b83bdab09cda48bc2d89ac75aJust
7797842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_vvcurveto(self, index):
7807842e56b97ce677b83bdab09cda48bc2d89ac75aJust		"dx1? {dya dxb dyb dyc}+ vvcurveto"
7817842e56b97ce677b83bdab09cda48bc2d89ac75aJust		args = self.popall()
7827842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if len(args) % 2:
7837842e56b97ce677b83bdab09cda48bc2d89ac75aJust			dx1 = args[0]
7847842e56b97ce677b83bdab09cda48bc2d89ac75aJust			args = args[1:]
7857842e56b97ce677b83bdab09cda48bc2d89ac75aJust		else:
7867842e56b97ce677b83bdab09cda48bc2d89ac75aJust			dx1 = 0
7877842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for i in range(0, len(args), 4):
7887842e56b97ce677b83bdab09cda48bc2d89ac75aJust			dya, dxb, dyb, dyc = args[i:i+4]
789489d76a340845361def6af9ab7d9152f8e66f417jvr			self.rCurveTo((dx1, dya), (dxb, dyb), (0, dyc))
7907842e56b97ce677b83bdab09cda48bc2d89ac75aJust			dx1 = 0
7917842e56b97ce677b83bdab09cda48bc2d89ac75aJust
7927842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_hhcurveto(self, index):
7937842e56b97ce677b83bdab09cda48bc2d89ac75aJust		"""dy1? {dxa dxb dyb dxc}+ hhcurveto"""
7947842e56b97ce677b83bdab09cda48bc2d89ac75aJust		args = self.popall()
7957842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if len(args) % 2:
7967842e56b97ce677b83bdab09cda48bc2d89ac75aJust			dy1 = args[0]
7977842e56b97ce677b83bdab09cda48bc2d89ac75aJust			args = args[1:]
7987842e56b97ce677b83bdab09cda48bc2d89ac75aJust		else:
7997842e56b97ce677b83bdab09cda48bc2d89ac75aJust			dy1 = 0
8007842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for i in range(0, len(args), 4):
8017842e56b97ce677b83bdab09cda48bc2d89ac75aJust			dxa, dxb, dyb, dxc = args[i:i+4]
802489d76a340845361def6af9ab7d9152f8e66f417jvr			self.rCurveTo((dxa, dy1), (dxb, dyb), (dxc, 0))
8037842e56b97ce677b83bdab09cda48bc2d89ac75aJust			dy1 = 0
8047842e56b97ce677b83bdab09cda48bc2d89ac75aJust
8057842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_vhcurveto(self, index):
8067842e56b97ce677b83bdab09cda48bc2d89ac75aJust		"""dy1 dx2 dy2 dx3 {dxa dxb dyb dyc dyd dxe dye dxf}* dyf? vhcurveto (30)
8077842e56b97ce677b83bdab09cda48bc2d89ac75aJust		{dya dxb dyb dxc dxd dxe dye dyf}+ dxf? vhcurveto
8087842e56b97ce677b83bdab09cda48bc2d89ac75aJust		"""
8097842e56b97ce677b83bdab09cda48bc2d89ac75aJust		args = self.popall()
8107842e56b97ce677b83bdab09cda48bc2d89ac75aJust		while args:
8117842e56b97ce677b83bdab09cda48bc2d89ac75aJust			args = self.vcurveto(args)
8127842e56b97ce677b83bdab09cda48bc2d89ac75aJust			if args:
8137842e56b97ce677b83bdab09cda48bc2d89ac75aJust				args = self.hcurveto(args)
8147842e56b97ce677b83bdab09cda48bc2d89ac75aJust
8157842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_hvcurveto(self, index):
8167842e56b97ce677b83bdab09cda48bc2d89ac75aJust		"""dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* dxf?
8177842e56b97ce677b83bdab09cda48bc2d89ac75aJust		{dxa dxb dyb dyc dyd dxe dye dxf}+ dyf?
8187842e56b97ce677b83bdab09cda48bc2d89ac75aJust		"""
8197842e56b97ce677b83bdab09cda48bc2d89ac75aJust		args = self.popall()
8207842e56b97ce677b83bdab09cda48bc2d89ac75aJust		while args:
8217842e56b97ce677b83bdab09cda48bc2d89ac75aJust			args = self.hcurveto(args)
8227842e56b97ce677b83bdab09cda48bc2d89ac75aJust			if args:
8237842e56b97ce677b83bdab09cda48bc2d89ac75aJust				args = self.vcurveto(args)
8247842e56b97ce677b83bdab09cda48bc2d89ac75aJust
8257842e56b97ce677b83bdab09cda48bc2d89ac75aJust	#
8267842e56b97ce677b83bdab09cda48bc2d89ac75aJust	# path constructors, flex
8277842e56b97ce677b83bdab09cda48bc2d89ac75aJust	#
8287842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_hflex(self, index):
8298b8b44904e116287ca0eb587f9c5b21296fb3123jvr		dx1, dx2, dy2, dx3, dx4, dx5, dx6 = self.popall()
830d4561ec1b4ac67b2c29d0db13913431a3d2fbd50jvr		dy1 = dy3 = dy4 = dy6 = 0
831d4561ec1b4ac67b2c29d0db13913431a3d2fbd50jvr		dy5 = -dy2
8328b8b44904e116287ca0eb587f9c5b21296fb3123jvr		self.rCurveTo((dx1, dy1), (dx2, dy2), (dx3, dy3))
8338b8b44904e116287ca0eb587f9c5b21296fb3123jvr		self.rCurveTo((dx4, dy4), (dx5, dy5), (dx6, dy6))
8347842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_flex(self, index):
8358b8b44904e116287ca0eb587f9c5b21296fb3123jvr		dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4, dx5, dy5, dx6, dy6, fd = self.popall()
8368b8b44904e116287ca0eb587f9c5b21296fb3123jvr		self.rCurveTo((dx1, dy1), (dx2, dy2), (dx3, dy3))
8378b8b44904e116287ca0eb587f9c5b21296fb3123jvr		self.rCurveTo((dx4, dy4), (dx5, dy5), (dx6, dy6))
8387842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_hflex1(self, index):
8398b8b44904e116287ca0eb587f9c5b21296fb3123jvr		dx1, dy1, dx2, dy2, dx3, dx4, dx5, dy5, dx6 = self.popall()
840d4561ec1b4ac67b2c29d0db13913431a3d2fbd50jvr		dy3 = dy4 = 0
841d4561ec1b4ac67b2c29d0db13913431a3d2fbd50jvr		dy6 = -(dy1 + dy2 + dy3 + dy4 + dy5)
842d4561ec1b4ac67b2c29d0db13913431a3d2fbd50jvr
8438b8b44904e116287ca0eb587f9c5b21296fb3123jvr		self.rCurveTo((dx1, dy1), (dx2, dy2), (dx3, dy3))
8448b8b44904e116287ca0eb587f9c5b21296fb3123jvr		self.rCurveTo((dx4, dy4), (dx5, dy5), (dx6, dy6))
8457842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_flex1(self, index):
8468b8b44904e116287ca0eb587f9c5b21296fb3123jvr		dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4, dx5, dy5, d6 = self.popall()
8478b8b44904e116287ca0eb587f9c5b21296fb3123jvr		dx = dx1 + dx2 + dx3 + dx4 + dx5
8488b8b44904e116287ca0eb587f9c5b21296fb3123jvr		dy = dy1 + dy2 + dy3 + dy4 + dy5
8498b8b44904e116287ca0eb587f9c5b21296fb3123jvr		if abs(dx) > abs(dy):
8508b8b44904e116287ca0eb587f9c5b21296fb3123jvr			dx6 = d6
851d4561ec1b4ac67b2c29d0db13913431a3d2fbd50jvr			dy6 = -dy
8528b8b44904e116287ca0eb587f9c5b21296fb3123jvr		else:
853d4561ec1b4ac67b2c29d0db13913431a3d2fbd50jvr			dx6 = -dx
8548b8b44904e116287ca0eb587f9c5b21296fb3123jvr			dy6 = d6
8558b8b44904e116287ca0eb587f9c5b21296fb3123jvr		self.rCurveTo((dx1, dy1), (dx2, dy2), (dx3, dy3))
8568b8b44904e116287ca0eb587f9c5b21296fb3123jvr		self.rCurveTo((dx4, dy4), (dx5, dy5), (dx6, dy6))
8577842e56b97ce677b83bdab09cda48bc2d89ac75aJust
8587842e56b97ce677b83bdab09cda48bc2d89ac75aJust	#
8597842e56b97ce677b83bdab09cda48bc2d89ac75aJust	# MultipleMaster. Well...
8607842e56b97ce677b83bdab09cda48bc2d89ac75aJust	#
8617842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_blend(self, index):
862153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod		self.popall()
8637842e56b97ce677b83bdab09cda48bc2d89ac75aJust
8647842e56b97ce677b83bdab09cda48bc2d89ac75aJust	# misc
8657842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_and(self, index):
8668b8b44904e116287ca0eb587f9c5b21296fb3123jvr		raise NotImplementedError
8677842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_or(self, index):
8688b8b44904e116287ca0eb587f9c5b21296fb3123jvr		raise NotImplementedError
8697842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_not(self, index):
8708b8b44904e116287ca0eb587f9c5b21296fb3123jvr		raise NotImplementedError
8717842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_store(self, index):
8728b8b44904e116287ca0eb587f9c5b21296fb3123jvr		raise NotImplementedError
8737842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_abs(self, index):
8748b8b44904e116287ca0eb587f9c5b21296fb3123jvr		raise NotImplementedError
8757842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_add(self, index):
8768b8b44904e116287ca0eb587f9c5b21296fb3123jvr		raise NotImplementedError
8777842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_sub(self, index):
8788b8b44904e116287ca0eb587f9c5b21296fb3123jvr		raise NotImplementedError
8797842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_div(self, index):
8807842e56b97ce677b83bdab09cda48bc2d89ac75aJust		num2 = self.pop()
8817842e56b97ce677b83bdab09cda48bc2d89ac75aJust		num1 = self.pop()
88232c10eecffb4923e0721c395e4b80fb732543f18Behdad Esfahbod		d1 = num1//num2
88332c10eecffb4923e0721c395e4b80fb732543f18Behdad Esfahbod		d2 = num1/num2
8847842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if d1 == d2:
8857842e56b97ce677b83bdab09cda48bc2d89ac75aJust			self.push(d1)
8867842e56b97ce677b83bdab09cda48bc2d89ac75aJust		else:
8877842e56b97ce677b83bdab09cda48bc2d89ac75aJust			self.push(d2)
8887842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_load(self, index):
8898b8b44904e116287ca0eb587f9c5b21296fb3123jvr		raise NotImplementedError
8907842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_neg(self, index):
8918b8b44904e116287ca0eb587f9c5b21296fb3123jvr		raise NotImplementedError
8927842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_eq(self, index):
8938b8b44904e116287ca0eb587f9c5b21296fb3123jvr		raise NotImplementedError
8947842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_drop(self, index):
8958b8b44904e116287ca0eb587f9c5b21296fb3123jvr		raise NotImplementedError
8967842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_put(self, index):
8978b8b44904e116287ca0eb587f9c5b21296fb3123jvr		raise NotImplementedError
8987842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_get(self, index):
8998b8b44904e116287ca0eb587f9c5b21296fb3123jvr		raise NotImplementedError
9007842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_ifelse(self, index):
9018b8b44904e116287ca0eb587f9c5b21296fb3123jvr		raise NotImplementedError
9027842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_random(self, index):
9038b8b44904e116287ca0eb587f9c5b21296fb3123jvr		raise NotImplementedError
9047842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_mul(self, index):
9058b8b44904e116287ca0eb587f9c5b21296fb3123jvr		raise NotImplementedError
9067842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_sqrt(self, index):
9078b8b44904e116287ca0eb587f9c5b21296fb3123jvr		raise NotImplementedError
9087842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_dup(self, index):
9098b8b44904e116287ca0eb587f9c5b21296fb3123jvr		raise NotImplementedError
9107842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_exch(self, index):
9118b8b44904e116287ca0eb587f9c5b21296fb3123jvr		raise NotImplementedError
9127842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_index(self, index):
9138b8b44904e116287ca0eb587f9c5b21296fb3123jvr		raise NotImplementedError
9147842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_roll(self, index):
9158b8b44904e116287ca0eb587f9c5b21296fb3123jvr		raise NotImplementedError
9167842e56b97ce677b83bdab09cda48bc2d89ac75aJust
9177842e56b97ce677b83bdab09cda48bc2d89ac75aJust	#
918f918ab4cf65c8000a639bc834bc0f362dd997358Behdad Esfahbod	# miscellaneous helpers
9197842e56b97ce677b83bdab09cda48bc2d89ac75aJust	#
9207842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def alternatingLineto(self, isHorizontal):
9217842e56b97ce677b83bdab09cda48bc2d89ac75aJust		args = self.popall()
9227842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for arg in args:
9237842e56b97ce677b83bdab09cda48bc2d89ac75aJust			if isHorizontal:
9247842e56b97ce677b83bdab09cda48bc2d89ac75aJust				point = (arg, 0)
9257842e56b97ce677b83bdab09cda48bc2d89ac75aJust			else:
9267842e56b97ce677b83bdab09cda48bc2d89ac75aJust				point = (0, arg)
927489d76a340845361def6af9ab7d9152f8e66f417jvr			self.rLineTo(point)
9287842e56b97ce677b83bdab09cda48bc2d89ac75aJust			isHorizontal = not isHorizontal
9297842e56b97ce677b83bdab09cda48bc2d89ac75aJust
9307842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def vcurveto(self, args):
9317842e56b97ce677b83bdab09cda48bc2d89ac75aJust		dya, dxb, dyb, dxc = args[:4]
9327842e56b97ce677b83bdab09cda48bc2d89ac75aJust		args = args[4:]
9337842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if len(args) == 1:
9347842e56b97ce677b83bdab09cda48bc2d89ac75aJust			dyc = args[0]
9357842e56b97ce677b83bdab09cda48bc2d89ac75aJust			args = []
9367842e56b97ce677b83bdab09cda48bc2d89ac75aJust		else:
9377842e56b97ce677b83bdab09cda48bc2d89ac75aJust			dyc = 0
938489d76a340845361def6af9ab7d9152f8e66f417jvr		self.rCurveTo((0, dya), (dxb, dyb), (dxc, dyc))
9397842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return args
9407842e56b97ce677b83bdab09cda48bc2d89ac75aJust
9417842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def hcurveto(self, args):
9427842e56b97ce677b83bdab09cda48bc2d89ac75aJust		dxa, dxb, dyb, dyc = args[:4]
9437842e56b97ce677b83bdab09cda48bc2d89ac75aJust		args = args[4:]
9447842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if len(args) == 1:
9457842e56b97ce677b83bdab09cda48bc2d89ac75aJust			dxc = args[0]
9467842e56b97ce677b83bdab09cda48bc2d89ac75aJust			args = []
9477842e56b97ce677b83bdab09cda48bc2d89ac75aJust		else:
9487842e56b97ce677b83bdab09cda48bc2d89ac75aJust			dxc = 0
949489d76a340845361def6af9ab7d9152f8e66f417jvr		self.rCurveTo((dxa, 0), (dxb, dyb), (dxc, dyc))
9507842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return args
9517842e56b97ce677b83bdab09cda48bc2d89ac75aJust
9527842e56b97ce677b83bdab09cda48bc2d89ac75aJust
9537842e56b97ce677b83bdab09cda48bc2d89ac75aJustclass T1OutlineExtractor(T2OutlineExtractor):
9547842e56b97ce677b83bdab09cda48bc2d89ac75aJust
955489d76a340845361def6af9ab7d9152f8e66f417jvr	def __init__(self, pen, subrs):
956489d76a340845361def6af9ab7d9152f8e66f417jvr		self.pen = pen
9577842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.subrs = subrs
9587842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.reset()
9597842e56b97ce677b83bdab09cda48bc2d89ac75aJust
9607842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def reset(self):
9617842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.flexing = 0
9627842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.width = 0
9637842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.sbx = 0
9647842e56b97ce677b83bdab09cda48bc2d89ac75aJust		T2OutlineExtractor.reset(self)
9657842e56b97ce677b83bdab09cda48bc2d89ac75aJust
966d3ee2d4319742ec61cb299665ccba66c139e4834jvr	def endPath(self):
967d3ee2d4319742ec61cb299665ccba66c139e4834jvr		if self.sawMoveTo:
968d3ee2d4319742ec61cb299665ccba66c139e4834jvr			self.pen.endPath()
969d3ee2d4319742ec61cb299665ccba66c139e4834jvr		self.sawMoveTo = 0
970d3ee2d4319742ec61cb299665ccba66c139e4834jvr
9717842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def popallWidth(self, evenOdd=0):
9727842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return self.popall()
9737842e56b97ce677b83bdab09cda48bc2d89ac75aJust
9747842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def exch(self):
9757842e56b97ce677b83bdab09cda48bc2d89ac75aJust		stack = self.operandStack
9767842e56b97ce677b83bdab09cda48bc2d89ac75aJust		stack[-1], stack[-2] = stack[-2], stack[-1]
9777842e56b97ce677b83bdab09cda48bc2d89ac75aJust
9787842e56b97ce677b83bdab09cda48bc2d89ac75aJust	#
9797842e56b97ce677b83bdab09cda48bc2d89ac75aJust	# path constructors
9807842e56b97ce677b83bdab09cda48bc2d89ac75aJust	#
9817842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_rmoveto(self, index):
9827842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if self.flexing:
9837842e56b97ce677b83bdab09cda48bc2d89ac75aJust			return
984e56bc902cf6a707349ae6ddfe8a83a1bd7b155b9jvr		self.endPath()
985489d76a340845361def6af9ab7d9152f8e66f417jvr		self.rMoveTo(self.popall())
9867842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_hmoveto(self, index):
9877842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if self.flexing:
9887842e56b97ce677b83bdab09cda48bc2d89ac75aJust			# We must add a parameter to the stack if we are flexing
9897842e56b97ce677b83bdab09cda48bc2d89ac75aJust			self.push(0)
9907842e56b97ce677b83bdab09cda48bc2d89ac75aJust			return
991d3ee2d4319742ec61cb299665ccba66c139e4834jvr		self.endPath()
992489d76a340845361def6af9ab7d9152f8e66f417jvr		self.rMoveTo((self.popall()[0], 0))
9937842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_vmoveto(self, index):
9947842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if self.flexing:
9957842e56b97ce677b83bdab09cda48bc2d89ac75aJust			# We must add a parameter to the stack if we are flexing
9967842e56b97ce677b83bdab09cda48bc2d89ac75aJust			self.push(0)
9977842e56b97ce677b83bdab09cda48bc2d89ac75aJust			self.exch()
9987842e56b97ce677b83bdab09cda48bc2d89ac75aJust			return
999d3ee2d4319742ec61cb299665ccba66c139e4834jvr		self.endPath()
1000489d76a340845361def6af9ab7d9152f8e66f417jvr		self.rMoveTo((0, self.popall()[0]))
10017842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_closepath(self, index):
10027842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.closePath()
10037842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_setcurrentpoint(self, index):
10047842e56b97ce677b83bdab09cda48bc2d89ac75aJust		args = self.popall()
10057842e56b97ce677b83bdab09cda48bc2d89ac75aJust		x, y = args
1006489d76a340845361def6af9ab7d9152f8e66f417jvr		self.currentPoint = x, y
10077842e56b97ce677b83bdab09cda48bc2d89ac75aJust
10087842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_endchar(self, index):
1009d3ee2d4319742ec61cb299665ccba66c139e4834jvr		self.endPath()
10107842e56b97ce677b83bdab09cda48bc2d89ac75aJust
10117842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_hsbw(self, index):
10127842e56b97ce677b83bdab09cda48bc2d89ac75aJust		sbx, wx = self.popall()
10137842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.width = wx
10147842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.sbx = sbx
1015489d76a340845361def6af9ab7d9152f8e66f417jvr		self.currentPoint = sbx, self.currentPoint[1]
10167842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_sbw(self, index):
10177842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.popall()  # XXX
10187842e56b97ce677b83bdab09cda48bc2d89ac75aJust
10197842e56b97ce677b83bdab09cda48bc2d89ac75aJust	#
10207842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_callsubr(self, index):
10217842e56b97ce677b83bdab09cda48bc2d89ac75aJust		subrIndex = self.pop()
10227842e56b97ce677b83bdab09cda48bc2d89ac75aJust		subr = self.subrs[subrIndex]
10237842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.execute(subr)
10247842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_callothersubr(self, index):
10257842e56b97ce677b83bdab09cda48bc2d89ac75aJust		subrIndex = self.pop()
10267842e56b97ce677b83bdab09cda48bc2d89ac75aJust		nArgs = self.pop()
10277842e56b97ce677b83bdab09cda48bc2d89ac75aJust		#print nArgs, subrIndex, "callothersubr"
10287842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if subrIndex == 0 and nArgs == 3:
10297842e56b97ce677b83bdab09cda48bc2d89ac75aJust			self.doFlex()
10307842e56b97ce677b83bdab09cda48bc2d89ac75aJust			self.flexing = 0
10317842e56b97ce677b83bdab09cda48bc2d89ac75aJust		elif subrIndex == 1 and nArgs == 0:
10327842e56b97ce677b83bdab09cda48bc2d89ac75aJust			self.flexing = 1
10337842e56b97ce677b83bdab09cda48bc2d89ac75aJust		# ignore...
10347842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_pop(self, index):
10357842e56b97ce677b83bdab09cda48bc2d89ac75aJust		pass  # ignore...
10367842e56b97ce677b83bdab09cda48bc2d89ac75aJust
10377842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def doFlex(self):
10387842e56b97ce677b83bdab09cda48bc2d89ac75aJust		finaly = self.pop()
10397842e56b97ce677b83bdab09cda48bc2d89ac75aJust		finalx = self.pop()
10407842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.pop()	# flex height is unused
10417842e56b97ce677b83bdab09cda48bc2d89ac75aJust
10427842e56b97ce677b83bdab09cda48bc2d89ac75aJust		p3y = self.pop()
10437842e56b97ce677b83bdab09cda48bc2d89ac75aJust		p3x = self.pop()
10447842e56b97ce677b83bdab09cda48bc2d89ac75aJust		bcp4y = self.pop()
10457842e56b97ce677b83bdab09cda48bc2d89ac75aJust		bcp4x = self.pop()
10467842e56b97ce677b83bdab09cda48bc2d89ac75aJust		bcp3y = self.pop()
10477842e56b97ce677b83bdab09cda48bc2d89ac75aJust		bcp3x = self.pop()
10487842e56b97ce677b83bdab09cda48bc2d89ac75aJust		p2y = self.pop()
10497842e56b97ce677b83bdab09cda48bc2d89ac75aJust		p2x = self.pop()
10507842e56b97ce677b83bdab09cda48bc2d89ac75aJust		bcp2y = self.pop()
10517842e56b97ce677b83bdab09cda48bc2d89ac75aJust		bcp2x = self.pop()
10527842e56b97ce677b83bdab09cda48bc2d89ac75aJust		bcp1y = self.pop()
10537842e56b97ce677b83bdab09cda48bc2d89ac75aJust		bcp1x = self.pop()
10547842e56b97ce677b83bdab09cda48bc2d89ac75aJust		rpy = self.pop()
10557842e56b97ce677b83bdab09cda48bc2d89ac75aJust		rpx = self.pop()
10567842e56b97ce677b83bdab09cda48bc2d89ac75aJust
10577842e56b97ce677b83bdab09cda48bc2d89ac75aJust		# call rrcurveto
10587842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.push(bcp1x+rpx)
10597842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.push(bcp1y+rpy)
10607842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.push(bcp2x)
10617842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.push(bcp2y)
10627842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.push(p2x)
10637842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.push(p2y)
10647842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.op_rrcurveto(None)
10657842e56b97ce677b83bdab09cda48bc2d89ac75aJust
10667842e56b97ce677b83bdab09cda48bc2d89ac75aJust		# call rrcurveto
10677842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.push(bcp3x)
10687842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.push(bcp3y)
10697842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.push(bcp4x)
10707842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.push(bcp4y)
10717842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.push(p3x)
10727842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.push(p3y)
10737842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.op_rrcurveto(None)
10747842e56b97ce677b83bdab09cda48bc2d89ac75aJust
10757842e56b97ce677b83bdab09cda48bc2d89ac75aJust		# Push back final coords so subr 0 can find them
10767842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.push(finalx)
10777842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.push(finaly)
10787842e56b97ce677b83bdab09cda48bc2d89ac75aJust
10797842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_dotsection(self, index):
10807842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.popall()  # XXX
10817842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_hstem3(self, index):
10827842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.popall()  # XXX
10837842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_seac(self, index):
10847842e56b97ce677b83bdab09cda48bc2d89ac75aJust		"asb adx ady bchar achar seac"
1085489d76a340845361def6af9ab7d9152f8e66f417jvr		from fontTools.encodings.StandardEncoding import StandardEncoding
1086489d76a340845361def6af9ab7d9152f8e66f417jvr		asb, adx, ady, bchar, achar = self.popall()
1087489d76a340845361def6af9ab7d9152f8e66f417jvr		baseGlyph = StandardEncoding[bchar]
1088489d76a340845361def6af9ab7d9152f8e66f417jvr		self.pen.addComponent(baseGlyph, (1, 0, 0, 1, 0, 0))
1089489d76a340845361def6af9ab7d9152f8e66f417jvr		accentGlyph = StandardEncoding[achar]
1090489d76a340845361def6af9ab7d9152f8e66f417jvr		adx = adx + self.sbx - asb  # seac weirdness
1091489d76a340845361def6af9ab7d9152f8e66f417jvr		self.pen.addComponent(accentGlyph, (1, 0, 0, 1, adx, ady))
10927842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def op_vstem3(self, index):
10937842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.popall()  # XXX
10947842e56b97ce677b83bdab09cda48bc2d89ac75aJust
10957842e56b97ce677b83bdab09cda48bc2d89ac75aJust
1096f2cf9c5d6d503e16ee43dc9b617d96aed38806a8jvrclass DictDecompiler(ByteCodeBase):
10977842e56b97ce677b83bdab09cda48bc2d89ac75aJust
10987842e56b97ce677b83bdab09cda48bc2d89ac75aJust	operandEncoding = cffDictOperandEncoding
10997842e56b97ce677b83bdab09cda48bc2d89ac75aJust
11007842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def __init__(self, strings):
11017842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.stack = []
11027842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.strings = strings
11037842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.dict = {}
11047842e56b97ce677b83bdab09cda48bc2d89ac75aJust
11057842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def getDict(self):
11067842e56b97ce677b83bdab09cda48bc2d89ac75aJust		assert len(self.stack) == 0, "non-empty stack"
11077842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return self.dict
11087842e56b97ce677b83bdab09cda48bc2d89ac75aJust
11097842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def decompile(self, data):
11107842e56b97ce677b83bdab09cda48bc2d89ac75aJust		index = 0
11117842e56b97ce677b83bdab09cda48bc2d89ac75aJust		lenData = len(data)
11127842e56b97ce677b83bdab09cda48bc2d89ac75aJust		push = self.stack.append
11137842e56b97ce677b83bdab09cda48bc2d89ac75aJust		while index < lenData:
1114319c5fd10e2ea84304bd299b7483e05b5b0d5480Behdad Esfahbod			b0 = byteord(data[index])
11157842e56b97ce677b83bdab09cda48bc2d89ac75aJust			index = index + 1
11167842e56b97ce677b83bdab09cda48bc2d89ac75aJust			code = self.operandEncoding[b0]
11177842e56b97ce677b83bdab09cda48bc2d89ac75aJust			handler = getattr(self, code)
11187842e56b97ce677b83bdab09cda48bc2d89ac75aJust			value, index = handler(b0, data, index)
11197842e56b97ce677b83bdab09cda48bc2d89ac75aJust			if value is not None:
11207842e56b97ce677b83bdab09cda48bc2d89ac75aJust				push(value)
11217842e56b97ce677b83bdab09cda48bc2d89ac75aJust
11227842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def pop(self):
11237842e56b97ce677b83bdab09cda48bc2d89ac75aJust		value = self.stack[-1]
11247842e56b97ce677b83bdab09cda48bc2d89ac75aJust		del self.stack[-1]
11257842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return value
11267842e56b97ce677b83bdab09cda48bc2d89ac75aJust
11277842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def popall(self):
1128153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod		args = self.stack[:]
11297842e56b97ce677b83bdab09cda48bc2d89ac75aJust		del self.stack[:]
1130153ec402094adbea673e914385b87f1d99191d0bBehdad Esfahbod		return args
11317842e56b97ce677b83bdab09cda48bc2d89ac75aJust
11327842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def do_operator(self, b0, data, index):
11337842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if b0 == 12:
1134319c5fd10e2ea84304bd299b7483e05b5b0d5480Behdad Esfahbod			op = (b0, byteord(data[index]))
11357842e56b97ce677b83bdab09cda48bc2d89ac75aJust			index = index+1
11367842e56b97ce677b83bdab09cda48bc2d89ac75aJust		else:
11377842e56b97ce677b83bdab09cda48bc2d89ac75aJust			op = b0
11387842e56b97ce677b83bdab09cda48bc2d89ac75aJust		operator, argType = self.operators[op]
11397842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.handle_operator(operator, argType)
11407842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return None, index
11417842e56b97ce677b83bdab09cda48bc2d89ac75aJust
11427842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def handle_operator(self, operator, argType):
1143ac1b4359467ca3deab03186a15eae1d55eb35567Behdad Esfahbod		if isinstance(argType, type(())):
11447842e56b97ce677b83bdab09cda48bc2d89ac75aJust			value = ()
1145bf2f402913a2706dfa92190e60cba7acbf01c9d7jvr			for i in range(len(argType)-1, -1, -1):
1146bf2f402913a2706dfa92190e60cba7acbf01c9d7jvr				arg = argType[i]
11477842e56b97ce677b83bdab09cda48bc2d89ac75aJust				arghandler = getattr(self, "arg_" + arg)
11487842e56b97ce677b83bdab09cda48bc2d89ac75aJust				value = (arghandler(operator),) + value
11497842e56b97ce677b83bdab09cda48bc2d89ac75aJust		else:
11507842e56b97ce677b83bdab09cda48bc2d89ac75aJust			arghandler = getattr(self, "arg_" + argType)
11517842e56b97ce677b83bdab09cda48bc2d89ac75aJust			value = arghandler(operator)
11527842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.dict[operator] = value
11537842e56b97ce677b83bdab09cda48bc2d89ac75aJust
11547842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def arg_number(self, name):
11557842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return self.pop()
11567842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def arg_SID(self, name):
11577842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return self.strings[self.pop()]
11587842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def arg_array(self, name):
11597842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return self.popall()
1160dc18128aa9b3f6b98a623c294ac615195159025ejvr	def arg_delta(self, name):
1161dc18128aa9b3f6b98a623c294ac615195159025ejvr		out = []
1162dc18128aa9b3f6b98a623c294ac615195159025ejvr		current = 0
1163dc18128aa9b3f6b98a623c294ac615195159025ejvr		for v in self.popall():
11646f03a58f59fb20662602e3d4bb153d7db2f778d3jvr			current = current + v
1165dc18128aa9b3f6b98a623c294ac615195159025ejvr			out.append(current)
1166dc18128aa9b3f6b98a623c294ac615195159025ejvr		return out
11677842e56b97ce677b83bdab09cda48bc2d89ac75aJust
11687842e56b97ce677b83bdab09cda48bc2d89ac75aJust
11697842e56b97ce677b83bdab09cda48bc2d89ac75aJustdef calcSubrBias(subrs):
11707842e56b97ce677b83bdab09cda48bc2d89ac75aJust	nSubrs = len(subrs)
11717842e56b97ce677b83bdab09cda48bc2d89ac75aJust	if nSubrs < 1240:
11727842e56b97ce677b83bdab09cda48bc2d89ac75aJust		bias = 107
11737842e56b97ce677b83bdab09cda48bc2d89ac75aJust	elif nSubrs < 33900:
11747842e56b97ce677b83bdab09cda48bc2d89ac75aJust		bias = 1131
11757842e56b97ce677b83bdab09cda48bc2d89ac75aJust	else:
11767842e56b97ce677b83bdab09cda48bc2d89ac75aJust		bias = 32768
11777842e56b97ce677b83bdab09cda48bc2d89ac75aJust	return bias
1178