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