Home | History | Annotate | Download | only in animator
      1 
      2 /*
      3  * Copyright 2011 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 #include "SkScriptRuntime.h"
      9 #include "SkScript2.h"
     10 #include "SkMath.h"
     11 #include "SkParse.h"
     12 #include "SkScriptCallBack.h"
     13 #include "SkString.h"
     14 #include "SkOpArray.h"
     15 
     16 // script tokenizer
     17 
     18 // turn text into token string
     19 // turn number literals into inline UTF8-style values
     20 // process operators to turn standard notation into stack notation
     21 
     22 // defer processing until the tokens can all be resolved
     23 // then, turn token strings into indices into the appropriate tables / dictionaries
     24 
     25 // consider: const evaluation?
     26 
     27 // replace script string with script tokens preceeded by special value
     28 
     29 // need second version of script plugins that return private index of found value?
     30 	// then would need in script index of plugin, private index
     31 
     32 // encode brace stack push/pop as opcodes
     33 
     34 // should token script enocde type where possible?
     35 
     36 // current flow:
     37 	// strip whitespace
     38 	// if in array brace [ recurse, continue
     39 	// if token, handle function, or array, or property (continue)
     40 	// parse number, continue
     41 	// parse token, continue
     42 	// parse string literal, continue
     43 	// if dot operator, handle dot, continue
     44 	// if [ , handle array literal or accessor, continue
     45 	// if ), pop (if function, break)
     46 	// if ], pop ; if ',' break
     47 	// handle logical ops
     48 	// or, handle arithmetic ops
     49 	// loop
     50 
     51 // !!! things to do
     52 	// add separate processing loop to advance while suppressed
     53 	// or, include jump offset to skip suppressed code?
     54 
     55 SkScriptRuntime::~SkScriptRuntime() {
     56 	for (SkString** stringPtr = fTrackString.begin(); stringPtr < fTrackString.end(); stringPtr++)
     57 		delete *stringPtr;
     58 	for (SkOpArray** arrayPtr = fTrackArray.begin(); arrayPtr < fTrackArray.end(); arrayPtr++)
     59 		delete *arrayPtr;
     60 }
     61 
     62 bool SkScriptRuntime::executeTokens(unsigned char* opCode) {
     63 	SkOperand2 operand[2];	// 1=accumulator and 2=operand
     64 	SkScriptEngine2::TypeOp op;
     65 	size_t ref;
     66 	int index, size;
     67 	int registerLoad;
     68 	SkScriptCallBack* callBack SK_INIT_TO_AVOID_WARNING;
     69 	do {
     70 	switch ((op = (SkScriptEngine2::TypeOp) *opCode++)) {
     71 		case SkScriptEngine2::kArrayToken:	// create an array
     72 			operand[0].fArray = new SkOpArray(SkOperand2::kNoType /*fReturnType*/);
     73 			break;
     74 		case SkScriptEngine2::kArrayIndex:	// array accessor
     75 			index = operand[1].fS32;
     76 			if (index >= operand[0].fArray->count()) {
     77 				fError = kArrayIndexOutOfBounds;
     78 				return false;
     79 			}
     80 			operand[0] = operand[0].fArray->begin()[index];
     81 			break;
     82 		case SkScriptEngine2::kArrayParam:	// array initializer, or function param
     83 			*operand[0].fArray->append() = operand[1];
     84 			break;
     85 		case SkScriptEngine2::kCallback:
     86 			memcpy(&index, opCode, sizeof(index));
     87 			opCode += sizeof(index);
     88 			callBack = fCallBackArray[index];
     89 			break;
     90 		case SkScriptEngine2::kFunctionCall: {
     91 			memcpy(&ref, opCode, sizeof(ref));
     92 			opCode += sizeof(ref);
     93 			SkScriptCallBackFunction* callBackFunction = (SkScriptCallBackFunction*) callBack;
     94 			if (callBackFunction->invoke(ref, operand[0].fArray, /* params */
     95 					&operand[0] /* result */) == false) {
     96 				fError = kFunctionCallFailed;
     97 				return false;
     98 			}
     99 			} break;
    100 		case SkScriptEngine2::kMemberOp: {
    101 			memcpy(&ref, opCode, sizeof(ref));
    102 			opCode += sizeof(ref);
    103 			SkScriptCallBackMember* callBackMember = (SkScriptCallBackMember*) callBack;
    104 			if (callBackMember->invoke(ref, operand[0].fObject, &operand[0]) == false) {
    105 				fError = kMemberOpFailed;
    106 				return false;
    107 			}
    108 			} break;
    109 		case SkScriptEngine2::kPropertyOp: {
    110 			memcpy(&ref, opCode, sizeof(ref));
    111 			opCode += sizeof(ref);
    112 			SkScriptCallBackProperty* callBackProperty = (SkScriptCallBackProperty*) callBack;
    113 			if (callBackProperty->getResult(ref, &operand[0])== false) {
    114 				fError = kPropertyOpFailed;
    115 				return false;
    116 			}
    117 			} break;
    118 		case SkScriptEngine2::kAccumulatorPop:
    119 			fRunStack.pop(&operand[0]);
    120 			break;
    121 		case SkScriptEngine2::kAccumulatorPush:
    122 			*fRunStack.push() = operand[0];
    123 			break;
    124 		case SkScriptEngine2::kIntegerAccumulator:
    125 		case SkScriptEngine2::kIntegerOperand:
    126 			registerLoad = op - SkScriptEngine2::kIntegerAccumulator;
    127 			memcpy(&operand[registerLoad].fS32, opCode, sizeof(int32_t));
    128 			opCode += sizeof(int32_t);
    129 			break;
    130 		case SkScriptEngine2::kScalarAccumulator:
    131 		case SkScriptEngine2::kScalarOperand:
    132 			registerLoad = op - SkScriptEngine2::kScalarAccumulator;
    133 			memcpy(&operand[registerLoad].fScalar, opCode, sizeof(SkScalar));
    134 			opCode += sizeof(SkScalar);
    135 			break;
    136 		case SkScriptEngine2::kStringAccumulator:
    137 		case SkScriptEngine2::kStringOperand: {
    138 			SkString* strPtr = new SkString();
    139 			track(strPtr);
    140 			registerLoad = op - SkScriptEngine2::kStringAccumulator;
    141 			memcpy(&size, opCode, sizeof(size));
    142 			opCode += sizeof(size);
    143 			strPtr->set((char*) opCode, size);
    144 			opCode += size;
    145 			operand[registerLoad].fString = strPtr;
    146 			} break;
    147 		case SkScriptEngine2::kStringTrack: // call after kObjectToValue
    148 			track(operand[0].fString);
    149 			break;
    150 		case SkScriptEngine2::kBoxToken: {
    151 			SkOperand2::OpType type;
    152 			memcpy(&type, opCode, sizeof(type));
    153 			opCode += sizeof(type);
    154 			SkScriptCallBackConvert* callBackBox = (SkScriptCallBackConvert*) callBack;
    155 			if (callBackBox->convert(type, &operand[0]) == false)
    156 				return false;
    157 			} break;
    158 		case SkScriptEngine2::kUnboxToken:
    159 		case SkScriptEngine2::kUnboxToken2: {
    160 			SkScriptCallBackConvert* callBackUnbox = (SkScriptCallBackConvert*) callBack;
    161 			if (callBackUnbox->convert(SkOperand2::kObject, &operand[0]) == false)
    162 				return false;
    163 			} break;
    164 		case SkScriptEngine2::kIfOp:
    165 		case SkScriptEngine2::kLogicalAndInt:
    166 			memcpy(&size, opCode, sizeof(size));
    167 			opCode += sizeof(size);
    168 			if (operand[0].fS32 == 0)
    169 				opCode += size; // skip to else (or end of if predicate)
    170 			break;
    171 		case SkScriptEngine2::kElseOp:
    172 			memcpy(&size, opCode, sizeof(size));
    173 			opCode += sizeof(size);
    174 			opCode += size; // if true: after predicate, always skip to end of else
    175 			break;
    176 		case SkScriptEngine2::kLogicalOrInt:
    177 			memcpy(&size, opCode, sizeof(size));
    178 			opCode += sizeof(size);
    179 			if (operand[0].fS32 != 0)
    180 				opCode += size; // skip to kToBool opcode after || predicate
    181 			break;
    182 		// arithmetic conversion ops
    183 		case SkScriptEngine2::kFlipOpsOp:
    184 			SkTSwap(operand[0], operand[1]);
    185 			break;
    186 		case SkScriptEngine2::kIntToString:
    187 		case SkScriptEngine2::kIntToString2:
    188 		case SkScriptEngine2::kScalarToString:
    189 		case SkScriptEngine2::kScalarToString2:{
    190 			SkString* strPtr = new SkString();
    191 			track(strPtr);
    192 			if (op == SkScriptEngine2::kIntToString || op == SkScriptEngine2::kIntToString2)
    193 				strPtr->appendS32(operand[op - SkScriptEngine2::kIntToString].fS32);
    194 			else
    195 				strPtr->appendScalar(operand[op - SkScriptEngine2::kScalarToString].fScalar);
    196 			operand[0].fString = strPtr;
    197 			} break;
    198 		case SkScriptEngine2::kIntToScalar:
    199 		case SkScriptEngine2::kIntToScalar2:
    200 			operand[0].fScalar = SkScriptEngine2::IntToScalar(operand[op - SkScriptEngine2::kIntToScalar].fS32);
    201 			break;
    202 		case SkScriptEngine2::kStringToInt:
    203 			if (SkParse::FindS32(operand[0].fString->c_str(), &operand[0].fS32) == false)
    204 				return false;
    205 			break;
    206 		case SkScriptEngine2::kStringToScalar:
    207 		case SkScriptEngine2::kStringToScalar2:
    208 			if (SkParse::FindScalar(operand[0].fString->c_str(),
    209 					&operand[op - SkScriptEngine2::kStringToScalar].fScalar) == false)
    210 				return false;
    211 			break;
    212 		case SkScriptEngine2::kScalarToInt:
    213 			operand[0].fS32 = SkScalarFloor(operand[0].fScalar);
    214 			break;
    215 		// arithmetic ops
    216 		case SkScriptEngine2::kAddInt:
    217 			operand[0].fS32 += operand[1].fS32;
    218 			break;
    219 		case SkScriptEngine2::kAddScalar:
    220 			operand[0].fScalar += operand[1].fScalar;
    221 			break;
    222 		case SkScriptEngine2::kAddString:
    223 //			if (fTrackString.find(operand[1].fString) < 0) {
    224 //				operand[1].fString = SkNEW_ARGS(SkString, (*operand[1].fString));
    225 //				track(operand[1].fString);
    226 //			}
    227 			operand[0].fString->append(*operand[1].fString);
    228 			break;
    229 		case SkScriptEngine2::kBitAndInt:
    230 			operand[0].fS32 &= operand[1].fS32;
    231 			break;
    232 		case SkScriptEngine2::kBitNotInt:
    233 			operand[0].fS32 = ~operand[0].fS32;
    234 			break;
    235 		case SkScriptEngine2::kBitOrInt:
    236 			operand[0].fS32 |= operand[1].fS32;
    237 			break;
    238 		case SkScriptEngine2::kDivideInt:
    239 			SkASSERT(operand[1].fS32 != 0);
    240 			if (operand[1].fS32 == 0)
    241 				operand[0].fS32 = operand[0].fS32 == 0 ? SK_NaN32 :
    242 					operand[0].fS32 > 0 ? SK_MaxS32 : -SK_MaxS32;
    243 			else
    244 			if (operand[1].fS32 != 0) // throw error on divide by zero?
    245 				operand[0].fS32 /= operand[1].fS32;
    246 			break;
    247 		case SkScriptEngine2::kDivideScalar:
    248 			if (operand[1].fScalar == 0)
    249 				operand[0].fScalar = operand[0].fScalar == 0 ? SK_ScalarNaN :
    250 					operand[0].fScalar > 0 ? SK_ScalarMax : -SK_ScalarMax;
    251 			else
    252 				operand[0].fScalar = SkScalarDiv(operand[0].fScalar, operand[1].fScalar);
    253 			break;
    254 		case SkScriptEngine2::kEqualInt:
    255 			operand[0].fS32 = operand[0].fS32 == operand[1].fS32;
    256 			break;
    257 		case SkScriptEngine2::kEqualScalar:
    258 			operand[0].fS32 = operand[0].fScalar == operand[1].fScalar;
    259 			break;
    260 		case SkScriptEngine2::kEqualString:
    261 			operand[0].fS32 = *operand[0].fString == *operand[1].fString;
    262 			break;
    263 		case SkScriptEngine2::kGreaterEqualInt:
    264 			operand[0].fS32 = operand[0].fS32 >= operand[1].fS32;
    265 			break;
    266 		case SkScriptEngine2::kGreaterEqualScalar:
    267 			operand[0].fS32 = operand[0].fScalar >= operand[1].fScalar;
    268 			break;
    269 		case SkScriptEngine2::kGreaterEqualString:
    270 			operand[0].fS32 = strcmp(operand[0].fString->c_str(), operand[1].fString->c_str()) >= 0;
    271 			break;
    272 		case SkScriptEngine2::kToBool:
    273 			operand[0].fS32 = !! operand[0].fS32;
    274 			break;
    275 		case SkScriptEngine2::kLogicalNotInt:
    276 			operand[0].fS32 = ! operand[0].fS32;
    277 			break;
    278 		case SkScriptEngine2::kMinusInt:
    279 			operand[0].fS32 = -operand[0].fS32;
    280 			break;
    281 		case SkScriptEngine2::kMinusScalar:
    282 			operand[0].fScalar = -operand[0].fScalar;
    283 			break;
    284 		case SkScriptEngine2::kModuloInt:
    285 			operand[0].fS32 %= operand[1].fS32;
    286 			break;
    287 		case SkScriptEngine2::kModuloScalar:
    288 			operand[0].fScalar = SkScalarMod(operand[0].fScalar, operand[1].fScalar);
    289 			break;
    290 		case SkScriptEngine2::kMultiplyInt:
    291 			operand[0].fS32 *= operand[1].fS32;
    292 			break;
    293 		case SkScriptEngine2::kMultiplyScalar:
    294 			operand[0].fScalar = SkScalarMul(operand[0].fScalar, operand[1].fScalar);
    295 			break;
    296 		case SkScriptEngine2::kShiftLeftInt:
    297 			operand[0].fS32 <<= operand[1].fS32;
    298 			break;
    299 		case SkScriptEngine2::kShiftRightInt:
    300 			operand[0].fS32 >>= operand[1].fS32;
    301 			break;
    302 		case SkScriptEngine2::kSubtractInt:
    303 			operand[0].fS32 -= operand[1].fS32;
    304 			break;
    305 		case SkScriptEngine2::kSubtractScalar:
    306 			operand[0].fScalar -= operand[1].fScalar;
    307 			break;
    308 		case SkScriptEngine2::kXorInt:
    309 			operand[0].fS32 ^= operand[1].fS32;
    310 			break;
    311 		case SkScriptEngine2::kEnd:
    312 			goto done;
    313 		case SkScriptEngine2::kNop:
    314 				SkASSERT(0);
    315     default:
    316         break;
    317 	}
    318 	} while (true);
    319 done:
    320 	fRunStack.push(operand[0]);
    321 	return true;
    322 }
    323 
    324 bool SkScriptRuntime::getResult(SkOperand2* result) {
    325 	if (fRunStack.count() == 0)
    326 		return false;
    327 	fRunStack.pop(result);
    328 	return true;
    329 }
    330 
    331 void SkScriptRuntime::track(SkOpArray* array) {
    332 	SkASSERT(fTrackArray.find(array) < 0);
    333 	*fTrackArray.append() = array;
    334 }
    335 
    336 void SkScriptRuntime::track(SkString* string) {
    337 	SkASSERT(fTrackString.find(string) < 0);
    338 	*fTrackString.append() = string;
    339 }
    340 
    341 void SkScriptRuntime::untrack(SkOpArray* array) {
    342 	int index = fTrackArray.find(array);
    343 	SkASSERT(index >= 0);
    344 	fTrackArray.begin()[index] = NULL;
    345 }
    346 
    347 void SkScriptRuntime::untrack(SkString* string) {
    348 	int index = fTrackString.find(string);
    349 	SkASSERT(index >= 0);
    350 	fTrackString.begin()[index] = NULL;
    351 }
    352 
    353