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