Home | History | Annotate | Download | only in misc
      1 from __future__ import print_function, division, absolute_import
      2 from fontTools.misc.py23 import *
      3 
      4 _accessstrings = {0: "", 1: "readonly", 2: "executeonly", 3: "noaccess"}
      5 
      6 
      7 class ps_object:
      8 	
      9 	literal = 1
     10 	access = 0
     11 	value = None
     12 	
     13 	def __init__(self, value):
     14 		self.value = value
     15 		self.type = self.__class__.__name__[3:] + "type"
     16 	
     17 	def __repr__(self):
     18 		return "<%s %s>" % (self.__class__.__name__[3:], repr(self.value))
     19 
     20 
     21 class ps_operator(ps_object):
     22 	
     23 	literal = 0
     24 	
     25 	def __init__(self, name, function):
     26 		self.name = name
     27 		self.function = function
     28 		self.type = self.__class__.__name__[3:] + "type"
     29 	def __repr__(self):
     30 		return "<operator %s>" % self.name
     31 
     32 class ps_procedure(ps_object):
     33 	literal = 0
     34 	def __repr__(self):
     35 		return "<procedure>"
     36 	def __str__(self):
     37 		psstring = '{'
     38 		for i in range(len(self.value)):
     39 			if i:
     40 				psstring = psstring + ' ' + str(self.value[i])
     41 			else:
     42 				psstring = psstring + str(self.value[i])
     43 		return psstring + '}'
     44 
     45 class ps_name(ps_object):
     46 	literal = 0
     47 	def __str__(self):
     48 		if self.literal:
     49 			return '/' + self.value
     50 		else:
     51 			return self.value
     52 
     53 class ps_literal(ps_object):
     54 	def __str__(self):
     55 		return '/' + self.value
     56 
     57 class ps_array(ps_object):
     58 	def __str__(self):
     59 		psstring = '['
     60 		for i in range(len(self.value)):
     61 			item = self.value[i]
     62 			access = _accessstrings[item.access]
     63 			if access:
     64 				access = ' ' + access
     65 			if i:
     66 				psstring = psstring + ' ' + str(item) + access
     67 			else:
     68 				psstring = psstring + str(item) + access
     69 		return psstring + ']'
     70 	def __repr__(self):
     71 		return "<array>"
     72 
     73 _type1_pre_eexec_order = [
     74 		"FontInfo",
     75 		"FontName",
     76 		"Encoding",
     77 		"PaintType",
     78 		"FontType",
     79 		"FontMatrix",
     80 		"FontBBox",
     81 		"UniqueID",
     82 		"Metrics",
     83 		"StrokeWidth"
     84 	]
     85 
     86 _type1_fontinfo_order = [
     87 		"version",
     88 		"Notice",
     89 		"FullName",
     90 		"FamilyName",
     91 		"Weight",
     92 		"ItalicAngle",
     93 		"isFixedPitch",
     94 		"UnderlinePosition",
     95 		"UnderlineThickness"
     96 	]
     97 
     98 _type1_post_eexec_order = [
     99 		"Private",
    100 		"CharStrings",
    101 		"FID"
    102 	]
    103 
    104 def _type1_item_repr(key, value):
    105 	psstring = ""
    106 	access = _accessstrings[value.access]
    107 	if access:
    108 		access = access + ' '
    109 	if key == 'CharStrings':
    110 		psstring = psstring + "/%s %s def\n" % (key, _type1_CharString_repr(value.value))
    111 	elif key == 'Encoding':
    112 		psstring = psstring + _type1_Encoding_repr(value, access)
    113 	else:
    114 		psstring = psstring + "/%s %s %sdef\n" % (str(key), str(value), access)
    115 	return psstring
    116 
    117 def _type1_Encoding_repr(encoding, access):
    118 	encoding = encoding.value
    119 	psstring = "/Encoding 256 array\n0 1 255 {1 index exch /.notdef put} for\n"
    120 	for i in range(256):
    121 		name = encoding[i].value
    122 		if name != '.notdef':
    123 			psstring = psstring + "dup %d /%s put\n" % (i, name)
    124 	return psstring + access + "def\n"
    125 
    126 def _type1_CharString_repr(charstrings):
    127 	items = sorted(charstrings.items())
    128 	return 'xxx'
    129 
    130 class ps_font(ps_object):
    131 	def __str__(self):
    132 		psstring = "%d dict dup begin\n" % len(self.value)
    133 		for key in _type1_pre_eexec_order:
    134 			try:
    135 				value = self.value[key]
    136 			except KeyError:
    137 				pass
    138 			else:
    139 				psstring = psstring + _type1_item_repr(key, value)
    140 		items = sorted(self.value.items())
    141 		for key, value in items:
    142 			if key not in _type1_pre_eexec_order + _type1_post_eexec_order:
    143 				psstring = psstring + _type1_item_repr(key, value)
    144 		psstring = psstring + "currentdict end\ncurrentfile eexec\ndup "
    145 		for key in _type1_post_eexec_order:
    146 			try:
    147 				value = self.value[key]
    148 			except KeyError:
    149 				pass
    150 			else:
    151 				psstring = psstring + _type1_item_repr(key, value)
    152 		return psstring + 'dup/FontName get exch definefont pop\nmark currentfile closefile\n' + \
    153 				8 * (64 * '0' + '\n') + 'cleartomark' + '\n'
    154 	def __repr__(self):
    155 		return '<font>'
    156 
    157 class ps_file(ps_object):
    158 	pass
    159 
    160 class ps_dict(ps_object):
    161 	def __str__(self):
    162 		psstring = "%d dict dup begin\n" % len(self.value)
    163 		items = sorted(self.value.items())
    164 		for key, value in items:
    165 			access = _accessstrings[value.access]
    166 			if access:
    167 				access = access + ' '
    168 			psstring = psstring + "/%s %s %sdef\n" % (str(key), str(value), access)
    169 		return psstring + 'end '
    170 	def __repr__(self):
    171 		return "<dict>"
    172 
    173 class ps_mark(ps_object):
    174 	def __init__(self): 
    175 		self.value = 'mark'
    176 		self.type = self.__class__.__name__[3:] + "type"
    177 
    178 class ps_procmark(ps_object):
    179 	def __init__(self):
    180 		self.value = 'procmark'
    181 		self.type = self.__class__.__name__[3:] + "type"
    182 
    183 class ps_null(ps_object):
    184 	def __init__(self):
    185 		self.type = self.__class__.__name__[3:] + "type"
    186 
    187 class ps_boolean(ps_object):
    188 	def __str__(self):
    189 		if self.value:
    190 			return 'true'
    191 		else:
    192 			return 'false'
    193 
    194 class ps_string(ps_object):
    195 	def __str__(self):
    196 		return "(%s)" % repr(self.value)[1:-1]
    197 
    198 class ps_integer(ps_object):
    199 	def __str__(self):
    200 		return repr(self.value)
    201 
    202 class ps_real(ps_object):
    203 	def __str__(self):
    204 		return repr(self.value)
    205 
    206 
    207 class PSOperators:
    208 	
    209 	def ps_def(self):
    210 		obj = self.pop()
    211 		name = self.pop()
    212 		self.dictstack[-1][name.value] = obj
    213 	
    214 	def ps_bind(self):
    215 		proc = self.pop('proceduretype')
    216 		self.proc_bind(proc)
    217 		self.push(proc)
    218 	
    219 	def proc_bind(self, proc):
    220 		for i in range(len(proc.value)):
    221 			item = proc.value[i]
    222 			if item.type == 'proceduretype':
    223 				self.proc_bind(item)
    224 			else:
    225 				if not item.literal:
    226 					try:
    227 						obj = self.resolve_name(item.value)
    228 					except:
    229 						pass
    230 					else:
    231 						if obj.type == 'operatortype':
    232 							proc.value[i] = obj
    233 	
    234 	def ps_exch(self):
    235 		if len(self.stack) < 2:
    236 			raise RuntimeError('stack underflow')
    237 		obj1 = self.pop()
    238 		obj2 = self.pop()
    239 		self.push(obj1)
    240 		self.push(obj2)
    241 	
    242 	def ps_dup(self):
    243 		if not self.stack:
    244 			raise RuntimeError('stack underflow')
    245 		self.push(self.stack[-1])
    246 	
    247 	def ps_exec(self):
    248 		obj = self.pop()
    249 		if obj.type == 'proceduretype':
    250 			self.call_procedure(obj)
    251 		else:
    252 			self.handle_object(obj)
    253 	
    254 	def ps_count(self):
    255 		self.push(ps_integer(len(self.stack)))
    256 	
    257 	def ps_eq(self):
    258 		any1 = self.pop()
    259 		any2 = self.pop()
    260 		self.push(ps_boolean(any1.value == any2.value))
    261 	
    262 	def ps_ne(self):
    263 		any1 = self.pop()
    264 		any2 = self.pop()
    265 		self.push(ps_boolean(any1.value != any2.value))
    266 	
    267 	def ps_cvx(self):
    268 		obj = self.pop()
    269 		obj.literal = 0
    270 		self.push(obj)
    271 	
    272 	def ps_matrix(self):
    273 		matrix = [ps_real(1.0), ps_integer(0), ps_integer(0), ps_real(1.0), ps_integer(0), ps_integer(0)]
    274 		self.push(ps_array(matrix))
    275 	
    276 	def ps_string(self):
    277 		num = self.pop('integertype').value
    278 		self.push(ps_string('\0' * num))
    279 	
    280 	def ps_type(self):
    281 		obj = self.pop()
    282 		self.push(ps_string(obj.type))
    283 	
    284 	def ps_store(self):
    285 		value = self.pop()
    286 		key = self.pop()
    287 		name = key.value
    288 		for i in range(len(self.dictstack)-1, -1, -1):
    289 			if name in self.dictstack[i]:
    290 				self.dictstack[i][name] = value
    291 				break
    292 		self.dictstack[-1][name] = value
    293 	
    294 	def ps_where(self):
    295 		name = self.pop()
    296 		# XXX
    297 		self.push(ps_boolean(0))
    298 	
    299 	def ps_systemdict(self):
    300 		self.push(ps_dict(self.dictstack[0]))
    301 	
    302 	def ps_userdict(self):
    303 		self.push(ps_dict(self.dictstack[1]))
    304 	
    305 	def ps_currentdict(self):
    306 		self.push(ps_dict(self.dictstack[-1]))
    307 	
    308 	def ps_currentfile(self):
    309 		self.push(ps_file(self.tokenizer))
    310 	
    311 	def ps_eexec(self):
    312 		f = self.pop('filetype').value
    313 		f.starteexec()
    314 	
    315 	def ps_closefile(self):
    316 		f = self.pop('filetype').value
    317 		f.skipwhite()
    318 		f.stopeexec()
    319 	
    320 	def ps_cleartomark(self):
    321 		obj = self.pop()
    322 		while obj != self.mark:
    323 			obj = self.pop()
    324 	
    325 	def ps_readstring(self,
    326 				ps_boolean = ps_boolean,
    327 				len = len):
    328 		s = self.pop('stringtype')
    329 		oldstr = s.value
    330 		f = self.pop('filetype')
    331 		#pad = file.value.read(1)
    332 		# for StringIO, this is faster
    333 		f.value.pos = f.value.pos + 1
    334 		newstr = f.value.read(len(oldstr))
    335 		s.value = newstr
    336 		self.push(s)
    337 		self.push(ps_boolean(len(oldstr) == len(newstr)))
    338 	
    339 	def ps_known(self):
    340 		key = self.pop()
    341 		d = self.pop('dicttype', 'fonttype')
    342 		self.push(ps_boolean(key.value in d.value))
    343 	
    344 	def ps_if(self):
    345 		proc = self.pop('proceduretype')
    346 		if self.pop('booleantype').value:
    347 			self.call_procedure(proc)
    348 	
    349 	def ps_ifelse(self):
    350 		proc2 = self.pop('proceduretype')
    351 		proc1 = self.pop('proceduretype')
    352 		if self.pop('booleantype').value:
    353 			self.call_procedure(proc1)
    354 		else:
    355 			self.call_procedure(proc2)
    356 	
    357 	def ps_readonly(self):
    358 		obj = self.pop()
    359 		if obj.access < 1:
    360 			obj.access = 1
    361 		self.push(obj)
    362 	
    363 	def ps_executeonly(self):
    364 		obj = self.pop()
    365 		if obj.access < 2:
    366 			obj.access = 2
    367 		self.push(obj)
    368 	
    369 	def ps_noaccess(self):
    370 		obj = self.pop()
    371 		if obj.access < 3:
    372 			obj.access = 3
    373 		self.push(obj)
    374 	
    375 	def ps_not(self):
    376 		obj = self.pop('booleantype', 'integertype')
    377 		if obj.type == 'booleantype':
    378 			self.push(ps_boolean(not obj.value))
    379 		else:
    380 			self.push(ps_integer(~obj.value))
    381 	
    382 	def ps_print(self):
    383 		str = self.pop('stringtype')
    384 		print('PS output --->', str.value)
    385 	
    386 	def ps_anchorsearch(self):
    387 		seek = self.pop('stringtype')
    388 		s = self.pop('stringtype')
    389 		seeklen = len(seek.value)
    390 		if s.value[:seeklen] == seek.value:
    391 			self.push(ps_string(s.value[seeklen:]))
    392 			self.push(seek)
    393 			self.push(ps_boolean(1))
    394 		else:
    395 			self.push(s)
    396 			self.push(ps_boolean(0))
    397 	
    398 	def ps_array(self):
    399 		num = self.pop('integertype')
    400 		array = ps_array([None] * num.value)
    401 		self.push(array)
    402 	
    403 	def ps_astore(self):
    404 		array = self.pop('arraytype')
    405 		for i in range(len(array.value)-1, -1, -1):
    406 			array.value[i] = self.pop()
    407 		self.push(array)
    408 	
    409 	def ps_load(self):
    410 		name = self.pop()
    411 		self.push(self.resolve_name(name.value))
    412 	
    413 	def ps_put(self):
    414 		obj1 = self.pop()
    415 		obj2 = self.pop()
    416 		obj3 = self.pop('arraytype', 'dicttype', 'stringtype', 'proceduretype')
    417 		tp = obj3.type
    418 		if tp == 'arraytype' or tp == 'proceduretype':
    419 			obj3.value[obj2.value] = obj1
    420 		elif tp == 'dicttype':
    421 			obj3.value[obj2.value] = obj1
    422 		elif tp == 'stringtype':
    423 			index = obj2.value
    424 			obj3.value = obj3.value[:index] + chr(obj1.value) + obj3.value[index+1:]
    425 	
    426 	def ps_get(self):
    427 		obj1 = self.pop()
    428 		if obj1.value == "Encoding":
    429 			pass
    430 		obj2 = self.pop('arraytype', 'dicttype', 'stringtype', 'proceduretype', 'fonttype')
    431 		tp = obj2.type
    432 		if tp in ('arraytype', 'proceduretype'):
    433 			self.push(obj2.value[obj1.value])
    434 		elif tp in ('dicttype', 'fonttype'):
    435 			self.push(obj2.value[obj1.value])
    436 		elif tp == 'stringtype':
    437 			self.push(ps_integer(ord(obj2.value[obj1.value])))
    438 		else:
    439 			assert False, "shouldn't get here"
    440 	
    441 	def ps_getinterval(self):
    442 		obj1 = self.pop('integertype')
    443 		obj2 = self.pop('integertype')
    444 		obj3 = self.pop('arraytype', 'stringtype')
    445 		tp = obj3.type
    446 		if tp == 'arraytype':
    447 			self.push(ps_array(obj3.value[obj2.value:obj2.value + obj1.value]))
    448 		elif tp == 'stringtype':
    449 			self.push(ps_string(obj3.value[obj2.value:obj2.value + obj1.value]))
    450 	
    451 	def ps_putinterval(self):
    452 		obj1 = self.pop('arraytype', 'stringtype')
    453 		obj2 = self.pop('integertype')
    454 		obj3 = self.pop('arraytype', 'stringtype')
    455 		tp = obj3.type
    456 		if tp == 'arraytype':
    457 			obj3.value[obj2.value:obj2.value + len(obj1.value)] = obj1.value
    458 		elif tp == 'stringtype':
    459 			newstr = obj3.value[:obj2.value]
    460 			newstr = newstr + obj1.value
    461 			newstr = newstr + obj3.value[obj2.value + len(obj1.value):]
    462 			obj3.value = newstr
    463 	
    464 	def ps_cvn(self):
    465 		self.push(ps_name(self.pop('stringtype').value))
    466 	
    467 	def ps_index(self):
    468 		n = self.pop('integertype').value
    469 		if n < 0:
    470 			raise RuntimeError('index may not be negative')
    471 		self.push(self.stack[-1-n])
    472 	
    473 	def ps_for(self):
    474 		proc = self.pop('proceduretype')
    475 		limit = self.pop('integertype', 'realtype').value
    476 		increment = self.pop('integertype', 'realtype').value
    477 		i = self.pop('integertype', 'realtype').value
    478 		while 1:
    479 			if increment > 0:
    480 				if i > limit:
    481 					break
    482 			else:
    483 				if i < limit:
    484 					break
    485 			if type(i) == type(0.0):
    486 				self.push(ps_real(i))
    487 			else:
    488 				self.push(ps_integer(i))
    489 			self.call_procedure(proc)
    490 			i = i + increment
    491 	
    492 	def ps_forall(self):
    493 		proc = self.pop('proceduretype')
    494 		obj = self.pop('arraytype', 'stringtype', 'dicttype')
    495 		tp = obj.type
    496 		if tp == 'arraytype':
    497 			for item in obj.value:
    498 				self.push(item)
    499 				self.call_procedure(proc)
    500 		elif tp == 'stringtype':
    501 			for item in obj.value:
    502 				self.push(ps_integer(ord(item)))
    503 				self.call_procedure(proc)
    504 		elif tp == 'dicttype':
    505 			for key, value in obj.value.items():
    506 				self.push(ps_name(key))
    507 				self.push(value)
    508 				self.call_procedure(proc)		
    509 	
    510 	def ps_definefont(self):
    511 		font = self.pop('dicttype')
    512 		name = self.pop()
    513 		font = ps_font(font.value)
    514 		self.dictstack[0]['FontDirectory'].value[name.value] = font
    515 		self.push(font)
    516 	
    517 	def ps_findfont(self):
    518 		name = self.pop()
    519 		font = self.dictstack[0]['FontDirectory'].value[name.value]
    520 		self.push(font)
    521 	
    522 	def ps_pop(self):
    523 		self.pop()
    524 	
    525 	def ps_dict(self):
    526 		self.pop('integertype')
    527 		self.push(ps_dict({}))
    528 	
    529 	def ps_begin(self):
    530 		self.dictstack.append(self.pop('dicttype').value)
    531 	
    532 	def ps_end(self):
    533 		if len(self.dictstack) > 2:
    534 			del self.dictstack[-1]
    535 		else:
    536 			raise RuntimeError('dictstack underflow')
    537 	
    538 notdef = '.notdef'
    539 from fontTools.encodings.StandardEncoding import StandardEncoding
    540 ps_StandardEncoding = list(map(ps_name, StandardEncoding))
    541 
    542