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