def _makeTTFragments_delta(delta, relSet): """ Returns a Hints object containing a fragment of TrueType code designed to add the specified delta to the stack elements at the positions noted in the relSet (whose length will always be greater than one; if there is only one value, the client should call _makeTTFragment_delta instead). >>> _makeTTFragments_delta(20, set([-1, -3])) [PUSH [3], MINDEX, PUSH [20], ADD, PUSH [3], MINDEX, PUSH [3], MINDEX, PUSH [20], ADD] >>> _makeTTFragments_delta(20, set([-2, -4])) [PUSH [4], MINDEX, PUSH [20], ADD, PUSH [4], MINDEX, PUSH [4], MINDEX, PUSH [20], ADD, PUSH [4], MINDEX] """ lowest = min(relSet) _p = opcode_tt.Opcode_push([-lowest]) _delta = opcode_tt.Opcode_push([delta]) v = [] while lowest < 0: v.extend([_p, _mindexOpcode]) if lowest in relSet: v.extend([_delta, _addOpcode]) lowest += 1 return hints_tt.Hints(v)
def _makeTTFragment_call(fdefSet, fdefMap): """ Returns a Hints object containing a fragment of TrueType code designed to map any value in fdefSet into the corresponding value in fdefMap. Note that idempotent mappings do not result in any TrueType code. If no changes need to be made, None is returned. """ # First determine which functions actually need to be altered. needMap = dict((fIn, fOut) for fIn, fOut in fdefMap.items() if fIn in fdefSet if fIn != fOut) if not needMap: return None # Now generate the code H = hints_tt.Hints if len(needMap) == 1: # for a single map, just add the difference fIn, fOut = needMap.popitem() _delta = opcode_tt.Opcode_push([fOut - fIn]) return H([_delta, _addOpcode]) stillToDo = len(needMap) v = [] for fIn, fOut in needMap.items(): stillToDo -= 1 _trial = opcode_tt.Opcode_push([fIn]) _delta = opcode_tt.Opcode_push([fOut - fIn]) v.extend([_dupOpcode, _trial, _eqOpcode, _ifOpcode, _delta, _addOpcode]) if stillToDo: v.append(_elseOpcode) v.extend([_eifOpcode] * len(needMap)) return H(v)
def _makePiece_setOneConstant(storeIndex, constant): """ Returns hints to set the storage index to the constant. (starting stack) *** PUSH *** storeIndex constant WS *** >>> print(_makePiece_setOneConstant(20, 4)) [PUSH [20, 4], WS] """ _push = opcode_tt.Opcode_push([storeIndex, constant]) return [_push, _wsOpcode]
def _addSynthCall(self, hString, which, isAACase): """ Given a hint string (which might be potentially empty), adds a call to self.synthFDEFIndex to the beginning, integrating with existing PUSHes, if present, to make the addition as small as possible. If isAACase is True, and the hint string is empty, adds an explicit AA 0 after the synth call. Returns the augmented hint string. """ if hString: h = hints_tt.Hints.frombytes(hString) if not h[0].isPush(): _push = opcode_tt.Opcode_push([which, self.synthFDEFIndex]) return hints_tt.Hints([_push, _callOpcode] + h).binaryString() for i, op in enumerate(h): if not op.isPush(): break # i is first non-push, so add values to h[i-1] push h[i - 1] = opcode_tt.Opcode_push(h[i - 1].data + (which, self.synthFDEFIndex)) h.insert(i, _callOpcode) elif isAACase: _push = opcode_tt.Opcode_push([0, which, self.synthFDEFIndex]) h = hints_tt.Hints([_push, _callOpcode, _aaOpcode]) else: _push = opcode_tt.Opcode_push([which, self.synthFDEFIndex]) h = hints_tt.Hints([_push, _callOpcode]) return h.binaryString()
def _makePiece_dupOne(storeIndex): """ Returns hints to copy the top stack value thus: (starting stack) a PUSH a storeIndex 2 CINDEX a storeIndex a WS a >>> print(_makePiece_dupOne(20)) [PUSH [20, 2], CINDEX, WS] """ _push = opcode_tt.Opcode_push([storeIndex, 2]) return [_push, _cindexOpcode, _wsOpcode]
def _makePiece_dupSkipOne(storeIndex): """ Returns hints to copy the second-from-the-top stack value thus: (starting stack) a ignore PUSH a ignore storeIndex 3 CINDEX a ignore storeIndex a WS a ignore >>> print(_makePiece_dupSkipOne(20)) [PUSH [20, 3], CINDEX, WS] """ _push = opcode_tt.Opcode_push([storeIndex, 3]) return [_push, _cindexOpcode, _wsOpcode]
def _makeTTFragment_delta(delta, relStack): """ Returns a Hints object containing a fragment of TrueType code designed to add the specified delta to the stack element at the relStack position. >>> _makeTTFragment_delta(20, -1) [PUSH [20], ADD] >>> _makeTTFragment_delta(20, -2) [SWAP, PUSH [20], ADD, SWAP] >>> _makeTTFragment_delta(20, -3) [ROLL, PUSH [20], ADD, ROLL, ROLL] >>> _makeTTFragment_delta(20, -4) [PUSH [4], MINDEX, PUSH [20], ADD, PUSH [4], MINDEX, PUSH [4], MINDEX, PUSH [4], MINDEX] """ H = hints_tt.Hints _delta = opcode_tt.Opcode_push([delta]) if relStack == -1: # top of stack is easy case; just PUSH and ADD return H([_delta, _addOpcode]) if relStack == -2: return H([_swapOpcode, _delta, _addOpcode, _swapOpcode]) if relStack == -3: return H([_rollOpcode, _delta, _addOpcode, _rollOpcode, _rollOpcode]) # if we get here, the element to be changed is very deep, so we handle it # in a generic way _count = opcode_tt.Opcode_push([-relStack]) v = [_count, _mindexOpcode, _delta, _addOpcode] v.extend([_count, _mindexOpcode] * (-relStack - 1)) return H(v)
def _makePiece_setTwoConstants(storeIndex, constant1, constant2): """ Returns hints to set storeIndex to constant1 and storeIndex+1 to constant2. (starting stack) *** PUSH *** storeIndex+1 constant2 storeIndex constant WS *** storeIndex+1 constant2 WS *** >>> print(_makePiece_setTwoConstants(20, 4, 1)) [PUSH [21, 1, 20, 4], WS, WS] """ _push = opcode_tt.Opcode_push( [storeIndex + 1, constant2, storeIndex, constant1]) return [_push, _wsOpcode, _wsOpcode]
def _makePiece_dupOneSetOne(storeIndex, constant): """ Returns hints that store the specified constant in storeIndex and duplicates the top of the stack into storeIndex + 1. (starting stack) a PUSH a storeIndex+1 3 storeIndex constant WS a storeIndex+1 3 CINDEX a storeIndex+1 a WS a >>> print(_makePiece_dupOneSetOne(20, 1)) [PUSH [21, 3, 20, 1], WS, CINDEX, WS] """ _push = opcode_tt.Opcode_push([storeIndex + 1, 3, storeIndex, constant]) return [_push, _wsOpcode, _cindexOpcode, _wsOpcode]
def _makePiece_dupTwo(storeIndex): """ Returns hints to copy the top two stack values thus: (starting stack) a b PUSH a b storeIndex 2 storeIndex+1 5 CINDEX a b storeIndex 2 storeIndex+1 a WS a b storeIndex 2 CINDEX a b storeIndex b WS a b Note if storeIndex+1 doesn't fit in one byte, this effect might be able to be done in fewer hint bytes by single pushes and swaps. >>> print(_makePiece_dupTwo(20)) [PUSH [20, 2, 21, 5], CINDEX, WS, CINDEX, WS] """ _push = opcode_tt.Opcode_push([storeIndex, 2, storeIndex + 1, 5]) return [_push, _cindexOpcode, _wsOpcode, _cindexOpcode, _wsOpcode]
def buildBinary(self, w, **kwArgs): """ Adds the binary content for the Fpgm object to the specified writer. >>> utilities.hexdump(_testingValues[1].binaryString()) 0 | B119 022C B201 0203 502D 2C00 012D |...,....P-,..- | """ if 'stakeValue' in kwArgs: stakeValue = kwArgs.pop('stakeValue') w.stakeCurrentWithValue(stakeValue) else: stakeValue = w.stakeCurrent() keysObj = opcode_tt.Opcode_push(sorted(self, reverse=True)) w.addString(keysObj.binaryString()) op_ENDF = common.nameToOpcodeMap["ENDF"] op_FDEF = common.nameToOpcodeMap["FDEF"] for key in sorted(self): w.add("B", op_FDEF) w.addString(self[key].binaryString()) w.add("B", op_ENDF)