1*e1fe3e4aSElliott Hughes"""psCharStrings.py -- module implementing various kinds of CharStrings: 2*e1fe3e4aSElliott HughesCFF dictionary data and Type1/Type2 CharStrings. 3*e1fe3e4aSElliott Hughes""" 4*e1fe3e4aSElliott Hughes 5*e1fe3e4aSElliott Hughesfrom fontTools.misc.fixedTools import ( 6*e1fe3e4aSElliott Hughes fixedToFloat, 7*e1fe3e4aSElliott Hughes floatToFixed, 8*e1fe3e4aSElliott Hughes floatToFixedToStr, 9*e1fe3e4aSElliott Hughes strToFixedToFloat, 10*e1fe3e4aSElliott Hughes) 11*e1fe3e4aSElliott Hughesfrom fontTools.misc.textTools import bytechr, byteord, bytesjoin, strjoin 12*e1fe3e4aSElliott Hughesfrom fontTools.pens.boundsPen import BoundsPen 13*e1fe3e4aSElliott Hughesimport struct 14*e1fe3e4aSElliott Hughesimport logging 15*e1fe3e4aSElliott Hughes 16*e1fe3e4aSElliott Hughes 17*e1fe3e4aSElliott Hugheslog = logging.getLogger(__name__) 18*e1fe3e4aSElliott Hughes 19*e1fe3e4aSElliott Hughes 20*e1fe3e4aSElliott Hughesdef read_operator(self, b0, data, index): 21*e1fe3e4aSElliott Hughes if b0 == 12: 22*e1fe3e4aSElliott Hughes op = (b0, byteord(data[index])) 23*e1fe3e4aSElliott Hughes index = index + 1 24*e1fe3e4aSElliott Hughes else: 25*e1fe3e4aSElliott Hughes op = b0 26*e1fe3e4aSElliott Hughes try: 27*e1fe3e4aSElliott Hughes operator = self.operators[op] 28*e1fe3e4aSElliott Hughes except KeyError: 29*e1fe3e4aSElliott Hughes return None, index 30*e1fe3e4aSElliott Hughes value = self.handle_operator(operator) 31*e1fe3e4aSElliott Hughes return value, index 32*e1fe3e4aSElliott Hughes 33*e1fe3e4aSElliott Hughes 34*e1fe3e4aSElliott Hughesdef read_byte(self, b0, data, index): 35*e1fe3e4aSElliott Hughes return b0 - 139, index 36*e1fe3e4aSElliott Hughes 37*e1fe3e4aSElliott Hughes 38*e1fe3e4aSElliott Hughesdef read_smallInt1(self, b0, data, index): 39*e1fe3e4aSElliott Hughes b1 = byteord(data[index]) 40*e1fe3e4aSElliott Hughes return (b0 - 247) * 256 + b1 + 108, index + 1 41*e1fe3e4aSElliott Hughes 42*e1fe3e4aSElliott Hughes 43*e1fe3e4aSElliott Hughesdef read_smallInt2(self, b0, data, index): 44*e1fe3e4aSElliott Hughes b1 = byteord(data[index]) 45*e1fe3e4aSElliott Hughes return -(b0 - 251) * 256 - b1 - 108, index + 1 46*e1fe3e4aSElliott Hughes 47*e1fe3e4aSElliott Hughes 48*e1fe3e4aSElliott Hughesdef read_shortInt(self, b0, data, index): 49*e1fe3e4aSElliott Hughes (value,) = struct.unpack(">h", data[index : index + 2]) 50*e1fe3e4aSElliott Hughes return value, index + 2 51*e1fe3e4aSElliott Hughes 52*e1fe3e4aSElliott Hughes 53*e1fe3e4aSElliott Hughesdef read_longInt(self, b0, data, index): 54*e1fe3e4aSElliott Hughes (value,) = struct.unpack(">l", data[index : index + 4]) 55*e1fe3e4aSElliott Hughes return value, index + 4 56*e1fe3e4aSElliott Hughes 57*e1fe3e4aSElliott Hughes 58*e1fe3e4aSElliott Hughesdef read_fixed1616(self, b0, data, index): 59*e1fe3e4aSElliott Hughes (value,) = struct.unpack(">l", data[index : index + 4]) 60*e1fe3e4aSElliott Hughes return fixedToFloat(value, precisionBits=16), index + 4 61*e1fe3e4aSElliott Hughes 62*e1fe3e4aSElliott Hughes 63*e1fe3e4aSElliott Hughesdef read_reserved(self, b0, data, index): 64*e1fe3e4aSElliott Hughes assert NotImplementedError 65*e1fe3e4aSElliott Hughes return NotImplemented, index 66*e1fe3e4aSElliott Hughes 67*e1fe3e4aSElliott Hughes 68*e1fe3e4aSElliott Hughesdef read_realNumber(self, b0, data, index): 69*e1fe3e4aSElliott Hughes number = "" 70*e1fe3e4aSElliott Hughes while True: 71*e1fe3e4aSElliott Hughes b = byteord(data[index]) 72*e1fe3e4aSElliott Hughes index = index + 1 73*e1fe3e4aSElliott Hughes nibble0 = (b & 0xF0) >> 4 74*e1fe3e4aSElliott Hughes nibble1 = b & 0x0F 75*e1fe3e4aSElliott Hughes if nibble0 == 0xF: 76*e1fe3e4aSElliott Hughes break 77*e1fe3e4aSElliott Hughes number = number + realNibbles[nibble0] 78*e1fe3e4aSElliott Hughes if nibble1 == 0xF: 79*e1fe3e4aSElliott Hughes break 80*e1fe3e4aSElliott Hughes number = number + realNibbles[nibble1] 81*e1fe3e4aSElliott Hughes return float(number), index 82*e1fe3e4aSElliott Hughes 83*e1fe3e4aSElliott Hughes 84*e1fe3e4aSElliott Hughest1OperandEncoding = [None] * 256 85*e1fe3e4aSElliott Hughest1OperandEncoding[0:32] = (32) * [read_operator] 86*e1fe3e4aSElliott Hughest1OperandEncoding[32:247] = (247 - 32) * [read_byte] 87*e1fe3e4aSElliott Hughest1OperandEncoding[247:251] = (251 - 247) * [read_smallInt1] 88*e1fe3e4aSElliott Hughest1OperandEncoding[251:255] = (255 - 251) * [read_smallInt2] 89*e1fe3e4aSElliott Hughest1OperandEncoding[255] = read_longInt 90*e1fe3e4aSElliott Hughesassert len(t1OperandEncoding) == 256 91*e1fe3e4aSElliott Hughes 92*e1fe3e4aSElliott Hughest2OperandEncoding = t1OperandEncoding[:] 93*e1fe3e4aSElliott Hughest2OperandEncoding[28] = read_shortInt 94*e1fe3e4aSElliott Hughest2OperandEncoding[255] = read_fixed1616 95*e1fe3e4aSElliott Hughes 96*e1fe3e4aSElliott HughescffDictOperandEncoding = t2OperandEncoding[:] 97*e1fe3e4aSElliott HughescffDictOperandEncoding[29] = read_longInt 98*e1fe3e4aSElliott HughescffDictOperandEncoding[30] = read_realNumber 99*e1fe3e4aSElliott HughescffDictOperandEncoding[255] = read_reserved 100*e1fe3e4aSElliott Hughes 101*e1fe3e4aSElliott Hughes 102*e1fe3e4aSElliott HughesrealNibbles = [ 103*e1fe3e4aSElliott Hughes "0", 104*e1fe3e4aSElliott Hughes "1", 105*e1fe3e4aSElliott Hughes "2", 106*e1fe3e4aSElliott Hughes "3", 107*e1fe3e4aSElliott Hughes "4", 108*e1fe3e4aSElliott Hughes "5", 109*e1fe3e4aSElliott Hughes "6", 110*e1fe3e4aSElliott Hughes "7", 111*e1fe3e4aSElliott Hughes "8", 112*e1fe3e4aSElliott Hughes "9", 113*e1fe3e4aSElliott Hughes ".", 114*e1fe3e4aSElliott Hughes "E", 115*e1fe3e4aSElliott Hughes "E-", 116*e1fe3e4aSElliott Hughes None, 117*e1fe3e4aSElliott Hughes "-", 118*e1fe3e4aSElliott Hughes] 119*e1fe3e4aSElliott HughesrealNibblesDict = {v: i for i, v in enumerate(realNibbles)} 120*e1fe3e4aSElliott Hughes 121*e1fe3e4aSElliott HughesmaxOpStack = 193 122*e1fe3e4aSElliott Hughes 123*e1fe3e4aSElliott Hughes 124*e1fe3e4aSElliott Hughesdef buildOperatorDict(operatorList): 125*e1fe3e4aSElliott Hughes oper = {} 126*e1fe3e4aSElliott Hughes opc = {} 127*e1fe3e4aSElliott Hughes for item in operatorList: 128*e1fe3e4aSElliott Hughes if len(item) == 2: 129*e1fe3e4aSElliott Hughes oper[item[0]] = item[1] 130*e1fe3e4aSElliott Hughes else: 131*e1fe3e4aSElliott Hughes oper[item[0]] = item[1:] 132*e1fe3e4aSElliott Hughes if isinstance(item[0], tuple): 133*e1fe3e4aSElliott Hughes opc[item[1]] = item[0] 134*e1fe3e4aSElliott Hughes else: 135*e1fe3e4aSElliott Hughes opc[item[1]] = (item[0],) 136*e1fe3e4aSElliott Hughes return oper, opc 137*e1fe3e4aSElliott Hughes 138*e1fe3e4aSElliott Hughes 139*e1fe3e4aSElliott Hughest2Operators = [ 140*e1fe3e4aSElliott Hughes # opcode name 141*e1fe3e4aSElliott Hughes (1, "hstem"), 142*e1fe3e4aSElliott Hughes (3, "vstem"), 143*e1fe3e4aSElliott Hughes (4, "vmoveto"), 144*e1fe3e4aSElliott Hughes (5, "rlineto"), 145*e1fe3e4aSElliott Hughes (6, "hlineto"), 146*e1fe3e4aSElliott Hughes (7, "vlineto"), 147*e1fe3e4aSElliott Hughes (8, "rrcurveto"), 148*e1fe3e4aSElliott Hughes (10, "callsubr"), 149*e1fe3e4aSElliott Hughes (11, "return"), 150*e1fe3e4aSElliott Hughes (14, "endchar"), 151*e1fe3e4aSElliott Hughes (15, "vsindex"), 152*e1fe3e4aSElliott Hughes (16, "blend"), 153*e1fe3e4aSElliott Hughes (18, "hstemhm"), 154*e1fe3e4aSElliott Hughes (19, "hintmask"), 155*e1fe3e4aSElliott Hughes (20, "cntrmask"), 156*e1fe3e4aSElliott Hughes (21, "rmoveto"), 157*e1fe3e4aSElliott Hughes (22, "hmoveto"), 158*e1fe3e4aSElliott Hughes (23, "vstemhm"), 159*e1fe3e4aSElliott Hughes (24, "rcurveline"), 160*e1fe3e4aSElliott Hughes (25, "rlinecurve"), 161*e1fe3e4aSElliott Hughes (26, "vvcurveto"), 162*e1fe3e4aSElliott Hughes (27, "hhcurveto"), 163*e1fe3e4aSElliott Hughes # (28, 'shortint'), # not really an operator 164*e1fe3e4aSElliott Hughes (29, "callgsubr"), 165*e1fe3e4aSElliott Hughes (30, "vhcurveto"), 166*e1fe3e4aSElliott Hughes (31, "hvcurveto"), 167*e1fe3e4aSElliott Hughes ((12, 0), "ignore"), # dotsection. Yes, there a few very early OTF/CFF 168*e1fe3e4aSElliott Hughes # fonts with this deprecated operator. Just ignore it. 169*e1fe3e4aSElliott Hughes ((12, 3), "and"), 170*e1fe3e4aSElliott Hughes ((12, 4), "or"), 171*e1fe3e4aSElliott Hughes ((12, 5), "not"), 172*e1fe3e4aSElliott Hughes ((12, 8), "store"), 173*e1fe3e4aSElliott Hughes ((12, 9), "abs"), 174*e1fe3e4aSElliott Hughes ((12, 10), "add"), 175*e1fe3e4aSElliott Hughes ((12, 11), "sub"), 176*e1fe3e4aSElliott Hughes ((12, 12), "div"), 177*e1fe3e4aSElliott Hughes ((12, 13), "load"), 178*e1fe3e4aSElliott Hughes ((12, 14), "neg"), 179*e1fe3e4aSElliott Hughes ((12, 15), "eq"), 180*e1fe3e4aSElliott Hughes ((12, 18), "drop"), 181*e1fe3e4aSElliott Hughes ((12, 20), "put"), 182*e1fe3e4aSElliott Hughes ((12, 21), "get"), 183*e1fe3e4aSElliott Hughes ((12, 22), "ifelse"), 184*e1fe3e4aSElliott Hughes ((12, 23), "random"), 185*e1fe3e4aSElliott Hughes ((12, 24), "mul"), 186*e1fe3e4aSElliott Hughes ((12, 26), "sqrt"), 187*e1fe3e4aSElliott Hughes ((12, 27), "dup"), 188*e1fe3e4aSElliott Hughes ((12, 28), "exch"), 189*e1fe3e4aSElliott Hughes ((12, 29), "index"), 190*e1fe3e4aSElliott Hughes ((12, 30), "roll"), 191*e1fe3e4aSElliott Hughes ((12, 34), "hflex"), 192*e1fe3e4aSElliott Hughes ((12, 35), "flex"), 193*e1fe3e4aSElliott Hughes ((12, 36), "hflex1"), 194*e1fe3e4aSElliott Hughes ((12, 37), "flex1"), 195*e1fe3e4aSElliott Hughes] 196*e1fe3e4aSElliott Hughes 197*e1fe3e4aSElliott Hughes 198*e1fe3e4aSElliott Hughesdef getIntEncoder(format): 199*e1fe3e4aSElliott Hughes if format == "cff": 200*e1fe3e4aSElliott Hughes twoByteOp = bytechr(28) 201*e1fe3e4aSElliott Hughes fourByteOp = bytechr(29) 202*e1fe3e4aSElliott Hughes elif format == "t1": 203*e1fe3e4aSElliott Hughes twoByteOp = None 204*e1fe3e4aSElliott Hughes fourByteOp = bytechr(255) 205*e1fe3e4aSElliott Hughes else: 206*e1fe3e4aSElliott Hughes assert format == "t2" 207*e1fe3e4aSElliott Hughes twoByteOp = bytechr(28) 208*e1fe3e4aSElliott Hughes fourByteOp = None 209*e1fe3e4aSElliott Hughes 210*e1fe3e4aSElliott Hughes def encodeInt( 211*e1fe3e4aSElliott Hughes value, 212*e1fe3e4aSElliott Hughes fourByteOp=fourByteOp, 213*e1fe3e4aSElliott Hughes bytechr=bytechr, 214*e1fe3e4aSElliott Hughes pack=struct.pack, 215*e1fe3e4aSElliott Hughes unpack=struct.unpack, 216*e1fe3e4aSElliott Hughes twoByteOp=twoByteOp, 217*e1fe3e4aSElliott Hughes ): 218*e1fe3e4aSElliott Hughes if -107 <= value <= 107: 219*e1fe3e4aSElliott Hughes code = bytechr(value + 139) 220*e1fe3e4aSElliott Hughes elif 108 <= value <= 1131: 221*e1fe3e4aSElliott Hughes value = value - 108 222*e1fe3e4aSElliott Hughes code = bytechr((value >> 8) + 247) + bytechr(value & 0xFF) 223*e1fe3e4aSElliott Hughes elif -1131 <= value <= -108: 224*e1fe3e4aSElliott Hughes value = -value - 108 225*e1fe3e4aSElliott Hughes code = bytechr((value >> 8) + 251) + bytechr(value & 0xFF) 226*e1fe3e4aSElliott Hughes elif twoByteOp is not None and -32768 <= value <= 32767: 227*e1fe3e4aSElliott Hughes code = twoByteOp + pack(">h", value) 228*e1fe3e4aSElliott Hughes elif fourByteOp is None: 229*e1fe3e4aSElliott Hughes # Backwards compatible hack: due to a previous bug in FontTools, 230*e1fe3e4aSElliott Hughes # 16.16 fixed numbers were written out as 4-byte ints. When 231*e1fe3e4aSElliott Hughes # these numbers were small, they were wrongly written back as 232*e1fe3e4aSElliott Hughes # small ints instead of 4-byte ints, breaking round-tripping. 233*e1fe3e4aSElliott Hughes # This here workaround doesn't do it any better, since we can't 234*e1fe3e4aSElliott Hughes # distinguish anymore between small ints that were supposed to 235*e1fe3e4aSElliott Hughes # be small fixed numbers and small ints that were just small 236*e1fe3e4aSElliott Hughes # ints. Hence the warning. 237*e1fe3e4aSElliott Hughes log.warning( 238*e1fe3e4aSElliott Hughes "4-byte T2 number got passed to the " 239*e1fe3e4aSElliott Hughes "IntType handler. This should happen only when reading in " 240*e1fe3e4aSElliott Hughes "old XML files.\n" 241*e1fe3e4aSElliott Hughes ) 242*e1fe3e4aSElliott Hughes code = bytechr(255) + pack(">l", value) 243*e1fe3e4aSElliott Hughes else: 244*e1fe3e4aSElliott Hughes code = fourByteOp + pack(">l", value) 245*e1fe3e4aSElliott Hughes return code 246*e1fe3e4aSElliott Hughes 247*e1fe3e4aSElliott Hughes return encodeInt 248*e1fe3e4aSElliott Hughes 249*e1fe3e4aSElliott Hughes 250*e1fe3e4aSElliott HughesencodeIntCFF = getIntEncoder("cff") 251*e1fe3e4aSElliott HughesencodeIntT1 = getIntEncoder("t1") 252*e1fe3e4aSElliott HughesencodeIntT2 = getIntEncoder("t2") 253*e1fe3e4aSElliott Hughes 254*e1fe3e4aSElliott Hughes 255*e1fe3e4aSElliott Hughesdef encodeFixed(f, pack=struct.pack): 256*e1fe3e4aSElliott Hughes """For T2 only""" 257*e1fe3e4aSElliott Hughes value = floatToFixed(f, precisionBits=16) 258*e1fe3e4aSElliott Hughes if value & 0xFFFF == 0: # check if the fractional part is zero 259*e1fe3e4aSElliott Hughes return encodeIntT2(value >> 16) # encode only the integer part 260*e1fe3e4aSElliott Hughes else: 261*e1fe3e4aSElliott Hughes return b"\xff" + pack(">l", value) # encode the entire fixed point value 262*e1fe3e4aSElliott Hughes 263*e1fe3e4aSElliott Hughes 264*e1fe3e4aSElliott HughesrealZeroBytes = bytechr(30) + bytechr(0xF) 265*e1fe3e4aSElliott Hughes 266*e1fe3e4aSElliott Hughes 267*e1fe3e4aSElliott Hughesdef encodeFloat(f): 268*e1fe3e4aSElliott Hughes # For CFF only, used in cffLib 269*e1fe3e4aSElliott Hughes if f == 0.0: # 0.0 == +0.0 == -0.0 270*e1fe3e4aSElliott Hughes return realZeroBytes 271*e1fe3e4aSElliott Hughes # Note: 14 decimal digits seems to be the limitation for CFF real numbers 272*e1fe3e4aSElliott Hughes # in macOS. However, we use 8 here to match the implementation of AFDKO. 273*e1fe3e4aSElliott Hughes s = "%.8G" % f 274*e1fe3e4aSElliott Hughes if s[:2] == "0.": 275*e1fe3e4aSElliott Hughes s = s[1:] 276*e1fe3e4aSElliott Hughes elif s[:3] == "-0.": 277*e1fe3e4aSElliott Hughes s = "-" + s[2:] 278*e1fe3e4aSElliott Hughes nibbles = [] 279*e1fe3e4aSElliott Hughes while s: 280*e1fe3e4aSElliott Hughes c = s[0] 281*e1fe3e4aSElliott Hughes s = s[1:] 282*e1fe3e4aSElliott Hughes if c == "E": 283*e1fe3e4aSElliott Hughes c2 = s[:1] 284*e1fe3e4aSElliott Hughes if c2 == "-": 285*e1fe3e4aSElliott Hughes s = s[1:] 286*e1fe3e4aSElliott Hughes c = "E-" 287*e1fe3e4aSElliott Hughes elif c2 == "+": 288*e1fe3e4aSElliott Hughes s = s[1:] 289*e1fe3e4aSElliott Hughes nibbles.append(realNibblesDict[c]) 290*e1fe3e4aSElliott Hughes nibbles.append(0xF) 291*e1fe3e4aSElliott Hughes if len(nibbles) % 2: 292*e1fe3e4aSElliott Hughes nibbles.append(0xF) 293*e1fe3e4aSElliott Hughes d = bytechr(30) 294*e1fe3e4aSElliott Hughes for i in range(0, len(nibbles), 2): 295*e1fe3e4aSElliott Hughes d = d + bytechr(nibbles[i] << 4 | nibbles[i + 1]) 296*e1fe3e4aSElliott Hughes return d 297*e1fe3e4aSElliott Hughes 298*e1fe3e4aSElliott Hughes 299*e1fe3e4aSElliott Hughesclass CharStringCompileError(Exception): 300*e1fe3e4aSElliott Hughes pass 301*e1fe3e4aSElliott Hughes 302*e1fe3e4aSElliott Hughes 303*e1fe3e4aSElliott Hughesclass SimpleT2Decompiler(object): 304*e1fe3e4aSElliott Hughes def __init__(self, localSubrs, globalSubrs, private=None, blender=None): 305*e1fe3e4aSElliott Hughes self.localSubrs = localSubrs 306*e1fe3e4aSElliott Hughes self.localBias = calcSubrBias(localSubrs) 307*e1fe3e4aSElliott Hughes self.globalSubrs = globalSubrs 308*e1fe3e4aSElliott Hughes self.globalBias = calcSubrBias(globalSubrs) 309*e1fe3e4aSElliott Hughes self.private = private 310*e1fe3e4aSElliott Hughes self.blender = blender 311*e1fe3e4aSElliott Hughes self.reset() 312*e1fe3e4aSElliott Hughes 313*e1fe3e4aSElliott Hughes def reset(self): 314*e1fe3e4aSElliott Hughes self.callingStack = [] 315*e1fe3e4aSElliott Hughes self.operandStack = [] 316*e1fe3e4aSElliott Hughes self.hintCount = 0 317*e1fe3e4aSElliott Hughes self.hintMaskBytes = 0 318*e1fe3e4aSElliott Hughes self.numRegions = 0 319*e1fe3e4aSElliott Hughes self.vsIndex = 0 320*e1fe3e4aSElliott Hughes 321*e1fe3e4aSElliott Hughes def execute(self, charString): 322*e1fe3e4aSElliott Hughes self.callingStack.append(charString) 323*e1fe3e4aSElliott Hughes needsDecompilation = charString.needsDecompilation() 324*e1fe3e4aSElliott Hughes if needsDecompilation: 325*e1fe3e4aSElliott Hughes program = [] 326*e1fe3e4aSElliott Hughes pushToProgram = program.append 327*e1fe3e4aSElliott Hughes else: 328*e1fe3e4aSElliott Hughes pushToProgram = lambda x: None 329*e1fe3e4aSElliott Hughes pushToStack = self.operandStack.append 330*e1fe3e4aSElliott Hughes index = 0 331*e1fe3e4aSElliott Hughes while True: 332*e1fe3e4aSElliott Hughes token, isOperator, index = charString.getToken(index) 333*e1fe3e4aSElliott Hughes if token is None: 334*e1fe3e4aSElliott Hughes break # we're done! 335*e1fe3e4aSElliott Hughes pushToProgram(token) 336*e1fe3e4aSElliott Hughes if isOperator: 337*e1fe3e4aSElliott Hughes handlerName = "op_" + token 338*e1fe3e4aSElliott Hughes handler = getattr(self, handlerName, None) 339*e1fe3e4aSElliott Hughes if handler is not None: 340*e1fe3e4aSElliott Hughes rv = handler(index) 341*e1fe3e4aSElliott Hughes if rv: 342*e1fe3e4aSElliott Hughes hintMaskBytes, index = rv 343*e1fe3e4aSElliott Hughes pushToProgram(hintMaskBytes) 344*e1fe3e4aSElliott Hughes else: 345*e1fe3e4aSElliott Hughes self.popall() 346*e1fe3e4aSElliott Hughes else: 347*e1fe3e4aSElliott Hughes pushToStack(token) 348*e1fe3e4aSElliott Hughes if needsDecompilation: 349*e1fe3e4aSElliott Hughes charString.setProgram(program) 350*e1fe3e4aSElliott Hughes del self.callingStack[-1] 351*e1fe3e4aSElliott Hughes 352*e1fe3e4aSElliott Hughes def pop(self): 353*e1fe3e4aSElliott Hughes value = self.operandStack[-1] 354*e1fe3e4aSElliott Hughes del self.operandStack[-1] 355*e1fe3e4aSElliott Hughes return value 356*e1fe3e4aSElliott Hughes 357*e1fe3e4aSElliott Hughes def popall(self): 358*e1fe3e4aSElliott Hughes stack = self.operandStack[:] 359*e1fe3e4aSElliott Hughes self.operandStack[:] = [] 360*e1fe3e4aSElliott Hughes return stack 361*e1fe3e4aSElliott Hughes 362*e1fe3e4aSElliott Hughes def push(self, value): 363*e1fe3e4aSElliott Hughes self.operandStack.append(value) 364*e1fe3e4aSElliott Hughes 365*e1fe3e4aSElliott Hughes def op_return(self, index): 366*e1fe3e4aSElliott Hughes if self.operandStack: 367*e1fe3e4aSElliott Hughes pass 368*e1fe3e4aSElliott Hughes 369*e1fe3e4aSElliott Hughes def op_endchar(self, index): 370*e1fe3e4aSElliott Hughes pass 371*e1fe3e4aSElliott Hughes 372*e1fe3e4aSElliott Hughes def op_ignore(self, index): 373*e1fe3e4aSElliott Hughes pass 374*e1fe3e4aSElliott Hughes 375*e1fe3e4aSElliott Hughes def op_callsubr(self, index): 376*e1fe3e4aSElliott Hughes subrIndex = self.pop() 377*e1fe3e4aSElliott Hughes subr = self.localSubrs[subrIndex + self.localBias] 378*e1fe3e4aSElliott Hughes self.execute(subr) 379*e1fe3e4aSElliott Hughes 380*e1fe3e4aSElliott Hughes def op_callgsubr(self, index): 381*e1fe3e4aSElliott Hughes subrIndex = self.pop() 382*e1fe3e4aSElliott Hughes subr = self.globalSubrs[subrIndex + self.globalBias] 383*e1fe3e4aSElliott Hughes self.execute(subr) 384*e1fe3e4aSElliott Hughes 385*e1fe3e4aSElliott Hughes def op_hstem(self, index): 386*e1fe3e4aSElliott Hughes self.countHints() 387*e1fe3e4aSElliott Hughes 388*e1fe3e4aSElliott Hughes def op_vstem(self, index): 389*e1fe3e4aSElliott Hughes self.countHints() 390*e1fe3e4aSElliott Hughes 391*e1fe3e4aSElliott Hughes def op_hstemhm(self, index): 392*e1fe3e4aSElliott Hughes self.countHints() 393*e1fe3e4aSElliott Hughes 394*e1fe3e4aSElliott Hughes def op_vstemhm(self, index): 395*e1fe3e4aSElliott Hughes self.countHints() 396*e1fe3e4aSElliott Hughes 397*e1fe3e4aSElliott Hughes def op_hintmask(self, index): 398*e1fe3e4aSElliott Hughes if not self.hintMaskBytes: 399*e1fe3e4aSElliott Hughes self.countHints() 400*e1fe3e4aSElliott Hughes self.hintMaskBytes = (self.hintCount + 7) // 8 401*e1fe3e4aSElliott Hughes hintMaskBytes, index = self.callingStack[-1].getBytes(index, self.hintMaskBytes) 402*e1fe3e4aSElliott Hughes return hintMaskBytes, index 403*e1fe3e4aSElliott Hughes 404*e1fe3e4aSElliott Hughes op_cntrmask = op_hintmask 405*e1fe3e4aSElliott Hughes 406*e1fe3e4aSElliott Hughes def countHints(self): 407*e1fe3e4aSElliott Hughes args = self.popall() 408*e1fe3e4aSElliott Hughes self.hintCount = self.hintCount + len(args) // 2 409*e1fe3e4aSElliott Hughes 410*e1fe3e4aSElliott Hughes # misc 411*e1fe3e4aSElliott Hughes def op_and(self, index): 412*e1fe3e4aSElliott Hughes raise NotImplementedError 413*e1fe3e4aSElliott Hughes 414*e1fe3e4aSElliott Hughes def op_or(self, index): 415*e1fe3e4aSElliott Hughes raise NotImplementedError 416*e1fe3e4aSElliott Hughes 417*e1fe3e4aSElliott Hughes def op_not(self, index): 418*e1fe3e4aSElliott Hughes raise NotImplementedError 419*e1fe3e4aSElliott Hughes 420*e1fe3e4aSElliott Hughes def op_store(self, index): 421*e1fe3e4aSElliott Hughes raise NotImplementedError 422*e1fe3e4aSElliott Hughes 423*e1fe3e4aSElliott Hughes def op_abs(self, index): 424*e1fe3e4aSElliott Hughes raise NotImplementedError 425*e1fe3e4aSElliott Hughes 426*e1fe3e4aSElliott Hughes def op_add(self, index): 427*e1fe3e4aSElliott Hughes raise NotImplementedError 428*e1fe3e4aSElliott Hughes 429*e1fe3e4aSElliott Hughes def op_sub(self, index): 430*e1fe3e4aSElliott Hughes raise NotImplementedError 431*e1fe3e4aSElliott Hughes 432*e1fe3e4aSElliott Hughes def op_div(self, index): 433*e1fe3e4aSElliott Hughes raise NotImplementedError 434*e1fe3e4aSElliott Hughes 435*e1fe3e4aSElliott Hughes def op_load(self, index): 436*e1fe3e4aSElliott Hughes raise NotImplementedError 437*e1fe3e4aSElliott Hughes 438*e1fe3e4aSElliott Hughes def op_neg(self, index): 439*e1fe3e4aSElliott Hughes raise NotImplementedError 440*e1fe3e4aSElliott Hughes 441*e1fe3e4aSElliott Hughes def op_eq(self, index): 442*e1fe3e4aSElliott Hughes raise NotImplementedError 443*e1fe3e4aSElliott Hughes 444*e1fe3e4aSElliott Hughes def op_drop(self, index): 445*e1fe3e4aSElliott Hughes raise NotImplementedError 446*e1fe3e4aSElliott Hughes 447*e1fe3e4aSElliott Hughes def op_put(self, index): 448*e1fe3e4aSElliott Hughes raise NotImplementedError 449*e1fe3e4aSElliott Hughes 450*e1fe3e4aSElliott Hughes def op_get(self, index): 451*e1fe3e4aSElliott Hughes raise NotImplementedError 452*e1fe3e4aSElliott Hughes 453*e1fe3e4aSElliott Hughes def op_ifelse(self, index): 454*e1fe3e4aSElliott Hughes raise NotImplementedError 455*e1fe3e4aSElliott Hughes 456*e1fe3e4aSElliott Hughes def op_random(self, index): 457*e1fe3e4aSElliott Hughes raise NotImplementedError 458*e1fe3e4aSElliott Hughes 459*e1fe3e4aSElliott Hughes def op_mul(self, index): 460*e1fe3e4aSElliott Hughes raise NotImplementedError 461*e1fe3e4aSElliott Hughes 462*e1fe3e4aSElliott Hughes def op_sqrt(self, index): 463*e1fe3e4aSElliott Hughes raise NotImplementedError 464*e1fe3e4aSElliott Hughes 465*e1fe3e4aSElliott Hughes def op_dup(self, index): 466*e1fe3e4aSElliott Hughes raise NotImplementedError 467*e1fe3e4aSElliott Hughes 468*e1fe3e4aSElliott Hughes def op_exch(self, index): 469*e1fe3e4aSElliott Hughes raise NotImplementedError 470*e1fe3e4aSElliott Hughes 471*e1fe3e4aSElliott Hughes def op_index(self, index): 472*e1fe3e4aSElliott Hughes raise NotImplementedError 473*e1fe3e4aSElliott Hughes 474*e1fe3e4aSElliott Hughes def op_roll(self, index): 475*e1fe3e4aSElliott Hughes raise NotImplementedError 476*e1fe3e4aSElliott Hughes 477*e1fe3e4aSElliott Hughes def op_blend(self, index): 478*e1fe3e4aSElliott Hughes if self.numRegions == 0: 479*e1fe3e4aSElliott Hughes self.numRegions = self.private.getNumRegions() 480*e1fe3e4aSElliott Hughes numBlends = self.pop() 481*e1fe3e4aSElliott Hughes numOps = numBlends * (self.numRegions + 1) 482*e1fe3e4aSElliott Hughes if self.blender is None: 483*e1fe3e4aSElliott Hughes del self.operandStack[ 484*e1fe3e4aSElliott Hughes -(numOps - numBlends) : 485*e1fe3e4aSElliott Hughes ] # Leave the default operands on the stack. 486*e1fe3e4aSElliott Hughes else: 487*e1fe3e4aSElliott Hughes argi = len(self.operandStack) - numOps 488*e1fe3e4aSElliott Hughes end_args = tuplei = argi + numBlends 489*e1fe3e4aSElliott Hughes while argi < end_args: 490*e1fe3e4aSElliott Hughes next_ti = tuplei + self.numRegions 491*e1fe3e4aSElliott Hughes deltas = self.operandStack[tuplei:next_ti] 492*e1fe3e4aSElliott Hughes delta = self.blender(self.vsIndex, deltas) 493*e1fe3e4aSElliott Hughes self.operandStack[argi] += delta 494*e1fe3e4aSElliott Hughes tuplei = next_ti 495*e1fe3e4aSElliott Hughes argi += 1 496*e1fe3e4aSElliott Hughes self.operandStack[end_args:] = [] 497*e1fe3e4aSElliott Hughes 498*e1fe3e4aSElliott Hughes def op_vsindex(self, index): 499*e1fe3e4aSElliott Hughes vi = self.pop() 500*e1fe3e4aSElliott Hughes self.vsIndex = vi 501*e1fe3e4aSElliott Hughes self.numRegions = self.private.getNumRegions(vi) 502*e1fe3e4aSElliott Hughes 503*e1fe3e4aSElliott Hughes 504*e1fe3e4aSElliott Hughest1Operators = [ 505*e1fe3e4aSElliott Hughes # opcode name 506*e1fe3e4aSElliott Hughes (1, "hstem"), 507*e1fe3e4aSElliott Hughes (3, "vstem"), 508*e1fe3e4aSElliott Hughes (4, "vmoveto"), 509*e1fe3e4aSElliott Hughes (5, "rlineto"), 510*e1fe3e4aSElliott Hughes (6, "hlineto"), 511*e1fe3e4aSElliott Hughes (7, "vlineto"), 512*e1fe3e4aSElliott Hughes (8, "rrcurveto"), 513*e1fe3e4aSElliott Hughes (9, "closepath"), 514*e1fe3e4aSElliott Hughes (10, "callsubr"), 515*e1fe3e4aSElliott Hughes (11, "return"), 516*e1fe3e4aSElliott Hughes (13, "hsbw"), 517*e1fe3e4aSElliott Hughes (14, "endchar"), 518*e1fe3e4aSElliott Hughes (21, "rmoveto"), 519*e1fe3e4aSElliott Hughes (22, "hmoveto"), 520*e1fe3e4aSElliott Hughes (30, "vhcurveto"), 521*e1fe3e4aSElliott Hughes (31, "hvcurveto"), 522*e1fe3e4aSElliott Hughes ((12, 0), "dotsection"), 523*e1fe3e4aSElliott Hughes ((12, 1), "vstem3"), 524*e1fe3e4aSElliott Hughes ((12, 2), "hstem3"), 525*e1fe3e4aSElliott Hughes ((12, 6), "seac"), 526*e1fe3e4aSElliott Hughes ((12, 7), "sbw"), 527*e1fe3e4aSElliott Hughes ((12, 12), "div"), 528*e1fe3e4aSElliott Hughes ((12, 16), "callothersubr"), 529*e1fe3e4aSElliott Hughes ((12, 17), "pop"), 530*e1fe3e4aSElliott Hughes ((12, 33), "setcurrentpoint"), 531*e1fe3e4aSElliott Hughes] 532*e1fe3e4aSElliott Hughes 533*e1fe3e4aSElliott Hughes 534*e1fe3e4aSElliott Hughesclass T2WidthExtractor(SimpleT2Decompiler): 535*e1fe3e4aSElliott Hughes def __init__( 536*e1fe3e4aSElliott Hughes self, 537*e1fe3e4aSElliott Hughes localSubrs, 538*e1fe3e4aSElliott Hughes globalSubrs, 539*e1fe3e4aSElliott Hughes nominalWidthX, 540*e1fe3e4aSElliott Hughes defaultWidthX, 541*e1fe3e4aSElliott Hughes private=None, 542*e1fe3e4aSElliott Hughes blender=None, 543*e1fe3e4aSElliott Hughes ): 544*e1fe3e4aSElliott Hughes SimpleT2Decompiler.__init__(self, localSubrs, globalSubrs, private, blender) 545*e1fe3e4aSElliott Hughes self.nominalWidthX = nominalWidthX 546*e1fe3e4aSElliott Hughes self.defaultWidthX = defaultWidthX 547*e1fe3e4aSElliott Hughes 548*e1fe3e4aSElliott Hughes def reset(self): 549*e1fe3e4aSElliott Hughes SimpleT2Decompiler.reset(self) 550*e1fe3e4aSElliott Hughes self.gotWidth = 0 551*e1fe3e4aSElliott Hughes self.width = 0 552*e1fe3e4aSElliott Hughes 553*e1fe3e4aSElliott Hughes def popallWidth(self, evenOdd=0): 554*e1fe3e4aSElliott Hughes args = self.popall() 555*e1fe3e4aSElliott Hughes if not self.gotWidth: 556*e1fe3e4aSElliott Hughes if evenOdd ^ (len(args) % 2): 557*e1fe3e4aSElliott Hughes # For CFF2 charstrings, this should never happen 558*e1fe3e4aSElliott Hughes assert ( 559*e1fe3e4aSElliott Hughes self.defaultWidthX is not None 560*e1fe3e4aSElliott Hughes ), "CFF2 CharStrings must not have an initial width value" 561*e1fe3e4aSElliott Hughes self.width = self.nominalWidthX + args[0] 562*e1fe3e4aSElliott Hughes args = args[1:] 563*e1fe3e4aSElliott Hughes else: 564*e1fe3e4aSElliott Hughes self.width = self.defaultWidthX 565*e1fe3e4aSElliott Hughes self.gotWidth = 1 566*e1fe3e4aSElliott Hughes return args 567*e1fe3e4aSElliott Hughes 568*e1fe3e4aSElliott Hughes def countHints(self): 569*e1fe3e4aSElliott Hughes args = self.popallWidth() 570*e1fe3e4aSElliott Hughes self.hintCount = self.hintCount + len(args) // 2 571*e1fe3e4aSElliott Hughes 572*e1fe3e4aSElliott Hughes def op_rmoveto(self, index): 573*e1fe3e4aSElliott Hughes self.popallWidth() 574*e1fe3e4aSElliott Hughes 575*e1fe3e4aSElliott Hughes def op_hmoveto(self, index): 576*e1fe3e4aSElliott Hughes self.popallWidth(1) 577*e1fe3e4aSElliott Hughes 578*e1fe3e4aSElliott Hughes def op_vmoveto(self, index): 579*e1fe3e4aSElliott Hughes self.popallWidth(1) 580*e1fe3e4aSElliott Hughes 581*e1fe3e4aSElliott Hughes def op_endchar(self, index): 582*e1fe3e4aSElliott Hughes self.popallWidth() 583*e1fe3e4aSElliott Hughes 584*e1fe3e4aSElliott Hughes 585*e1fe3e4aSElliott Hughesclass T2OutlineExtractor(T2WidthExtractor): 586*e1fe3e4aSElliott Hughes def __init__( 587*e1fe3e4aSElliott Hughes self, 588*e1fe3e4aSElliott Hughes pen, 589*e1fe3e4aSElliott Hughes localSubrs, 590*e1fe3e4aSElliott Hughes globalSubrs, 591*e1fe3e4aSElliott Hughes nominalWidthX, 592*e1fe3e4aSElliott Hughes defaultWidthX, 593*e1fe3e4aSElliott Hughes private=None, 594*e1fe3e4aSElliott Hughes blender=None, 595*e1fe3e4aSElliott Hughes ): 596*e1fe3e4aSElliott Hughes T2WidthExtractor.__init__( 597*e1fe3e4aSElliott Hughes self, 598*e1fe3e4aSElliott Hughes localSubrs, 599*e1fe3e4aSElliott Hughes globalSubrs, 600*e1fe3e4aSElliott Hughes nominalWidthX, 601*e1fe3e4aSElliott Hughes defaultWidthX, 602*e1fe3e4aSElliott Hughes private, 603*e1fe3e4aSElliott Hughes blender, 604*e1fe3e4aSElliott Hughes ) 605*e1fe3e4aSElliott Hughes self.pen = pen 606*e1fe3e4aSElliott Hughes self.subrLevel = 0 607*e1fe3e4aSElliott Hughes 608*e1fe3e4aSElliott Hughes def reset(self): 609*e1fe3e4aSElliott Hughes T2WidthExtractor.reset(self) 610*e1fe3e4aSElliott Hughes self.currentPoint = (0, 0) 611*e1fe3e4aSElliott Hughes self.sawMoveTo = 0 612*e1fe3e4aSElliott Hughes self.subrLevel = 0 613*e1fe3e4aSElliott Hughes 614*e1fe3e4aSElliott Hughes def execute(self, charString): 615*e1fe3e4aSElliott Hughes self.subrLevel += 1 616*e1fe3e4aSElliott Hughes super().execute(charString) 617*e1fe3e4aSElliott Hughes self.subrLevel -= 1 618*e1fe3e4aSElliott Hughes if self.subrLevel == 0: 619*e1fe3e4aSElliott Hughes self.endPath() 620*e1fe3e4aSElliott Hughes 621*e1fe3e4aSElliott Hughes def _nextPoint(self, point): 622*e1fe3e4aSElliott Hughes x, y = self.currentPoint 623*e1fe3e4aSElliott Hughes point = x + point[0], y + point[1] 624*e1fe3e4aSElliott Hughes self.currentPoint = point 625*e1fe3e4aSElliott Hughes return point 626*e1fe3e4aSElliott Hughes 627*e1fe3e4aSElliott Hughes def rMoveTo(self, point): 628*e1fe3e4aSElliott Hughes self.pen.moveTo(self._nextPoint(point)) 629*e1fe3e4aSElliott Hughes self.sawMoveTo = 1 630*e1fe3e4aSElliott Hughes 631*e1fe3e4aSElliott Hughes def rLineTo(self, point): 632*e1fe3e4aSElliott Hughes if not self.sawMoveTo: 633*e1fe3e4aSElliott Hughes self.rMoveTo((0, 0)) 634*e1fe3e4aSElliott Hughes self.pen.lineTo(self._nextPoint(point)) 635*e1fe3e4aSElliott Hughes 636*e1fe3e4aSElliott Hughes def rCurveTo(self, pt1, pt2, pt3): 637*e1fe3e4aSElliott Hughes if not self.sawMoveTo: 638*e1fe3e4aSElliott Hughes self.rMoveTo((0, 0)) 639*e1fe3e4aSElliott Hughes nextPoint = self._nextPoint 640*e1fe3e4aSElliott Hughes self.pen.curveTo(nextPoint(pt1), nextPoint(pt2), nextPoint(pt3)) 641*e1fe3e4aSElliott Hughes 642*e1fe3e4aSElliott Hughes def closePath(self): 643*e1fe3e4aSElliott Hughes if self.sawMoveTo: 644*e1fe3e4aSElliott Hughes self.pen.closePath() 645*e1fe3e4aSElliott Hughes self.sawMoveTo = 0 646*e1fe3e4aSElliott Hughes 647*e1fe3e4aSElliott Hughes def endPath(self): 648*e1fe3e4aSElliott Hughes # In T2 there are no open paths, so always do a closePath when 649*e1fe3e4aSElliott Hughes # finishing a sub path. We avoid spurious calls to closePath() 650*e1fe3e4aSElliott Hughes # because its a real T1 op we're emulating in T2 whereas 651*e1fe3e4aSElliott Hughes # endPath() is just a means to that emulation 652*e1fe3e4aSElliott Hughes if self.sawMoveTo: 653*e1fe3e4aSElliott Hughes self.closePath() 654*e1fe3e4aSElliott Hughes 655*e1fe3e4aSElliott Hughes # 656*e1fe3e4aSElliott Hughes # hint operators 657*e1fe3e4aSElliott Hughes # 658*e1fe3e4aSElliott Hughes # def op_hstem(self, index): 659*e1fe3e4aSElliott Hughes # self.countHints() 660*e1fe3e4aSElliott Hughes # def op_vstem(self, index): 661*e1fe3e4aSElliott Hughes # self.countHints() 662*e1fe3e4aSElliott Hughes # def op_hstemhm(self, index): 663*e1fe3e4aSElliott Hughes # self.countHints() 664*e1fe3e4aSElliott Hughes # def op_vstemhm(self, index): 665*e1fe3e4aSElliott Hughes # self.countHints() 666*e1fe3e4aSElliott Hughes # def op_hintmask(self, index): 667*e1fe3e4aSElliott Hughes # self.countHints() 668*e1fe3e4aSElliott Hughes # def op_cntrmask(self, index): 669*e1fe3e4aSElliott Hughes # self.countHints() 670*e1fe3e4aSElliott Hughes 671*e1fe3e4aSElliott Hughes # 672*e1fe3e4aSElliott Hughes # path constructors, moveto 673*e1fe3e4aSElliott Hughes # 674*e1fe3e4aSElliott Hughes def op_rmoveto(self, index): 675*e1fe3e4aSElliott Hughes self.endPath() 676*e1fe3e4aSElliott Hughes self.rMoveTo(self.popallWidth()) 677*e1fe3e4aSElliott Hughes 678*e1fe3e4aSElliott Hughes def op_hmoveto(self, index): 679*e1fe3e4aSElliott Hughes self.endPath() 680*e1fe3e4aSElliott Hughes self.rMoveTo((self.popallWidth(1)[0], 0)) 681*e1fe3e4aSElliott Hughes 682*e1fe3e4aSElliott Hughes def op_vmoveto(self, index): 683*e1fe3e4aSElliott Hughes self.endPath() 684*e1fe3e4aSElliott Hughes self.rMoveTo((0, self.popallWidth(1)[0])) 685*e1fe3e4aSElliott Hughes 686*e1fe3e4aSElliott Hughes def op_endchar(self, index): 687*e1fe3e4aSElliott Hughes self.endPath() 688*e1fe3e4aSElliott Hughes args = self.popallWidth() 689*e1fe3e4aSElliott Hughes if args: 690*e1fe3e4aSElliott Hughes from fontTools.encodings.StandardEncoding import StandardEncoding 691*e1fe3e4aSElliott Hughes 692*e1fe3e4aSElliott Hughes # endchar can do seac accent bulding; The T2 spec says it's deprecated, 693*e1fe3e4aSElliott Hughes # but recent software that shall remain nameless does output it. 694*e1fe3e4aSElliott Hughes adx, ady, bchar, achar = args 695*e1fe3e4aSElliott Hughes baseGlyph = StandardEncoding[bchar] 696*e1fe3e4aSElliott Hughes self.pen.addComponent(baseGlyph, (1, 0, 0, 1, 0, 0)) 697*e1fe3e4aSElliott Hughes accentGlyph = StandardEncoding[achar] 698*e1fe3e4aSElliott Hughes self.pen.addComponent(accentGlyph, (1, 0, 0, 1, adx, ady)) 699*e1fe3e4aSElliott Hughes 700*e1fe3e4aSElliott Hughes # 701*e1fe3e4aSElliott Hughes # path constructors, lines 702*e1fe3e4aSElliott Hughes # 703*e1fe3e4aSElliott Hughes def op_rlineto(self, index): 704*e1fe3e4aSElliott Hughes args = self.popall() 705*e1fe3e4aSElliott Hughes for i in range(0, len(args), 2): 706*e1fe3e4aSElliott Hughes point = args[i : i + 2] 707*e1fe3e4aSElliott Hughes self.rLineTo(point) 708*e1fe3e4aSElliott Hughes 709*e1fe3e4aSElliott Hughes def op_hlineto(self, index): 710*e1fe3e4aSElliott Hughes self.alternatingLineto(1) 711*e1fe3e4aSElliott Hughes 712*e1fe3e4aSElliott Hughes def op_vlineto(self, index): 713*e1fe3e4aSElliott Hughes self.alternatingLineto(0) 714*e1fe3e4aSElliott Hughes 715*e1fe3e4aSElliott Hughes # 716*e1fe3e4aSElliott Hughes # path constructors, curves 717*e1fe3e4aSElliott Hughes # 718*e1fe3e4aSElliott Hughes def op_rrcurveto(self, index): 719*e1fe3e4aSElliott Hughes """{dxa dya dxb dyb dxc dyc}+ rrcurveto""" 720*e1fe3e4aSElliott Hughes args = self.popall() 721*e1fe3e4aSElliott Hughes for i in range(0, len(args), 6): 722*e1fe3e4aSElliott Hughes ( 723*e1fe3e4aSElliott Hughes dxa, 724*e1fe3e4aSElliott Hughes dya, 725*e1fe3e4aSElliott Hughes dxb, 726*e1fe3e4aSElliott Hughes dyb, 727*e1fe3e4aSElliott Hughes dxc, 728*e1fe3e4aSElliott Hughes dyc, 729*e1fe3e4aSElliott Hughes ) = args[i : i + 6] 730*e1fe3e4aSElliott Hughes self.rCurveTo((dxa, dya), (dxb, dyb), (dxc, dyc)) 731*e1fe3e4aSElliott Hughes 732*e1fe3e4aSElliott Hughes def op_rcurveline(self, index): 733*e1fe3e4aSElliott Hughes """{dxa dya dxb dyb dxc dyc}+ dxd dyd rcurveline""" 734*e1fe3e4aSElliott Hughes args = self.popall() 735*e1fe3e4aSElliott Hughes for i in range(0, len(args) - 2, 6): 736*e1fe3e4aSElliott Hughes dxb, dyb, dxc, dyc, dxd, dyd = args[i : i + 6] 737*e1fe3e4aSElliott Hughes self.rCurveTo((dxb, dyb), (dxc, dyc), (dxd, dyd)) 738*e1fe3e4aSElliott Hughes self.rLineTo(args[-2:]) 739*e1fe3e4aSElliott Hughes 740*e1fe3e4aSElliott Hughes def op_rlinecurve(self, index): 741*e1fe3e4aSElliott Hughes """{dxa dya}+ dxb dyb dxc dyc dxd dyd rlinecurve""" 742*e1fe3e4aSElliott Hughes args = self.popall() 743*e1fe3e4aSElliott Hughes lineArgs = args[:-6] 744*e1fe3e4aSElliott Hughes for i in range(0, len(lineArgs), 2): 745*e1fe3e4aSElliott Hughes self.rLineTo(lineArgs[i : i + 2]) 746*e1fe3e4aSElliott Hughes dxb, dyb, dxc, dyc, dxd, dyd = args[-6:] 747*e1fe3e4aSElliott Hughes self.rCurveTo((dxb, dyb), (dxc, dyc), (dxd, dyd)) 748*e1fe3e4aSElliott Hughes 749*e1fe3e4aSElliott Hughes def op_vvcurveto(self, index): 750*e1fe3e4aSElliott Hughes "dx1? {dya dxb dyb dyc}+ vvcurveto" 751*e1fe3e4aSElliott Hughes args = self.popall() 752*e1fe3e4aSElliott Hughes if len(args) % 2: 753*e1fe3e4aSElliott Hughes dx1 = args[0] 754*e1fe3e4aSElliott Hughes args = args[1:] 755*e1fe3e4aSElliott Hughes else: 756*e1fe3e4aSElliott Hughes dx1 = 0 757*e1fe3e4aSElliott Hughes for i in range(0, len(args), 4): 758*e1fe3e4aSElliott Hughes dya, dxb, dyb, dyc = args[i : i + 4] 759*e1fe3e4aSElliott Hughes self.rCurveTo((dx1, dya), (dxb, dyb), (0, dyc)) 760*e1fe3e4aSElliott Hughes dx1 = 0 761*e1fe3e4aSElliott Hughes 762*e1fe3e4aSElliott Hughes def op_hhcurveto(self, index): 763*e1fe3e4aSElliott Hughes """dy1? {dxa dxb dyb dxc}+ hhcurveto""" 764*e1fe3e4aSElliott Hughes args = self.popall() 765*e1fe3e4aSElliott Hughes if len(args) % 2: 766*e1fe3e4aSElliott Hughes dy1 = args[0] 767*e1fe3e4aSElliott Hughes args = args[1:] 768*e1fe3e4aSElliott Hughes else: 769*e1fe3e4aSElliott Hughes dy1 = 0 770*e1fe3e4aSElliott Hughes for i in range(0, len(args), 4): 771*e1fe3e4aSElliott Hughes dxa, dxb, dyb, dxc = args[i : i + 4] 772*e1fe3e4aSElliott Hughes self.rCurveTo((dxa, dy1), (dxb, dyb), (dxc, 0)) 773*e1fe3e4aSElliott Hughes dy1 = 0 774*e1fe3e4aSElliott Hughes 775*e1fe3e4aSElliott Hughes def op_vhcurveto(self, index): 776*e1fe3e4aSElliott Hughes """dy1 dx2 dy2 dx3 {dxa dxb dyb dyc dyd dxe dye dxf}* dyf? vhcurveto (30) 777*e1fe3e4aSElliott Hughes {dya dxb dyb dxc dxd dxe dye dyf}+ dxf? vhcurveto 778*e1fe3e4aSElliott Hughes """ 779*e1fe3e4aSElliott Hughes args = self.popall() 780*e1fe3e4aSElliott Hughes while args: 781*e1fe3e4aSElliott Hughes args = self.vcurveto(args) 782*e1fe3e4aSElliott Hughes if args: 783*e1fe3e4aSElliott Hughes args = self.hcurveto(args) 784*e1fe3e4aSElliott Hughes 785*e1fe3e4aSElliott Hughes def op_hvcurveto(self, index): 786*e1fe3e4aSElliott Hughes """dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* dxf? 787*e1fe3e4aSElliott Hughes {dxa dxb dyb dyc dyd dxe dye dxf}+ dyf? 788*e1fe3e4aSElliott Hughes """ 789*e1fe3e4aSElliott Hughes args = self.popall() 790*e1fe3e4aSElliott Hughes while args: 791*e1fe3e4aSElliott Hughes args = self.hcurveto(args) 792*e1fe3e4aSElliott Hughes if args: 793*e1fe3e4aSElliott Hughes args = self.vcurveto(args) 794*e1fe3e4aSElliott Hughes 795*e1fe3e4aSElliott Hughes # 796*e1fe3e4aSElliott Hughes # path constructors, flex 797*e1fe3e4aSElliott Hughes # 798*e1fe3e4aSElliott Hughes def op_hflex(self, index): 799*e1fe3e4aSElliott Hughes dx1, dx2, dy2, dx3, dx4, dx5, dx6 = self.popall() 800*e1fe3e4aSElliott Hughes dy1 = dy3 = dy4 = dy6 = 0 801*e1fe3e4aSElliott Hughes dy5 = -dy2 802*e1fe3e4aSElliott Hughes self.rCurveTo((dx1, dy1), (dx2, dy2), (dx3, dy3)) 803*e1fe3e4aSElliott Hughes self.rCurveTo((dx4, dy4), (dx5, dy5), (dx6, dy6)) 804*e1fe3e4aSElliott Hughes 805*e1fe3e4aSElliott Hughes def op_flex(self, index): 806*e1fe3e4aSElliott Hughes dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4, dx5, dy5, dx6, dy6, fd = self.popall() 807*e1fe3e4aSElliott Hughes self.rCurveTo((dx1, dy1), (dx2, dy2), (dx3, dy3)) 808*e1fe3e4aSElliott Hughes self.rCurveTo((dx4, dy4), (dx5, dy5), (dx6, dy6)) 809*e1fe3e4aSElliott Hughes 810*e1fe3e4aSElliott Hughes def op_hflex1(self, index): 811*e1fe3e4aSElliott Hughes dx1, dy1, dx2, dy2, dx3, dx4, dx5, dy5, dx6 = self.popall() 812*e1fe3e4aSElliott Hughes dy3 = dy4 = 0 813*e1fe3e4aSElliott Hughes dy6 = -(dy1 + dy2 + dy3 + dy4 + dy5) 814*e1fe3e4aSElliott Hughes 815*e1fe3e4aSElliott Hughes self.rCurveTo((dx1, dy1), (dx2, dy2), (dx3, dy3)) 816*e1fe3e4aSElliott Hughes self.rCurveTo((dx4, dy4), (dx5, dy5), (dx6, dy6)) 817*e1fe3e4aSElliott Hughes 818*e1fe3e4aSElliott Hughes def op_flex1(self, index): 819*e1fe3e4aSElliott Hughes dx1, dy1, dx2, dy2, dx3, dy3, dx4, dy4, dx5, dy5, d6 = self.popall() 820*e1fe3e4aSElliott Hughes dx = dx1 + dx2 + dx3 + dx4 + dx5 821*e1fe3e4aSElliott Hughes dy = dy1 + dy2 + dy3 + dy4 + dy5 822*e1fe3e4aSElliott Hughes if abs(dx) > abs(dy): 823*e1fe3e4aSElliott Hughes dx6 = d6 824*e1fe3e4aSElliott Hughes dy6 = -dy 825*e1fe3e4aSElliott Hughes else: 826*e1fe3e4aSElliott Hughes dx6 = -dx 827*e1fe3e4aSElliott Hughes dy6 = d6 828*e1fe3e4aSElliott Hughes self.rCurveTo((dx1, dy1), (dx2, dy2), (dx3, dy3)) 829*e1fe3e4aSElliott Hughes self.rCurveTo((dx4, dy4), (dx5, dy5), (dx6, dy6)) 830*e1fe3e4aSElliott Hughes 831*e1fe3e4aSElliott Hughes # misc 832*e1fe3e4aSElliott Hughes def op_and(self, index): 833*e1fe3e4aSElliott Hughes raise NotImplementedError 834*e1fe3e4aSElliott Hughes 835*e1fe3e4aSElliott Hughes def op_or(self, index): 836*e1fe3e4aSElliott Hughes raise NotImplementedError 837*e1fe3e4aSElliott Hughes 838*e1fe3e4aSElliott Hughes def op_not(self, index): 839*e1fe3e4aSElliott Hughes raise NotImplementedError 840*e1fe3e4aSElliott Hughes 841*e1fe3e4aSElliott Hughes def op_store(self, index): 842*e1fe3e4aSElliott Hughes raise NotImplementedError 843*e1fe3e4aSElliott Hughes 844*e1fe3e4aSElliott Hughes def op_abs(self, index): 845*e1fe3e4aSElliott Hughes raise NotImplementedError 846*e1fe3e4aSElliott Hughes 847*e1fe3e4aSElliott Hughes def op_add(self, index): 848*e1fe3e4aSElliott Hughes raise NotImplementedError 849*e1fe3e4aSElliott Hughes 850*e1fe3e4aSElliott Hughes def op_sub(self, index): 851*e1fe3e4aSElliott Hughes raise NotImplementedError 852*e1fe3e4aSElliott Hughes 853*e1fe3e4aSElliott Hughes def op_div(self, index): 854*e1fe3e4aSElliott Hughes num2 = self.pop() 855*e1fe3e4aSElliott Hughes num1 = self.pop() 856*e1fe3e4aSElliott Hughes d1 = num1 // num2 857*e1fe3e4aSElliott Hughes d2 = num1 / num2 858*e1fe3e4aSElliott Hughes if d1 == d2: 859*e1fe3e4aSElliott Hughes self.push(d1) 860*e1fe3e4aSElliott Hughes else: 861*e1fe3e4aSElliott Hughes self.push(d2) 862*e1fe3e4aSElliott Hughes 863*e1fe3e4aSElliott Hughes def op_load(self, index): 864*e1fe3e4aSElliott Hughes raise NotImplementedError 865*e1fe3e4aSElliott Hughes 866*e1fe3e4aSElliott Hughes def op_neg(self, index): 867*e1fe3e4aSElliott Hughes raise NotImplementedError 868*e1fe3e4aSElliott Hughes 869*e1fe3e4aSElliott Hughes def op_eq(self, index): 870*e1fe3e4aSElliott Hughes raise NotImplementedError 871*e1fe3e4aSElliott Hughes 872*e1fe3e4aSElliott Hughes def op_drop(self, index): 873*e1fe3e4aSElliott Hughes raise NotImplementedError 874*e1fe3e4aSElliott Hughes 875*e1fe3e4aSElliott Hughes def op_put(self, index): 876*e1fe3e4aSElliott Hughes raise NotImplementedError 877*e1fe3e4aSElliott Hughes 878*e1fe3e4aSElliott Hughes def op_get(self, index): 879*e1fe3e4aSElliott Hughes raise NotImplementedError 880*e1fe3e4aSElliott Hughes 881*e1fe3e4aSElliott Hughes def op_ifelse(self, index): 882*e1fe3e4aSElliott Hughes raise NotImplementedError 883*e1fe3e4aSElliott Hughes 884*e1fe3e4aSElliott Hughes def op_random(self, index): 885*e1fe3e4aSElliott Hughes raise NotImplementedError 886*e1fe3e4aSElliott Hughes 887*e1fe3e4aSElliott Hughes def op_mul(self, index): 888*e1fe3e4aSElliott Hughes raise NotImplementedError 889*e1fe3e4aSElliott Hughes 890*e1fe3e4aSElliott Hughes def op_sqrt(self, index): 891*e1fe3e4aSElliott Hughes raise NotImplementedError 892*e1fe3e4aSElliott Hughes 893*e1fe3e4aSElliott Hughes def op_dup(self, index): 894*e1fe3e4aSElliott Hughes raise NotImplementedError 895*e1fe3e4aSElliott Hughes 896*e1fe3e4aSElliott Hughes def op_exch(self, index): 897*e1fe3e4aSElliott Hughes raise NotImplementedError 898*e1fe3e4aSElliott Hughes 899*e1fe3e4aSElliott Hughes def op_index(self, index): 900*e1fe3e4aSElliott Hughes raise NotImplementedError 901*e1fe3e4aSElliott Hughes 902*e1fe3e4aSElliott Hughes def op_roll(self, index): 903*e1fe3e4aSElliott Hughes raise NotImplementedError 904*e1fe3e4aSElliott Hughes 905*e1fe3e4aSElliott Hughes # 906*e1fe3e4aSElliott Hughes # miscellaneous helpers 907*e1fe3e4aSElliott Hughes # 908*e1fe3e4aSElliott Hughes def alternatingLineto(self, isHorizontal): 909*e1fe3e4aSElliott Hughes args = self.popall() 910*e1fe3e4aSElliott Hughes for arg in args: 911*e1fe3e4aSElliott Hughes if isHorizontal: 912*e1fe3e4aSElliott Hughes point = (arg, 0) 913*e1fe3e4aSElliott Hughes else: 914*e1fe3e4aSElliott Hughes point = (0, arg) 915*e1fe3e4aSElliott Hughes self.rLineTo(point) 916*e1fe3e4aSElliott Hughes isHorizontal = not isHorizontal 917*e1fe3e4aSElliott Hughes 918*e1fe3e4aSElliott Hughes def vcurveto(self, args): 919*e1fe3e4aSElliott Hughes dya, dxb, dyb, dxc = args[:4] 920*e1fe3e4aSElliott Hughes args = args[4:] 921*e1fe3e4aSElliott Hughes if len(args) == 1: 922*e1fe3e4aSElliott Hughes dyc = args[0] 923*e1fe3e4aSElliott Hughes args = [] 924*e1fe3e4aSElliott Hughes else: 925*e1fe3e4aSElliott Hughes dyc = 0 926*e1fe3e4aSElliott Hughes self.rCurveTo((0, dya), (dxb, dyb), (dxc, dyc)) 927*e1fe3e4aSElliott Hughes return args 928*e1fe3e4aSElliott Hughes 929*e1fe3e4aSElliott Hughes def hcurveto(self, args): 930*e1fe3e4aSElliott Hughes dxa, dxb, dyb, dyc = args[:4] 931*e1fe3e4aSElliott Hughes args = args[4:] 932*e1fe3e4aSElliott Hughes if len(args) == 1: 933*e1fe3e4aSElliott Hughes dxc = args[0] 934*e1fe3e4aSElliott Hughes args = [] 935*e1fe3e4aSElliott Hughes else: 936*e1fe3e4aSElliott Hughes dxc = 0 937*e1fe3e4aSElliott Hughes self.rCurveTo((dxa, 0), (dxb, dyb), (dxc, dyc)) 938*e1fe3e4aSElliott Hughes return args 939*e1fe3e4aSElliott Hughes 940*e1fe3e4aSElliott Hughes 941*e1fe3e4aSElliott Hughesclass T1OutlineExtractor(T2OutlineExtractor): 942*e1fe3e4aSElliott Hughes def __init__(self, pen, subrs): 943*e1fe3e4aSElliott Hughes self.pen = pen 944*e1fe3e4aSElliott Hughes self.subrs = subrs 945*e1fe3e4aSElliott Hughes self.reset() 946*e1fe3e4aSElliott Hughes 947*e1fe3e4aSElliott Hughes def reset(self): 948*e1fe3e4aSElliott Hughes self.flexing = 0 949*e1fe3e4aSElliott Hughes self.width = 0 950*e1fe3e4aSElliott Hughes self.sbx = 0 951*e1fe3e4aSElliott Hughes T2OutlineExtractor.reset(self) 952*e1fe3e4aSElliott Hughes 953*e1fe3e4aSElliott Hughes def endPath(self): 954*e1fe3e4aSElliott Hughes if self.sawMoveTo: 955*e1fe3e4aSElliott Hughes self.pen.endPath() 956*e1fe3e4aSElliott Hughes self.sawMoveTo = 0 957*e1fe3e4aSElliott Hughes 958*e1fe3e4aSElliott Hughes def popallWidth(self, evenOdd=0): 959*e1fe3e4aSElliott Hughes return self.popall() 960*e1fe3e4aSElliott Hughes 961*e1fe3e4aSElliott Hughes def exch(self): 962*e1fe3e4aSElliott Hughes stack = self.operandStack 963*e1fe3e4aSElliott Hughes stack[-1], stack[-2] = stack[-2], stack[-1] 964*e1fe3e4aSElliott Hughes 965*e1fe3e4aSElliott Hughes # 966*e1fe3e4aSElliott Hughes # path constructors 967*e1fe3e4aSElliott Hughes # 968*e1fe3e4aSElliott Hughes def op_rmoveto(self, index): 969*e1fe3e4aSElliott Hughes if self.flexing: 970*e1fe3e4aSElliott Hughes return 971*e1fe3e4aSElliott Hughes self.endPath() 972*e1fe3e4aSElliott Hughes self.rMoveTo(self.popall()) 973*e1fe3e4aSElliott Hughes 974*e1fe3e4aSElliott Hughes def op_hmoveto(self, index): 975*e1fe3e4aSElliott Hughes if self.flexing: 976*e1fe3e4aSElliott Hughes # We must add a parameter to the stack if we are flexing 977*e1fe3e4aSElliott Hughes self.push(0) 978*e1fe3e4aSElliott Hughes return 979*e1fe3e4aSElliott Hughes self.endPath() 980*e1fe3e4aSElliott Hughes self.rMoveTo((self.popall()[0], 0)) 981*e1fe3e4aSElliott Hughes 982*e1fe3e4aSElliott Hughes def op_vmoveto(self, index): 983*e1fe3e4aSElliott Hughes if self.flexing: 984*e1fe3e4aSElliott Hughes # We must add a parameter to the stack if we are flexing 985*e1fe3e4aSElliott Hughes self.push(0) 986*e1fe3e4aSElliott Hughes self.exch() 987*e1fe3e4aSElliott Hughes return 988*e1fe3e4aSElliott Hughes self.endPath() 989*e1fe3e4aSElliott Hughes self.rMoveTo((0, self.popall()[0])) 990*e1fe3e4aSElliott Hughes 991*e1fe3e4aSElliott Hughes def op_closepath(self, index): 992*e1fe3e4aSElliott Hughes self.closePath() 993*e1fe3e4aSElliott Hughes 994*e1fe3e4aSElliott Hughes def op_setcurrentpoint(self, index): 995*e1fe3e4aSElliott Hughes args = self.popall() 996*e1fe3e4aSElliott Hughes x, y = args 997*e1fe3e4aSElliott Hughes self.currentPoint = x, y 998*e1fe3e4aSElliott Hughes 999*e1fe3e4aSElliott Hughes def op_endchar(self, index): 1000*e1fe3e4aSElliott Hughes self.endPath() 1001*e1fe3e4aSElliott Hughes 1002*e1fe3e4aSElliott Hughes def op_hsbw(self, index): 1003*e1fe3e4aSElliott Hughes sbx, wx = self.popall() 1004*e1fe3e4aSElliott Hughes self.width = wx 1005*e1fe3e4aSElliott Hughes self.sbx = sbx 1006*e1fe3e4aSElliott Hughes self.currentPoint = sbx, self.currentPoint[1] 1007*e1fe3e4aSElliott Hughes 1008*e1fe3e4aSElliott Hughes def op_sbw(self, index): 1009*e1fe3e4aSElliott Hughes self.popall() # XXX 1010*e1fe3e4aSElliott Hughes 1011*e1fe3e4aSElliott Hughes # 1012*e1fe3e4aSElliott Hughes def op_callsubr(self, index): 1013*e1fe3e4aSElliott Hughes subrIndex = self.pop() 1014*e1fe3e4aSElliott Hughes subr = self.subrs[subrIndex] 1015*e1fe3e4aSElliott Hughes self.execute(subr) 1016*e1fe3e4aSElliott Hughes 1017*e1fe3e4aSElliott Hughes def op_callothersubr(self, index): 1018*e1fe3e4aSElliott Hughes subrIndex = self.pop() 1019*e1fe3e4aSElliott Hughes nArgs = self.pop() 1020*e1fe3e4aSElliott Hughes # print nArgs, subrIndex, "callothersubr" 1021*e1fe3e4aSElliott Hughes if subrIndex == 0 and nArgs == 3: 1022*e1fe3e4aSElliott Hughes self.doFlex() 1023*e1fe3e4aSElliott Hughes self.flexing = 0 1024*e1fe3e4aSElliott Hughes elif subrIndex == 1 and nArgs == 0: 1025*e1fe3e4aSElliott Hughes self.flexing = 1 1026*e1fe3e4aSElliott Hughes # ignore... 1027*e1fe3e4aSElliott Hughes 1028*e1fe3e4aSElliott Hughes def op_pop(self, index): 1029*e1fe3e4aSElliott Hughes pass # ignore... 1030*e1fe3e4aSElliott Hughes 1031*e1fe3e4aSElliott Hughes def doFlex(self): 1032*e1fe3e4aSElliott Hughes finaly = self.pop() 1033*e1fe3e4aSElliott Hughes finalx = self.pop() 1034*e1fe3e4aSElliott Hughes self.pop() # flex height is unused 1035*e1fe3e4aSElliott Hughes 1036*e1fe3e4aSElliott Hughes p3y = self.pop() 1037*e1fe3e4aSElliott Hughes p3x = self.pop() 1038*e1fe3e4aSElliott Hughes bcp4y = self.pop() 1039*e1fe3e4aSElliott Hughes bcp4x = self.pop() 1040*e1fe3e4aSElliott Hughes bcp3y = self.pop() 1041*e1fe3e4aSElliott Hughes bcp3x = self.pop() 1042*e1fe3e4aSElliott Hughes p2y = self.pop() 1043*e1fe3e4aSElliott Hughes p2x = self.pop() 1044*e1fe3e4aSElliott Hughes bcp2y = self.pop() 1045*e1fe3e4aSElliott Hughes bcp2x = self.pop() 1046*e1fe3e4aSElliott Hughes bcp1y = self.pop() 1047*e1fe3e4aSElliott Hughes bcp1x = self.pop() 1048*e1fe3e4aSElliott Hughes rpy = self.pop() 1049*e1fe3e4aSElliott Hughes rpx = self.pop() 1050*e1fe3e4aSElliott Hughes 1051*e1fe3e4aSElliott Hughes # call rrcurveto 1052*e1fe3e4aSElliott Hughes self.push(bcp1x + rpx) 1053*e1fe3e4aSElliott Hughes self.push(bcp1y + rpy) 1054*e1fe3e4aSElliott Hughes self.push(bcp2x) 1055*e1fe3e4aSElliott Hughes self.push(bcp2y) 1056*e1fe3e4aSElliott Hughes self.push(p2x) 1057*e1fe3e4aSElliott Hughes self.push(p2y) 1058*e1fe3e4aSElliott Hughes self.op_rrcurveto(None) 1059*e1fe3e4aSElliott Hughes 1060*e1fe3e4aSElliott Hughes # call rrcurveto 1061*e1fe3e4aSElliott Hughes self.push(bcp3x) 1062*e1fe3e4aSElliott Hughes self.push(bcp3y) 1063*e1fe3e4aSElliott Hughes self.push(bcp4x) 1064*e1fe3e4aSElliott Hughes self.push(bcp4y) 1065*e1fe3e4aSElliott Hughes self.push(p3x) 1066*e1fe3e4aSElliott Hughes self.push(p3y) 1067*e1fe3e4aSElliott Hughes self.op_rrcurveto(None) 1068*e1fe3e4aSElliott Hughes 1069*e1fe3e4aSElliott Hughes # Push back final coords so subr 0 can find them 1070*e1fe3e4aSElliott Hughes self.push(finalx) 1071*e1fe3e4aSElliott Hughes self.push(finaly) 1072*e1fe3e4aSElliott Hughes 1073*e1fe3e4aSElliott Hughes def op_dotsection(self, index): 1074*e1fe3e4aSElliott Hughes self.popall() # XXX 1075*e1fe3e4aSElliott Hughes 1076*e1fe3e4aSElliott Hughes def op_hstem3(self, index): 1077*e1fe3e4aSElliott Hughes self.popall() # XXX 1078*e1fe3e4aSElliott Hughes 1079*e1fe3e4aSElliott Hughes def op_seac(self, index): 1080*e1fe3e4aSElliott Hughes "asb adx ady bchar achar seac" 1081*e1fe3e4aSElliott Hughes from fontTools.encodings.StandardEncoding import StandardEncoding 1082*e1fe3e4aSElliott Hughes 1083*e1fe3e4aSElliott Hughes asb, adx, ady, bchar, achar = self.popall() 1084*e1fe3e4aSElliott Hughes baseGlyph = StandardEncoding[bchar] 1085*e1fe3e4aSElliott Hughes self.pen.addComponent(baseGlyph, (1, 0, 0, 1, 0, 0)) 1086*e1fe3e4aSElliott Hughes accentGlyph = StandardEncoding[achar] 1087*e1fe3e4aSElliott Hughes adx = adx + self.sbx - asb # seac weirdness 1088*e1fe3e4aSElliott Hughes self.pen.addComponent(accentGlyph, (1, 0, 0, 1, adx, ady)) 1089*e1fe3e4aSElliott Hughes 1090*e1fe3e4aSElliott Hughes def op_vstem3(self, index): 1091*e1fe3e4aSElliott Hughes self.popall() # XXX 1092*e1fe3e4aSElliott Hughes 1093*e1fe3e4aSElliott Hughes 1094*e1fe3e4aSElliott Hughesclass T2CharString(object): 1095*e1fe3e4aSElliott Hughes operandEncoding = t2OperandEncoding 1096*e1fe3e4aSElliott Hughes operators, opcodes = buildOperatorDict(t2Operators) 1097*e1fe3e4aSElliott Hughes decompilerClass = SimpleT2Decompiler 1098*e1fe3e4aSElliott Hughes outlineExtractor = T2OutlineExtractor 1099*e1fe3e4aSElliott Hughes 1100*e1fe3e4aSElliott Hughes def __init__(self, bytecode=None, program=None, private=None, globalSubrs=None): 1101*e1fe3e4aSElliott Hughes if program is None: 1102*e1fe3e4aSElliott Hughes program = [] 1103*e1fe3e4aSElliott Hughes self.bytecode = bytecode 1104*e1fe3e4aSElliott Hughes self.program = program 1105*e1fe3e4aSElliott Hughes self.private = private 1106*e1fe3e4aSElliott Hughes self.globalSubrs = globalSubrs if globalSubrs is not None else [] 1107*e1fe3e4aSElliott Hughes self._cur_vsindex = None 1108*e1fe3e4aSElliott Hughes 1109*e1fe3e4aSElliott Hughes def getNumRegions(self, vsindex=None): 1110*e1fe3e4aSElliott Hughes pd = self.private 1111*e1fe3e4aSElliott Hughes assert pd is not None 1112*e1fe3e4aSElliott Hughes if vsindex is not None: 1113*e1fe3e4aSElliott Hughes self._cur_vsindex = vsindex 1114*e1fe3e4aSElliott Hughes elif self._cur_vsindex is None: 1115*e1fe3e4aSElliott Hughes self._cur_vsindex = pd.vsindex if hasattr(pd, "vsindex") else 0 1116*e1fe3e4aSElliott Hughes return pd.getNumRegions(self._cur_vsindex) 1117*e1fe3e4aSElliott Hughes 1118*e1fe3e4aSElliott Hughes def __repr__(self): 1119*e1fe3e4aSElliott Hughes if self.bytecode is None: 1120*e1fe3e4aSElliott Hughes return "<%s (source) at %x>" % (self.__class__.__name__, id(self)) 1121*e1fe3e4aSElliott Hughes else: 1122*e1fe3e4aSElliott Hughes return "<%s (bytecode) at %x>" % (self.__class__.__name__, id(self)) 1123*e1fe3e4aSElliott Hughes 1124*e1fe3e4aSElliott Hughes def getIntEncoder(self): 1125*e1fe3e4aSElliott Hughes return encodeIntT2 1126*e1fe3e4aSElliott Hughes 1127*e1fe3e4aSElliott Hughes def getFixedEncoder(self): 1128*e1fe3e4aSElliott Hughes return encodeFixed 1129*e1fe3e4aSElliott Hughes 1130*e1fe3e4aSElliott Hughes def decompile(self): 1131*e1fe3e4aSElliott Hughes if not self.needsDecompilation(): 1132*e1fe3e4aSElliott Hughes return 1133*e1fe3e4aSElliott Hughes subrs = getattr(self.private, "Subrs", []) 1134*e1fe3e4aSElliott Hughes decompiler = self.decompilerClass(subrs, self.globalSubrs, self.private) 1135*e1fe3e4aSElliott Hughes decompiler.execute(self) 1136*e1fe3e4aSElliott Hughes 1137*e1fe3e4aSElliott Hughes def draw(self, pen, blender=None): 1138*e1fe3e4aSElliott Hughes subrs = getattr(self.private, "Subrs", []) 1139*e1fe3e4aSElliott Hughes extractor = self.outlineExtractor( 1140*e1fe3e4aSElliott Hughes pen, 1141*e1fe3e4aSElliott Hughes subrs, 1142*e1fe3e4aSElliott Hughes self.globalSubrs, 1143*e1fe3e4aSElliott Hughes self.private.nominalWidthX, 1144*e1fe3e4aSElliott Hughes self.private.defaultWidthX, 1145*e1fe3e4aSElliott Hughes self.private, 1146*e1fe3e4aSElliott Hughes blender, 1147*e1fe3e4aSElliott Hughes ) 1148*e1fe3e4aSElliott Hughes extractor.execute(self) 1149*e1fe3e4aSElliott Hughes self.width = extractor.width 1150*e1fe3e4aSElliott Hughes 1151*e1fe3e4aSElliott Hughes def calcBounds(self, glyphSet): 1152*e1fe3e4aSElliott Hughes boundsPen = BoundsPen(glyphSet) 1153*e1fe3e4aSElliott Hughes self.draw(boundsPen) 1154*e1fe3e4aSElliott Hughes return boundsPen.bounds 1155*e1fe3e4aSElliott Hughes 1156*e1fe3e4aSElliott Hughes def compile(self, isCFF2=False): 1157*e1fe3e4aSElliott Hughes if self.bytecode is not None: 1158*e1fe3e4aSElliott Hughes return 1159*e1fe3e4aSElliott Hughes opcodes = self.opcodes 1160*e1fe3e4aSElliott Hughes program = self.program 1161*e1fe3e4aSElliott Hughes 1162*e1fe3e4aSElliott Hughes if isCFF2: 1163*e1fe3e4aSElliott Hughes # If present, remove return and endchar operators. 1164*e1fe3e4aSElliott Hughes if program and program[-1] in ("return", "endchar"): 1165*e1fe3e4aSElliott Hughes program = program[:-1] 1166*e1fe3e4aSElliott Hughes elif program and not isinstance(program[-1], str): 1167*e1fe3e4aSElliott Hughes raise CharStringCompileError( 1168*e1fe3e4aSElliott Hughes "T2CharString or Subr has items on the stack after last operator." 1169*e1fe3e4aSElliott Hughes ) 1170*e1fe3e4aSElliott Hughes 1171*e1fe3e4aSElliott Hughes bytecode = [] 1172*e1fe3e4aSElliott Hughes encodeInt = self.getIntEncoder() 1173*e1fe3e4aSElliott Hughes encodeFixed = self.getFixedEncoder() 1174*e1fe3e4aSElliott Hughes i = 0 1175*e1fe3e4aSElliott Hughes end = len(program) 1176*e1fe3e4aSElliott Hughes while i < end: 1177*e1fe3e4aSElliott Hughes token = program[i] 1178*e1fe3e4aSElliott Hughes i = i + 1 1179*e1fe3e4aSElliott Hughes if isinstance(token, str): 1180*e1fe3e4aSElliott Hughes try: 1181*e1fe3e4aSElliott Hughes bytecode.extend(bytechr(b) for b in opcodes[token]) 1182*e1fe3e4aSElliott Hughes except KeyError: 1183*e1fe3e4aSElliott Hughes raise CharStringCompileError("illegal operator: %s" % token) 1184*e1fe3e4aSElliott Hughes if token in ("hintmask", "cntrmask"): 1185*e1fe3e4aSElliott Hughes bytecode.append(program[i]) # hint mask 1186*e1fe3e4aSElliott Hughes i = i + 1 1187*e1fe3e4aSElliott Hughes elif isinstance(token, int): 1188*e1fe3e4aSElliott Hughes bytecode.append(encodeInt(token)) 1189*e1fe3e4aSElliott Hughes elif isinstance(token, float): 1190*e1fe3e4aSElliott Hughes bytecode.append(encodeFixed(token)) 1191*e1fe3e4aSElliott Hughes else: 1192*e1fe3e4aSElliott Hughes assert 0, "unsupported type: %s" % type(token) 1193*e1fe3e4aSElliott Hughes try: 1194*e1fe3e4aSElliott Hughes bytecode = bytesjoin(bytecode) 1195*e1fe3e4aSElliott Hughes except TypeError: 1196*e1fe3e4aSElliott Hughes log.error(bytecode) 1197*e1fe3e4aSElliott Hughes raise 1198*e1fe3e4aSElliott Hughes self.setBytecode(bytecode) 1199*e1fe3e4aSElliott Hughes 1200*e1fe3e4aSElliott Hughes def needsDecompilation(self): 1201*e1fe3e4aSElliott Hughes return self.bytecode is not None 1202*e1fe3e4aSElliott Hughes 1203*e1fe3e4aSElliott Hughes def setProgram(self, program): 1204*e1fe3e4aSElliott Hughes self.program = program 1205*e1fe3e4aSElliott Hughes self.bytecode = None 1206*e1fe3e4aSElliott Hughes 1207*e1fe3e4aSElliott Hughes def setBytecode(self, bytecode): 1208*e1fe3e4aSElliott Hughes self.bytecode = bytecode 1209*e1fe3e4aSElliott Hughes self.program = None 1210*e1fe3e4aSElliott Hughes 1211*e1fe3e4aSElliott Hughes def getToken(self, index, len=len, byteord=byteord, isinstance=isinstance): 1212*e1fe3e4aSElliott Hughes if self.bytecode is not None: 1213*e1fe3e4aSElliott Hughes if index >= len(self.bytecode): 1214*e1fe3e4aSElliott Hughes return None, 0, 0 1215*e1fe3e4aSElliott Hughes b0 = byteord(self.bytecode[index]) 1216*e1fe3e4aSElliott Hughes index = index + 1 1217*e1fe3e4aSElliott Hughes handler = self.operandEncoding[b0] 1218*e1fe3e4aSElliott Hughes token, index = handler(self, b0, self.bytecode, index) 1219*e1fe3e4aSElliott Hughes else: 1220*e1fe3e4aSElliott Hughes if index >= len(self.program): 1221*e1fe3e4aSElliott Hughes return None, 0, 0 1222*e1fe3e4aSElliott Hughes token = self.program[index] 1223*e1fe3e4aSElliott Hughes index = index + 1 1224*e1fe3e4aSElliott Hughes isOperator = isinstance(token, str) 1225*e1fe3e4aSElliott Hughes return token, isOperator, index 1226*e1fe3e4aSElliott Hughes 1227*e1fe3e4aSElliott Hughes def getBytes(self, index, nBytes): 1228*e1fe3e4aSElliott Hughes if self.bytecode is not None: 1229*e1fe3e4aSElliott Hughes newIndex = index + nBytes 1230*e1fe3e4aSElliott Hughes bytes = self.bytecode[index:newIndex] 1231*e1fe3e4aSElliott Hughes index = newIndex 1232*e1fe3e4aSElliott Hughes else: 1233*e1fe3e4aSElliott Hughes bytes = self.program[index] 1234*e1fe3e4aSElliott Hughes index = index + 1 1235*e1fe3e4aSElliott Hughes assert len(bytes) == nBytes 1236*e1fe3e4aSElliott Hughes return bytes, index 1237*e1fe3e4aSElliott Hughes 1238*e1fe3e4aSElliott Hughes def handle_operator(self, operator): 1239*e1fe3e4aSElliott Hughes return operator 1240*e1fe3e4aSElliott Hughes 1241*e1fe3e4aSElliott Hughes def toXML(self, xmlWriter, ttFont=None): 1242*e1fe3e4aSElliott Hughes from fontTools.misc.textTools import num2binary 1243*e1fe3e4aSElliott Hughes 1244*e1fe3e4aSElliott Hughes if self.bytecode is not None: 1245*e1fe3e4aSElliott Hughes xmlWriter.dumphex(self.bytecode) 1246*e1fe3e4aSElliott Hughes else: 1247*e1fe3e4aSElliott Hughes index = 0 1248*e1fe3e4aSElliott Hughes args = [] 1249*e1fe3e4aSElliott Hughes while True: 1250*e1fe3e4aSElliott Hughes token, isOperator, index = self.getToken(index) 1251*e1fe3e4aSElliott Hughes if token is None: 1252*e1fe3e4aSElliott Hughes break 1253*e1fe3e4aSElliott Hughes if isOperator: 1254*e1fe3e4aSElliott Hughes if token in ("hintmask", "cntrmask"): 1255*e1fe3e4aSElliott Hughes hintMask, isOperator, index = self.getToken(index) 1256*e1fe3e4aSElliott Hughes bits = [] 1257*e1fe3e4aSElliott Hughes for byte in hintMask: 1258*e1fe3e4aSElliott Hughes bits.append(num2binary(byteord(byte), 8)) 1259*e1fe3e4aSElliott Hughes hintMask = strjoin(bits) 1260*e1fe3e4aSElliott Hughes line = " ".join(args + [token, hintMask]) 1261*e1fe3e4aSElliott Hughes else: 1262*e1fe3e4aSElliott Hughes line = " ".join(args + [token]) 1263*e1fe3e4aSElliott Hughes xmlWriter.write(line) 1264*e1fe3e4aSElliott Hughes xmlWriter.newline() 1265*e1fe3e4aSElliott Hughes args = [] 1266*e1fe3e4aSElliott Hughes else: 1267*e1fe3e4aSElliott Hughes if isinstance(token, float): 1268*e1fe3e4aSElliott Hughes token = floatToFixedToStr(token, precisionBits=16) 1269*e1fe3e4aSElliott Hughes else: 1270*e1fe3e4aSElliott Hughes token = str(token) 1271*e1fe3e4aSElliott Hughes args.append(token) 1272*e1fe3e4aSElliott Hughes if args: 1273*e1fe3e4aSElliott Hughes # NOTE: only CFF2 charstrings/subrs can have numeric arguments on 1274*e1fe3e4aSElliott Hughes # the stack after the last operator. Compiling this would fail if 1275*e1fe3e4aSElliott Hughes # this is part of CFF 1.0 table. 1276*e1fe3e4aSElliott Hughes line = " ".join(args) 1277*e1fe3e4aSElliott Hughes xmlWriter.write(line) 1278*e1fe3e4aSElliott Hughes 1279*e1fe3e4aSElliott Hughes def fromXML(self, name, attrs, content): 1280*e1fe3e4aSElliott Hughes from fontTools.misc.textTools import binary2num, readHex 1281*e1fe3e4aSElliott Hughes 1282*e1fe3e4aSElliott Hughes if attrs.get("raw"): 1283*e1fe3e4aSElliott Hughes self.setBytecode(readHex(content)) 1284*e1fe3e4aSElliott Hughes return 1285*e1fe3e4aSElliott Hughes content = strjoin(content) 1286*e1fe3e4aSElliott Hughes content = content.split() 1287*e1fe3e4aSElliott Hughes program = [] 1288*e1fe3e4aSElliott Hughes end = len(content) 1289*e1fe3e4aSElliott Hughes i = 0 1290*e1fe3e4aSElliott Hughes while i < end: 1291*e1fe3e4aSElliott Hughes token = content[i] 1292*e1fe3e4aSElliott Hughes i = i + 1 1293*e1fe3e4aSElliott Hughes try: 1294*e1fe3e4aSElliott Hughes token = int(token) 1295*e1fe3e4aSElliott Hughes except ValueError: 1296*e1fe3e4aSElliott Hughes try: 1297*e1fe3e4aSElliott Hughes token = strToFixedToFloat(token, precisionBits=16) 1298*e1fe3e4aSElliott Hughes except ValueError: 1299*e1fe3e4aSElliott Hughes program.append(token) 1300*e1fe3e4aSElliott Hughes if token in ("hintmask", "cntrmask"): 1301*e1fe3e4aSElliott Hughes mask = content[i] 1302*e1fe3e4aSElliott Hughes maskBytes = b"" 1303*e1fe3e4aSElliott Hughes for j in range(0, len(mask), 8): 1304*e1fe3e4aSElliott Hughes maskBytes = maskBytes + bytechr(binary2num(mask[j : j + 8])) 1305*e1fe3e4aSElliott Hughes program.append(maskBytes) 1306*e1fe3e4aSElliott Hughes i = i + 1 1307*e1fe3e4aSElliott Hughes else: 1308*e1fe3e4aSElliott Hughes program.append(token) 1309*e1fe3e4aSElliott Hughes else: 1310*e1fe3e4aSElliott Hughes program.append(token) 1311*e1fe3e4aSElliott Hughes self.setProgram(program) 1312*e1fe3e4aSElliott Hughes 1313*e1fe3e4aSElliott Hughes 1314*e1fe3e4aSElliott Hughesclass T1CharString(T2CharString): 1315*e1fe3e4aSElliott Hughes operandEncoding = t1OperandEncoding 1316*e1fe3e4aSElliott Hughes operators, opcodes = buildOperatorDict(t1Operators) 1317*e1fe3e4aSElliott Hughes 1318*e1fe3e4aSElliott Hughes def __init__(self, bytecode=None, program=None, subrs=None): 1319*e1fe3e4aSElliott Hughes super().__init__(bytecode, program) 1320*e1fe3e4aSElliott Hughes self.subrs = subrs 1321*e1fe3e4aSElliott Hughes 1322*e1fe3e4aSElliott Hughes def getIntEncoder(self): 1323*e1fe3e4aSElliott Hughes return encodeIntT1 1324*e1fe3e4aSElliott Hughes 1325*e1fe3e4aSElliott Hughes def getFixedEncoder(self): 1326*e1fe3e4aSElliott Hughes def encodeFixed(value): 1327*e1fe3e4aSElliott Hughes raise TypeError("Type 1 charstrings don't support floating point operands") 1328*e1fe3e4aSElliott Hughes 1329*e1fe3e4aSElliott Hughes def decompile(self): 1330*e1fe3e4aSElliott Hughes if self.bytecode is None: 1331*e1fe3e4aSElliott Hughes return 1332*e1fe3e4aSElliott Hughes program = [] 1333*e1fe3e4aSElliott Hughes index = 0 1334*e1fe3e4aSElliott Hughes while True: 1335*e1fe3e4aSElliott Hughes token, isOperator, index = self.getToken(index) 1336*e1fe3e4aSElliott Hughes if token is None: 1337*e1fe3e4aSElliott Hughes break 1338*e1fe3e4aSElliott Hughes program.append(token) 1339*e1fe3e4aSElliott Hughes self.setProgram(program) 1340*e1fe3e4aSElliott Hughes 1341*e1fe3e4aSElliott Hughes def draw(self, pen): 1342*e1fe3e4aSElliott Hughes extractor = T1OutlineExtractor(pen, self.subrs) 1343*e1fe3e4aSElliott Hughes extractor.execute(self) 1344*e1fe3e4aSElliott Hughes self.width = extractor.width 1345*e1fe3e4aSElliott Hughes 1346*e1fe3e4aSElliott Hughes 1347*e1fe3e4aSElliott Hughesclass DictDecompiler(object): 1348*e1fe3e4aSElliott Hughes operandEncoding = cffDictOperandEncoding 1349*e1fe3e4aSElliott Hughes 1350*e1fe3e4aSElliott Hughes def __init__(self, strings, parent=None): 1351*e1fe3e4aSElliott Hughes self.stack = [] 1352*e1fe3e4aSElliott Hughes self.strings = strings 1353*e1fe3e4aSElliott Hughes self.dict = {} 1354*e1fe3e4aSElliott Hughes self.parent = parent 1355*e1fe3e4aSElliott Hughes 1356*e1fe3e4aSElliott Hughes def getDict(self): 1357*e1fe3e4aSElliott Hughes assert len(self.stack) == 0, "non-empty stack" 1358*e1fe3e4aSElliott Hughes return self.dict 1359*e1fe3e4aSElliott Hughes 1360*e1fe3e4aSElliott Hughes def decompile(self, data): 1361*e1fe3e4aSElliott Hughes index = 0 1362*e1fe3e4aSElliott Hughes lenData = len(data) 1363*e1fe3e4aSElliott Hughes push = self.stack.append 1364*e1fe3e4aSElliott Hughes while index < lenData: 1365*e1fe3e4aSElliott Hughes b0 = byteord(data[index]) 1366*e1fe3e4aSElliott Hughes index = index + 1 1367*e1fe3e4aSElliott Hughes handler = self.operandEncoding[b0] 1368*e1fe3e4aSElliott Hughes value, index = handler(self, b0, data, index) 1369*e1fe3e4aSElliott Hughes if value is not None: 1370*e1fe3e4aSElliott Hughes push(value) 1371*e1fe3e4aSElliott Hughes 1372*e1fe3e4aSElliott Hughes def pop(self): 1373*e1fe3e4aSElliott Hughes value = self.stack[-1] 1374*e1fe3e4aSElliott Hughes del self.stack[-1] 1375*e1fe3e4aSElliott Hughes return value 1376*e1fe3e4aSElliott Hughes 1377*e1fe3e4aSElliott Hughes def popall(self): 1378*e1fe3e4aSElliott Hughes args = self.stack[:] 1379*e1fe3e4aSElliott Hughes del self.stack[:] 1380*e1fe3e4aSElliott Hughes return args 1381*e1fe3e4aSElliott Hughes 1382*e1fe3e4aSElliott Hughes def handle_operator(self, operator): 1383*e1fe3e4aSElliott Hughes operator, argType = operator 1384*e1fe3e4aSElliott Hughes if isinstance(argType, tuple): 1385*e1fe3e4aSElliott Hughes value = () 1386*e1fe3e4aSElliott Hughes for i in range(len(argType) - 1, -1, -1): 1387*e1fe3e4aSElliott Hughes arg = argType[i] 1388*e1fe3e4aSElliott Hughes arghandler = getattr(self, "arg_" + arg) 1389*e1fe3e4aSElliott Hughes value = (arghandler(operator),) + value 1390*e1fe3e4aSElliott Hughes else: 1391*e1fe3e4aSElliott Hughes arghandler = getattr(self, "arg_" + argType) 1392*e1fe3e4aSElliott Hughes value = arghandler(operator) 1393*e1fe3e4aSElliott Hughes if operator == "blend": 1394*e1fe3e4aSElliott Hughes self.stack.extend(value) 1395*e1fe3e4aSElliott Hughes else: 1396*e1fe3e4aSElliott Hughes self.dict[operator] = value 1397*e1fe3e4aSElliott Hughes 1398*e1fe3e4aSElliott Hughes def arg_number(self, name): 1399*e1fe3e4aSElliott Hughes if isinstance(self.stack[0], list): 1400*e1fe3e4aSElliott Hughes out = self.arg_blend_number(self.stack) 1401*e1fe3e4aSElliott Hughes else: 1402*e1fe3e4aSElliott Hughes out = self.pop() 1403*e1fe3e4aSElliott Hughes return out 1404*e1fe3e4aSElliott Hughes 1405*e1fe3e4aSElliott Hughes def arg_blend_number(self, name): 1406*e1fe3e4aSElliott Hughes out = [] 1407*e1fe3e4aSElliott Hughes blendArgs = self.pop() 1408*e1fe3e4aSElliott Hughes numMasters = len(blendArgs) 1409*e1fe3e4aSElliott Hughes out.append(blendArgs) 1410*e1fe3e4aSElliott Hughes out.append("blend") 1411*e1fe3e4aSElliott Hughes dummy = self.popall() 1412*e1fe3e4aSElliott Hughes return blendArgs 1413*e1fe3e4aSElliott Hughes 1414*e1fe3e4aSElliott Hughes def arg_SID(self, name): 1415*e1fe3e4aSElliott Hughes return self.strings[self.pop()] 1416*e1fe3e4aSElliott Hughes 1417*e1fe3e4aSElliott Hughes def arg_array(self, name): 1418*e1fe3e4aSElliott Hughes return self.popall() 1419*e1fe3e4aSElliott Hughes 1420*e1fe3e4aSElliott Hughes def arg_blendList(self, name): 1421*e1fe3e4aSElliott Hughes """ 1422*e1fe3e4aSElliott Hughes There may be non-blend args at the top of the stack. We first calculate 1423*e1fe3e4aSElliott Hughes where the blend args start in the stack. These are the last 1424*e1fe3e4aSElliott Hughes numMasters*numBlends) +1 args. 1425*e1fe3e4aSElliott Hughes The blend args starts with numMasters relative coordinate values, the BlueValues in the list from the default master font. This is followed by 1426*e1fe3e4aSElliott Hughes numBlends list of values. Each of value in one of these lists is the 1427*e1fe3e4aSElliott Hughes Variable Font delta for the matching region. 1428*e1fe3e4aSElliott Hughes 1429*e1fe3e4aSElliott Hughes We re-arrange this to be a list of numMaster entries. Each entry starts with the corresponding default font relative value, and is followed by 1430*e1fe3e4aSElliott Hughes the delta values. We then convert the default values, the first item in each entry, to an absolute value. 1431*e1fe3e4aSElliott Hughes """ 1432*e1fe3e4aSElliott Hughes vsindex = self.dict.get("vsindex", 0) 1433*e1fe3e4aSElliott Hughes numMasters = ( 1434*e1fe3e4aSElliott Hughes self.parent.getNumRegions(vsindex) + 1 1435*e1fe3e4aSElliott Hughes ) # only a PrivateDict has blended ops. 1436*e1fe3e4aSElliott Hughes numBlends = self.pop() 1437*e1fe3e4aSElliott Hughes args = self.popall() 1438*e1fe3e4aSElliott Hughes numArgs = len(args) 1439*e1fe3e4aSElliott Hughes # The spec says that there should be no non-blended Blue Values,. 1440*e1fe3e4aSElliott Hughes assert numArgs == numMasters * numBlends 1441*e1fe3e4aSElliott Hughes value = [None] * numBlends 1442*e1fe3e4aSElliott Hughes numDeltas = numMasters - 1 1443*e1fe3e4aSElliott Hughes i = 0 1444*e1fe3e4aSElliott Hughes prevVal = 0 1445*e1fe3e4aSElliott Hughes while i < numBlends: 1446*e1fe3e4aSElliott Hughes newVal = args[i] + prevVal 1447*e1fe3e4aSElliott Hughes prevVal = newVal 1448*e1fe3e4aSElliott Hughes masterOffset = numBlends + (i * numDeltas) 1449*e1fe3e4aSElliott Hughes blendList = [newVal] + args[masterOffset : masterOffset + numDeltas] 1450*e1fe3e4aSElliott Hughes value[i] = blendList 1451*e1fe3e4aSElliott Hughes i += 1 1452*e1fe3e4aSElliott Hughes return value 1453*e1fe3e4aSElliott Hughes 1454*e1fe3e4aSElliott Hughes def arg_delta(self, name): 1455*e1fe3e4aSElliott Hughes valueList = self.popall() 1456*e1fe3e4aSElliott Hughes out = [] 1457*e1fe3e4aSElliott Hughes if valueList and isinstance(valueList[0], list): 1458*e1fe3e4aSElliott Hughes # arg_blendList() has already converted these to absolute values. 1459*e1fe3e4aSElliott Hughes out = valueList 1460*e1fe3e4aSElliott Hughes else: 1461*e1fe3e4aSElliott Hughes current = 0 1462*e1fe3e4aSElliott Hughes for v in valueList: 1463*e1fe3e4aSElliott Hughes current = current + v 1464*e1fe3e4aSElliott Hughes out.append(current) 1465*e1fe3e4aSElliott Hughes return out 1466*e1fe3e4aSElliott Hughes 1467*e1fe3e4aSElliott Hughes 1468*e1fe3e4aSElliott Hughesdef calcSubrBias(subrs): 1469*e1fe3e4aSElliott Hughes nSubrs = len(subrs) 1470*e1fe3e4aSElliott Hughes if nSubrs < 1240: 1471*e1fe3e4aSElliott Hughes bias = 107 1472*e1fe3e4aSElliott Hughes elif nSubrs < 33900: 1473*e1fe3e4aSElliott Hughes bias = 1131 1474*e1fe3e4aSElliott Hughes else: 1475*e1fe3e4aSElliott Hughes bias = 32768 1476*e1fe3e4aSElliott Hughes return bias 1477