def hint_NOT(self, **kwArgs): """ NOT: Logical NOT, opcode 0x5C >>> logger = utilities.makeDoctestLogger("NOT_test") >>> _popSync, _testingState = _testFuncs() >>> h = _testingState(Collection([Triple(0, 8, 4)]), 0, 5) >>> h.append(opcode_tt.Opcode_nonpush(nameToOpcodeMap["NOT"])) >>> hint_NOT(h, logger=logger) >>> len(h.state.stack) == len(h.state.pushHistory) True >>> pp.PP().sequence_deep(h.state.pushHistory) Extra index 0 in PUSH opcode index 0 in test Extra index 1 in PUSH opcode index 0 in test Result of opcode NOT at index 0 in test, with inputs: Extra index 2 in PUSH opcode index 0 in test >>> _popSync(h.state) 0 >>> h.state.assign('pc', 0) >>> hint_NOT(h, logger=logger) >>> _popSync(h.state) 1 >>> h.state.assign('pc', 0) >>> hint_NOT(h, logger=logger) >>> _popSync(h.state) Singles: [0, 1] >>> hint_NOT(h, logger=logger) NOT_test - CRITICAL - Stack underflow in test (PC 1). """ state = self.state logger = self._getLogger(**kwArgs) n = self._popRemove(state, 'stack', coerceToCollection=True) if n is None: state.assign('pc', doNotProceedPC) return h = self._popRemove(state, 'pushHistory') if h is None: state.assign('pc', doNotProceedPC) return v = list(n.encompassedBooleans()) if len(v) == 1: v = [1 - v[0]] state.append('stack', (v[0] if len(v) == 1 else toCollection(v))) state.append( 'pushHistory', op.HistoryEntry_op(hintsObj=(id(self.ultParent), self.ultParent), hintsPC=state.pc + self.ultDelta, opcode=self[state.pc].opcode, historyIterable=[h])) fatObj = kwArgs.get('fdefArgTracer', None) if fatObj is not None: fatObj.notePop(None, 'NOT') fatObj.notePush() state.assign('pc', state.pc + 1)
def hint_MIRP(self, **kwArgs): """ MIRP: Move indirect relative point, opcodes 0xE0-0xFF >>> logger = utilities.makeDoctestLogger("MIRP_test") >>> _popSync, _testingState = _testFuncs() >>> h = _testingState(7, 11, 12, 3, 15) >>> m = h.state.statistics.maxima >>> hint_MIRP(h, logger=logger) >>> len(h.state.stack) == len(h.state.pushHistory) True >>> m.point, m.cvt (3, 15) >>> hint_srp0.hint_SRP0(h, logger=logger) >>> hint_MIRP(h, logger=logger) >>> m.point, m.cvt (12, 15) >>> h.state.statistics.pprint(keys=('cvt', 'point')) History for CVT values: 11: Extra index 1 in PUSH opcode index 0 in test 15: Extra index 4 in PUSH opcode index 0 in test History for outline points (glyph zone): 0: Implicit zero for RP0 used at opcode index 0 in test 3: Extra index 3 in PUSH opcode index 0 in test 7: Extra index 0 in PUSH opcode index 0 in test 12: Extra index 2 in PUSH opcode index 0 in test >>> hint_MIRP(h, logger=logger) MIRP_test - CRITICAL - Stack underflow in test (PC 3). """ state = self.state stack = state.stack stats = state.statistics gs = state.graphicsState rph = state.refPtHistory logger = self._getLogger(**kwArgs) t = self._popRemove(state, 'stack', 2, coerceToCollection=True) if t is None: state.assign('pc', doNotProceedPC) return point, cvtIndex = t t = self._popRemove(state, 'pushHistory', 2) if t is None: state.assign('pc', doNotProceedPC) return pointHist, cvtHist = t missing = sorted(n for n in cvtIndex if n not in state.cvt) if missing: logger.error(( 'E6005', (self.ultParent.infoString, state.pc + self.ultDelta, missing), "For MIRP opcode in %s (PC %d), " "CVTs not present in CVT table: %s")) state._validationFailed = True elif self._zoneCheck("MIRP", (0, 1), logger): zp0, zp1 = gs.zonePointer0, gs.zonePointer1 v = [ (zp1, point, True), (zp0, toCollection(gs.referencePoint0), False)] if self._pointCheck( "MIRP", v, logger, kwArgs.get('extraInfo', {})): stats.addHistory('cvt', cvtIndex, cvtHist) stats.noteEffect( 'cvt', cvtIndex, self.ultParent.infoString, state.pc + self.ultDelta, -1) stats.addHistory('pointMoved', (zp1, point), pointHist) refHist = self._synthRefHistory(0) stats.addHistory( 'point', (zp0, gs.referencePoint0), refHist) state.assignDeep( 'graphicsState', 'referencePoint1', gs.referencePoint0) state.assignDeep('graphicsState', 'referencePoint1', point) rph[1] = rph[0] rph[2] = pointHist state.changed('refPtHistory') if kwArgs.get('setRP0', False): state.assignDeep('graphicsState', 'referencePoint0', point) rph[0] = pointHist state.changed('refPtHistory') if 'fdefEntryStack' in kwArgs: # We only note graphicsState effects when a # FDEF stack is available state.statistics.noteGSEffect( tuple(kwArgs['fdefEntryStack']), state.pc + self.ultDelta) fatObj = kwArgs.get('fdefArgTracer', None) if fatObj is not None: fatObj.notePop('cvtIndex', 'MIRP') fatObj.notePop('pointIndex', 'MIRP') state.assign('pc', state.pc + 1)
def hint_WS(self, **kwArgs): """ WS: Write to storage, opcode 0x42 >>> logger = utilities.makeDoctestLogger("WS_test") >>> _popSync, _testingState = _testFuncs() >>> h = _testingState(toCollection([8, 15]), 64, 15, -128) >>> h.state.storage[8] = 32 >>> h.state.changed('storage') >>> hint_WS(h, logger=logger) >>> h.state.storage[15] -128 >>> hint_WS(h, logger=logger) >>> h.state.storage[8] Singles: [32, 64] >>> h.state.storage[15] Singles: [-128, 64] >>> h.state.statistics.pprint(keys=('storage',)) History for storage locations: 8: Extra index 0 in PUSH opcode index 0 in test 15: Extra index 0 in PUSH opcode index 0 in test Extra index 2 in PUSH opcode index 0 in test >>> hint_WS(h, logger=logger) WS_test - CRITICAL - Stack underflow in test (PC 2). """ state = self.state stats = state.statistics logger = self._getLogger(**kwArgs) t = self._popRemove(state, 'stack', 2, coerceToCollection=True) if t is None: state.assign('pc', doNotProceedPC) return storageIndex, value = t t = self._popRemove(state, 'pushHistory', 2) if t is None: state.assign('pc', doNotProceedPC) return indexHistory, valueHistory = t stats.addHistory('storage', storageIndex, indexHistory) stats.noteEffect( kind = 'storage', value = storageIndex, infoString = self.ultParent.infoString, pc = state.pc + self.ultDelta, relStackIndex = -2) if len(storageIndex) == 1: indivIndex = int(storageIndex) n2 = value.toNumber() if n2 is not None: value = n2 state.storage[indivIndex] = value state.storageHistory[indivIndex] = valueHistory else: for indivIndex in storageIndex: orig = toCollection(state.storage[indivIndex]) orig = orig.addToCollection(value) n2 = orig.toNumber() if n2 is not None: orig = n2 origHistory = self._synthStorageHistory(indivIndex) state.storage[indivIndex] = orig state.storageHistory[indivIndex] = ( HG([origHistory, valueHistory])) fatObj = kwArgs.get('fdefArgTracer', None) if fatObj is not None: fatObj.notePop(None, 'WS') fatObj.notePop('storageIndex', 'WS') state.changed('storage') state.changed('storageHistory') state.assign('pc', state.pc + 1)
def hint_IP(self, **kwArgs): """ IP: Interpolate point, opcode 0x39 >>> logger = utilities.makeDoctestLogger("IP_test") >>> _popSync, _testingState = _testFuncs() >>> h = _testingState(3, 4, 6, 7, 2, 12, 3, 5) >>> m = h.state.statistics.maxima >>> h.state.assignDeep('graphicsState', 'loop', 4) >>> hint_IP(h, logger=logger) >>> len(h.state.stack) == len(h.state.pushHistory) True >>> m.point 12 >>> h.state.graphicsState.loop 1 >>> h.state.assignDeep('graphicsState', 'loop', 2) >>> h.state.assignDeep('graphicsState', 'referencePoint2', 14) >>> hint_IP(h, logger=logger) >>> m.point 14 >>> h.state.statistics.pprint(keys=('point',)) History for outline points (glyph zone): 0: Implicit zero for RP1 used at opcode index 0 in test Implicit zero for RP2 used at opcode index 0 in test Implicit zero for RP1 used at opcode index 1 in test 2: Extra index 4 in PUSH opcode index 0 in test 3: Extra index 6 in PUSH opcode index 0 in test 5: Extra index 7 in PUSH opcode index 0 in test 6: Extra index 2 in PUSH opcode index 0 in test 7: Extra index 3 in PUSH opcode index 0 in test 12: Extra index 5 in PUSH opcode index 0 in test 14: Implicit zero for RP2 used at opcode index 1 in test >>> h.state.assignDeep('graphicsState', 'loop', 3) >>> hint_IP(h, logger=logger) IP_test - CRITICAL - Stack underflow in test (PC 2). """ state = self.state gs = state.graphicsState logger = self._getLogger(**kwArgs) points = self._popRemove(state, 'stack', gs.loop, coerceToCollection=True, coerceToList=True) if points is None: state.assign('pc', doNotProceedPC) return histories = self._popRemove(state, 'pushHistory', gs.loop, coerceToList=True) if histories is None: state.assign('pc', doNotProceedPC) return if self._zoneCheck("IP", (0, 1, 2), logger): zp0 = gs.zonePointer0 zp1 = gs.zonePointer1 zp2 = gs.zonePointer2 v = [(zp2, p, True) for p in points] v.append((zp0, toCollection(gs.referencePoint1), False)) v.append((zp1, toCollection(gs.referencePoint2), False)) if self._pointCheck("IP", v, logger, kwArgs.get('extraInfo', {})): for i, p in enumerate(points): state.statistics.addHistory('pointMoved', (gs.zonePointer2, p), histories[i]) rh1 = self._synthRefHistory(1) state.statistics.addHistory('point', (gs.zonePointer0, gs.referencePoint1), rh1) rh2 = self._synthRefHistory(2) state.statistics.addHistory('point', (gs.zonePointer1, gs.referencePoint2), rh2) state.assignDeep('graphicsState', 'loop', 1) state.assign('pc', state.pc + 1) fatObj = kwArgs.get('fdefArgTracer', None) if fatObj is not None: for p in points: fatObj.notePop('pointIndex', 'IP')
def hint_SHZ(self, **kwArgs): """ SHZ: Shift zone, opcodes 0x36-0x37 >>> logger = utilities.makeDoctestLogger("SHZ_test") >>> _popSync, _testingState = _testFuncs() >>> h = _testingState(1, 0, 12, 8) >>> hint_srp1.hint_SRP1(h, logger=logger) >>> hint_srp2.hint_SRP2(h, logger=logger) >>> hint_SHZ(h, refPt=1, logger=logger) >>> hint_SHZ(h, refPt=2, logger=logger) >>> h.state.statistics.maxima.pprint(keys=('point', 'stack')) Highest point index in the glyph zone: 12 Deepest stack attained: 4 >>> h.state.statistics.pprint(keys=('point', 'zone')) History for outline points (glyph zone): 8: Extra index 3 in PUSH opcode index 0 in test 12: Extra index 2 in PUSH opcode index 0 in test History for SHZ zones: 0: Extra index 1 in PUSH opcode index 0 in test 1: Extra index 0 in PUSH opcode index 0 in test >>> len(h.state.stack) == len(h.state.pushHistory) True >>> hint_SHZ(h, logger=logger) SHZ_test - CRITICAL - Stack underflow in test (PC 4). """ state = self.state gs = state.graphicsState logger = self._getLogger(**kwArgs) zone = self._popRemove(state, 'stack') if zone is None: state.assign('pc', doNotProceedPC) return history = self._popRemove(state, 'pushHistory') if history is None: state.assign('pc', doNotProceedPC) return if self._zoneCheck("SHZ", (zone, ), logger): state.statistics.addHistory('zone', zone, history) if kwArgs.get('refPt', 1) == 1: if self._pointCheck( "SHZ", [(gs.zonePointer0, toCollection(gs.referencePoint1), False)], logger, kwArgs.get('extraInfo', {})): state.statistics.addHistory( 'point', (gs.zonePointer0, gs.referencePoint1), self._synthRefHistory(1)) else: if self._pointCheck( "SHZ", [(gs.zonePointer1, toCollection(gs.referencePoint2), False)], logger, kwArgs.get('extraInfo', {})): state.statistics.addHistory( 'point', (gs.zonePointer1, gs.referencePoint2), self._synthRefHistory(2)) fatObj = kwArgs.get('fdefArgTracer', None) if fatObj is not None: fatObj.notePop('zoneIndex', 'SHZ') state.assign('pc', state.pc + 1)
def hint_MDRP(self, **kwArgs): """ MDRP: Move direct relative point, opcodes 0xC0-0xDF >>> logger = utilities.makeDoctestLogger("MDRP_test") >>> _popSync, _testingState = _testFuncs() >>> h = _testingState(6, 12) >>> pp.PP().mapping_deep_smart(h.state.refPtHistory, lambda x: False) 0: (no data) 1: (no data) 2: (no data) >>> m = h.state.statistics.maxima >>> hint_MDRP(h, logger=logger) >>> len(h.state.stack) == len(h.state.pushHistory) True >>> m.point 12 >>> h.state.assignDeep('graphicsState', 'referencePoint0', 16) >>> hint_MDRP(h, logger=logger) >>> m.point 16 >>> pp.PP().mapping_deep_smart(h.state.refPtHistory, lambda x: False) 0: (no data) 1: (no data) 2: Extra index 0 in PUSH opcode index 0 in test >>> h.state.statistics.pprint(keys=('point',)) History for outline points (glyph zone): 0: Implicit zero for RP0 used at opcode index 0 in test 6: Extra index 0 in PUSH opcode index 0 in test 12: Extra index 1 in PUSH opcode index 0 in test 16: Implicit zero for RP0 used at opcode index 1 in test >>> hint_MDRP(h, logger=logger) MDRP_test - CRITICAL - Stack underflow in test (PC 2). """ state = self.state gs = state.graphicsState rph = state.refPtHistory logger = self._getLogger(**kwArgs) p = self._popRemove(state, 'stack', coerceToCollection=True) if p is None: state.assign('pc', doNotProceedPC) return history = self._popRemove(state, 'pushHistory') if history is None: state.assign('pc', doNotProceedPC) return if self._zoneCheck("MDRP", (0, 1), logger): zp1 = gs.zonePointer1 v = [ (zp1, p, True), (gs.zonePointer0, toCollection(gs.referencePoint0), False)] if self._pointCheck( "MDRP", v, logger, kwArgs.get('extraInfo', {})): state.statistics.addHistory('pointMoved', (zp1, p), history) refHist = self._synthRefHistory(0) state.statistics.addHistory( 'point', (gs.zonePointer0, gs.referencePoint0), refHist) state.assignDeep( 'graphicsState', 'referencePoint1', gs.referencePoint0) state.assignDeep('graphicsState', 'referencePoint2', p) rph[1] = rph[0] rph[2] = history state.changed('refPtHistory') if kwArgs.get('setRP0', False): state.assignDeep('graphicsState', 'referencePoint0', p) rph[0] = history state.changed('refPtHistory') if 'fdefEntryStack' in kwArgs: # We only note graphicsState effects when a # FDEF stack is available state.statistics.noteGSEffect( tuple(kwArgs['fdefEntryStack']), state.pc + self.ultDelta) fatObj = kwArgs.get('fdefArgTracer', None) if fatObj is not None: fatObj.notePop('pointIndex', 'MDRP') state.assign('pc', state.pc + 1)
def hint_SHP(self, **kwArgs): """ SHP: Shift points, opcodes 0x32-0x33 >>> logger = utilities.makeDoctestLogger("SHP_test") >>> _popSync, _testingState = _testFuncs() >>> h = _testingState(11, 4, 2, 6, 5, 2, 10, 8) >>> hint_srp1.hint_SRP1(h, logger=logger) >>> hint_srp2.hint_SRP2(h, logger=logger) >>> hint_sloop.hint_SLOOP(h, logger=logger) >>> hint_SHP(h, refPt=1, logger=logger) >>> hint_sloop.hint_SLOOP(h, logger=logger) >>> hint_SHP(h, refPt=2, logger=logger) >>> h.state.statistics.maxima.pprint(keys=('point', 'stack')) Highest point index in the glyph zone: 11 Deepest stack attained: 8 >>> h.state.statistics.pprint(keys=('point',)) History for outline points (glyph zone): 4: Extra index 1 in PUSH opcode index 0 in test 5: Extra index 4 in PUSH opcode index 0 in test 6: Extra index 3 in PUSH opcode index 0 in test 8: Extra index 7 in PUSH opcode index 0 in test 10: Extra index 6 in PUSH opcode index 0 in test 11: Extra index 0 in PUSH opcode index 0 in test >>> len(h.state.stack) == len(h.state.pushHistory) True >>> hint_SHP(h, logger=logger) SHP_test - CRITICAL - Stack underflow in test (PC 6). """ state = self.state gs = state.graphicsState logger = self._getLogger(**kwArgs) points = self._popRemove( state, 'stack', gs.loop, coerceToCollection = True, coerceToList = True) if points is None: state.assign('pc', doNotProceedPC) return histories = self._popRemove( state, 'pushHistory', gs.loop, coerceToList = True) if histories is None: state.assign('pc', doNotProceedPC) return if self._zoneCheck("SHP", (0, 1, 2), logger): v = [(gs.zonePointer2, p, True) for p in points] v.append((gs.zonePointer0, toCollection(gs.referencePoint1), False)) v.append((gs.zonePointer1, toCollection(gs.referencePoint2), False)) if self._pointCheck( "SHP", v, logger, kwArgs.get('extraInfo', {})): for i, p in enumerate(points): state.statistics.addHistory( 'pointMoved', (gs.zonePointer2, p), histories[i]) if kwArgs.get('refPt', 1) == 1: state.statistics.addHistory( 'point', (gs.zonePointer0, gs.referencePoint1), self._synthRefHistory(1)) else: state.statistics.addHistory( 'point', (gs.zonePointer1, gs.referencePoint2), self._synthRefHistory(2)) fatObj = kwArgs.get('fdefArgTracer', None) if fatObj is not None: for p in points: fatObj.notePop('pointIndex', 'SHP') state.assignDeep('graphicsState', 'loop', 1) state.assign('pc', state.pc + 1)
def hint_SROUND(self, **kwArgs): """ SROUND: Super round, opcode 0x76 >>> logger = utilities.makeDoctestLogger("SROUND_test") >>> _popSync, _testingState = _testFuncs() >>> h = _testingState(toCollection([0x61, 0xD5]), 0x61) >>> hint_SROUND(h, logger=logger) >>> h.state.graphicsState.roundState [Singles: [1.0], Singles: [0.5], Singles: [-0.375]] >>> hint_SROUND(h, logger=logger) SROUND_test - ERROR - In test (PC 1) a Collection value was used, but is not supported in fontio. >>> h.state.assign('pc', 0) >>> hint_SROUND(h, logger=logger) SROUND_test - CRITICAL - Stack underflow in test (PC 0). """ is45Case = kwArgs.get('is45Case', False) state = self.state logger = self._getLogger(**kwArgs) n = self._popRemove(state, 'stack', coerceToCollection=True) if n is None: state.assign('pc', doNotProceedPC) return if self._popRemove(state, 'pushHistory') is None: state.assign('pc', doNotProceedPC) return n = self._toNumber(n) if n is None: state.assign('pc', doNotProceedPC) return if self._8BitCheck(("S45ROUND" if is45Case else "SROUND"), n, logger): thresholdIndex = n & 15 phaseIndex = (n // 16) & 3 periodIndex = (n // 64) & 3 if periodIndex == 3: logger.error(( 'E6000', (self.ultParent.infoString, state.pc + self.ultDelta), "Reserved value of 3 used for period in SROUND or " "S45ROUND hint in %s (PC %d).")) state._validationFailed = True else: if is45Case: sqrt2 = math.sqrt(2.0) period = [0.5 * sqrt2, sqrt2, 2.0 * sqrt2][periodIndex] else: period = [0.5, 1.0, 2.0][periodIndex] phase = [0.0, 0.25, 0.5, 0.75][phaseIndex] threshold = [x / 8.0 for x in range(-4, 12)] if thresholdIndex: threshold = threshold[thresholdIndex] else: threshold = -1.0 need = [ toCollection(period, 64), toCollection(phase, 64), toCollection(threshold, 64)] state.assignDeep('graphicsState', 'roundState', need) if 'fdefEntryStack' in kwArgs: # We only note graphicsState effects when a # FDEF stack is available state.statistics.noteGSEffect( tuple(kwArgs['fdefEntryStack']), state.pc + self.ultDelta) fatObj = kwArgs.get('fdefArgTracer', None) if fatObj is not None: fatObj.notePop('roundState', 'SROUND') state.assign('pc', state.pc + 1)
def hint_DELTAC(self, **kwArgs): """ DELTAC[1-3]: CVT-based delta hint, opcodes 0x73-0x75 Note that this current implementation ignores the bandDelta kwArg. >>> logger = utilities.makeDoctestLogger("DELTAC_test") >>> _popSync, _testingState = _testFuncs() >>> h = _testingState(98, 4, 114, 6, 2) >>> hint_DELTAC(h, logger=logger) >>> len(h.state.stack) == len(h.state.pushHistory) True >>> h.state.statistics.maxima.cvt 6 >>> h.state.stack[:] = [0] >>> h.state.changed('stack') >>> hint_DELTAC(h, logger=logger) DELTAC_test - ERROR - In test (PC 1) the value 0 is too low. >>> h.state.stack[:] = [] >>> h.state.changed('stack') >>> h.state.assign('pc', 0) >>> hint_DELTAC(h, logger=logger) DELTAC_test - CRITICAL - Stack underflow in test (PC 0). >>> h = _testingState(98, 4, 114, 6, toCollection([2])) >>> hint_DELTAC(h, logger=logger) >>> len(h.state.stack) == len(h.state.pushHistory) True >>> h.state.statistics.maxima.cvt 6 >>> h = _testingState(98, 4, 114, 6, toCollection([2, 3])) >>> hint_DELTAC(h, logger=logger) DELTAC_test - ERROR - In test (PC 0) a Collection value was used, but is not supported in fontio. """ state = self.state stats = state.statistics logger = self._getLogger(**kwArgs) n = self._popRemove(state, 'stack') if n is None: state.assign('pc', doNotProceedPC) return count = self._toNumber(n, doCheck=True) if count is None or self._popRemove(state, 'pushHistory') is None: state.assign('pc', doNotProceedPC) return if count: # some fonts have a zero count as a pseudo-NOP, hmph. historyPiece = self._popRemove(state, 'pushHistory', 2 * count) if historyPiece is None: state.assign('pc', doNotProceedPC) return historyPiece = historyPiece[1::2] allPieces = self._popRemove(state, 'stack', 2 * count) if allPieces is None: state.assign('pc', doNotProceedPC) return argPiece = allPieces[0::2] okToProceed = True for arg in argPiece: okToProceed = ( self._8BitCheck("DELTAC", arg, logger) and okToProceed) if okToProceed: if argPiece != sorted(argPiece): logger.warning(( 'V0491', (self.ultParent.infoString, state.pc + self.ultDelta), "The DELTAC opcode in %s (PC %d) has args unsorted " "by PPEM. They should be sorted if this font is " "to be used with iType.")) cvtPiece = allPieces[1::2] missing = sorted( n for x in cvtPiece for n in toCollection(x) if n not in state.cvt) if missing: logger.error(( 'E6005', (self.ultParent.infoString, state.pc + self.ultDelta, missing), "For DELTAC opcode in %s (PC %d), these " "CVT indices are not present in CVT table: %s")) state._validationFailed = True thisHint = self.ultParent thisPC = state.pc + self.ultDelta for i, cvtIndex in enumerate(cvtPiece): he = historyPiece[i] stats.addHistory('cvt', cvtIndex, he) stats.noteEffect( 'cvt', cvtIndex, thisHint.infoString, thisPC, 2 * (i - count)) else: logger.warning(( 'V0490', (self.ultParent.infoString, state.pc + self.ultDelta), "DELTAC opcode in %s (PC %d) has a specification count " "of zero, meaning it's being used as a pseudo-NOP.")) fatObj = kwArgs.get('fdefArgTracer', None) if fatObj is not None: fatObj.notePop(None, 'DELTAC') for i in range(count): fatObj.notePop('cvtIndex', 'DELTAC') fatObj.notePop('deltaArg', 'DELTAC') state.assign('pc', state.pc + 1)
def hint_RS(self, **kwArgs): """ RS: Read storage, opcode 0x43 >>> logger = utilities.makeDoctestLogger("RS_test") >>> _popSync, _testingState = _testFuncs() >>> h = _testingState(toCollection([2, 5, 19]), 5) >>> h.state.storage[5] = 10 >>> h.state.changed('storage') >>> hint_RS(h, logger=logger) >>> len(h.state.stack) == len(h.state.pushHistory) True >>> h.state.statistics.maxima.storage 5 >>> _popSync(h.state) 10 >>> h.state.statistics.pprint(keys=('storage',)) History for storage locations: 5: Extra index 1 in PUSH opcode index 0 in test >>> hint_RS(h, logger=logger) >>> h.state.statistics.pprint(keys=('storage',)) History for storage locations: 2: Extra index 0 in PUSH opcode index 0 in test 5: Extra index 0 in PUSH opcode index 0 in test Extra index 1 in PUSH opcode index 0 in test 19: Extra index 0 in PUSH opcode index 0 in test >>> _popSync(h.state) Singles: [0, 10] >>> hint_RS(h, logger=logger) RS_test - CRITICAL - Stack underflow in test (PC 2). """ state = self.state stats = state.statistics store = state.storage logger = self._getLogger(**kwArgs) index = self._popRemove(state, 'stack', coerceToCollection=True) if index is None: state.assign('pc', doNotProceedPC) return history = self._popRemove(state, 'pushHistory') if history is None: state.assign('pc', doNotProceedPC) return it = iter(index) n = toCollection(store.get(next(it), 0)) for i in it: n = n.addToCollection(store.get(i, 0)) n2 = n.toNumber() if n2 is not None: n = n2 state.append('stack', n) stats.addHistory('storage', index, history) stats.noteEffect('storage', index, self.ultParent.infoString, state.pc + self.ultDelta, -1) state.append('pushHistory', self._synthStorageHistory(index)) state.assign('pc', state.pc + 1) fatObj = kwArgs.get('fdefArgTracer', None) if fatObj is not None: fatObj.notePop('storageIndex', 'RS') fatObj.notePush()
def hint_MSIRP(self, **kwArgs): """ MSIRP: Move stack indirect relative point, opcodes 0x3A-0x3B >>> logger = utilities.makeDoctestLogger("MSIRP_test") >>> _popSync, _testingState = _testFuncs() >>> h = _testingState(7, -32, 12, 3, 64) >>> m = h.state.statistics.maxima >>> hint_MSIRP(h, logger=logger) >>> len(h.state.stack) == len(h.state.pushHistory) True >>> m.point 3 >>> hint_srp0.hint_SRP0(h, logger=logger) >>> hint_MSIRP(h, logger=logger) >>> m.point 12 >>> h.state.statistics.pprint(keys=('point',)) History for outline points (glyph zone): 0: Implicit zero for RP0 used at opcode index 0 in test 3: Extra index 3 in PUSH opcode index 0 in test 7: Extra index 0 in PUSH opcode index 0 in test 12: Extra index 2 in PUSH opcode index 0 in test >>> hint_MSIRP(h, logger=logger) MSIRP_test - CRITICAL - Stack underflow in test (PC 3). """ state = self.state gs = state.graphicsState logger = self._getLogger(**kwArgs) distance = self._popRemove(state, 'stack', coerceToCollection=True) if distance is None: state.assign('pc', doNotProceedPC) return distance = distance.changedBasis(1) point = self._popRemove(state, 'stack', coerceToCollection=True) if point is None: state.assign('pc', doNotProceedPC) return history = self._popRemove(state, 'pushHistory', 2) if history is None: state.assign('pc', doNotProceedPC) return history = history[0] if (None not in distance) and any(n < -16384 or n >= 16384 for n in distance): logger.error(( 'E6019', (self.ultParent.infoString, state.pc + self.ultDelta), "MSIRP opcode in %s (PC %d) has out-of-range FUnit distance.")) state._validationFailed = True elif self._zoneCheck("MSIRP", (0, 1), logger): zp0, zp1 = gs.zonePointer0, gs.zonePointer1 v = [ (zp1, point, True), (zp0, toCollection(gs.referencePoint0), False)] if self._pointCheck( "MSIRP", v, logger, kwArgs.get('extraInfo', {})): state.statistics.addHistory( 'pointMoved', (zp1, point), history) refHist = self._synthRefHistory(0) state.statistics.addHistory( 'point', (zp0, gs.referencePoint0), refHist) if kwArgs.get('setRP0', False): state.assignDeep('graphicsState', 'referencePoint0', point) state.refPtHistory[0] = history state.changed('refPtHistory') if 'fdefEntryStack' in kwArgs: # We only note graphicsState effects when a # FDEF stack is available state.statistics.noteGSEffect( tuple(kwArgs['fdefEntryStack']), state.pc + self.ultDelta) fatObj = kwArgs.get('fdefArgTracer', None) if fatObj is not None: fatObj.notePop(None, 'MSIRP') fatObj.notePop('pointIndex', 'MSIRP') state.assign('pc', state.pc + 1)
class GraphicsState(object): """ Objects representing the graphics state used during interpretation of TrueType hints. """ # # Initialization method # def __init__(self, setAllAttrs=True): """ Creates a graphics state with all values at their default initial values. >>> gs = GraphicsState() >>> gs.roundState [Singles: [1.0], Singles: [0.0], Singles: [0.5]] >>> gs.scanControl 0 """ if setAllAttrs: d = self.__dict__ kd = self.keyData self._stamps = dict.fromkeys(kd, -1) self._stamper = stamp.Stamper() for key, t in kd.items(): d[key] = t[KEYINIT]() # # Class methods # @classmethod def fromargs(cls, **kwArgs): """ Class method that can be used as an alternative constructor when actual values (as opposed to defaults) are needed. >>> g = GraphicsState.fromargs(loop=19) >>> g.loop, g.autoFlip (19, True) """ r = GraphicsState() r.__dict__.update(kwArgs) return r # # Special methods # # def __copy__(self): # r = GraphicsState(setAllAttrs=False) # r.__dict__ = self.__dict__.copy() # return r def __deepcopy__(self, memo=None): r = GraphicsState(setAllAttrs=False) r._stamps = self._stamps.copy() # NOT DEEP r._stamper = self._stamper d = self.__dict__ rd = r.__dict__ for k, t in self.keyData.items(): rd[k] = t[KEYDEEPCOPY](d[k]) return r def __eq__(self, other): """ Returns True if the two GraphicsState objects are equal. This method only compares items whose stamps differ, to gain speed. >>> t1 = GraphicsState() >>> t2 = t1.__deepcopy__() >>> t1 == t2 True >>> t1.assign('deltaShift', 2) >>> t1 == t2 False >>> t1.assign('deltaShift', 3) >>> t1 == t2 True """ if self is other: return True dSelf = self.__dict__ dOther = other.__dict__ if self._stamper is other._stamper: selfStamps = self._stamps otherStamps = other._stamps for k in dSelf: if k[0] != '_': if selfStamps[k] != otherStamps[k]: # Only do actual comparison if stamps differ if dSelf[k] != dOther[k]: return False return True return all(dSelf[k] == dOther[k] for k in self.keyData) # def __ne__(self, other): return self is not other and self.__dict__ != other.__dict__ # # Public methods # # def asDict(self): # """ # Sometimes it's useful to have the contents of a GraphicsState object as # a dict. Remember, though, for regular processing the object and # attribute approach is much, much faster. # # >>> g = GraphicsState() # >>> d = g.asDict() # >>> for key in sorted(d): print(key, d[key]) # autoFlip True # cvtCutIn Singles: [1.0625] # deltaBase 9 # deltaShift 3 # dualVector (Singles: [1.0], Singles: [0.0]) # freedomVector (Singles: [1.0], Singles: [0.0]) # instructControl 0 # loop 1 # minimumDistance Singles: [1.0] # projectionVector (Singles: [1.0], Singles: [0.0]) # referencePoint0 0 # referencePoint1 0 # referencePoint2 0 # roundState [Singles: [1.0], Singles: [0.0], Singles: [0.5]] # scanControl 0 # scanType 0 # singleWidthCutIn Singles: [1.0] # singleWidthValue 0 # zonePointer0 1 # zonePointer1 1 # zonePointer2 1 # """ # # return self.__dict__.copy() def asImmutable(self): """ Returns an immutable version of the object. """ kd = self.keyData d = self.__dict__ v = [] for k in self.sortedKeys: t = kd[k] v.append((k, t[KEYASIMMUTABLE](d[k]))) return tuple(v) def assign(self, key, value): """ Sets the specified value, adjusting stamps if needed. """ d = self.__dict__ if d[key] != value: d[key] = value d['_stamps'][key] = d['_stamper'].stamp() def changed(self, key): """ This method is called when a client changes one of the attributes; it updates the stamp for that attribute. """ self._stamps[key] = self._stamper.stamp() def combine(self, other): """ Merges other into self. >>> g1 = GraphicsState() >>> g2 = GraphicsState.fromargs(deltaBase=12, freedomVector=yAxis) >>> g1.combine(g2) >>> g1.pprint() Auto-flip: True CVT cut-in: Singles: [1.0625] DELTA base: Singles: [9, 12] DELTA shift: 3 Dual projection vector: (Singles: [1], Singles: [0]) Freedom vector: (Ranges: [(*, *, 1, phase=0)], Ranges: [(*, *, 1, phase=0)]) Instruction control: 0 Loop counter: 1 Minimum distance: Singles: [1.0] Projection vector: (Singles: [1], Singles: [0]) Reference point 0: 0 Reference point 1: 0 Reference point 2: 0 Round state: [Singles: [1.0], Singles: [0.0], Singles: [0.5]] Scan control: 0 Scan type: 0 Single width cut-in: Singles: [1.0] Single width value: 0 Zone pointer 0: 1 Zone pointer 1: 1 Zone pointer 2: 1 """ dSelf = self.__dict__ dOther = other.__dict__ selfStamps = dSelf['_stamps'] kd = self.keyData if dSelf['_stamper'] is dOther['_stamper']: otherStamps = dOther['_stamps'] for k in kd: if selfStamps[k] == otherStamps[k]: continue valueSelf = dSelf[k] valueOther = dOther[k] if valueSelf is valueOther or valueSelf == valueOther: continue dSelf[k] = kd[k][KEYCOMBINE](valueSelf, valueOther) selfStamps[k] = dSelf['_stamper'].stamp() else: for k in kd: valueSelf = dSelf[k] valueOther = dOther[k] if valueSelf is valueOther or valueSelf == valueOther: continue dSelf[k] = kd[k][KEYCOMBINE](valueSelf, valueOther) selfStamps[k] = dSelf['_stamper'].stamp() def merged(self, other): """ Returns a new GraphicsState object whose contents are the merger of the contents of the two input GraphicsState objects, creating Collections where needed. >>> g1 = GraphicsState() >>> g2 = GraphicsState.fromargs(deltaBase=12, freedomVector=yAxis) >>> g1.merged(g2).pprint() Auto-flip: True CVT cut-in: Singles: [1.0625] DELTA base: Singles: [9, 12] DELTA shift: 3 Dual projection vector: (Singles: [1], Singles: [0]) Freedom vector: (Ranges: [(*, *, 1, phase=0)], Ranges: [(*, *, 1, phase=0)]) Instruction control: 0 Loop counter: 1 Minimum distance: Singles: [1.0] Projection vector: (Singles: [1], Singles: [0]) Reference point 0: 0 Reference point 1: 0 Reference point 2: 0 Round state: [Singles: [1.0], Singles: [0.0], Singles: [0.5]] Scan control: 0 Scan type: 0 Single width cut-in: Singles: [1.0] Single width value: 0 Zone pointer 0: 1 Zone pointer 1: 1 Zone pointer 2: 1 """ r = self.__deepcopy__() r.combine(other) return r def pprint(self, **kwArgs): """ Pretty-prints the object to the specified stream. Two keyword arguments are used: indent How many spaces to indent on left (default 0) keys Which keys to report (default all) stream Stream to receive output (default sys.stdout) >>> g = GraphicsState() >>> g.pprint() Auto-flip: True CVT cut-in: Singles: [1.0625] DELTA base: 9 DELTA shift: 3 Dual projection vector: (Singles: [1], Singles: [0]) Freedom vector: (Singles: [1], Singles: [0]) Instruction control: 0 Loop counter: 1 Minimum distance: Singles: [1.0] Projection vector: (Singles: [1], Singles: [0]) Reference point 0: 0 Reference point 1: 0 Reference point 2: 0 Round state: [Singles: [1.0], Singles: [0.0], Singles: [0.5]] Scan control: 0 Scan type: 0 Single width cut-in: Singles: [1.0] Single width value: 0 Zone pointer 0: 1 Zone pointer 1: 1 Zone pointer 2: 1 >>> g.pprint(indent=3, keys=('loop', 'autoFlip')) Loop counter: 1 Auto-flip: True """ p = pp.PP(**kwArgs) f = p.simple d = self.__dict__ kd = self.keyData for k in kwArgs.get('keys', self.sortedKeys): if k[0] != '_': f(d[k], kd[k][KEYLABEL]) def pprint_changes(self, prior, **kwArgs): """ Prints nothing if the two objects are equal. Otherwise prints a label (if specified) and what changed. Keyword arguments used are: indent How many spaces to indent on left (default 0) indentDelta Extra spaces per new indent (default 2) keys Which keys to report (default all) label Header label (no default) stream Stream to receive output (default sys.stdout) >>> gs1 = GraphicsState() >>> gs2 = GraphicsState.fromargs(loop=4, freedomVector=yAxis, zonePointer1=0) >>> gs2.pprint_changes(gs1) Freedom vector changed from (Singles: [1], Singles: [0]) to (Singles: [0], Singles: [1]) Loop counter changed from 1 to 4 Zone pointer 1 changed from 1 to 0 >>> gs2.pprint_changes(gs1, label="Graphics state changes", keys=('loop',)) Graphics state changes: Loop counter changed from 1 to 4 """ p = pp.PP(**kwArgs) f = p.diff dSelf = self.__dict__ dPrior = prior.__dict__ kd = self.keyData for k in kwArgs.get('keys', self.sortedKeys): selfValue = dSelf[k] priorValue = dPrior[k] if selfValue != priorValue: f(selfValue, priorValue, kd[k][KEYLABEL]) # # Dispatch table # # keyData is a dict of tuples, indexed by key: # [0] label # [1] item initialization function (no args) # [2] item combine function (two args) # [3] item deepcopy function (one arg) # [4] item asImmutable function (one arg) f = functools.partial c = collection.cluster idem = lambda x: x asImm = lambda x: collection.toCollection(x).asImmutable() asImmSeq = (lambda x: tuple( collection.toCollection(obj).asImmutable() for obj in x)) keyData = { 'autoFlip': ("Auto-flip", lambda: True, lambda x, y: collection.toCollection([0, 1]), idem, asImm), 'cvtCutIn': ("CVT cut-in", lambda: cvtCutInDefault26Dot6, f(c, coerceToNumber=False), idem, asImm), 'deltaBase': ("DELTA base", lambda: 9, c, idem, asImm), 'deltaShift': ("DELTA shift", lambda: 3, c, idem, asImm), 'dualVector': ("Dual projection vector", lambda: xAxis, _seqCombine_special, idem, asImmSeq), 'freedomVector': ("Freedom vector", lambda: xAxis, _seqCombine_special, idem, asImmSeq), 'instructControl': ("Instruction control", lambda: 0, c, idem, asImm), 'loop': ("Loop counter", lambda: 1, c, idem, asImm), 'minimumDistance': ("Minimum distance", lambda: one26Dot6, c, idem, asImm), 'projectionVector': ("Projection vector", lambda: xAxis, _seqCombine_special, idem, asImmSeq), 'referencePoint0': ("Reference point 0", lambda: 0, c, idem, asImm), 'referencePoint1': ("Reference point 1", lambda: 0, c, idem, asImm), 'referencePoint2': ("Reference point 2", lambda: 0, c, idem, asImm), 'roundState': ("Round state", lambda: [one26Dot6, zero26Dot6, half26Dot6], f(_seqCombine_list, n=3), list, asImmSeq), 'scanControl': ("Scan control", lambda: 0, c, idem, asImm), 'scanType': ("Scan type", lambda: 0, c, idem, asImm), 'singleWidthCutIn': ("Single width cut-in", lambda: one26Dot6, f(c, coerceToNumber=False), idem, asImm), 'singleWidthValue': ( "Single width value", lambda: 0, # 0 is FUnits, not 26.6 c, idem, asImm), 'zonePointer0': ("Zone pointer 0", lambda: 1, c, idem, asImm), 'zonePointer1': ("Zone pointer 1", lambda: 1, c, idem, asImm), 'zonePointer2': ("Zone pointer 2", lambda: 1, c, idem, asImm) } sortedKeys = sorted(keyData) del f, c, idem, asImm, asImmSeq