1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/animator/SkScriptTokenizer.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1506 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2011 Google Inc. 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 +#include "SkScript2.h" 1.12 +#include "SkData.h" 1.13 +#include "SkFloatingPoint.h" 1.14 +#include "SkMath.h" 1.15 +#include "SkParse.h" 1.16 +#include "SkScriptCallBack.h" 1.17 +#include "SkScriptRuntime.h" 1.18 +#include "SkString.h" 1.19 +#include "SkOpArray.h" 1.20 + 1.21 +const SkScriptEngine2::OperatorAttributes SkScriptEngine2::gOpAttributes[] = { 1.22 +{ SkOperand2::kNoType, SkOperand2::kNoType, kNoBias, kResultIsNotBoolean }, 1.23 +{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), 1.24 + SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), kTowardsString, kResultIsNotBoolean }, // kAdd 1.25 +{ SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kBitAnd 1.26 +{ SkOperand2::kNoType, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kBitNot 1.27 +{ SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kBitOr 1.28 +{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), 1.29 + SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias, kResultIsNotBoolean }, // kDivide 1.30 +{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), 1.31 + SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar |SkOperand2:: kString), kTowardsNumber, 1.32 + kResultIsBoolean }, // kEqual 1.33 +{ SkOperand2::kS32, SkOperand2::kNoType, kNoBias, kResultIsNotBoolean }, // kFlipOps 1.34 +{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), 1.35 + SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), kTowardsNumber, 1.36 + kResultIsBoolean }, // kGreaterEqual 1.37 +{ SkOperand2::kNoType, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kLogicalAnd (really, ToBool) 1.38 +{ SkOperand2::kNoType, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kLogicalNot 1.39 +{ SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kLogicalOr 1.40 +{ SkOperand2::kNoType, SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias, kResultIsNotBoolean }, // kMinus 1.41 +{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), 1.42 + SkOperand2::OpType(SkOperand2::kS32 |SkOperand2:: kScalar), kNoBias, kResultIsNotBoolean }, // kModulo 1.43 +{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), 1.44 + SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias, kResultIsNotBoolean }, // kMultiply 1.45 +{ SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kShiftLeft 1.46 +{ SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kShiftRight 1.47 +{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), 1.48 + SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias, kResultIsNotBoolean }, // kSubtract 1.49 +{ SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean } // kXor 1.50 +}; 1.51 + 1.52 +#define kBracketPrecedence 16 1.53 +#define kIfElsePrecedence 15 1.54 + 1.55 +const signed char SkScriptEngine2::gPrecedence[] = { 1.56 + 17, // kUnassigned, 1.57 + 6, // kAdd, 1.58 + 10, // kBitAnd, 1.59 + 4, // kBitNot, 1.60 + 12, // kBitOr, 1.61 + 5, // kDivide, 1.62 + 9, // kEqual, 1.63 + -1, // kFlipOps, 1.64 + 8, // kGreaterEqual, 1.65 + 13, // kLogicalAnd, 1.66 + 4, // kLogicalNot, 1.67 + 14, // kLogicalOr, 1.68 + 4, // kMinus, 1.69 + 5, // kModulo, 1.70 + 5, // kMultiply, 1.71 + 7, // kShiftLeft, 1.72 + 7, // kShiftRight, // signed 1.73 + 6, // kSubtract, 1.74 + 11, // kXor 1.75 + kBracketPrecedence, // kArrayOp 1.76 + kIfElsePrecedence, // kElse 1.77 + kIfElsePrecedence, // kIf 1.78 + kBracketPrecedence, // kParen 1.79 +}; 1.80 + 1.81 +const SkScriptEngine2::TypeOp SkScriptEngine2::gTokens[] = { 1.82 + kNop, // unassigned 1.83 + kAddInt, // kAdd, 1.84 + kBitAndInt, // kBitAnd, 1.85 + kBitNotInt, // kBitNot, 1.86 + kBitOrInt, // kBitOr, 1.87 + kDivideInt, // kDivide, 1.88 + kEqualInt, // kEqual, 1.89 + kFlipOpsOp, // kFlipOps, 1.90 + kGreaterEqualInt, // kGreaterEqual, 1.91 + kLogicalAndInt, // kLogicalAnd, 1.92 + kLogicalNotInt, // kLogicalNot, 1.93 + kLogicalOrInt, // kLogicalOr, 1.94 + kMinusInt, // kMinus, 1.95 + kModuloInt, // kModulo, 1.96 + kMultiplyInt, // kMultiply, 1.97 + kShiftLeftInt, // kShiftLeft, 1.98 + kShiftRightInt, // kShiftRight, // signed 1.99 + kSubtractInt, // kSubtract, 1.100 + kXorInt // kXor 1.101 +}; 1.102 + 1.103 +static inline bool is_between(int c, int min, int max) 1.104 +{ 1.105 + return (unsigned)(c - min) <= (unsigned)(max - min); 1.106 +} 1.107 + 1.108 +static inline bool is_ws(int c) 1.109 +{ 1.110 + return is_between(c, 1, 32); 1.111 +} 1.112 + 1.113 +static int token_length(const char* start) { 1.114 + char ch = start[0]; 1.115 + if (! is_between(ch, 'a' , 'z') && ! is_between(ch, 'A', 'Z') && ch != '_' && ch != '$') 1.116 + return -1; 1.117 + int length = 0; 1.118 + do 1.119 + ch = start[++length]; 1.120 + while (is_between(ch, 'a' , 'z') || is_between(ch, 'A', 'Z') || is_between(ch, '0', '9') || 1.121 + ch == '_' || ch == '$'); 1.122 + return length; 1.123 +} 1.124 + 1.125 +SkScriptEngine2::SkScriptEngine2(SkOperand2::OpType returnType) : fActiveStream(&fStream), 1.126 +fTokenLength(0), fReturnType(returnType), fError(kNoError), 1.127 +fAccumulatorType(SkOperand2::kNoType), 1.128 +fBranchPopAllowed(true), fConstExpression(true), fOperandInUse(false) 1.129 +{ 1.130 + Branch branch(kUnassigned, 0, 0); 1.131 + fBranchStack.push(branch); 1.132 + *fOpStack.push() = (Op) kParen; 1.133 +} 1.134 + 1.135 +SkScriptEngine2::~SkScriptEngine2() { 1.136 + for (SkString** stringPtr = fTrackString.begin(); stringPtr < fTrackString.end(); stringPtr++) 1.137 + delete *stringPtr; 1.138 + for (SkOpArray** arrayPtr = fTrackArray.begin(); arrayPtr < fTrackArray.end(); arrayPtr++) 1.139 + delete *arrayPtr; 1.140 +} 1.141 + 1.142 +void SkScriptEngine2::addToken(SkScriptEngine2::TypeOp op) { 1.143 + int limit = fBranchStack.count() - 1; 1.144 + for (int index = 0; index < limit; index++) { 1.145 + Branch& branch = fBranchStack.index(index); 1.146 + if (branch.fPrimed == Branch::kIsPrimed) 1.147 + resolveBranch(branch); 1.148 + } 1.149 + if (fBranchPopAllowed) { 1.150 + while (fBranchStack.top().fDone == Branch::kIsDone) 1.151 + fBranchStack.pop(); 1.152 + } 1.153 + unsigned char charOp = (unsigned char) op; 1.154 + fActiveStream->write(&charOp, sizeof(charOp)); 1.155 +} 1.156 + 1.157 +void SkScriptEngine2::addTokenConst(SkScriptValue2* value, AddTokenRegister reg, 1.158 + SkOperand2::OpType toType, SkScriptEngine2::TypeOp op) { 1.159 + if (value->fIsConstant == SkScriptValue2::kConstant && convertTo(toType, value)) 1.160 + return; 1.161 + addTokenValue(*value, reg); 1.162 + addToken(op); 1.163 + value->fIsWritten = SkScriptValue2::kWritten; 1.164 + value->fType = toType; 1.165 +} 1.166 + 1.167 +void SkScriptEngine2::addTokenInt(int integer) { 1.168 + fActiveStream->write(&integer, sizeof(integer)); 1.169 +} 1.170 + 1.171 +void SkScriptEngine2::addTokenScalar(SkScalar scalar) { 1.172 + fActiveStream->write(&scalar, sizeof(scalar)); 1.173 +} 1.174 + 1.175 +void SkScriptEngine2::addTokenString(const SkString& string) { 1.176 + int size = string.size(); 1.177 + addTokenInt(size); 1.178 + fActiveStream->write(string.c_str(), size); 1.179 +} 1.180 + 1.181 +void SkScriptEngine2::addTokenValue(const SkScriptValue2& value, AddTokenRegister reg) { 1.182 + if (value.isConstant() == false) { 1.183 + if (reg == kAccumulator) { 1.184 + if (fAccumulatorType == SkOperand2::kNoType) 1.185 + addToken(kAccumulatorPop); 1.186 + } else { 1.187 + ; // !!! incomplete? 1.188 + } 1.189 + return; 1.190 + } 1.191 + if (reg == kAccumulator && fAccumulatorType != SkOperand2::kNoType) 1.192 + addToken(kAccumulatorPush); 1.193 + switch (value.fType) { 1.194 + case SkOperand2::kS32: 1.195 + addToken(reg == kAccumulator ? kIntegerAccumulator : kIntegerOperand); 1.196 + addTokenInt(value.fOperand.fS32); 1.197 + if (reg == kAccumulator) 1.198 + fAccumulatorType = SkOperand2::kS32; 1.199 + else 1.200 + fOperandInUse = true; 1.201 + break; 1.202 + case SkOperand2::kScalar: 1.203 + addToken(reg == kAccumulator ? kScalarAccumulator : kScalarOperand); 1.204 + addTokenScalar(value.fOperand.fScalar); 1.205 + if (reg == kAccumulator) 1.206 + fAccumulatorType = SkOperand2::kScalar; 1.207 + else 1.208 + fOperandInUse = true; 1.209 + break; 1.210 + case SkOperand2::kString: 1.211 + addToken(reg == kAccumulator ? kStringAccumulator : kStringOperand); 1.212 + addTokenString(*value.fOperand.fString); 1.213 + if (reg == kAccumulator) 1.214 + fAccumulatorType = SkOperand2::kString; 1.215 + else 1.216 + fOperandInUse = true; 1.217 + break; 1.218 + default: 1.219 + SkASSERT(0); //!!! not implemented yet 1.220 + } 1.221 +} 1.222 + 1.223 +int SkScriptEngine2::arithmeticOp(char ch, char nextChar, bool lastPush) { 1.224 + Op op = kUnassigned; 1.225 + bool reverseOperands = false; 1.226 + bool negateResult = false; 1.227 + int advance = 1; 1.228 + switch (ch) { 1.229 + case '+': 1.230 + // !!! ignoring unary plus as implemented here has the side effect of 1.231 + // suppressing errors like +"hi" 1.232 + if (lastPush == false) // unary plus, don't push an operator 1.233 + return advance; 1.234 + op = kAdd; 1.235 + break; 1.236 + case '-': 1.237 + op = lastPush ? kSubtract : kMinus; 1.238 + break; 1.239 + case '*': 1.240 + op = kMultiply; 1.241 + break; 1.242 + case '/': 1.243 + op = kDivide; 1.244 + break; 1.245 + case '>': 1.246 + if (nextChar == '>') { 1.247 + op = kShiftRight; 1.248 + goto twoChar; 1.249 + } 1.250 + op = kGreaterEqual; 1.251 + if (nextChar == '=') 1.252 + goto twoChar; 1.253 + reverseOperands = negateResult = true; 1.254 + break; 1.255 + case '<': 1.256 + if (nextChar == '<') { 1.257 + op = kShiftLeft; 1.258 + goto twoChar; 1.259 + } 1.260 + op = kGreaterEqual; 1.261 + reverseOperands = nextChar == '='; 1.262 + negateResult = ! reverseOperands; 1.263 + advance += reverseOperands; 1.264 + break; 1.265 + case '=': 1.266 + if (nextChar == '=') { 1.267 + op = kEqual; 1.268 + goto twoChar; 1.269 + } 1.270 + break; 1.271 + case '!': 1.272 + if (nextChar == '=') { 1.273 + op = kEqual; 1.274 + negateResult = true; 1.275 +twoChar: 1.276 + advance++; 1.277 + break; 1.278 + } 1.279 + op = kLogicalNot; 1.280 + break; 1.281 + case '?': 1.282 + op =(Op) kIf; 1.283 + break; 1.284 + case ':': 1.285 + op = (Op) kElse; 1.286 + break; 1.287 + case '^': 1.288 + op = kXor; 1.289 + break; 1.290 + case '(': 1.291 + *fOpStack.push() = (Op) kParen; 1.292 + return advance; 1.293 + case '&': 1.294 + SkASSERT(nextChar != '&'); 1.295 + op = kBitAnd; 1.296 + break; 1.297 + case '|': 1.298 + SkASSERT(nextChar != '|'); 1.299 + op = kBitOr; 1.300 + break; 1.301 + case '%': 1.302 + op = kModulo; 1.303 + break; 1.304 + case '~': 1.305 + op = kBitNot; 1.306 + break; 1.307 + } 1.308 + if (op == kUnassigned) 1.309 + return 0; 1.310 + signed char precedence = gPrecedence[op]; 1.311 + do { 1.312 + int idx = 0; 1.313 + Op compare; 1.314 + do { 1.315 + compare = fOpStack.index(idx); 1.316 + if ((compare & kArtificialOp) == 0) 1.317 + break; 1.318 + idx++; 1.319 + } while (true); 1.320 + signed char topPrecedence = gPrecedence[compare]; 1.321 + SkASSERT(topPrecedence != -1); 1.322 + if (topPrecedence > precedence || (topPrecedence == precedence && 1.323 + gOpAttributes[op].fLeftType == SkOperand2::kNoType)) { 1.324 + break; 1.325 + } 1.326 + processOp(); 1.327 + } while (true); 1.328 + if (negateResult) 1.329 + *fOpStack.push() = (Op) (kLogicalNot | kArtificialOp); 1.330 + fOpStack.push(op); 1.331 + if (reverseOperands) 1.332 + *fOpStack.push() = (Op) (kFlipOps | kArtificialOp); 1.333 + 1.334 + return advance; 1.335 +} 1.336 + 1.337 +bool SkScriptEngine2::convertParams(SkTDArray<SkScriptValue2>* params, 1.338 + const SkOperand2::OpType* paramTypes, int paramCount) { 1.339 + int count = params->count(); 1.340 + if (count > paramCount) { 1.341 + SkASSERT(0); 1.342 + return false; // too many parameters passed 1.343 + } 1.344 + for (int index = 0; index < count; index++) 1.345 + convertTo(paramTypes[index], &(*params)[index]); 1.346 + return true; 1.347 +} 1.348 + 1.349 +bool SkScriptEngine2::convertTo(SkOperand2::OpType toType, SkScriptValue2* value ) { 1.350 + SkOperand2::OpType type = value->fType; 1.351 + if (type == toType) 1.352 + return true; 1.353 + if (type == SkOperand2::kObject) { 1.354 + if (handleUnbox(value) == false) 1.355 + return false; 1.356 + return convertTo(toType, value); 1.357 + } 1.358 + return ConvertTo(this, toType, value); 1.359 +} 1.360 + 1.361 +bool SkScriptEngine2::evaluateDot(const char*& script) { 1.362 + size_t fieldLength = token_length(++script); // skip dot 1.363 + SkASSERT(fieldLength > 0); // !!! add error handling 1.364 + const char* field = script; 1.365 + script += fieldLength; 1.366 + bool success = handleProperty(); 1.367 + if (success == false) { 1.368 + fError = kCouldNotFindReferencedID; 1.369 + goto error; 1.370 + } 1.371 + return evaluateDotParam(script, field, fieldLength); 1.372 +error: 1.373 + return false; 1.374 +} 1.375 + 1.376 +bool SkScriptEngine2::evaluateDotParam(const char*& script, const char* field, size_t fieldLength) { 1.377 + SkScriptValue2& top = fValueStack.top(); 1.378 + if (top.fType != SkOperand2::kObject) 1.379 + return false; 1.380 + void* object = top.fOperand.fObject; 1.381 + fValueStack.pop(); 1.382 + char ch; // see if it is a simple member or a function 1.383 + while (is_ws(ch = script[0])) 1.384 + script++; 1.385 + bool success = true; 1.386 + if (ch != '(') 1.387 + success = handleMember(field, fieldLength, object); 1.388 + else { 1.389 + SkTDArray<SkScriptValue2> params; 1.390 + *fBraceStack.push() = kFunctionBrace; 1.391 + success = functionParams(&script, ¶ms); 1.392 + if (success) 1.393 + success = handleMemberFunction(field, fieldLength, object, ¶ms); 1.394 + } 1.395 + return success; 1.396 +} 1.397 + 1.398 +bool SkScriptEngine2::evaluateScript(const char** scriptPtr, SkScriptValue2* value) { 1.399 + // fArrayOffset = 0; // no support for structures for now 1.400 + bool success; 1.401 + const char* inner; 1.402 + if (strncmp(*scriptPtr, "#script:", sizeof("#script:") - 1) == 0) { 1.403 + *scriptPtr += sizeof("#script:") - 1; 1.404 + if (fReturnType == SkOperand2::kNoType || fReturnType == SkOperand2::kString) { 1.405 + success = innerScript(scriptPtr, value); 1.406 + SkASSERT(success); 1.407 + inner = value->fOperand.fString->c_str(); 1.408 + scriptPtr = &inner; 1.409 + } 1.410 + } 1.411 + success = innerScript(scriptPtr, value); 1.412 + const char* script = *scriptPtr; 1.413 + char ch; 1.414 + while (is_ws(ch = script[0])) 1.415 + script++; 1.416 + if (ch != '\0') { 1.417 + // error may trigger on scripts like "50,0" that were intended to be written as "[50, 0]" 1.418 + return false; 1.419 + } 1.420 + return success; 1.421 +} 1.422 + 1.423 +void SkScriptEngine2::forget(SkOpArray* array) { 1.424 + if (array->getType() == SkOperand2::kString) { 1.425 + for (int index = 0; index < array->count(); index++) { 1.426 + SkString* string = (*array)[index].fString; 1.427 + int found = fTrackString.find(string); 1.428 + if (found >= 0) 1.429 + fTrackString.remove(found); 1.430 + } 1.431 + return; 1.432 + } 1.433 + if (array->getType() == SkOperand2::kArray) { 1.434 + for (int index = 0; index < array->count(); index++) { 1.435 + SkOpArray* child = (*array)[index].fArray; 1.436 + forget(child); // forgets children of child 1.437 + int found = fTrackArray.find(child); 1.438 + if (found >= 0) 1.439 + fTrackArray.remove(found); 1.440 + } 1.441 + } 1.442 +} 1.443 + 1.444 +bool SkScriptEngine2::functionParams(const char** scriptPtr, SkTDArray<SkScriptValue2>* params) { 1.445 + (*scriptPtr)++; // skip open paren 1.446 + *fOpStack.push() = (Op) kParen; 1.447 + *fBraceStack.push() = kFunctionBrace; 1.448 + do { 1.449 + SkScriptValue2 value; 1.450 + bool success = innerScript(scriptPtr, &value); 1.451 + SkASSERT(success); 1.452 + if (success == false) 1.453 + return false; 1.454 + *params->append() = value; 1.455 + } while ((*scriptPtr)[-1] == ','); 1.456 + fBraceStack.pop(); 1.457 + fOpStack.pop(); // pop paren 1.458 + (*scriptPtr)++; // advance beyond close paren 1.459 + return true; 1.460 +} 1.461 + 1.462 +size_t SkScriptEngine2::getTokenOffset() { 1.463 + return fActiveStream->getOffset(); 1.464 +} 1.465 + 1.466 +SkOperand2::OpType SkScriptEngine2::getUnboxType(SkOperand2 scriptValue) { 1.467 + for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) { 1.468 + if ((*callBack)->getType() != SkScriptCallBack::kUnbox) 1.469 + continue; 1.470 + return (*callBack)->getReturnType(0, &scriptValue); 1.471 + } 1.472 + return SkOperand2::kObject; 1.473 +} 1.474 + 1.475 +bool SkScriptEngine2::innerScript(const char** scriptPtr, SkScriptValue2* value) { 1.476 + const char* script = *scriptPtr; 1.477 + char ch; 1.478 + bool lastPush = false; 1.479 + bool success = true; 1.480 + int opBalance = fOpStack.count(); 1.481 + int baseBrace = fBraceStack.count(); 1.482 + int branchBalance = fBranchStack.count(); 1.483 + while ((ch = script[0]) != '\0') { 1.484 + if (is_ws(ch)) { 1.485 + script++; 1.486 + continue; 1.487 + } 1.488 + SkScriptValue2 operand; 1.489 + const char* dotCheck; 1.490 + if (fBraceStack.count() > baseBrace) { 1.491 + if (fBraceStack.top() == kArrayBrace) { 1.492 + SkScriptValue2 tokenValue; 1.493 + success = innerScript(&script, &tokenValue); // terminate and return on comma, close brace 1.494 + SkASSERT(success); 1.495 + { 1.496 + SkOperand2::OpType type = fReturnType; 1.497 + if (fReturnType == SkOperand2::kNoType) { 1.498 + // !!! short sighted; in the future, allow each returned array component to carry 1.499 + // its own type, and let caller do any needed conversions 1.500 + if (value->fOperand.fArray->count() == 0) 1.501 + value->fOperand.fArray->setType(type = tokenValue.fType); 1.502 + else 1.503 + type = value->fOperand.fArray->getType(); 1.504 + } 1.505 + if (tokenValue.fType != type) 1.506 + convertTo(type, &tokenValue); 1.507 + *value->fOperand.fArray->append() = tokenValue.fOperand; 1.508 + } 1.509 + lastPush = false; 1.510 + continue; 1.511 + } else { 1.512 + SkASSERT(token_length(script) > 0); 1.513 + } 1.514 + } 1.515 + if (lastPush != false && fTokenLength > 0) { 1.516 + if (ch == '(') { 1.517 + *fBraceStack.push() = kFunctionBrace; 1.518 + SkString functionName(fToken, fTokenLength); 1.519 + 1.520 + if (handleFunction(&script) == false) 1.521 + return false; 1.522 + lastPush = true; 1.523 + continue; 1.524 + } else if (ch == '[') { 1.525 + if (handleProperty() == false) { 1.526 + SkASSERT(0); 1.527 + return false; 1.528 + } 1.529 + if (handleArrayIndexer(&script) == false) 1.530 + return false; 1.531 + lastPush = true; 1.532 + continue; 1.533 + } else if (ch != '.') { 1.534 + if (handleProperty() == false) { 1.535 + SkASSERT(0); 1.536 + return false; 1.537 + } 1.538 + lastPush = true; 1.539 + continue; 1.540 + } 1.541 + } 1.542 + if (ch == '0' && (script[1] & ~0x20) == 'X') { 1.543 + SkASSERT(lastPush == false); 1.544 + script += 2; 1.545 + script = SkParse::FindHex(script, (uint32_t*) &operand.fOperand.fS32); 1.546 + SkASSERT(script); 1.547 + goto intCommon; 1.548 + } 1.549 + if (lastPush == false && ch == '.') 1.550 + goto scalarCommon; 1.551 + if (ch >= '0' && ch <= '9') { 1.552 + SkASSERT(lastPush == false); 1.553 + dotCheck = SkParse::FindS32(script, &operand.fOperand.fS32); 1.554 + if (dotCheck[0] != '.') { 1.555 + script = dotCheck; 1.556 +intCommon: 1.557 + operand.fType = SkOperand2::kS32; 1.558 + } else { 1.559 +scalarCommon: 1.560 + script = SkParse::FindScalar(script, &operand.fOperand.fScalar); 1.561 + operand.fType = SkOperand2::kScalar; 1.562 + } 1.563 + operand.fIsConstant = SkScriptValue2::kConstant; 1.564 + fValueStack.push(operand); 1.565 + lastPush = true; 1.566 + continue; 1.567 + } 1.568 + int length = token_length(script); 1.569 + if (length > 0) { 1.570 + SkASSERT(lastPush == false); 1.571 + fToken = script; 1.572 + fTokenLength = length; 1.573 + script += length; 1.574 + lastPush = true; 1.575 + continue; 1.576 + } 1.577 + char startQuote = ch; 1.578 + if (startQuote == '\'' || startQuote == '\"') { 1.579 + SkASSERT(lastPush == false); 1.580 + operand.fOperand.fString = new SkString(); 1.581 + ++script; 1.582 + const char* stringStart = script; 1.583 + do { // measure string 1.584 + if (script[0] == '\\') 1.585 + ++script; 1.586 + ++script; 1.587 + SkASSERT(script[0]); // !!! throw an error 1.588 + } while (script[0] != startQuote); 1.589 + operand.fOperand.fString->set(stringStart, script - stringStart); 1.590 + script = stringStart; 1.591 + char* stringWrite = operand.fOperand.fString->writable_str(); 1.592 + do { // copy string 1.593 + if (script[0] == '\\') 1.594 + ++script; 1.595 + *stringWrite++ = script[0]; 1.596 + ++script; 1.597 + SkASSERT(script[0]); // !!! throw an error 1.598 + } while (script[0] != startQuote); 1.599 + ++script; 1.600 + track(operand.fOperand.fString); 1.601 + operand.fType = SkOperand2::kString; 1.602 + operand.fIsConstant = SkScriptValue2::kConstant; 1.603 + fValueStack.push(operand); 1.604 + lastPush = true; 1.605 + continue; 1.606 + } 1.607 + if (ch == '.') { 1.608 + if (fTokenLength == 0) { 1.609 + int tokenLength = token_length(++script); 1.610 + const char* token = script; 1.611 + script += tokenLength; 1.612 + SkASSERT(fValueStack.count() > 0); // !!! add error handling 1.613 + SkScriptValue2 top; 1.614 + fValueStack.pop(&top); 1.615 + 1.616 + addTokenInt(top.fType); 1.617 + addToken(kBoxToken); 1.618 + top.fType = SkOperand2::kObject; 1.619 + top.fIsConstant = SkScriptValue2::kVariable; 1.620 + fConstExpression = false; 1.621 + fValueStack.push(top); 1.622 + success = evaluateDotParam(script, token, tokenLength); 1.623 + SkASSERT(success); 1.624 + lastPush = true; 1.625 + continue; 1.626 + } 1.627 + // get next token, and evaluate immediately 1.628 + success = evaluateDot(script); 1.629 + if (success == false) { 1.630 + // SkASSERT(0); 1.631 + return false; 1.632 + } 1.633 + lastPush = true; 1.634 + continue; 1.635 + } 1.636 + if (ch == '[') { 1.637 + if (lastPush == false) { 1.638 + script++; 1.639 + *fBraceStack.push() = kArrayBrace; 1.640 + operand.fOperand.fArray = value->fOperand.fArray = new SkOpArray(fReturnType); 1.641 + track(value->fOperand.fArray); 1.642 + 1.643 + operand.fType = SkOperand2::kArray; 1.644 + operand.fIsConstant = SkScriptValue2::kVariable; 1.645 + fValueStack.push(operand); 1.646 + continue; 1.647 + } 1.648 + if (handleArrayIndexer(&script) == false) 1.649 + return false; 1.650 + lastPush = true; 1.651 + continue; 1.652 + } 1.653 +#if 0 // structs not supported for now 1.654 + if (ch == '{') { 1.655 + if (lastPush == false) { 1.656 + script++; 1.657 + *fBraceStack.push() = kStructBrace; 1.658 + operand.fS32 = 0; 1.659 + *fTypeStack.push() = (SkOpType) kStruct; 1.660 + fOperandStack.push(operand); 1.661 + continue; 1.662 + } 1.663 + SkASSERT(0); // braces in other contexts aren't supported yet 1.664 + } 1.665 +#endif 1.666 + if (ch == ')' && fBraceStack.count() > 0) { 1.667 + BraceStyle braceStyle = fBraceStack.top(); 1.668 + if (braceStyle == kFunctionBrace) { 1.669 + fBraceStack.pop(); 1.670 + break; 1.671 + } 1.672 + } 1.673 + if (ch == ',' || ch == ']') { 1.674 + if (ch != ',') { 1.675 + BraceStyle match; 1.676 + fBraceStack.pop(&match); 1.677 + SkASSERT(match == kArrayBrace); 1.678 + } 1.679 + script++; 1.680 + // !!! see if brace or bracket is correct closer 1.681 + break; 1.682 + } 1.683 + char nextChar = script[1]; 1.684 + int advance = logicalOp(ch, nextChar); 1.685 + if (advance == 0) 1.686 + advance = arithmeticOp(ch, nextChar, lastPush); 1.687 + if (advance == 0) // unknown token 1.688 + return false; 1.689 + if (advance > 0) 1.690 + script += advance; 1.691 + lastPush = ch == ']' || ch == ')'; 1.692 + } 1.693 + if (fTokenLength > 0) { 1.694 + success = handleProperty(); 1.695 + SkASSERT(success); 1.696 + } 1.697 + int branchIndex = 0; 1.698 + branchBalance = fBranchStack.count() - branchBalance; 1.699 + fBranchPopAllowed = false; 1.700 + while (branchIndex < branchBalance) { 1.701 + Branch& branch = fBranchStack.index(branchIndex++); 1.702 + if (branch.fPrimed == Branch::kIsPrimed) 1.703 + break; 1.704 + Op branchOp = branch.fOperator; 1.705 + SkOperand2::OpType lastType = fValueStack.top().fType; 1.706 + addTokenValue(fValueStack.top(), kAccumulator); 1.707 + fValueStack.pop(); 1.708 + if (branchOp == kLogicalAnd || branchOp == kLogicalOr) { 1.709 + if (branch.fOperator == kLogicalAnd) 1.710 + branch.prime(); 1.711 + addToken(kToBool); 1.712 + } else { 1.713 + resolveBranch(branch); 1.714 + SkScriptValue2 operand; 1.715 + operand.fType = lastType; 1.716 + // !!! note that many branching expressions could be constant 1.717 + // today, we always evaluate branches as returning variables 1.718 + operand.fIsConstant = SkScriptValue2::kVariable; 1.719 + fValueStack.push(operand); 1.720 + } 1.721 + if (branch.fDone == Branch::kIsNotDone) 1.722 + branch.prime(); 1.723 + } 1.724 + fBranchPopAllowed = true; 1.725 + while (fBranchStack.top().fDone == Branch::kIsDone) 1.726 + fBranchStack.pop(); 1.727 + while (fOpStack.count() > opBalance) { // leave open paren 1.728 + if (processOp() == false) 1.729 + return false; 1.730 + } 1.731 + SkOperand2::OpType topType = fValueStack.count() > 0 ? fValueStack.top().fType : SkOperand2::kNoType; 1.732 + if (topType != fReturnType && 1.733 + topType == SkOperand2::kString && fReturnType != SkOperand2::kNoType) { // if result is a string, give handle property a chance to convert it to the property value 1.734 + SkString* string = fValueStack.top().fOperand.fString; 1.735 + fToken = string->c_str(); 1.736 + fTokenLength = string->size(); 1.737 + fValueStack.pop(); 1.738 + success = handleProperty(); 1.739 + if (success == false) { // if it couldn't convert, return string (error?) 1.740 + SkScriptValue2 operand; 1.741 + operand.fType = SkOperand2::kString; 1.742 + operand.fOperand.fString = string; 1.743 + operand.fIsConstant = SkScriptValue2::kVariable; // !!! ? 1.744 + fValueStack.push(operand); 1.745 + } 1.746 + } 1.747 + if (fStream.getOffset() > 0) { 1.748 + addToken(kEnd); 1.749 + SkAutoDataUnref data(fStream.copyToData()); 1.750 +#ifdef SK_DEBUG 1.751 + decompile(data->bytes(), data->size()); 1.752 +#endif 1.753 + SkScriptRuntime runtime(fCallBackArray); 1.754 + runtime.executeTokens((unsigned char*) data->bytes()); 1.755 + SkScriptValue2 value1; 1.756 + runtime.getResult(&value1.fOperand); 1.757 + value1.fType = fReturnType; 1.758 + fValueStack.push(value1); 1.759 + } 1.760 + if (value) { 1.761 + if (fValueStack.count() == 0) 1.762 + return false; 1.763 + fValueStack.pop(value); 1.764 + if (value->fType != fReturnType && value->fType == SkOperand2::kObject && 1.765 + fReturnType != SkOperand2::kNoType) 1.766 + convertTo(fReturnType, value); 1.767 + } 1.768 + // if (fBranchStack.top().fOpStackDepth > fOpStack.count()) 1.769 + // resolveBranch(); 1.770 + *scriptPtr = script; 1.771 + return true; // no error 1.772 +} 1.773 + 1.774 +bool SkScriptEngine2::handleArrayIndexer(const char** scriptPtr) { 1.775 + SkScriptValue2 scriptValue; 1.776 + (*scriptPtr)++; 1.777 + *fOpStack.push() = (Op) kParen; 1.778 + *fBraceStack.push() = kArrayBrace; 1.779 + SkOperand2::OpType saveType = fReturnType; 1.780 + fReturnType = SkOperand2::kS32; 1.781 + bool success = innerScript(scriptPtr, &scriptValue); 1.782 + fReturnType = saveType; 1.783 + SkASSERT(success); 1.784 + success = convertTo(SkOperand2::kS32, &scriptValue); 1.785 + SkASSERT(success); 1.786 + int index = scriptValue.fOperand.fS32; 1.787 + fValueStack.pop(&scriptValue); 1.788 + if (scriptValue.fType == SkOperand2::kObject) { 1.789 + success = handleUnbox(&scriptValue); 1.790 + SkASSERT(success); 1.791 + SkASSERT(scriptValue.fType == SkOperand2::kArray); 1.792 + } 1.793 + scriptValue.fType = scriptValue.fOperand.fArray->getType(); 1.794 + // SkASSERT(index >= 0); 1.795 + if ((unsigned) index >= (unsigned) scriptValue.fOperand.fArray->count()) { 1.796 + fError = kArrayIndexOutOfBounds; 1.797 + return false; 1.798 + } 1.799 + scriptValue.fOperand = scriptValue.fOperand.fArray->begin()[index]; 1.800 + scriptValue.fIsConstant = SkScriptValue2::kVariable; 1.801 + fValueStack.push(scriptValue); 1.802 + fOpStack.pop(); // pop paren 1.803 + return success; 1.804 +} 1.805 + 1.806 +bool SkScriptEngine2::handleFunction(const char** scriptPtr) { 1.807 + const char* functionName = fToken; 1.808 + size_t functionNameLen = fTokenLength; 1.809 + fTokenLength = 0; 1.810 + SkTDArray<SkScriptValue2> params; 1.811 + bool success = functionParams(scriptPtr, ¶ms); 1.812 + if (success == false) 1.813 + goto done; 1.814 + { 1.815 + for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) { 1.816 + if ((*callBack)->getType() != SkScriptCallBack::kFunction) 1.817 + continue; 1.818 + SkScriptValue2 callbackResult; 1.819 + success = (*callBack)->getReference(functionName, functionNameLen, &callbackResult); 1.820 + if (success) { 1.821 + callbackResult.fType = (*callBack)->getReturnType(callbackResult.fOperand.fReference, NULL); 1.822 + callbackResult.fIsConstant = SkScriptValue2::kVariable; 1.823 + fValueStack.push(callbackResult); 1.824 + goto done; 1.825 + } 1.826 + } 1.827 + } 1.828 + return false; 1.829 +done: 1.830 + fOpStack.pop(); 1.831 + return success; 1.832 +} 1.833 + 1.834 +bool SkScriptEngine2::handleMember(const char* field, size_t len, void* object) { 1.835 + bool success = true; 1.836 + for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) { 1.837 + if ((*callBack)->getType() != SkScriptCallBack::kMember) 1.838 + continue; 1.839 + SkScriptValue2 callbackResult; 1.840 + success = (*callBack)->getReference(field, len, &callbackResult); 1.841 + if (success) { 1.842 + if (callbackResult.fType == SkOperand2::kString) 1.843 + track(callbackResult.fOperand.fString); 1.844 + callbackResult.fIsConstant = SkScriptValue2::kVariable; 1.845 + fValueStack.push(callbackResult); 1.846 + goto done; 1.847 + } 1.848 + } 1.849 + return false; 1.850 +done: 1.851 + return success; 1.852 +} 1.853 + 1.854 +bool SkScriptEngine2::handleMemberFunction(const char* field, size_t len, void* object, 1.855 + SkTDArray<SkScriptValue2>* params) { 1.856 + bool success = true; 1.857 + for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) { 1.858 + if ((*callBack)->getType() != SkScriptCallBack::kMemberFunction) 1.859 + continue; 1.860 + SkScriptValue2 callbackResult; 1.861 + success = (*callBack)->getReference(field, len, &callbackResult); 1.862 + if (success) { 1.863 + if (callbackResult.fType == SkOperand2::kString) 1.864 + track(callbackResult.fOperand.fString); 1.865 + callbackResult.fIsConstant = SkScriptValue2::kVariable; 1.866 + fValueStack.push(callbackResult); 1.867 + goto done; 1.868 + } 1.869 + } 1.870 + return false; 1.871 +done: 1.872 + return success; 1.873 +} 1.874 + 1.875 +bool SkScriptEngine2::handleProperty() { 1.876 + bool success = true; 1.877 + for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) { 1.878 + if ((*callBack)->getType() != SkScriptCallBack::kProperty) 1.879 + continue; 1.880 + SkScriptValue2 callbackResult; 1.881 + success = (*callBack)->getReference(fToken, fTokenLength, &callbackResult); 1.882 + if (success) { 1.883 + if (callbackResult.fType == SkOperand2::kString && callbackResult.fOperand.fString == NULL) { 1.884 + callbackResult.fOperand.fString = new SkString(fToken, fTokenLength); 1.885 + track(callbackResult.fOperand.fString); 1.886 + } 1.887 + callbackResult.fIsConstant = SkScriptValue2::kVariable; 1.888 + fValueStack.push(callbackResult); 1.889 + goto done; 1.890 + } 1.891 + } 1.892 +done: 1.893 + fTokenLength = 0; 1.894 + return success; 1.895 +} 1.896 + 1.897 +bool SkScriptEngine2::handleUnbox(SkScriptValue2* scriptValue) { 1.898 + bool success = true; 1.899 + for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) { 1.900 + if ((*callBack)->getType() != SkScriptCallBack::kUnbox) 1.901 + continue; 1.902 + SkScriptCallBackConvert* callBackConvert = (SkScriptCallBackConvert*) *callBack; 1.903 + success = callBackConvert->convert(scriptValue->fType, &scriptValue->fOperand); 1.904 + if (success) { 1.905 + if (scriptValue->fType == SkOperand2::kString) 1.906 + track(scriptValue->fOperand.fString); 1.907 + goto done; 1.908 + } 1.909 + } 1.910 + return false; 1.911 +done: 1.912 + return success; 1.913 +} 1.914 + 1.915 +// note that entire expression is treated as if it were enclosed in parens 1.916 +// an open paren is always the first thing in the op stack 1.917 + 1.918 +int SkScriptEngine2::logicalOp(char ch, char nextChar) { 1.919 + int advance = 1; 1.920 + Op op; 1.921 + signed char precedence; 1.922 + switch (ch) { 1.923 + case ')': 1.924 + op = (Op) kParen; 1.925 + break; 1.926 + case ']': 1.927 + op = (Op) kArrayOp; 1.928 + break; 1.929 + case '?': 1.930 + op = (Op) kIf; 1.931 + break; 1.932 + case ':': 1.933 + op = (Op) kElse; 1.934 + break; 1.935 + case '&': 1.936 + if (nextChar != '&') 1.937 + goto noMatch; 1.938 + op = kLogicalAnd; 1.939 + advance = 2; 1.940 + break; 1.941 + case '|': 1.942 + if (nextChar != '|') 1.943 + goto noMatch; 1.944 + op = kLogicalOr; 1.945 + advance = 2; 1.946 + break; 1.947 + default: 1.948 + noMatch: 1.949 + return 0; 1.950 + } 1.951 + precedence = gPrecedence[op]; 1.952 + int branchIndex = 0; 1.953 + fBranchPopAllowed = false; 1.954 + do { 1.955 + while (gPrecedence[fOpStack.top() & ~kArtificialOp] < precedence) 1.956 + processOp(); 1.957 + Branch& branch = fBranchStack.index(branchIndex++); 1.958 + Op branchOp = branch.fOperator; 1.959 + if (gPrecedence[branchOp] >= precedence) 1.960 + break; 1.961 + addTokenValue(fValueStack.top(), kAccumulator); 1.962 + fValueStack.pop(); 1.963 + if (branchOp == kLogicalAnd || branchOp == kLogicalOr) { 1.964 + if (branch.fOperator == kLogicalAnd) 1.965 + branch.prime(); 1.966 + addToken(kToBool); 1.967 + } else 1.968 + resolveBranch(branch); 1.969 + if (branch.fDone == Branch::kIsNotDone) 1.970 + branch.prime(); 1.971 + } while (true); 1.972 + fBranchPopAllowed = true; 1.973 + while (fBranchStack.top().fDone == Branch::kIsDone) 1.974 + fBranchStack.pop(); 1.975 + processLogicalOp(op); 1.976 + return advance; 1.977 +} 1.978 + 1.979 +void SkScriptEngine2::processLogicalOp(Op op) { 1.980 + switch (op) { 1.981 + case kParen: 1.982 + case kArrayOp: 1.983 + SkASSERT(fOpStack.count() > 1 && fOpStack.top() == op); // !!! add error handling 1.984 + if (op == kParen) 1.985 + fOpStack.pop(); 1.986 + else { 1.987 + SkScriptValue2 value; 1.988 + fValueStack.pop(&value); 1.989 + SkASSERT(value.fType == SkOperand2::kS32 || value.fType == SkOperand2::kScalar); // !!! add error handling (although, could permit strings eventually) 1.990 + int index = value.fType == SkOperand2::kScalar ? SkScalarFloorToInt(value.fOperand.fScalar) : 1.991 + value.fOperand.fS32; 1.992 + SkScriptValue2 arrayValue; 1.993 + fValueStack.pop(&arrayValue); 1.994 + SkASSERT(arrayValue.fType == SkOperand2::kArray); // !!! add error handling 1.995 + SkOpArray* array = arrayValue.fOperand.fArray; 1.996 + SkOperand2 operand; 1.997 + SkDEBUGCODE(bool success = ) array->getIndex(index, &operand); 1.998 + SkASSERT(success); // !!! add error handling 1.999 + SkScriptValue2 resultValue; 1.1000 + resultValue.fType = array->getType(); 1.1001 + resultValue.fOperand = operand; 1.1002 + resultValue.fIsConstant = SkScriptValue2::kVariable; 1.1003 + fValueStack.push(resultValue); 1.1004 + } 1.1005 + break; 1.1006 + case kIf: { 1.1007 + if (fAccumulatorType == SkOperand2::kNoType) { 1.1008 + addTokenValue(fValueStack.top(), kAccumulator); 1.1009 + fValueStack.pop(); 1.1010 + } 1.1011 + SkASSERT(fAccumulatorType != SkOperand2::kString); // !!! add error handling 1.1012 + addToken(kIfOp); 1.1013 + Branch branch(op, fOpStack.count(), getTokenOffset()); 1.1014 + *fBranchStack.push() = branch; 1.1015 + addTokenInt(0); // placeholder for future branch 1.1016 + fAccumulatorType = SkOperand2::kNoType; 1.1017 + } break; 1.1018 + case kElse: { 1.1019 + addTokenValue(fValueStack.top(), kAccumulator); 1.1020 + fValueStack.pop(); 1.1021 + addToken(kElseOp); 1.1022 + size_t newOffset = getTokenOffset(); 1.1023 + addTokenInt(0); // placeholder for future branch 1.1024 + Branch& branch = fBranchStack.top(); 1.1025 + resolveBranch(branch); 1.1026 + branch.fOperator = op; 1.1027 + branch.fDone = Branch::kIsNotDone; 1.1028 + SkASSERT(branch.fOpStackDepth == fOpStack.count()); 1.1029 + branch.fOffset = newOffset; 1.1030 + fAccumulatorType = SkOperand2::kNoType; 1.1031 + } break; 1.1032 + case kLogicalAnd: 1.1033 + case kLogicalOr: { 1.1034 + Branch& oldTop = fBranchStack.top(); 1.1035 + Branch::Primed wasPrime = oldTop.fPrimed; 1.1036 + Branch::Done wasDone = oldTop.fDone; 1.1037 + oldTop.fPrimed = Branch::kIsNotPrimed; 1.1038 + oldTop.fDone = Branch::kIsNotDone; 1.1039 + if (fAccumulatorType == SkOperand2::kNoType) { 1.1040 + SkASSERT(fValueStack.top().fType == SkOperand2::kS32); // !!! add error handling, and conversion to int? 1.1041 + addTokenValue(fValueStack.top(), kAccumulator); 1.1042 + fValueStack.pop(); 1.1043 + } else { 1.1044 + SkASSERT(fAccumulatorType == SkOperand2::kS32); 1.1045 + } 1.1046 + // if 'and', write beq goto opcode after end of predicate (after to bool) 1.1047 + // if 'or', write bne goto to bool 1.1048 + addToken(op == kLogicalAnd ? kLogicalAndInt : kLogicalOrInt); 1.1049 + Branch branch(op, fOpStack.count(), getTokenOffset()); 1.1050 + addTokenInt(0); // placeholder for future branch 1.1051 + oldTop.fPrimed = wasPrime; 1.1052 + oldTop.fDone = wasDone; 1.1053 + *fBranchStack.push() = branch; 1.1054 + fAccumulatorType = SkOperand2::kNoType; 1.1055 + } break; 1.1056 + default: 1.1057 + SkASSERT(0); 1.1058 + } 1.1059 +} 1.1060 + 1.1061 +bool SkScriptEngine2::processOp() { 1.1062 + Op op; 1.1063 + fOpStack.pop(&op); 1.1064 + op = (Op) (op & ~kArtificialOp); 1.1065 + const OperatorAttributes* attributes = &gOpAttributes[op]; 1.1066 + SkScriptValue2 value1; 1.1067 + memset(&value1, 0, sizeof(SkScriptValue2)); 1.1068 + SkScriptValue2 value2; 1.1069 + fValueStack.pop(&value2); 1.1070 + value2.fIsWritten = SkScriptValue2::kUnwritten; 1.1071 + // SkScriptEngine2::SkTypeOp convert1[3]; 1.1072 + // SkScriptEngine2::SkTypeOp convert2[3]; 1.1073 + // SkScriptEngine2::SkTypeOp* convert2Ptr = convert2; 1.1074 + bool constantOperands = value2.fIsConstant == SkScriptValue2::kConstant; 1.1075 + if (attributes->fLeftType != SkOperand2::kNoType) { 1.1076 + fValueStack.pop(&value1); 1.1077 + constantOperands &= value1.fIsConstant == SkScriptValue2::kConstant; 1.1078 + value1.fIsWritten = SkScriptValue2::kUnwritten; 1.1079 + if (op == kFlipOps) { 1.1080 + SkTSwap(value1, value2); 1.1081 + fOpStack.pop(&op); 1.1082 + op = (Op) (op & ~kArtificialOp); 1.1083 + attributes = &gOpAttributes[op]; 1.1084 + if (constantOperands == false) 1.1085 + addToken(kFlipOpsOp); 1.1086 + } 1.1087 + if (value1.fType == SkOperand2::kObject && (value1.fType & attributes->fLeftType) == 0) { 1.1088 + value1.fType = getUnboxType(value1.fOperand); 1.1089 + addToken(kUnboxToken); 1.1090 + } 1.1091 + } 1.1092 + if (value2.fType == SkOperand2::kObject && (value2.fType & attributes->fLeftType) == 0) { 1.1093 + value1.fType = getUnboxType(value2.fOperand); 1.1094 + addToken(kUnboxToken2); 1.1095 + } 1.1096 + if (attributes->fLeftType != SkOperand2::kNoType) { 1.1097 + if (value1.fType != value2.fType) { 1.1098 + if ((attributes->fLeftType & SkOperand2::kString) && attributes->fBias & kTowardsString && 1.1099 + ((value1.fType | value2.fType) & SkOperand2::kString)) { 1.1100 + if (value1.fType == SkOperand2::kS32 || value1.fType == SkOperand2::kScalar) { 1.1101 + addTokenConst(&value1, kAccumulator, SkOperand2::kString, 1.1102 + value1.fType == SkOperand2::kS32 ? kIntToString : kScalarToString); 1.1103 + } 1.1104 + if (value2.fType == SkOperand2::kS32 || value2.fType == SkOperand2::kScalar) { 1.1105 + addTokenConst(&value2, kOperand, SkOperand2::kString, 1.1106 + value2.fType == SkOperand2::kS32 ? kIntToString2 : kScalarToString2); 1.1107 + } 1.1108 + } else if (attributes->fLeftType & SkOperand2::kScalar && ((value1.fType | value2.fType) & 1.1109 + SkOperand2::kScalar)) { 1.1110 + if (value1.fType == SkOperand2::kS32) 1.1111 + addTokenConst(&value1, kAccumulator, SkOperand2::kScalar, kIntToScalar); 1.1112 + if (value2.fType == SkOperand2::kS32) 1.1113 + addTokenConst(&value2, kOperand, SkOperand2::kScalar, kIntToScalar2); 1.1114 + } 1.1115 + } 1.1116 + if ((value1.fType & attributes->fLeftType) == 0 || value1.fType != value2.fType) { 1.1117 + if (value1.fType == SkOperand2::kString) 1.1118 + addTokenConst(&value1, kAccumulator, SkOperand2::kScalar, kStringToScalar); 1.1119 + if (value1.fType == SkOperand2::kScalar && (attributes->fLeftType == SkOperand2::kS32 || 1.1120 + value2.fType == SkOperand2::kS32)) 1.1121 + addTokenConst(&value1, kAccumulator, SkOperand2::kS32, kScalarToInt); 1.1122 + } 1.1123 + } 1.1124 + AddTokenRegister rhRegister = attributes->fLeftType != SkOperand2::kNoType ? 1.1125 + kOperand : kAccumulator; 1.1126 + if ((value2.fType & attributes->fRightType) == 0 || value1.fType != value2.fType) { 1.1127 + if (value2.fType == SkOperand2::kString) 1.1128 + addTokenConst(&value2, rhRegister, SkOperand2::kScalar, kStringToScalar2); 1.1129 + if (value2.fType == SkOperand2::kScalar && (attributes->fRightType == SkOperand2::kS32 || 1.1130 + value1.fType == SkOperand2::kS32)) 1.1131 + addTokenConst(&value2, rhRegister, SkOperand2::kS32, kScalarToInt2); 1.1132 + } 1.1133 + TypeOp typeOp = gTokens[op]; 1.1134 + if (value2.fType == SkOperand2::kScalar) 1.1135 + typeOp = (TypeOp) (typeOp + 1); 1.1136 + else if (value2.fType == SkOperand2::kString) 1.1137 + typeOp = (TypeOp) (typeOp + 2); 1.1138 + SkDynamicMemoryWStream stream; 1.1139 + SkOperand2::OpType saveType = SkOperand2::kNoType; 1.1140 + SkBool saveOperand = false; 1.1141 + if (constantOperands) { 1.1142 + fActiveStream = &stream; 1.1143 + saveType = fAccumulatorType; 1.1144 + saveOperand = fOperandInUse; 1.1145 + fAccumulatorType = SkOperand2::kNoType; 1.1146 + fOperandInUse = false; 1.1147 + } 1.1148 + if (attributes->fLeftType != SkOperand2::kNoType) { // two operands 1.1149 + if (value1.fIsWritten == SkScriptValue2::kUnwritten) 1.1150 + addTokenValue(value1, kAccumulator); 1.1151 + } 1.1152 + if (value2.fIsWritten == SkScriptValue2::kUnwritten) 1.1153 + addTokenValue(value2, rhRegister); 1.1154 + addToken(typeOp); 1.1155 + if (constantOperands) { 1.1156 + addToken(kEnd); 1.1157 + SkAutoDataUnref data(fStream.copyToData()); 1.1158 +#ifdef SK_DEBUG 1.1159 + decompile(data->bytes(), data->size()); 1.1160 +#endif 1.1161 + SkScriptRuntime runtime(fCallBackArray); 1.1162 + runtime.executeTokens((unsigned char*)data->bytes()); 1.1163 + runtime.getResult(&value1.fOperand); 1.1164 + if (attributes->fResultIsBoolean == kResultIsBoolean) 1.1165 + value1.fType = SkOperand2::kS32; 1.1166 + else if (attributes->fLeftType == SkOperand2::kNoType) // unary operand 1.1167 + value1.fType = value2.fType; 1.1168 + fValueStack.push(value1); 1.1169 + if (value1.fType == SkOperand2::kString) 1.1170 + runtime.untrack(value1.fOperand.fString); 1.1171 + else if (value1.fType == SkOperand2::kArray) 1.1172 + runtime.untrack(value1.fOperand.fArray); 1.1173 + fActiveStream = &fStream; 1.1174 + fAccumulatorType = saveType; 1.1175 + fOperandInUse = saveOperand; 1.1176 + return true; 1.1177 + } 1.1178 + value2.fIsConstant = SkScriptValue2::kVariable; 1.1179 + fValueStack.push(value2); 1.1180 + return true; 1.1181 +} 1.1182 + 1.1183 +void SkScriptEngine2::Branch::resolve(SkDynamicMemoryWStream* stream, size_t off) { 1.1184 + SkASSERT(fDone == kIsNotDone); 1.1185 + fPrimed = kIsNotPrimed; 1.1186 + fDone = kIsDone; 1.1187 + SkASSERT(off > fOffset + sizeof(size_t)); 1.1188 + size_t offset = off - fOffset - sizeof(offset); 1.1189 + stream->write(&offset, fOffset, sizeof(offset)); 1.1190 +} 1.1191 + 1.1192 +void SkScriptEngine2::resolveBranch(SkScriptEngine2::Branch& branch) { 1.1193 + branch.resolve(fActiveStream, getTokenOffset()); 1.1194 +} 1.1195 + 1.1196 +bool SkScriptEngine2::ConvertTo(SkScriptEngine2* engine, SkOperand2::OpType toType, SkScriptValue2* value ) { 1.1197 + SkASSERT(value); 1.1198 + SkOperand2::OpType type = value->fType; 1.1199 + if (type == toType) 1.1200 + return true; 1.1201 + SkOperand2& operand = value->fOperand; 1.1202 + bool success = true; 1.1203 + switch (toType) { 1.1204 + case SkOperand2::kS32: 1.1205 + if (type == SkOperand2::kScalar) 1.1206 + operand.fS32 = SkScalarFloorToInt(operand.fScalar); 1.1207 + else { 1.1208 + SkASSERT(type == SkOperand2::kString); 1.1209 + success = SkParse::FindS32(operand.fString->c_str(), &operand.fS32) != NULL; 1.1210 + } 1.1211 + break; 1.1212 + case SkOperand2::kScalar: 1.1213 + if (type == SkOperand2::kS32) 1.1214 + operand.fScalar = IntToScalar(operand.fS32); 1.1215 + else { 1.1216 + SkASSERT(type == SkOperand2::kString); 1.1217 + success = SkParse::FindScalar(operand.fString->c_str(), &operand.fScalar) != NULL; 1.1218 + } 1.1219 + break; 1.1220 + case SkOperand2::kString: { 1.1221 + SkString* strPtr = new SkString(); 1.1222 + SkASSERT(engine); 1.1223 + engine->track(strPtr); 1.1224 + if (type == SkOperand2::kS32) 1.1225 + strPtr->appendS32(operand.fS32); 1.1226 + else { 1.1227 + SkASSERT(type == SkOperand2::kScalar); 1.1228 + strPtr->appendScalar(operand.fScalar); 1.1229 + } 1.1230 + operand.fString = strPtr; 1.1231 + } break; 1.1232 + case SkOperand2::kArray: { 1.1233 + SkOpArray* array = new SkOpArray(type); 1.1234 + *array->append() = operand; 1.1235 + engine->track(array); 1.1236 + operand.fArray = array; 1.1237 + } break; 1.1238 + default: 1.1239 + SkASSERT(0); 1.1240 + } 1.1241 + value->fType = toType; 1.1242 + return success; 1.1243 +} 1.1244 + 1.1245 +SkScalar SkScriptEngine2::IntToScalar(int32_t s32) { 1.1246 + SkScalar scalar; 1.1247 + if (s32 == (int32_t) SK_NaN32) 1.1248 + scalar = SK_ScalarNaN; 1.1249 + else if (SkAbs32(s32) == SK_MaxS32) 1.1250 + scalar = SkSign32(s32) * SK_ScalarMax; 1.1251 + else 1.1252 + scalar = SkIntToScalar(s32); 1.1253 + return scalar; 1.1254 +} 1.1255 + 1.1256 +bool SkScriptEngine2::ValueToString(const SkScriptValue2& value, SkString* string) { 1.1257 + switch (value.fType) { 1.1258 + case SkOperand2::kS32: 1.1259 + string->reset(); 1.1260 + string->appendS32(value.fOperand.fS32); 1.1261 + break; 1.1262 + case SkOperand2::kScalar: 1.1263 + string->reset(); 1.1264 + string->appendScalar(value.fOperand.fScalar); 1.1265 + break; 1.1266 + case SkOperand2::kString: 1.1267 + string->set(*value.fOperand.fString); 1.1268 + break; 1.1269 + default: 1.1270 + SkASSERT(0); 1.1271 + return false; 1.1272 + } 1.1273 + return true; // no error 1.1274 +} 1.1275 + 1.1276 +#ifdef SK_DEBUG 1.1277 +#if defined(SK_SUPPORT_UNITTEST) 1.1278 + 1.1279 +#define testInt(expression) { #expression, SkOperand2::kS32, expression, 0, NULL } 1.1280 +#define testScalar(expression) { #expression, SkOperand2::kScalar, 0, (float) (expression), NULL } 1.1281 +#define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkOperand2::kScalar, 0, fmodf((float) exp1, (float) exp2), NULL } 1.1282 +#define testTrue(expression) { #expression, SkOperand2::kS32, 1, 0, NULL } 1.1283 +#define testFalse(expression) { #expression, SkOperand2::kS32, 0, 0, NULL } 1.1284 + 1.1285 +static const SkScriptNAnswer2 scriptTests[] = { 1.1286 + testInt(1||(0&&3)), 1.1287 + testScalar(- -5.5- -1.5), 1.1288 + testScalar(1.0+5), 1.1289 + testInt((6+7)*8), 1.1290 + testInt(3*(4+5)), 1.1291 + testScalar(1.0+2.0), 1.1292 + testScalar(3.0-1.0), 1.1293 + testScalar(6-1.0), 1.1294 + testScalar(2.5*6.), 1.1295 + testScalar(0.5*4), 1.1296 + testScalar(4.5/.5), 1.1297 + testScalar(9.5/19), 1.1298 + testRemainder(9.5, 0.5), 1.1299 + testRemainder(9.,2), 1.1300 + testRemainder(9,2.5), 1.1301 + testRemainder(-9,2.5), 1.1302 + testTrue(-9==-9.0), 1.1303 + testTrue(-9.==-4.0-5), 1.1304 + testTrue(-9.*1==-4-5), 1.1305 + testFalse(-9!=-9.0), 1.1306 + testFalse(-9.!=-4.0-5), 1.1307 + testFalse(-9.*1!=-4-5), 1.1308 + testInt(0x123), 1.1309 + testInt(0XABC), 1.1310 + testInt(0xdeadBEEF), 1.1311 + { "'123'+\"456\"", SkOperand2::kString, 0, 0, "123456" }, 1.1312 + { "123+\"456\"", SkOperand2::kString, 0, 0, "123456" }, 1.1313 + { "'123'+456", SkOperand2::kString, 0, 0, "123456" }, 1.1314 + { "'123'|\"456\"", SkOperand2::kS32, 123|456, 0, NULL }, 1.1315 + { "123|\"456\"", SkOperand2::kS32, 123|456, 0, NULL }, 1.1316 + { "'123'|456", SkOperand2::kS32, 123|456, 0, NULL }, 1.1317 + { "'2'<11", SkOperand2::kS32, 1, 0, NULL }, 1.1318 + { "2<'11'", SkOperand2::kS32, 1, 0, NULL }, 1.1319 + { "'2'<'11'", SkOperand2::kS32, 0, 0, NULL }, 1.1320 + testInt(123), 1.1321 + testInt(-345), 1.1322 + testInt(+678), 1.1323 + testInt(1+2+3), 1.1324 + testInt(3*4+5), 1.1325 + testInt(6+7*8), 1.1326 + testInt(-1-2-8/4), 1.1327 + testInt(-9%4), 1.1328 + testInt(9%-4), 1.1329 + testInt(-9%-4), 1.1330 + testInt(123|978), 1.1331 + testInt(123&978), 1.1332 + testInt(123^978), 1.1333 + testInt(2<<4), 1.1334 + testInt(99>>3), 1.1335 + testInt(~55), 1.1336 + testInt(~~55), 1.1337 + testInt(!55), 1.1338 + testInt(!!55), 1.1339 + // both int 1.1340 + testInt(2<2), 1.1341 + testInt(2<11), 1.1342 + testInt(20<11), 1.1343 + testInt(2<=2), 1.1344 + testInt(2<=11), 1.1345 + testInt(20<=11), 1.1346 + testInt(2>2), 1.1347 + testInt(2>11), 1.1348 + testInt(20>11), 1.1349 + testInt(2>=2), 1.1350 + testInt(2>=11), 1.1351 + testInt(20>=11), 1.1352 + testInt(2==2), 1.1353 + testInt(2==11), 1.1354 + testInt(20==11), 1.1355 + testInt(2!=2), 1.1356 + testInt(2!=11), 1.1357 + testInt(20!=11), 1.1358 + // left int, right scalar 1.1359 + testInt(2<2.), 1.1360 + testInt(2<11.), 1.1361 + testInt(20<11.), 1.1362 + testInt(2<=2.), 1.1363 + testInt(2<=11.), 1.1364 + testInt(20<=11.), 1.1365 + testInt(2>2.), 1.1366 + testInt(2>11.), 1.1367 + testInt(20>11.), 1.1368 + testInt(2>=2.), 1.1369 + testInt(2>=11.), 1.1370 + testInt(20>=11.), 1.1371 + testInt(2==2.), 1.1372 + testInt(2==11.), 1.1373 + testInt(20==11.), 1.1374 + testInt(2!=2.), 1.1375 + testInt(2!=11.), 1.1376 + testInt(20!=11.), 1.1377 + // left scalar, right int 1.1378 + testInt(2.<2), 1.1379 + testInt(2.<11), 1.1380 + testInt(20.<11), 1.1381 + testInt(2.<=2), 1.1382 + testInt(2.<=11), 1.1383 + testInt(20.<=11), 1.1384 + testInt(2.>2), 1.1385 + testInt(2.>11), 1.1386 + testInt(20.>11), 1.1387 + testInt(2.>=2), 1.1388 + testInt(2.>=11), 1.1389 + testInt(20.>=11), 1.1390 + testInt(2.==2), 1.1391 + testInt(2.==11), 1.1392 + testInt(20.==11), 1.1393 + testInt(2.!=2), 1.1394 + testInt(2.!=11), 1.1395 + testInt(20.!=11), 1.1396 + // both scalar 1.1397 + testInt(2.<11.), 1.1398 + testInt(20.<11.), 1.1399 + testInt(2.<=2.), 1.1400 + testInt(2.<=11.), 1.1401 + testInt(20.<=11.), 1.1402 + testInt(2.>2.), 1.1403 + testInt(2.>11.), 1.1404 + testInt(20.>11.), 1.1405 + testInt(2.>=2.), 1.1406 + testInt(2.>=11.), 1.1407 + testInt(20.>=11.), 1.1408 + testInt(2.==2.), 1.1409 + testInt(2.==11.), 1.1410 + testInt(20.==11.), 1.1411 + testInt(2.!=2.), 1.1412 + testInt(2.!=11.), 1.1413 + testInt(20.!=11.), 1.1414 + // int, string (string is int) 1.1415 + testFalse(2<'2'), 1.1416 + testTrue(2<'11'), 1.1417 + testFalse(20<'11'), 1.1418 + testTrue(2<='2'), 1.1419 + testTrue(2<='11'), 1.1420 + testFalse(20<='11'), 1.1421 + testFalse(2>'2'), 1.1422 + testFalse(2>'11'), 1.1423 + testTrue(20>'11'), 1.1424 + testTrue(2>='2'), 1.1425 + testFalse(2>='11'), 1.1426 + testTrue(20>='11'), 1.1427 + testTrue(2=='2'), 1.1428 + testFalse(2=='11'), 1.1429 + testFalse(2!='2'), 1.1430 + testTrue(2!='11'), 1.1431 + // int, string (string is scalar) 1.1432 + testFalse(2<'2.'), 1.1433 + testTrue(2<'11.'), 1.1434 + testFalse(20<'11.'), 1.1435 + testTrue(2=='2.'), 1.1436 + testFalse(2=='11.'), 1.1437 + // scalar, string 1.1438 + testFalse(2.<'2.'), 1.1439 + testTrue(2.<'11.'), 1.1440 + testFalse(20.<'11.'), 1.1441 + testTrue(2.=='2.'), 1.1442 + testFalse(2.=='11.'), 1.1443 + // string, int 1.1444 + testFalse('2'<2), 1.1445 + testTrue('2'<11), 1.1446 + testFalse('20'<11), 1.1447 + testTrue('2'==2), 1.1448 + testFalse('2'==11), 1.1449 + // string, scalar 1.1450 + testFalse('2'<2.), 1.1451 + testTrue('2'<11.), 1.1452 + testFalse('20'<11.), 1.1453 + testTrue('2'==2.), 1.1454 + testFalse('2'==11.), 1.1455 + // string, string 1.1456 + testFalse('2'<'2'), 1.1457 + testFalse('2'<'11'), 1.1458 + testFalse('20'<'11'), 1.1459 + testTrue('2'=='2'), 1.1460 + testFalse('2'=='11'), 1.1461 + // logic 1.1462 + testInt(1?2:3), 1.1463 + testInt(0?2:3), 1.1464 + testInt((1&&2)||3), 1.1465 + testInt((1&&0)||3), 1.1466 + testInt((1&&0)||0), 1.1467 + testInt(1||(0&&3)), 1.1468 + testInt(0||(0&&3)), 1.1469 + testInt(0||(1&&3)), 1.1470 + testInt(0&&1?2:3) 1.1471 + , { "123.5", SkOperand2::kScalar, 0, SkIntToScalar(123) + SK_Scalar1/2, NULL } 1.1472 +}; 1.1473 + 1.1474 +#define SkScriptNAnswer_testCount SK_ARRAY_COUNT(scriptTests) 1.1475 +#endif // SK_SUPPORT_UNITTEST 1.1476 + 1.1477 +void SkScriptEngine2::UnitTest() { 1.1478 +#if defined(SK_SUPPORT_UNITTEST) 1.1479 + ValidateDecompileTable(); 1.1480 + for (size_t index = 0; index < SkScriptNAnswer_testCount; index++) { 1.1481 + SkScriptEngine2 engine(scriptTests[index].fType); 1.1482 + SkScriptValue2 value; 1.1483 + const char* script = scriptTests[index].fScript; 1.1484 + const char* scriptPtr = script; 1.1485 + SkASSERT(engine.evaluateScript(&scriptPtr, &value) == true); 1.1486 + SkASSERT(value.fType == scriptTests[index].fType); 1.1487 + SkScalar error; 1.1488 + switch (value.fType) { 1.1489 + case SkOperand2::kS32: 1.1490 + if (value.fOperand.fS32 != scriptTests[index].fIntAnswer) 1.1491 + SkDEBUGF(("script '%s' == value %d != expected answer %d\n", script, value.fOperand.fS32, scriptTests[index].fIntAnswer)); 1.1492 + SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer); 1.1493 + break; 1.1494 + case SkOperand2::kScalar: 1.1495 + error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer); 1.1496 + if (error >= SK_Scalar1 / 10000) 1.1497 + SkDEBUGF(("script '%s' == value %g != expected answer %g\n", script, value.fOperand.fScalar / (1.0f * SK_Scalar1), scriptTests[index].fScalarAnswer / (1.0f * SK_Scalar1))); 1.1498 + SkASSERT(error < SK_Scalar1 / 10000); 1.1499 + break; 1.1500 + case SkOperand2::kString: 1.1501 + SkASSERT(value.fOperand.fString->equals(scriptTests[index].fStringAnswer)); 1.1502 + break; 1.1503 + default: 1.1504 + SkASSERT(0); 1.1505 + } 1.1506 + } 1.1507 +#endif // SK_SUPPORT_UNITTEST 1.1508 +} 1.1509 +#endif // SK_DEBUG