gfx/skia/trunk/src/animator/SkScript.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1
michael@0 2 /*
michael@0 3 * Copyright 2006 The Android Open Source Project
michael@0 4 *
michael@0 5 * Use of this source code is governed by a BSD-style license that can be
michael@0 6 * found in the LICENSE file.
michael@0 7 */
michael@0 8
michael@0 9
michael@0 10 #include "SkScript.h"
michael@0 11 #include "SkMath.h"
michael@0 12 #include "SkParse.h"
michael@0 13 #include "SkString.h"
michael@0 14 #include "SkTypedArray.h"
michael@0 15
michael@0 16 /* things to do
michael@0 17 ? re-enable support for struct literals (e.g., for initializing points or rects)
michael@0 18 {x:1, y:2}
michael@0 19 ? use standard XML / script notation like document.getElementById("canvas");
michael@0 20 finish support for typed arrays
michael@0 21 ? allow indexing arrays by string
michael@0 22 this could map to the 'name' attribute of a given child of an array
michael@0 23 ? allow multiple types in the array
michael@0 24 remove SkDisplayType.h // from SkOperand.h
michael@0 25 merge type and operand arrays into scriptvalue array
michael@0 26 */
michael@0 27
michael@0 28 #ifdef SK_DEBUG
michael@0 29 static const char* errorStrings[] = {
michael@0 30 "array index of out bounds", // kArrayIndexOutOfBounds
michael@0 31 "could not find reference id", // kCouldNotFindReferencedID
michael@0 32 "dot operator expects object", // kDotOperatorExpectsObject
michael@0 33 "error in array index", // kErrorInArrrayIndex
michael@0 34 "error in function parameters", // kErrorInFunctionParameters
michael@0 35 "expected array", // kExpectedArray
michael@0 36 "expected boolean expression", // kExpectedBooleanExpression
michael@0 37 "expected field name", // kExpectedFieldName
michael@0 38 "expected hex", // kExpectedHex
michael@0 39 "expected int for condition operator", // kExpectedIntForConditionOperator
michael@0 40 "expected number", // kExpectedNumber
michael@0 41 "expected number for array index", // kExpectedNumberForArrayIndex
michael@0 42 "expected operator", // kExpectedOperator
michael@0 43 "expected token", // kExpectedToken
michael@0 44 "expected token before dot operator", // kExpectedTokenBeforeDotOperator
michael@0 45 "expected value", // kExpectedValue
michael@0 46 "handle member failed", // kHandleMemberFailed
michael@0 47 "handle member function failed", // kHandleMemberFunctionFailed
michael@0 48 "handle unbox failed", // kHandleUnboxFailed
michael@0 49 "index out of range", // kIndexOutOfRange
michael@0 50 "mismatched array brace", // kMismatchedArrayBrace
michael@0 51 "mismatched brackets", // kMismatchedBrackets
michael@0 52 "no function handler found", // kNoFunctionHandlerFound
michael@0 53 "premature end", // kPrematureEnd
michael@0 54 "too many parameters", // kTooManyParameters
michael@0 55 "type conversion failed", // kTypeConversionFailed
michael@0 56 "unterminated string" // kUnterminatedString
michael@0 57 };
michael@0 58 #endif
michael@0 59
michael@0 60 const SkScriptEngine::SkOperatorAttributes SkScriptEngine::gOpAttributes[] = {
michael@0 61 { kNoType, kNoType, kNoBias }, // kUnassigned,
michael@0 62 { SkOpType(kInt | kScalar | kString), SkOpType(kInt | kScalar | kString), kTowardsString }, // kAdd
michael@0 63 // kAddInt = kAdd,
michael@0 64 { kNoType, kNoType, kNoBias }, // kAddScalar,
michael@0 65 { kNoType, kNoType, kNoBias }, // kAddString,
michael@0 66 { kNoType, kNoType, kNoBias }, // kArrayOp,
michael@0 67 { kInt, kInt, kNoBias }, // kBitAnd
michael@0 68 { kNoType, kInt, kNoBias }, // kBitNot
michael@0 69 { kInt, kInt, kNoBias }, // kBitOr
michael@0 70 { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kDivide
michael@0 71 // kDivideInt = kDivide
michael@0 72 { kNoType, kNoType, kNoBias }, // kDivideScalar
michael@0 73 { kNoType, kNoType, kNoBias }, // kElse
michael@0 74 { SkOpType(kInt | kScalar | kString), SkOpType(kInt | kScalar | kString), kTowardsNumber }, // kEqual
michael@0 75 // kEqualInt = kEqual
michael@0 76 { kNoType, kNoType, kNoBias }, // kEqualScalar
michael@0 77 { kNoType, kNoType, kNoBias }, // kEqualString
michael@0 78 { kInt, kNoType, kNoBias }, // kFlipOps
michael@0 79 { SkOpType(kInt | kScalar | kString), SkOpType(kInt | kScalar | kString), kTowardsNumber }, // kGreaterEqual
michael@0 80 // kGreaterEqualInt = kGreaterEqual
michael@0 81 { kNoType, kNoType, kNoBias }, // kGreaterEqualScalar
michael@0 82 { kNoType, kNoType, kNoBias }, // kGreaterEqualString
michael@0 83 { kNoType, kNoType, kNoBias }, // kIf
michael@0 84 { kNoType, kInt, kNoBias }, // kLogicalAnd (really, ToBool)
michael@0 85 { kNoType, kInt, kNoBias }, // kLogicalNot
michael@0 86 { kInt, kInt, kNoBias }, // kLogicalOr
michael@0 87 { kNoType, SkOpType(kInt | kScalar), kNoBias }, // kMinus
michael@0 88 // kMinusInt = kMinus
michael@0 89 { kNoType, kNoType, kNoBias }, // kMinusScalar
michael@0 90 { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kModulo
michael@0 91 // kModuloInt = kModulo
michael@0 92 { kNoType, kNoType, kNoBias }, // kModuloScalar
michael@0 93 { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kMultiply
michael@0 94 // kMultiplyInt = kMultiply
michael@0 95 { kNoType, kNoType, kNoBias }, // kMultiplyScalar
michael@0 96 { kNoType, kNoType, kNoBias }, // kParen
michael@0 97 { kInt, kInt, kNoBias }, // kShiftLeft
michael@0 98 { kInt, kInt, kNoBias }, // kShiftRight
michael@0 99 { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kSubtract
michael@0 100 // kSubtractInt = kSubtract
michael@0 101 { kNoType, kNoType, kNoBias }, // kSubtractScalar
michael@0 102 { kInt, kInt, kNoBias } // kXor
michael@0 103 };
michael@0 104
michael@0 105 // Note that the real precedence for () [] is '2'
michael@0 106 // but here, precedence means 'while an equal or smaller precedence than the current operator
michael@0 107 // is on the stack, process it. This allows 3+5*2 to defer the add until after the multiply
michael@0 108 // is preformed, since the add precedence is not smaller than multiply.
michael@0 109 // But, (3*4 does not process the '(', since brackets are greater than all other precedences
michael@0 110 #define kBracketPrecedence 16
michael@0 111 #define kIfElsePrecedence 15
michael@0 112
michael@0 113 const signed char SkScriptEngine::gPrecedence[] = {
michael@0 114 -1, // kUnassigned,
michael@0 115 6, // kAdd,
michael@0 116 // kAddInt = kAdd,
michael@0 117 6, // kAddScalar,
michael@0 118 6, // kAddString, // string concat
michael@0 119 kBracketPrecedence, // kArrayOp,
michael@0 120 10, // kBitAnd,
michael@0 121 4, // kBitNot,
michael@0 122 12, // kBitOr,
michael@0 123 5, // kDivide,
michael@0 124 // kDivideInt = kDivide,
michael@0 125 5, // kDivideScalar,
michael@0 126 kIfElsePrecedence, // kElse,
michael@0 127 9, // kEqual,
michael@0 128 // kEqualInt = kEqual,
michael@0 129 9, // kEqualScalar,
michael@0 130 9, // kEqualString,
michael@0 131 -1, // kFlipOps,
michael@0 132 8, // kGreaterEqual,
michael@0 133 // kGreaterEqualInt = kGreaterEqual,
michael@0 134 8, // kGreaterEqualScalar,
michael@0 135 8, // kGreaterEqualString,
michael@0 136 kIfElsePrecedence, // kIf,
michael@0 137 13, // kLogicalAnd,
michael@0 138 4, // kLogicalNot,
michael@0 139 14, // kLogicalOr,
michael@0 140 4, // kMinus,
michael@0 141 // kMinusInt = kMinus,
michael@0 142 4, // kMinusScalar,
michael@0 143 5, // kModulo,
michael@0 144 // kModuloInt = kModulo,
michael@0 145 5, // kModuloScalar,
michael@0 146 5, // kMultiply,
michael@0 147 // kMultiplyInt = kMultiply,
michael@0 148 5, // kMultiplyScalar,
michael@0 149 kBracketPrecedence, // kParen,
michael@0 150 7, // kShiftLeft,
michael@0 151 7, // kShiftRight, // signed
michael@0 152 6, // kSubtract,
michael@0 153 // kSubtractInt = kSubtract,
michael@0 154 6, // kSubtractScalar,
michael@0 155 11, // kXor
michael@0 156 };
michael@0 157
michael@0 158 static inline bool is_between(int c, int min, int max)
michael@0 159 {
michael@0 160 return (unsigned)(c - min) <= (unsigned)(max - min);
michael@0 161 }
michael@0 162
michael@0 163 static inline bool is_ws(int c)
michael@0 164 {
michael@0 165 return is_between(c, 1, 32);
michael@0 166 }
michael@0 167
michael@0 168 static int token_length(const char* start) {
michael@0 169 char ch = start[0];
michael@0 170 if (! is_between(ch, 'a' , 'z') && ! is_between(ch, 'A', 'Z') && ch != '_' && ch != '$')
michael@0 171 return -1;
michael@0 172 int length = 0;
michael@0 173 do
michael@0 174 ch = start[++length];
michael@0 175 while (is_between(ch, 'a' , 'z') || is_between(ch, 'A', 'Z') || is_between(ch, '0', '9') ||
michael@0 176 ch == '_' || ch == '$');
michael@0 177 return length;
michael@0 178 }
michael@0 179
michael@0 180 SkScriptEngine::SkScriptEngine(SkOpType returnType) :
michael@0 181 fTokenLength(0), fReturnType(returnType), fError(kNoError)
michael@0 182 {
michael@0 183 SkSuppress noInitialSuppress;
michael@0 184 noInitialSuppress.fOperator = kUnassigned;
michael@0 185 noInitialSuppress.fOpStackDepth = 0;
michael@0 186 noInitialSuppress.fSuppress = false;
michael@0 187 noInitialSuppress.fElse = 0;
michael@0 188 fSuppressStack.push(noInitialSuppress);
michael@0 189 *fOpStack.push() = kParen;
michael@0 190 fTrackArray.appendClear();
michael@0 191 fTrackString.appendClear();
michael@0 192 }
michael@0 193
michael@0 194 SkScriptEngine::~SkScriptEngine() {
michael@0 195 for (SkString** stringPtr = fTrackString.begin(); stringPtr < fTrackString.end(); stringPtr++)
michael@0 196 delete *stringPtr;
michael@0 197 for (SkTypedArray** arrayPtr = fTrackArray.begin(); arrayPtr < fTrackArray.end(); arrayPtr++)
michael@0 198 delete *arrayPtr;
michael@0 199 }
michael@0 200
michael@0 201 int SkScriptEngine::arithmeticOp(char ch, char nextChar, bool lastPush) {
michael@0 202 SkOp op = kUnassigned;
michael@0 203 bool reverseOperands = false;
michael@0 204 bool negateResult = false;
michael@0 205 int advance = 1;
michael@0 206 switch (ch) {
michael@0 207 case '+':
michael@0 208 // !!! ignoring unary plus as implemented here has the side effect of
michael@0 209 // suppressing errors like +"hi"
michael@0 210 if (lastPush == false) // unary plus, don't push an operator
michael@0 211 goto returnAdv;
michael@0 212 op = kAdd;
michael@0 213 break;
michael@0 214 case '-':
michael@0 215 op = lastPush ? kSubtract : kMinus;
michael@0 216 break;
michael@0 217 case '*':
michael@0 218 op = kMultiply;
michael@0 219 break;
michael@0 220 case '/':
michael@0 221 op = kDivide;
michael@0 222 break;
michael@0 223 case '>':
michael@0 224 if (nextChar == '>') {
michael@0 225 op = kShiftRight;
michael@0 226 goto twoChar;
michael@0 227 }
michael@0 228 op = kGreaterEqual;
michael@0 229 if (nextChar == '=')
michael@0 230 goto twoChar;
michael@0 231 reverseOperands = negateResult = true;
michael@0 232 break;
michael@0 233 case '<':
michael@0 234 if (nextChar == '<') {
michael@0 235 op = kShiftLeft;
michael@0 236 goto twoChar;
michael@0 237 }
michael@0 238 op = kGreaterEqual;
michael@0 239 reverseOperands = nextChar == '=';
michael@0 240 negateResult = ! reverseOperands;
michael@0 241 advance += reverseOperands;
michael@0 242 break;
michael@0 243 case '=':
michael@0 244 if (nextChar == '=') {
michael@0 245 op = kEqual;
michael@0 246 goto twoChar;
michael@0 247 }
michael@0 248 break;
michael@0 249 case '!':
michael@0 250 if (nextChar == '=') {
michael@0 251 op = kEqual;
michael@0 252 negateResult = true;
michael@0 253 twoChar:
michael@0 254 advance++;
michael@0 255 break;
michael@0 256 }
michael@0 257 op = kLogicalNot;
michael@0 258 break;
michael@0 259 case '?':
michael@0 260 op = kIf;
michael@0 261 break;
michael@0 262 case ':':
michael@0 263 op = kElse;
michael@0 264 break;
michael@0 265 case '^':
michael@0 266 op = kXor;
michael@0 267 break;
michael@0 268 case '(':
michael@0 269 *fOpStack.push() = kParen; // push even if eval is suppressed
michael@0 270 goto returnAdv;
michael@0 271 case '&':
michael@0 272 SkASSERT(nextChar != '&');
michael@0 273 op = kBitAnd;
michael@0 274 break;
michael@0 275 case '|':
michael@0 276 SkASSERT(nextChar != '|');
michael@0 277 op = kBitOr;
michael@0 278 break;
michael@0 279 case '%':
michael@0 280 op = kModulo;
michael@0 281 break;
michael@0 282 case '~':
michael@0 283 op = kBitNot;
michael@0 284 break;
michael@0 285 }
michael@0 286 if (op == kUnassigned)
michael@0 287 return 0;
michael@0 288 if (fSuppressStack.top().fSuppress == false) {
michael@0 289 signed char precedence = gPrecedence[op];
michael@0 290 do {
michael@0 291 int idx = 0;
michael@0 292 SkOp compare;
michael@0 293 do {
michael@0 294 compare = fOpStack.index(idx);
michael@0 295 if ((compare & kArtificialOp) == 0)
michael@0 296 break;
michael@0 297 idx++;
michael@0 298 } while (true);
michael@0 299 signed char topPrecedence = gPrecedence[compare];
michael@0 300 SkASSERT(topPrecedence != -1);
michael@0 301 if (topPrecedence > precedence || (topPrecedence == precedence &&
michael@0 302 gOpAttributes[op].fLeftType == kNoType)) {
michael@0 303 break;
michael@0 304 }
michael@0 305 if (processOp() == false)
michael@0 306 return 0; // error
michael@0 307 } while (true);
michael@0 308 if (negateResult)
michael@0 309 *fOpStack.push() = (SkOp) (kLogicalNot | kArtificialOp);
michael@0 310 fOpStack.push(op);
michael@0 311 if (reverseOperands)
michael@0 312 *fOpStack.push() = (SkOp) (kFlipOps | kArtificialOp);
michael@0 313 }
michael@0 314 returnAdv:
michael@0 315 return advance;
michael@0 316 }
michael@0 317
michael@0 318 void SkScriptEngine::boxCallBack(_boxCallBack func, void* userStorage) {
michael@0 319 UserCallBack callBack;
michael@0 320 callBack.fBoxCallBack = func;
michael@0 321 commonCallBack(kBox, callBack, userStorage);
michael@0 322 }
michael@0 323
michael@0 324 void SkScriptEngine::commonCallBack(CallBackType type, UserCallBack& callBack, void* userStorage) {
michael@0 325 callBack.fCallBackType = type;
michael@0 326 callBack.fUserStorage = userStorage;
michael@0 327 *fUserCallBacks.prepend() = callBack;
michael@0 328 }
michael@0 329
michael@0 330 bool SkScriptEngine::convertParams(SkTDArray<SkScriptValue>& params,
michael@0 331 const SkFunctionParamType* paramTypes, int paramCount) {
michael@0 332 if (params.count() > paramCount) {
michael@0 333 fError = kTooManyParameters;
michael@0 334 return false; // too many parameters passed
michael@0 335 }
michael@0 336 for (int index = 0; index < params.count(); index++) {
michael@0 337 if (convertTo((SkDisplayTypes) paramTypes[index], &params[index]) == false)
michael@0 338 return false;
michael@0 339 }
michael@0 340 return true;
michael@0 341 }
michael@0 342
michael@0 343 bool SkScriptEngine::convertTo(SkDisplayTypes toType, SkScriptValue* value ) {
michael@0 344 SkDisplayTypes type = value->fType;
michael@0 345 if (type == toType)
michael@0 346 return true;
michael@0 347 if (ToOpType(type) == kObject) {
michael@0 348 #if 0 // !!! I want object->string to get string from displaystringtype, not id
michael@0 349 if (ToOpType(toType) == kString) {
michael@0 350 bool success = handleObjectToString(value->fOperand.fObject);
michael@0 351 if (success == false)
michael@0 352 return false;
michael@0 353 SkOpType type;
michael@0 354 fTypeStack.pop(&type);
michael@0 355 value->fType = ToDisplayType(type);
michael@0 356 fOperandStack.pop(&value->fOperand);
michael@0 357 return true;
michael@0 358 }
michael@0 359 #endif
michael@0 360 if (handleUnbox(value) == false) {
michael@0 361 fError = kHandleUnboxFailed;
michael@0 362 return false;
michael@0 363 }
michael@0 364 return convertTo(toType, value);
michael@0 365 }
michael@0 366 return ConvertTo(this, toType, value);
michael@0 367 }
michael@0 368
michael@0 369 bool SkScriptEngine::evaluateDot(const char*& script, bool suppressed) {
michael@0 370 size_t fieldLength = token_length(++script); // skip dot
michael@0 371 if (fieldLength == 0) {
michael@0 372 fError = kExpectedFieldName;
michael@0 373 return false;
michael@0 374 }
michael@0 375 const char* field = script;
michael@0 376 script += fieldLength;
michael@0 377 bool success = handleProperty(suppressed);
michael@0 378 if (success == false) {
michael@0 379 fError = kCouldNotFindReferencedID; // note: never generated by standard animator plugins
michael@0 380 return false;
michael@0 381 }
michael@0 382 return evaluateDotParam(script, suppressed, field, fieldLength);
michael@0 383 }
michael@0 384
michael@0 385 bool SkScriptEngine::evaluateDotParam(const char*& script, bool suppressed,
michael@0 386 const char* field, size_t fieldLength) {
michael@0 387 void* object;
michael@0 388 if (suppressed)
michael@0 389 object = NULL;
michael@0 390 else {
michael@0 391 if (fTypeStack.top() != kObject) {
michael@0 392 fError = kDotOperatorExpectsObject;
michael@0 393 return false;
michael@0 394 }
michael@0 395 object = fOperandStack.top().fObject;
michael@0 396 fTypeStack.pop();
michael@0 397 fOperandStack.pop();
michael@0 398 }
michael@0 399 char ch; // see if it is a simple member or a function
michael@0 400 while (is_ws(ch = script[0]))
michael@0 401 script++;
michael@0 402 bool success = true;
michael@0 403 if (ch != '(') {
michael@0 404 if (suppressed == false) {
michael@0 405 if ((success = handleMember(field, fieldLength, object)) == false)
michael@0 406 fError = kHandleMemberFailed;
michael@0 407 }
michael@0 408 } else {
michael@0 409 SkTDArray<SkScriptValue> params;
michael@0 410 *fBraceStack.push() = kFunctionBrace;
michael@0 411 success = functionParams(&script, params);
michael@0 412 if (success && suppressed == false &&
michael@0 413 (success = handleMemberFunction(field, fieldLength, object, params)) == false)
michael@0 414 fError = kHandleMemberFunctionFailed;
michael@0 415 }
michael@0 416 return success;
michael@0 417 }
michael@0 418
michael@0 419 bool SkScriptEngine::evaluateScript(const char** scriptPtr, SkScriptValue* value) {
michael@0 420 #ifdef SK_DEBUG
michael@0 421 const char** original = scriptPtr;
michael@0 422 #endif
michael@0 423 bool success;
michael@0 424 const char* inner;
michael@0 425 if (strncmp(*scriptPtr, "#script:", sizeof("#script:") - 1) == 0) {
michael@0 426 *scriptPtr += sizeof("#script:") - 1;
michael@0 427 if (fReturnType == kNoType || fReturnType == kString) {
michael@0 428 success = innerScript(scriptPtr, value);
michael@0 429 if (success == false)
michael@0 430 goto end;
michael@0 431 inner = value->fOperand.fString->c_str();
michael@0 432 scriptPtr = &inner;
michael@0 433 }
michael@0 434 }
michael@0 435 {
michael@0 436 success = innerScript(scriptPtr, value);
michael@0 437 if (success == false)
michael@0 438 goto end;
michael@0 439 const char* script = *scriptPtr;
michael@0 440 char ch;
michael@0 441 while (is_ws(ch = script[0]))
michael@0 442 script++;
michael@0 443 if (ch != '\0') {
michael@0 444 // error may trigger on scripts like "50,0" that were intended to be written as "[50, 0]"
michael@0 445 fError = kPrematureEnd;
michael@0 446 success = false;
michael@0 447 }
michael@0 448 }
michael@0 449 end:
michael@0 450 #ifdef SK_DEBUG
michael@0 451 if (success == false) {
michael@0 452 SkDebugf("script failed: %s", *original);
michael@0 453 if (fError)
michael@0 454 SkDebugf(" %s", errorStrings[fError - 1]);
michael@0 455 SkDebugf("\n");
michael@0 456 }
michael@0 457 #endif
michael@0 458 return success;
michael@0 459 }
michael@0 460
michael@0 461 void SkScriptEngine::forget(SkTypedArray* array) {
michael@0 462 if (array->getType() == SkType_String) {
michael@0 463 for (int index = 0; index < array->count(); index++) {
michael@0 464 SkString* string = (*array)[index].fString;
michael@0 465 int found = fTrackString.find(string);
michael@0 466 if (found >= 0)
michael@0 467 fTrackString.remove(found);
michael@0 468 }
michael@0 469 return;
michael@0 470 }
michael@0 471 if (array->getType() == SkType_Array) {
michael@0 472 for (int index = 0; index < array->count(); index++) {
michael@0 473 SkTypedArray* child = (*array)[index].fArray;
michael@0 474 forget(child); // forgets children of child
michael@0 475 int found = fTrackArray.find(child);
michael@0 476 if (found >= 0)
michael@0 477 fTrackArray.remove(found);
michael@0 478 }
michael@0 479 }
michael@0 480 }
michael@0 481
michael@0 482 void SkScriptEngine::functionCallBack(_functionCallBack func, void* userStorage) {
michael@0 483 UserCallBack callBack;
michael@0 484 callBack.fFunctionCallBack = func;
michael@0 485 commonCallBack(kFunction, callBack, userStorage);
michael@0 486 }
michael@0 487
michael@0 488 bool SkScriptEngine::functionParams(const char** scriptPtr, SkTDArray<SkScriptValue>& params) {
michael@0 489 (*scriptPtr)++; // skip open paren
michael@0 490 *fOpStack.push() = kParen;
michael@0 491 *fBraceStack.push() = kFunctionBrace;
michael@0 492 SkBool suppressed = fSuppressStack.top().fSuppress;
michael@0 493 do {
michael@0 494 SkScriptValue value;
michael@0 495 bool success = innerScript(scriptPtr, suppressed ? NULL : &value);
michael@0 496 if (success == false) {
michael@0 497 fError = kErrorInFunctionParameters;
michael@0 498 return false;
michael@0 499 }
michael@0 500 if (suppressed)
michael@0 501 continue;
michael@0 502 *params.append() = value;
michael@0 503 } while ((*scriptPtr)[-1] == ',');
michael@0 504 fBraceStack.pop();
michael@0 505 fOpStack.pop(); // pop paren
michael@0 506 (*scriptPtr)++; // advance beyond close paren
michael@0 507 return true;
michael@0 508 }
michael@0 509
michael@0 510 #ifdef SK_DEBUG
michael@0 511 bool SkScriptEngine::getErrorString(SkString* str) const {
michael@0 512 if (fError)
michael@0 513 str->set(errorStrings[fError - 1]);
michael@0 514 return fError != 0;
michael@0 515 }
michael@0 516 #endif
michael@0 517
michael@0 518 bool SkScriptEngine::innerScript(const char** scriptPtr, SkScriptValue* value) {
michael@0 519 const char* script = *scriptPtr;
michael@0 520 char ch;
michael@0 521 bool lastPush = false;
michael@0 522 bool success = true;
michael@0 523 int opBalance = fOpStack.count();
michael@0 524 int baseBrace = fBraceStack.count();
michael@0 525 int suppressBalance = fSuppressStack.count();
michael@0 526 while ((ch = script[0]) != '\0') {
michael@0 527 if (is_ws(ch)) {
michael@0 528 script++;
michael@0 529 continue;
michael@0 530 }
michael@0 531 SkBool suppressed = fSuppressStack.top().fSuppress;
michael@0 532 SkOperand operand;
michael@0 533 const char* dotCheck;
michael@0 534 if (fBraceStack.count() > baseBrace) {
michael@0 535 #if 0 // disable support for struct brace
michael@0 536 if (ch == ':') {
michael@0 537 SkASSERT(fTokenLength > 0);
michael@0 538 SkASSERT(fBraceStack.top() == kStructBrace);
michael@0 539 ++script;
michael@0 540 SkASSERT(fDisplayable);
michael@0 541 SkString token(fToken, fTokenLength);
michael@0 542 fTokenLength = 0;
michael@0 543 const char* tokenName = token.c_str();
michael@0 544 const SkMemberInfo* tokenInfo SK_INIT_TO_AVOID_WARNING;
michael@0 545 if (suppressed == false) {
michael@0 546 SkDisplayTypes type = fInfo->getType();
michael@0 547 tokenInfo = SkDisplayType::GetMember(type, &tokenName);
michael@0 548 SkASSERT(tokenInfo);
michael@0 549 }
michael@0 550 SkScriptValue tokenValue;
michael@0 551 success = innerScript(&script, &tokenValue); // terminate and return on comma, close brace
michael@0 552 SkASSERT(success);
michael@0 553 if (suppressed == false) {
michael@0 554 if (tokenValue.fType == SkType_Displayable) {
michael@0 555 SkASSERT(SkDisplayType::IsDisplayable(tokenInfo->getType()));
michael@0 556 fDisplayable->setReference(tokenInfo, tokenValue.fOperand.fDisplayable);
michael@0 557 } else {
michael@0 558 if (tokenValue.fType != tokenInfo->getType()) {
michael@0 559 if (convertTo(tokenInfo->getType(), &tokenValue) == false)
michael@0 560 return false;
michael@0 561 }
michael@0 562 tokenInfo->writeValue(fDisplayable, NULL, 0, 0,
michael@0 563 (void*) ((char*) fInfo->memberData(fDisplayable) + tokenInfo->fOffset + fArrayOffset),
michael@0 564 tokenInfo->getType(), tokenValue);
michael@0 565 }
michael@0 566 }
michael@0 567 lastPush = false;
michael@0 568 continue;
michael@0 569 } else
michael@0 570 #endif
michael@0 571 if (fBraceStack.top() == kArrayBrace) {
michael@0 572 SkScriptValue tokenValue;
michael@0 573 success = innerScript(&script, &tokenValue); // terminate and return on comma, close brace
michael@0 574 if (success == false) {
michael@0 575 fError = kErrorInArrrayIndex;
michael@0 576 return false;
michael@0 577 }
michael@0 578 if (suppressed == false) {
michael@0 579 #if 0 // no support for structures for now
michael@0 580 if (tokenValue.fType == SkType_Structure) {
michael@0 581 fArrayOffset += (int) fInfo->getSize(fDisplayable);
michael@0 582 } else
michael@0 583 #endif
michael@0 584 {
michael@0 585 SkDisplayTypes type = ToDisplayType(fReturnType);
michael@0 586 if (fReturnType == kNoType) {
michael@0 587 // !!! short sighted; in the future, allow each returned array component to carry
michael@0 588 // its own type, and let caller do any needed conversions
michael@0 589 if (value->fOperand.fArray->count() == 0)
michael@0 590 value->fOperand.fArray->setType(type = tokenValue.fType);
michael@0 591 else
michael@0 592 type = value->fOperand.fArray->getType();
michael@0 593 }
michael@0 594 if (tokenValue.fType != type) {
michael@0 595 if (convertTo(type, &tokenValue) == false)
michael@0 596 return false;
michael@0 597 }
michael@0 598 *value->fOperand.fArray->append() = tokenValue.fOperand;
michael@0 599 }
michael@0 600 }
michael@0 601 lastPush = false;
michael@0 602 continue;
michael@0 603 } else {
michael@0 604 if (token_length(script) == 0) {
michael@0 605 fError = kExpectedToken;
michael@0 606 return false;
michael@0 607 }
michael@0 608 }
michael@0 609 }
michael@0 610 if (lastPush != false && fTokenLength > 0) {
michael@0 611 if (ch == '(') {
michael@0 612 *fBraceStack.push() = kFunctionBrace;
michael@0 613 if (handleFunction(&script, SkToBool(suppressed)) == false)
michael@0 614 return false;
michael@0 615 lastPush = true;
michael@0 616 continue;
michael@0 617 } else if (ch == '[') {
michael@0 618 if (handleProperty(SkToBool(suppressed)) == false)
michael@0 619 return false; // note: never triggered by standard animator plugins
michael@0 620 if (handleArrayIndexer(&script, SkToBool(suppressed)) == false)
michael@0 621 return false;
michael@0 622 lastPush = true;
michael@0 623 continue;
michael@0 624 } else if (ch != '.') {
michael@0 625 if (handleProperty(SkToBool(suppressed)) == false)
michael@0 626 return false; // note: never triggered by standard animator plugins
michael@0 627 lastPush = true;
michael@0 628 continue;
michael@0 629 }
michael@0 630 }
michael@0 631 if (ch == '0' && (script[1] & ~0x20) == 'X') {
michael@0 632 if (lastPush != false) {
michael@0 633 fError = kExpectedOperator;
michael@0 634 return false;
michael@0 635 }
michael@0 636 script += 2;
michael@0 637 script = SkParse::FindHex(script, (uint32_t*)&operand.fS32);
michael@0 638 if (script == NULL) {
michael@0 639 fError = kExpectedHex;
michael@0 640 return false;
michael@0 641 }
michael@0 642 goto intCommon;
michael@0 643 }
michael@0 644 if (lastPush == false && ch == '.')
michael@0 645 goto scalarCommon;
michael@0 646 if (ch >= '0' && ch <= '9') {
michael@0 647 if (lastPush != false) {
michael@0 648 fError = kExpectedOperator;
michael@0 649 return false;
michael@0 650 }
michael@0 651 dotCheck = SkParse::FindS32(script, &operand.fS32);
michael@0 652 if (dotCheck[0] != '.') {
michael@0 653 script = dotCheck;
michael@0 654 intCommon:
michael@0 655 if (suppressed == false)
michael@0 656 *fTypeStack.push() = kInt;
michael@0 657 } else {
michael@0 658 scalarCommon:
michael@0 659 script = SkParse::FindScalar(script, &operand.fScalar);
michael@0 660 if (suppressed == false)
michael@0 661 *fTypeStack.push() = kScalar;
michael@0 662 }
michael@0 663 if (suppressed == false)
michael@0 664 fOperandStack.push(operand);
michael@0 665 lastPush = true;
michael@0 666 continue;
michael@0 667 }
michael@0 668 int length = token_length(script);
michael@0 669 if (length > 0) {
michael@0 670 if (lastPush != false) {
michael@0 671 fError = kExpectedOperator;
michael@0 672 return false;
michael@0 673 }
michael@0 674 fToken = script;
michael@0 675 fTokenLength = length;
michael@0 676 script += length;
michael@0 677 lastPush = true;
michael@0 678 continue;
michael@0 679 }
michael@0 680 char startQuote = ch;
michael@0 681 if (startQuote == '\'' || startQuote == '\"') {
michael@0 682 if (lastPush != false) {
michael@0 683 fError = kExpectedOperator;
michael@0 684 return false;
michael@0 685 }
michael@0 686 operand.fString = new SkString();
michael@0 687 track(operand.fString);
michael@0 688 ++script;
michael@0 689
michael@0 690 // <mrr> this is a lot of calls to append() one char at at time
michael@0 691 // how hard to preflight script so we know how much to grow fString by?
michael@0 692 do {
michael@0 693 if (script[0] == '\\')
michael@0 694 ++script;
michael@0 695 operand.fString->append(script, 1);
michael@0 696 ++script;
michael@0 697 if (script[0] == '\0') {
michael@0 698 fError = kUnterminatedString;
michael@0 699 return false;
michael@0 700 }
michael@0 701 } while (script[0] != startQuote);
michael@0 702 ++script;
michael@0 703 if (suppressed == false) {
michael@0 704 *fTypeStack.push() = kString;
michael@0 705 fOperandStack.push(operand);
michael@0 706 }
michael@0 707 lastPush = true;
michael@0 708 continue;
michael@0 709 }
michael@0 710 ;
michael@0 711 if (ch == '.') {
michael@0 712 if (fTokenLength == 0) {
michael@0 713 SkScriptValue scriptValue;
michael@0 714 SkDEBUGCODE(scriptValue.fOperand.fObject = NULL);
michael@0 715 int tokenLength = token_length(++script);
michael@0 716 const char* token = script;
michael@0 717 script += tokenLength;
michael@0 718 if (suppressed == false) {
michael@0 719 if (fTypeStack.count() == 0) {
michael@0 720 fError = kExpectedTokenBeforeDotOperator;
michael@0 721 return false;
michael@0 722 }
michael@0 723 SkOpType topType;
michael@0 724 fTypeStack.pop(&topType);
michael@0 725 fOperandStack.pop(&scriptValue.fOperand);
michael@0 726 scriptValue.fType = ToDisplayType(topType);
michael@0 727 handleBox(&scriptValue);
michael@0 728 }
michael@0 729 success = evaluateDotParam(script, SkToBool(suppressed), token, tokenLength);
michael@0 730 if (success == false)
michael@0 731 return false;
michael@0 732 lastPush = true;
michael@0 733 continue;
michael@0 734 }
michael@0 735 // get next token, and evaluate immediately
michael@0 736 success = evaluateDot(script, SkToBool(suppressed));
michael@0 737 if (success == false)
michael@0 738 return false;
michael@0 739 lastPush = true;
michael@0 740 continue;
michael@0 741 }
michael@0 742 if (ch == '[') {
michael@0 743 if (lastPush == false) {
michael@0 744 script++;
michael@0 745 *fBraceStack.push() = kArrayBrace;
michael@0 746 if (suppressed)
michael@0 747 continue;
michael@0 748 operand.fArray = value->fOperand.fArray = new SkTypedArray(ToDisplayType(fReturnType));
michael@0 749 track(value->fOperand.fArray);
michael@0 750 *fTypeStack.push() = (SkOpType) kArray;
michael@0 751 fOperandStack.push(operand);
michael@0 752 continue;
michael@0 753 }
michael@0 754 if (handleArrayIndexer(&script, SkToBool(suppressed)) == false)
michael@0 755 return false;
michael@0 756 lastPush = true;
michael@0 757 continue;
michael@0 758 }
michael@0 759 #if 0 // structs not supported for now
michael@0 760 if (ch == '{') {
michael@0 761 if (lastPush == false) {
michael@0 762 script++;
michael@0 763 *fBraceStack.push() = kStructBrace;
michael@0 764 if (suppressed)
michael@0 765 continue;
michael@0 766 operand.fS32 = 0;
michael@0 767 *fTypeStack.push() = (SkOpType) kStruct;
michael@0 768 fOperandStack.push(operand);
michael@0 769 continue;
michael@0 770 }
michael@0 771 SkASSERT(0); // braces in other contexts aren't supported yet
michael@0 772 }
michael@0 773 #endif
michael@0 774 if (ch == ')' && fBraceStack.count() > 0) {
michael@0 775 SkBraceStyle braceStyle = fBraceStack.top();
michael@0 776 if (braceStyle == kFunctionBrace) {
michael@0 777 fBraceStack.pop();
michael@0 778 break;
michael@0 779 }
michael@0 780 }
michael@0 781 if (ch == ',' || ch == ']') {
michael@0 782 if (ch != ',') {
michael@0 783 SkBraceStyle match;
michael@0 784 fBraceStack.pop(&match);
michael@0 785 if (match != kArrayBrace) {
michael@0 786 fError = kMismatchedArrayBrace;
michael@0 787 return false;
michael@0 788 }
michael@0 789 }
michael@0 790 script++;
michael@0 791 // !!! see if brace or bracket is correct closer
michael@0 792 break;
michael@0 793 }
michael@0 794 char nextChar = script[1];
michael@0 795 int advance = logicalOp(ch, nextChar);
michael@0 796 if (advance < 0) // error
michael@0 797 return false;
michael@0 798 if (advance == 0)
michael@0 799 advance = arithmeticOp(ch, nextChar, lastPush);
michael@0 800 if (advance == 0) // unknown token
michael@0 801 return false;
michael@0 802 if (advance > 0)
michael@0 803 script += advance;
michael@0 804 lastPush = ch == ']' || ch == ')';
michael@0 805 }
michael@0 806 bool suppressed = SkToBool(fSuppressStack.top().fSuppress);
michael@0 807 if (fTokenLength > 0) {
michael@0 808 success = handleProperty(suppressed);
michael@0 809 if (success == false)
michael@0 810 return false; // note: never triggered by standard animator plugins
michael@0 811 }
michael@0 812 while (fOpStack.count() > opBalance) { // leave open paren
michael@0 813 if ((fError = opError()) != kNoError)
michael@0 814 return false;
michael@0 815 if (processOp() == false)
michael@0 816 return false;
michael@0 817 }
michael@0 818 SkOpType topType = fTypeStack.count() > 0 ? fTypeStack.top() : kNoType;
michael@0 819 if (suppressed == false && topType != fReturnType &&
michael@0 820 topType == kString && fReturnType != kNoType) { // if result is a string, give handle property a chance to convert it to the property value
michael@0 821 SkString* string = fOperandStack.top().fString;
michael@0 822 fToken = string->c_str();
michael@0 823 fTokenLength = string->size();
michael@0 824 fOperandStack.pop();
michael@0 825 fTypeStack.pop();
michael@0 826 success = handleProperty(SkToBool(fSuppressStack.top().fSuppress));
michael@0 827 if (success == false) { // if it couldn't convert, return string (error?)
michael@0 828 SkOperand operand;
michael@0 829 operand.fS32 = 0;
michael@0 830 *fTypeStack.push() = kString;
michael@0 831 operand.fString = string;
michael@0 832 fOperandStack.push(operand);
michael@0 833 }
michael@0 834 }
michael@0 835 if (value) {
michael@0 836 if (fOperandStack.count() == 0)
michael@0 837 return false;
michael@0 838 SkASSERT(fOperandStack.count() >= 1);
michael@0 839 SkASSERT(fTypeStack.count() >= 1);
michael@0 840 fOperandStack.pop(&value->fOperand);
michael@0 841 SkOpType type;
michael@0 842 fTypeStack.pop(&type);
michael@0 843 value->fType = ToDisplayType(type);
michael@0 844 // SkASSERT(value->fType != SkType_Unknown);
michael@0 845 if (topType != fReturnType && topType == kObject && fReturnType != kNoType) {
michael@0 846 if (convertTo(ToDisplayType(fReturnType), value) == false)
michael@0 847 return false;
michael@0 848 }
michael@0 849 }
michael@0 850 while (fSuppressStack.count() > suppressBalance)
michael@0 851 fSuppressStack.pop();
michael@0 852 *scriptPtr = script;
michael@0 853 return true; // no error
michael@0 854 }
michael@0 855
michael@0 856 void SkScriptEngine::memberCallBack(_memberCallBack member , void* userStorage) {
michael@0 857 UserCallBack callBack;
michael@0 858 callBack.fMemberCallBack = member;
michael@0 859 commonCallBack(kMember, callBack, userStorage);
michael@0 860 }
michael@0 861
michael@0 862 void SkScriptEngine::memberFunctionCallBack(_memberFunctionCallBack func, void* userStorage) {
michael@0 863 UserCallBack callBack;
michael@0 864 callBack.fMemberFunctionCallBack = func;
michael@0 865 commonCallBack(kMemberFunction, callBack, userStorage);
michael@0 866 }
michael@0 867
michael@0 868 #if 0
michael@0 869 void SkScriptEngine::objectToStringCallBack(_objectToStringCallBack func, void* userStorage) {
michael@0 870 UserCallBack callBack;
michael@0 871 callBack.fObjectToStringCallBack = func;
michael@0 872 commonCallBack(kObjectToString, callBack, userStorage);
michael@0 873 }
michael@0 874 #endif
michael@0 875
michael@0 876 bool SkScriptEngine::handleArrayIndexer(const char** scriptPtr, bool suppressed) {
michael@0 877 SkScriptValue scriptValue;
michael@0 878 (*scriptPtr)++;
michael@0 879 *fOpStack.push() = kParen;
michael@0 880 *fBraceStack.push() = kArrayBrace;
michael@0 881 SkOpType saveType = fReturnType;
michael@0 882 fReturnType = kInt;
michael@0 883 bool success = innerScript(scriptPtr, suppressed == false ? &scriptValue : NULL);
michael@0 884 if (success == false)
michael@0 885 return false;
michael@0 886 fReturnType = saveType;
michael@0 887 if (suppressed == false) {
michael@0 888 if (convertTo(SkType_Int, &scriptValue) == false)
michael@0 889 return false;
michael@0 890 int index = scriptValue.fOperand.fS32;
michael@0 891 SkScriptValue scriptValue;
michael@0 892 SkOpType type;
michael@0 893 fTypeStack.pop(&type);
michael@0 894 fOperandStack.pop(&scriptValue.fOperand);
michael@0 895 scriptValue.fType = ToDisplayType(type);
michael@0 896 if (type == kObject) {
michael@0 897 success = handleUnbox(&scriptValue);
michael@0 898 if (success == false)
michael@0 899 return false;
michael@0 900 if (ToOpType(scriptValue.fType) != kArray) {
michael@0 901 fError = kExpectedArray;
michael@0 902 return false;
michael@0 903 }
michael@0 904 }
michael@0 905 *fTypeStack.push() = scriptValue.fOperand.fArray->getOpType();
michael@0 906 // SkASSERT(index >= 0);
michael@0 907 if ((unsigned) index >= (unsigned) scriptValue.fOperand.fArray->count()) {
michael@0 908 fError = kArrayIndexOutOfBounds;
michael@0 909 return false;
michael@0 910 }
michael@0 911 scriptValue.fOperand = scriptValue.fOperand.fArray->begin()[index];
michael@0 912 fOperandStack.push(scriptValue.fOperand);
michael@0 913 }
michael@0 914 fOpStack.pop(); // pop paren
michael@0 915 return success;
michael@0 916 }
michael@0 917
michael@0 918 bool SkScriptEngine::handleBox(SkScriptValue* scriptValue) {
michael@0 919 bool success = true;
michael@0 920 for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) {
michael@0 921 if (callBack->fCallBackType != kBox)
michael@0 922 continue;
michael@0 923 success = (*callBack->fBoxCallBack)(callBack->fUserStorage, scriptValue);
michael@0 924 if (success) {
michael@0 925 fOperandStack.push(scriptValue->fOperand);
michael@0 926 *fTypeStack.push() = ToOpType(scriptValue->fType);
michael@0 927 goto done;
michael@0 928 }
michael@0 929 }
michael@0 930 done:
michael@0 931 return success;
michael@0 932 }
michael@0 933
michael@0 934 bool SkScriptEngine::handleFunction(const char** scriptPtr, bool suppressed) {
michael@0 935 SkScriptValue callbackResult;
michael@0 936 SkTDArray<SkScriptValue> params;
michael@0 937 SkString functionName(fToken, fTokenLength);
michael@0 938 fTokenLength = 0;
michael@0 939 bool success = functionParams(scriptPtr, params);
michael@0 940 if (success == false)
michael@0 941 goto done;
michael@0 942 if (suppressed == true)
michael@0 943 return true;
michael@0 944 {
michael@0 945 for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) {
michael@0 946 if (callBack->fCallBackType != kFunction)
michael@0 947 continue;
michael@0 948 success = (*callBack->fFunctionCallBack)(functionName.c_str(), functionName.size(), params,
michael@0 949 callBack->fUserStorage, &callbackResult);
michael@0 950 if (success) {
michael@0 951 fOperandStack.push(callbackResult.fOperand);
michael@0 952 *fTypeStack.push() = ToOpType(callbackResult.fType);
michael@0 953 goto done;
michael@0 954 }
michael@0 955 }
michael@0 956 }
michael@0 957 fError = kNoFunctionHandlerFound;
michael@0 958 return false;
michael@0 959 done:
michael@0 960 return success;
michael@0 961 }
michael@0 962
michael@0 963 bool SkScriptEngine::handleMember(const char* field, size_t len, void* object) {
michael@0 964 SkScriptValue callbackResult;
michael@0 965 bool success = true;
michael@0 966 for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) {
michael@0 967 if (callBack->fCallBackType != kMember)
michael@0 968 continue;
michael@0 969 success = (*callBack->fMemberCallBack)(field, len, object, callBack->fUserStorage, &callbackResult);
michael@0 970 if (success) {
michael@0 971 if (callbackResult.fType == SkType_String)
michael@0 972 track(callbackResult.fOperand.fString);
michael@0 973 fOperandStack.push(callbackResult.fOperand);
michael@0 974 *fTypeStack.push() = ToOpType(callbackResult.fType);
michael@0 975 goto done;
michael@0 976 }
michael@0 977 }
michael@0 978 return false;
michael@0 979 done:
michael@0 980 return success;
michael@0 981 }
michael@0 982
michael@0 983 bool SkScriptEngine::handleMemberFunction(const char* field, size_t len, void* object, SkTDArray<SkScriptValue>& params) {
michael@0 984 SkScriptValue callbackResult;
michael@0 985 bool success = true;
michael@0 986 for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) {
michael@0 987 if (callBack->fCallBackType != kMemberFunction)
michael@0 988 continue;
michael@0 989 success = (*callBack->fMemberFunctionCallBack)(field, len, object, params,
michael@0 990 callBack->fUserStorage, &callbackResult);
michael@0 991 if (success) {
michael@0 992 if (callbackResult.fType == SkType_String)
michael@0 993 track(callbackResult.fOperand.fString);
michael@0 994 fOperandStack.push(callbackResult.fOperand);
michael@0 995 *fTypeStack.push() = ToOpType(callbackResult.fType);
michael@0 996 goto done;
michael@0 997 }
michael@0 998 }
michael@0 999 return false;
michael@0 1000 done:
michael@0 1001 return success;
michael@0 1002 }
michael@0 1003
michael@0 1004 #if 0
michael@0 1005 bool SkScriptEngine::handleObjectToString(void* object) {
michael@0 1006 SkScriptValue callbackResult;
michael@0 1007 bool success = true;
michael@0 1008 for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) {
michael@0 1009 if (callBack->fCallBackType != kObjectToString)
michael@0 1010 continue;
michael@0 1011 success = (*callBack->fObjectToStringCallBack)(object,
michael@0 1012 callBack->fUserStorage, &callbackResult);
michael@0 1013 if (success) {
michael@0 1014 if (callbackResult.fType == SkType_String)
michael@0 1015 track(callbackResult.fOperand.fString);
michael@0 1016 fOperandStack.push(callbackResult.fOperand);
michael@0 1017 *fTypeStack.push() = ToOpType(callbackResult.fType);
michael@0 1018 goto done;
michael@0 1019 }
michael@0 1020 }
michael@0 1021 return false;
michael@0 1022 done:
michael@0 1023 return success;
michael@0 1024 }
michael@0 1025 #endif
michael@0 1026
michael@0 1027 bool SkScriptEngine::handleProperty(bool suppressed) {
michael@0 1028 SkScriptValue callbackResult;
michael@0 1029 bool success = true;
michael@0 1030 if (suppressed)
michael@0 1031 goto done;
michael@0 1032 success = false; // note that with standard animator-script plugins, callback never returns false
michael@0 1033 {
michael@0 1034 for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) {
michael@0 1035 if (callBack->fCallBackType != kProperty)
michael@0 1036 continue;
michael@0 1037 success = (*callBack->fPropertyCallBack)(fToken, fTokenLength,
michael@0 1038 callBack->fUserStorage, &callbackResult);
michael@0 1039 if (success) {
michael@0 1040 if (callbackResult.fType == SkType_String && callbackResult.fOperand.fString == NULL) {
michael@0 1041 callbackResult.fOperand.fString = new SkString(fToken, fTokenLength);
michael@0 1042 track(callbackResult.fOperand.fString);
michael@0 1043 }
michael@0 1044 fOperandStack.push(callbackResult.fOperand);
michael@0 1045 *fTypeStack.push() = ToOpType(callbackResult.fType);
michael@0 1046 goto done;
michael@0 1047 }
michael@0 1048 }
michael@0 1049 }
michael@0 1050 done:
michael@0 1051 fTokenLength = 0;
michael@0 1052 return success;
michael@0 1053 }
michael@0 1054
michael@0 1055 bool SkScriptEngine::handleUnbox(SkScriptValue* scriptValue) {
michael@0 1056 bool success = true;
michael@0 1057 for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) {
michael@0 1058 if (callBack->fCallBackType != kUnbox)
michael@0 1059 continue;
michael@0 1060 success = (*callBack->fUnboxCallBack)(callBack->fUserStorage, scriptValue);
michael@0 1061 if (success) {
michael@0 1062 if (scriptValue->fType == SkType_String)
michael@0 1063 track(scriptValue->fOperand.fString);
michael@0 1064 goto done;
michael@0 1065 }
michael@0 1066 }
michael@0 1067 return false;
michael@0 1068 done:
michael@0 1069 return success;
michael@0 1070 }
michael@0 1071
michael@0 1072 // note that entire expression is treated as if it were enclosed in parens
michael@0 1073 // an open paren is always the first thing in the op stack
michael@0 1074
michael@0 1075 int SkScriptEngine::logicalOp(char ch, char nextChar) {
michael@0 1076 int advance = 1;
michael@0 1077 SkOp match;
michael@0 1078 signed char precedence;
michael@0 1079 switch (ch) {
michael@0 1080 case ')':
michael@0 1081 match = kParen;
michael@0 1082 break;
michael@0 1083 case ']':
michael@0 1084 match = kArrayOp;
michael@0 1085 break;
michael@0 1086 case '?':
michael@0 1087 match = kIf;
michael@0 1088 break;
michael@0 1089 case ':':
michael@0 1090 match = kElse;
michael@0 1091 break;
michael@0 1092 case '&':
michael@0 1093 if (nextChar != '&')
michael@0 1094 goto noMatch;
michael@0 1095 match = kLogicalAnd;
michael@0 1096 advance = 2;
michael@0 1097 break;
michael@0 1098 case '|':
michael@0 1099 if (nextChar != '|')
michael@0 1100 goto noMatch;
michael@0 1101 match = kLogicalOr;
michael@0 1102 advance = 2;
michael@0 1103 break;
michael@0 1104 default:
michael@0 1105 noMatch:
michael@0 1106 return 0;
michael@0 1107 }
michael@0 1108 SkSuppress suppress;
michael@0 1109 precedence = gPrecedence[match];
michael@0 1110 if (fSuppressStack.top().fSuppress) {
michael@0 1111 if (fSuppressStack.top().fOpStackDepth < fOpStack.count()) {
michael@0 1112 SkOp topOp = fOpStack.top();
michael@0 1113 if (gPrecedence[topOp] <= precedence)
michael@0 1114 fOpStack.pop();
michael@0 1115 goto goHome;
michael@0 1116 }
michael@0 1117 bool changedPrecedence = gPrecedence[fSuppressStack.top().fOperator] < precedence;
michael@0 1118 if (changedPrecedence)
michael@0 1119 fSuppressStack.pop();
michael@0 1120 if (precedence == kIfElsePrecedence) {
michael@0 1121 if (match == kIf) {
michael@0 1122 if (changedPrecedence)
michael@0 1123 fOpStack.pop();
michael@0 1124 else
michael@0 1125 *fOpStack.push() = kIf;
michael@0 1126 } else {
michael@0 1127 if (fSuppressStack.top().fOpStackDepth == fOpStack.count()) {
michael@0 1128 goto flipSuppress;
michael@0 1129 }
michael@0 1130 fOpStack.pop();
michael@0 1131 }
michael@0 1132 }
michael@0 1133 if (changedPrecedence == false)
michael@0 1134 goto goHome;
michael@0 1135 }
michael@0 1136 while (gPrecedence[fOpStack.top() & ~kArtificialOp] < precedence) {
michael@0 1137 if (processOp() == false)
michael@0 1138 return false;
michael@0 1139 }
michael@0 1140 if (fSuppressStack.top().fOpStackDepth > fOpStack.count())
michael@0 1141 fSuppressStack.pop();
michael@0 1142 switch (match) {
michael@0 1143 case kParen:
michael@0 1144 case kArrayOp:
michael@0 1145 if (fOpStack.count() <= 1 || fOpStack.top() != match) {
michael@0 1146 fError = kMismatchedBrackets;
michael@0 1147 return -1;
michael@0 1148 }
michael@0 1149 if (match == kParen)
michael@0 1150 fOpStack.pop();
michael@0 1151 else {
michael@0 1152 SkOpType indexType;
michael@0 1153 fTypeStack.pop(&indexType);
michael@0 1154 if (indexType != kInt && indexType != kScalar) {
michael@0 1155 fError = kExpectedNumberForArrayIndex; // (although, could permit strings eventually)
michael@0 1156 return -1;
michael@0 1157 }
michael@0 1158 SkOperand indexOperand;
michael@0 1159 fOperandStack.pop(&indexOperand);
michael@0 1160 int index = indexType == kScalar ? SkScalarFloorToInt(indexOperand.fScalar) :
michael@0 1161 indexOperand.fS32;
michael@0 1162 SkOpType arrayType;
michael@0 1163 fTypeStack.pop(&arrayType);
michael@0 1164 if ((unsigned)arrayType != (unsigned)kArray) {
michael@0 1165 fError = kExpectedArray;
michael@0 1166 return -1;
michael@0 1167 }
michael@0 1168 SkOperand arrayOperand;
michael@0 1169 fOperandStack.pop(&arrayOperand);
michael@0 1170 SkTypedArray* array = arrayOperand.fArray;
michael@0 1171 SkOperand operand;
michael@0 1172 if (array->getIndex(index, &operand) == false) {
michael@0 1173 fError = kIndexOutOfRange;
michael@0 1174 return -1;
michael@0 1175 }
michael@0 1176 SkOpType resultType = array->getOpType();
michael@0 1177 fTypeStack.push(resultType);
michael@0 1178 fOperandStack.push(operand);
michael@0 1179 }
michael@0 1180 break;
michael@0 1181 case kIf: {
michael@0 1182 SkScriptValue ifValue;
michael@0 1183 SkOpType ifType;
michael@0 1184 fTypeStack.pop(&ifType);
michael@0 1185 ifValue.fType = ToDisplayType(ifType);
michael@0 1186 fOperandStack.pop(&ifValue.fOperand);
michael@0 1187 if (convertTo(SkType_Int, &ifValue) == false)
michael@0 1188 return -1;
michael@0 1189 if (ifValue.fType != SkType_Int) {
michael@0 1190 fError = kExpectedIntForConditionOperator;
michael@0 1191 return -1;
michael@0 1192 }
michael@0 1193 suppress.fSuppress = ifValue.fOperand.fS32 == 0;
michael@0 1194 suppress.fOperator = kIf;
michael@0 1195 suppress.fOpStackDepth = fOpStack.count();
michael@0 1196 suppress.fElse = false;
michael@0 1197 fSuppressStack.push(suppress);
michael@0 1198 // if left is true, do only up to colon
michael@0 1199 // if left is false, do only after colon
michael@0 1200 } break;
michael@0 1201 case kElse:
michael@0 1202 flipSuppress:
michael@0 1203 if (fSuppressStack.top().fElse)
michael@0 1204 fSuppressStack.pop();
michael@0 1205 fSuppressStack.top().fElse = true;
michael@0 1206 fSuppressStack.top().fSuppress ^= true;
michael@0 1207 // flip last do / don't do consideration from last '?'
michael@0 1208 break;
michael@0 1209 case kLogicalAnd:
michael@0 1210 case kLogicalOr: {
michael@0 1211 if (fTypeStack.top() != kInt) {
michael@0 1212 fError = kExpectedBooleanExpression;
michael@0 1213 return -1;
michael@0 1214 }
michael@0 1215 int32_t topInt = fOperandStack.top().fS32;
michael@0 1216 if (fOpStack.top() != kLogicalAnd)
michael@0 1217 *fOpStack.push() = kLogicalAnd; // really means 'to bool', and is appropriate for 'or'
michael@0 1218 if (match == kLogicalOr ? topInt != 0 : topInt == 0) {
michael@0 1219 suppress.fSuppress = true;
michael@0 1220 suppress.fOperator = match;
michael@0 1221 suppress.fOpStackDepth = fOpStack.count();
michael@0 1222 suppress.fElse = false;
michael@0 1223 fSuppressStack.push(suppress);
michael@0 1224 } else {
michael@0 1225 fTypeStack.pop();
michael@0 1226 fOperandStack.pop();
michael@0 1227 }
michael@0 1228 } break;
michael@0 1229 default:
michael@0 1230 SkASSERT(0);
michael@0 1231 }
michael@0 1232 goHome:
michael@0 1233 return advance;
michael@0 1234 }
michael@0 1235
michael@0 1236 SkScriptEngine::Error SkScriptEngine::opError() {
michael@0 1237 int opCount = fOpStack.count();
michael@0 1238 int operandCount = fOperandStack.count();
michael@0 1239 if (opCount == 0) {
michael@0 1240 if (operandCount != 1)
michael@0 1241 return kExpectedOperator;
michael@0 1242 return kNoError;
michael@0 1243 }
michael@0 1244 SkOp op = (SkOp) (fOpStack.top() & ~kArtificialOp);
michael@0 1245 const SkOperatorAttributes* attributes = &gOpAttributes[op];
michael@0 1246 if (attributes->fLeftType != kNoType && operandCount < 2)
michael@0 1247 return kExpectedValue;
michael@0 1248 if (attributes->fLeftType == kNoType && operandCount < 1)
michael@0 1249 return kExpectedValue;
michael@0 1250 return kNoError;
michael@0 1251 }
michael@0 1252
michael@0 1253 bool SkScriptEngine::processOp() {
michael@0 1254 SkOp op;
michael@0 1255 fOpStack.pop(&op);
michael@0 1256 op = (SkOp) (op & ~kArtificialOp);
michael@0 1257 const SkOperatorAttributes* attributes = &gOpAttributes[op];
michael@0 1258 SkOpType type2;
michael@0 1259 fTypeStack.pop(&type2);
michael@0 1260 SkOpType type1 = type2;
michael@0 1261 SkOperand operand2;
michael@0 1262 fOperandStack.pop(&operand2);
michael@0 1263 SkOperand operand1 = operand2; // !!! not really needed, suppresses warning
michael@0 1264 if (attributes->fLeftType != kNoType) {
michael@0 1265 fTypeStack.pop(&type1);
michael@0 1266 fOperandStack.pop(&operand1);
michael@0 1267 if (op == kFlipOps) {
michael@0 1268 SkTSwap(type1, type2);
michael@0 1269 SkTSwap(operand1, operand2);
michael@0 1270 fOpStack.pop(&op);
michael@0 1271 op = (SkOp) (op & ~kArtificialOp);
michael@0 1272 attributes = &gOpAttributes[op];
michael@0 1273 }
michael@0 1274 if (type1 == kObject && (type1 & attributes->fLeftType) == 0) {
michael@0 1275 SkScriptValue val;
michael@0 1276 val.fType = ToDisplayType(type1);
michael@0 1277 val.fOperand = operand1;
michael@0 1278 bool success = handleUnbox(&val);
michael@0 1279 if (success == false)
michael@0 1280 return false;
michael@0 1281 type1 = ToOpType(val.fType);
michael@0 1282 operand1 = val.fOperand;
michael@0 1283 }
michael@0 1284 }
michael@0 1285 if (type2 == kObject && (type2 & attributes->fLeftType) == 0) {
michael@0 1286 SkScriptValue val;
michael@0 1287 val.fType = ToDisplayType(type2);
michael@0 1288 val.fOperand = operand2;
michael@0 1289 bool success = handleUnbox(&val);
michael@0 1290 if (success == false)
michael@0 1291 return false;
michael@0 1292 type2 = ToOpType(val.fType);
michael@0 1293 operand2 = val.fOperand;
michael@0 1294 }
michael@0 1295 if (attributes->fLeftType != kNoType) {
michael@0 1296 if (type1 != type2) {
michael@0 1297 if ((attributes->fLeftType & kString) && attributes->fBias & kTowardsString && ((type1 | type2) & kString)) {
michael@0 1298 if (type1 == kInt || type1 == kScalar) {
michael@0 1299 convertToString(operand1, type1 == kInt ? SkType_Int : SkType_Float);
michael@0 1300 type1 = kString;
michael@0 1301 }
michael@0 1302 if (type2 == kInt || type2 == kScalar) {
michael@0 1303 convertToString(operand2, type2 == kInt ? SkType_Int : SkType_Float);
michael@0 1304 type2 = kString;
michael@0 1305 }
michael@0 1306 } else if (attributes->fLeftType & kScalar && ((type1 | type2) & kScalar)) {
michael@0 1307 if (type1 == kInt) {
michael@0 1308 operand1.fScalar = IntToScalar(operand1.fS32);
michael@0 1309 type1 = kScalar;
michael@0 1310 }
michael@0 1311 if (type2 == kInt) {
michael@0 1312 operand2.fScalar = IntToScalar(operand2.fS32);
michael@0 1313 type2 = kScalar;
michael@0 1314 }
michael@0 1315 }
michael@0 1316 }
michael@0 1317 if ((type1 & attributes->fLeftType) == 0 || type1 != type2) {
michael@0 1318 if (type1 == kString) {
michael@0 1319 const char* result = SkParse::FindScalar(operand1.fString->c_str(), &operand1.fScalar);
michael@0 1320 if (result == NULL) {
michael@0 1321 fError = kExpectedNumber;
michael@0 1322 return false;
michael@0 1323 }
michael@0 1324 type1 = kScalar;
michael@0 1325 }
michael@0 1326 if (type1 == kScalar && (attributes->fLeftType == kInt || type2 == kInt)) {
michael@0 1327 operand1.fS32 = SkScalarFloorToInt(operand1.fScalar);
michael@0 1328 type1 = kInt;
michael@0 1329 }
michael@0 1330 }
michael@0 1331 }
michael@0 1332 if ((type2 & attributes->fRightType) == 0 || type1 != type2) {
michael@0 1333 if (type2 == kString) {
michael@0 1334 const char* result = SkParse::FindScalar(operand2.fString->c_str(), &operand2.fScalar);
michael@0 1335 if (result == NULL) {
michael@0 1336 fError = kExpectedNumber;
michael@0 1337 return false;
michael@0 1338 }
michael@0 1339 type2 = kScalar;
michael@0 1340 }
michael@0 1341 if (type2 == kScalar && (attributes->fRightType == kInt || type1 == kInt)) {
michael@0 1342 operand2.fS32 = SkScalarFloorToInt(operand2.fScalar);
michael@0 1343 type2 = kInt;
michael@0 1344 }
michael@0 1345 }
michael@0 1346 if (type2 == kScalar)
michael@0 1347 op = (SkOp) (op + 1);
michael@0 1348 else if (type2 == kString)
michael@0 1349 op = (SkOp) (op + 2);
michael@0 1350 switch(op) {
michael@0 1351 case kAddInt:
michael@0 1352 operand2.fS32 += operand1.fS32;
michael@0 1353 break;
michael@0 1354 case kAddScalar:
michael@0 1355 operand2.fScalar += operand1.fScalar;
michael@0 1356 break;
michael@0 1357 case kAddString:
michael@0 1358 if (fTrackString.find(operand1.fString) < 0) {
michael@0 1359 operand1.fString = SkNEW_ARGS(SkString, (*operand1.fString));
michael@0 1360 track(operand1.fString);
michael@0 1361 }
michael@0 1362 operand1.fString->append(*operand2.fString);
michael@0 1363 operand2 = operand1;
michael@0 1364 break;
michael@0 1365 case kBitAnd:
michael@0 1366 operand2.fS32 &= operand1.fS32;
michael@0 1367 break;
michael@0 1368 case kBitNot:
michael@0 1369 operand2.fS32 = ~operand2.fS32;
michael@0 1370 break;
michael@0 1371 case kBitOr:
michael@0 1372 operand2.fS32 |= operand1.fS32;
michael@0 1373 break;
michael@0 1374 case kDivideInt:
michael@0 1375 if (operand2.fS32 == 0) {
michael@0 1376 operand2.fS32 = operand1.fS32 == 0 ? SK_NaN32 : operand1.fS32 > 0 ? SK_MaxS32 : -SK_MaxS32;
michael@0 1377 break;
michael@0 1378 } else {
michael@0 1379 int32_t original = operand2.fS32;
michael@0 1380 operand2.fS32 = operand1.fS32 / operand2.fS32;
michael@0 1381 if (original * operand2.fS32 == operand1.fS32)
michael@0 1382 break; // integer divide was good enough
michael@0 1383 operand2.fS32 = original;
michael@0 1384 type2 = kScalar;
michael@0 1385 }
michael@0 1386 case kDivideScalar:
michael@0 1387 if (operand2.fScalar == 0)
michael@0 1388 operand2.fScalar = operand1.fScalar == 0 ? SK_ScalarNaN : operand1.fScalar > 0 ? SK_ScalarMax : -SK_ScalarMax;
michael@0 1389 else
michael@0 1390 operand2.fScalar = SkScalarDiv(operand1.fScalar, operand2.fScalar);
michael@0 1391 break;
michael@0 1392 case kEqualInt:
michael@0 1393 operand2.fS32 = operand1.fS32 == operand2.fS32;
michael@0 1394 break;
michael@0 1395 case kEqualScalar:
michael@0 1396 operand2.fS32 = operand1.fScalar == operand2.fScalar;
michael@0 1397 type2 = kInt;
michael@0 1398 break;
michael@0 1399 case kEqualString:
michael@0 1400 operand2.fS32 = *operand1.fString == *operand2.fString;
michael@0 1401 type2 = kInt;
michael@0 1402 break;
michael@0 1403 case kGreaterEqualInt:
michael@0 1404 operand2.fS32 = operand1.fS32 >= operand2.fS32;
michael@0 1405 break;
michael@0 1406 case kGreaterEqualScalar:
michael@0 1407 operand2.fS32 = operand1.fScalar >= operand2.fScalar;
michael@0 1408 type2 = kInt;
michael@0 1409 break;
michael@0 1410 case kGreaterEqualString:
michael@0 1411 operand2.fS32 = strcmp(operand1.fString->c_str(), operand2.fString->c_str()) >= 0;
michael@0 1412 type2 = kInt;
michael@0 1413 break;
michael@0 1414 case kLogicalAnd:
michael@0 1415 operand2.fS32 = !! operand2.fS32; // really, ToBool
michael@0 1416 break;
michael@0 1417 case kLogicalNot:
michael@0 1418 operand2.fS32 = ! operand2.fS32;
michael@0 1419 break;
michael@0 1420 case kLogicalOr:
michael@0 1421 SkASSERT(0); // should have already been processed
michael@0 1422 break;
michael@0 1423 case kMinusInt:
michael@0 1424 operand2.fS32 = -operand2.fS32;
michael@0 1425 break;
michael@0 1426 case kMinusScalar:
michael@0 1427 operand2.fScalar = -operand2.fScalar;
michael@0 1428 break;
michael@0 1429 case kModuloInt:
michael@0 1430 operand2.fS32 = operand1.fS32 % operand2.fS32;
michael@0 1431 break;
michael@0 1432 case kModuloScalar:
michael@0 1433 operand2.fScalar = SkScalarMod(operand1.fScalar, operand2.fScalar);
michael@0 1434 break;
michael@0 1435 case kMultiplyInt:
michael@0 1436 operand2.fS32 *= operand1.fS32;
michael@0 1437 break;
michael@0 1438 case kMultiplyScalar:
michael@0 1439 operand2.fScalar = SkScalarMul(operand1.fScalar, operand2.fScalar);
michael@0 1440 break;
michael@0 1441 case kShiftLeft:
michael@0 1442 operand2.fS32 = operand1.fS32 << operand2.fS32;
michael@0 1443 break;
michael@0 1444 case kShiftRight:
michael@0 1445 operand2.fS32 = operand1.fS32 >> operand2.fS32;
michael@0 1446 break;
michael@0 1447 case kSubtractInt:
michael@0 1448 operand2.fS32 = operand1.fS32 - operand2.fS32;
michael@0 1449 break;
michael@0 1450 case kSubtractScalar:
michael@0 1451 operand2.fScalar = operand1.fScalar - operand2.fScalar;
michael@0 1452 break;
michael@0 1453 case kXor:
michael@0 1454 operand2.fS32 ^= operand1.fS32;
michael@0 1455 break;
michael@0 1456 default:
michael@0 1457 SkASSERT(0);
michael@0 1458 }
michael@0 1459 fTypeStack.push(type2);
michael@0 1460 fOperandStack.push(operand2);
michael@0 1461 return true;
michael@0 1462 }
michael@0 1463
michael@0 1464 void SkScriptEngine::propertyCallBack(_propertyCallBack prop, void* userStorage) {
michael@0 1465 UserCallBack callBack;
michael@0 1466 callBack.fPropertyCallBack = prop;
michael@0 1467 commonCallBack(kProperty, callBack, userStorage);
michael@0 1468 }
michael@0 1469
michael@0 1470 void SkScriptEngine::track(SkTypedArray* array) {
michael@0 1471 SkASSERT(fTrackArray.find(array) < 0);
michael@0 1472 *(fTrackArray.end() - 1) = array;
michael@0 1473 fTrackArray.appendClear();
michael@0 1474 }
michael@0 1475
michael@0 1476 void SkScriptEngine::track(SkString* string) {
michael@0 1477 SkASSERT(fTrackString.find(string) < 0);
michael@0 1478 *(fTrackString.end() - 1) = string;
michael@0 1479 fTrackString.appendClear();
michael@0 1480 }
michael@0 1481
michael@0 1482 void SkScriptEngine::unboxCallBack(_unboxCallBack func, void* userStorage) {
michael@0 1483 UserCallBack callBack;
michael@0 1484 callBack.fUnboxCallBack = func;
michael@0 1485 commonCallBack(kUnbox, callBack, userStorage);
michael@0 1486 }
michael@0 1487
michael@0 1488 bool SkScriptEngine::ConvertTo(SkScriptEngine* engine, SkDisplayTypes toType, SkScriptValue* value ) {
michael@0 1489 SkASSERT(value);
michael@0 1490 if (SkDisplayType::IsEnum(NULL /* fMaker */, toType))
michael@0 1491 toType = SkType_Int;
michael@0 1492 if (toType == SkType_Point || toType == SkType_3D_Point)
michael@0 1493 toType = SkType_Float;
michael@0 1494 if (toType == SkType_Drawable)
michael@0 1495 toType = SkType_Displayable;
michael@0 1496 SkDisplayTypes type = value->fType;
michael@0 1497 if (type == toType)
michael@0 1498 return true;
michael@0 1499 SkOperand& operand = value->fOperand;
michael@0 1500 bool success = true;
michael@0 1501 switch (toType) {
michael@0 1502 case SkType_Int:
michael@0 1503 if (type == SkType_Boolean)
michael@0 1504 break;
michael@0 1505 if (type == SkType_Float)
michael@0 1506 operand.fS32 = SkScalarFloorToInt(operand.fScalar);
michael@0 1507 else {
michael@0 1508 if (type != SkType_String) {
michael@0 1509 success = false;
michael@0 1510 break; // error
michael@0 1511 }
michael@0 1512 success = SkParse::FindS32(operand.fString->c_str(), &operand.fS32) != NULL;
michael@0 1513 }
michael@0 1514 break;
michael@0 1515 case SkType_Float:
michael@0 1516 if (type == SkType_Int) {
michael@0 1517 if (operand.fS32 == SK_NaN32)
michael@0 1518 operand.fScalar = SK_ScalarNaN;
michael@0 1519 else if (SkAbs32(operand.fS32) == SK_MaxS32)
michael@0 1520 operand.fScalar = SkSign32(operand.fS32) * SK_ScalarMax;
michael@0 1521 else
michael@0 1522 operand.fScalar = SkIntToScalar(operand.fS32);
michael@0 1523 } else {
michael@0 1524 if (type != SkType_String) {
michael@0 1525 success = false;
michael@0 1526 break; // error
michael@0 1527 }
michael@0 1528 success = SkParse::FindScalar(operand.fString->c_str(), &operand.fScalar) != NULL;
michael@0 1529 }
michael@0 1530 break;
michael@0 1531 case SkType_String: {
michael@0 1532 SkString* strPtr = new SkString();
michael@0 1533 SkASSERT(engine);
michael@0 1534 engine->track(strPtr);
michael@0 1535 if (type == SkType_Int) {
michael@0 1536 strPtr->appendS32(operand.fS32);
michael@0 1537 } else if (type == SkType_Displayable) {
michael@0 1538 SkASSERT(0); // must call through instance version instead of static version
michael@0 1539 } else {
michael@0 1540 if (type != SkType_Float) {
michael@0 1541 success = false;
michael@0 1542 break;
michael@0 1543 }
michael@0 1544 strPtr->appendScalar(operand.fScalar);
michael@0 1545 }
michael@0 1546 operand.fString = strPtr;
michael@0 1547 } break;
michael@0 1548 case SkType_Array: {
michael@0 1549 SkTypedArray* array = new SkTypedArray(type);
michael@0 1550 *array->append() = operand;
michael@0 1551 engine->track(array);
michael@0 1552 operand.fArray = array;
michael@0 1553 } break;
michael@0 1554 default:
michael@0 1555 SkASSERT(0);
michael@0 1556 }
michael@0 1557 value->fType = toType;
michael@0 1558 if (success == false)
michael@0 1559 engine->fError = kTypeConversionFailed;
michael@0 1560 return success;
michael@0 1561 }
michael@0 1562
michael@0 1563 SkScalar SkScriptEngine::IntToScalar(int32_t s32) {
michael@0 1564 SkScalar scalar;
michael@0 1565 if (s32 == SK_NaN32)
michael@0 1566 scalar = SK_ScalarNaN;
michael@0 1567 else if (SkAbs32(s32) == SK_MaxS32)
michael@0 1568 scalar = SkSign32(s32) * SK_ScalarMax;
michael@0 1569 else
michael@0 1570 scalar = SkIntToScalar(s32);
michael@0 1571 return scalar;
michael@0 1572 }
michael@0 1573
michael@0 1574 SkDisplayTypes SkScriptEngine::ToDisplayType(SkOpType type) {
michael@0 1575 int val = type;
michael@0 1576 switch (val) {
michael@0 1577 case kNoType:
michael@0 1578 return SkType_Unknown;
michael@0 1579 case kInt:
michael@0 1580 return SkType_Int;
michael@0 1581 case kScalar:
michael@0 1582 return SkType_Float;
michael@0 1583 case kString:
michael@0 1584 return SkType_String;
michael@0 1585 case kArray:
michael@0 1586 return SkType_Array;
michael@0 1587 case kObject:
michael@0 1588 return SkType_Displayable;
michael@0 1589 // case kStruct:
michael@0 1590 // return SkType_Structure;
michael@0 1591 default:
michael@0 1592 SkASSERT(0);
michael@0 1593 return SkType_Unknown;
michael@0 1594 }
michael@0 1595 }
michael@0 1596
michael@0 1597 SkScriptEngine::SkOpType SkScriptEngine::ToOpType(SkDisplayTypes type) {
michael@0 1598 if (SkDisplayType::IsDisplayable(NULL /* fMaker */, type))
michael@0 1599 return (SkOpType) kObject;
michael@0 1600 if (SkDisplayType::IsEnum(NULL /* fMaker */, type))
michael@0 1601 return kInt;
michael@0 1602 switch (type) {
michael@0 1603 case SkType_ARGB:
michael@0 1604 case SkType_MSec:
michael@0 1605 case SkType_Int:
michael@0 1606 return kInt;
michael@0 1607 case SkType_Float:
michael@0 1608 case SkType_Point:
michael@0 1609 case SkType_3D_Point:
michael@0 1610 return kScalar;
michael@0 1611 case SkType_Base64:
michael@0 1612 case SkType_DynamicString:
michael@0 1613 case SkType_String:
michael@0 1614 return kString;
michael@0 1615 case SkType_Array:
michael@0 1616 return (SkOpType) kArray;
michael@0 1617 case SkType_Unknown:
michael@0 1618 return kNoType;
michael@0 1619 default:
michael@0 1620 SkASSERT(0);
michael@0 1621 return kNoType;
michael@0 1622 }
michael@0 1623 }
michael@0 1624
michael@0 1625 bool SkScriptEngine::ValueToString(SkScriptValue value, SkString* string) {
michael@0 1626 switch (value.fType) {
michael@0 1627 case kInt:
michael@0 1628 string->reset();
michael@0 1629 string->appendS32(value.fOperand.fS32);
michael@0 1630 break;
michael@0 1631 case kScalar:
michael@0 1632 string->reset();
michael@0 1633 string->appendScalar(value.fOperand.fScalar);
michael@0 1634 break;
michael@0 1635 case kString:
michael@0 1636 string->set(*value.fOperand.fString);
michael@0 1637 break;
michael@0 1638 default:
michael@0 1639 SkASSERT(0);
michael@0 1640 return false;
michael@0 1641 }
michael@0 1642 return true; // no error
michael@0 1643 }
michael@0 1644
michael@0 1645 #ifdef SK_SUPPORT_UNITTEST
michael@0 1646
michael@0 1647 #include "SkFloatingPoint.h"
michael@0 1648
michael@0 1649 #define DEF_SCALAR_ANSWER 0
michael@0 1650 #define DEF_STRING_ANSWER NULL
michael@0 1651
michael@0 1652 #define testInt(expression) { #expression, SkType_Int, expression, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }
michael@0 1653 #define testScalar(expression) { #expression, SkType_Float, 0, (float) expression, DEF_STRING_ANSWER }
michael@0 1654 #define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkType_Float, 0, sk_float_mod(exp1, exp2), DEF_STRING_ANSWER }
michael@0 1655 #define testTrue(expression) { #expression, SkType_Int, 1, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }
michael@0 1656 #define testFalse(expression) { #expression, SkType_Int, 0, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }
michael@0 1657
michael@0 1658 static const SkScriptNAnswer scriptTests[] = {
michael@0 1659 testInt(1>1/2),
michael@0 1660 testInt((6+7)*8),
michael@0 1661 testInt(0&&1?2:3),
michael@0 1662 testInt(3*(4+5)),
michael@0 1663 testScalar(1.0+2.0),
michael@0 1664 testScalar(1.0+5),
michael@0 1665 testScalar(3.0-1.0),
michael@0 1666 testScalar(6-1.0),
michael@0 1667 testScalar(- -5.5- -1.5),
michael@0 1668 testScalar(2.5*6.),
michael@0 1669 testScalar(0.5*4),
michael@0 1670 testScalar(4.5/.5),
michael@0 1671 testScalar(9.5/19),
michael@0 1672 testRemainder(9.5, 0.5),
michael@0 1673 testRemainder(9.,2),
michael@0 1674 testRemainder(9,2.5),
michael@0 1675 testRemainder(-9,2.5),
michael@0 1676 testTrue(-9==-9.0),
michael@0 1677 testTrue(-9.==-4.0-5),
michael@0 1678 testTrue(-9.*1==-4-5),
michael@0 1679 testFalse(-9!=-9.0),
michael@0 1680 testFalse(-9.!=-4.0-5),
michael@0 1681 testFalse(-9.*1!=-4-5),
michael@0 1682 testInt(0x123),
michael@0 1683 testInt(0XABC),
michael@0 1684 testInt(0xdeadBEEF),
michael@0 1685 { "'123'+\"456\"", SkType_String, 0, 0, "123456" },
michael@0 1686 { "123+\"456\"", SkType_String, 0, 0, "123456" },
michael@0 1687 { "'123'+456", SkType_String, 0, 0, "123456" },
michael@0 1688 { "'123'|\"456\"", SkType_Int, 123|456, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER },
michael@0 1689 { "123|\"456\"", SkType_Int, 123|456, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER },
michael@0 1690 { "'123'|456", SkType_Int, 123|456, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER },
michael@0 1691 { "'2'<11", SkType_Int, 1, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER },
michael@0 1692 { "2<'11'", SkType_Int, 1, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER },
michael@0 1693 { "'2'<'11'", SkType_Int, 0, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER },
michael@0 1694 testInt(123),
michael@0 1695 testInt(-345),
michael@0 1696 testInt(+678),
michael@0 1697 testInt(1+2+3),
michael@0 1698 testInt(3*4+5),
michael@0 1699 testInt(6+7*8),
michael@0 1700 testInt(-1-2-8/4),
michael@0 1701 testInt(-9%4),
michael@0 1702 testInt(9%-4),
michael@0 1703 testInt(-9%-4),
michael@0 1704 testInt(123|978),
michael@0 1705 testInt(123&978),
michael@0 1706 testInt(123^978),
michael@0 1707 testInt(2<<4),
michael@0 1708 testInt(99>>3),
michael@0 1709 testInt(~55),
michael@0 1710 testInt(~~55),
michael@0 1711 testInt(!55),
michael@0 1712 testInt(!!55),
michael@0 1713 // both int
michael@0 1714 testInt(2<2),
michael@0 1715 testInt(2<11),
michael@0 1716 testInt(20<11),
michael@0 1717 testInt(2<=2),
michael@0 1718 testInt(2<=11),
michael@0 1719 testInt(20<=11),
michael@0 1720 testInt(2>2),
michael@0 1721 testInt(2>11),
michael@0 1722 testInt(20>11),
michael@0 1723 testInt(2>=2),
michael@0 1724 testInt(2>=11),
michael@0 1725 testInt(20>=11),
michael@0 1726 testInt(2==2),
michael@0 1727 testInt(2==11),
michael@0 1728 testInt(20==11),
michael@0 1729 testInt(2!=2),
michael@0 1730 testInt(2!=11),
michael@0 1731 testInt(20!=11),
michael@0 1732 // left int, right scalar
michael@0 1733 testInt(2<2.),
michael@0 1734 testInt(2<11.),
michael@0 1735 testInt(20<11.),
michael@0 1736 testInt(2<=2.),
michael@0 1737 testInt(2<=11.),
michael@0 1738 testInt(20<=11.),
michael@0 1739 testInt(2>2.),
michael@0 1740 testInt(2>11.),
michael@0 1741 testInt(20>11.),
michael@0 1742 testInt(2>=2.),
michael@0 1743 testInt(2>=11.),
michael@0 1744 testInt(20>=11.),
michael@0 1745 testInt(2==2.),
michael@0 1746 testInt(2==11.),
michael@0 1747 testInt(20==11.),
michael@0 1748 testInt(2!=2.),
michael@0 1749 testInt(2!=11.),
michael@0 1750 testInt(20!=11.),
michael@0 1751 // left scalar, right int
michael@0 1752 testInt(2.<2),
michael@0 1753 testInt(2.<11),
michael@0 1754 testInt(20.<11),
michael@0 1755 testInt(2.<=2),
michael@0 1756 testInt(2.<=11),
michael@0 1757 testInt(20.<=11),
michael@0 1758 testInt(2.>2),
michael@0 1759 testInt(2.>11),
michael@0 1760 testInt(20.>11),
michael@0 1761 testInt(2.>=2),
michael@0 1762 testInt(2.>=11),
michael@0 1763 testInt(20.>=11),
michael@0 1764 testInt(2.==2),
michael@0 1765 testInt(2.==11),
michael@0 1766 testInt(20.==11),
michael@0 1767 testInt(2.!=2),
michael@0 1768 testInt(2.!=11),
michael@0 1769 testInt(20.!=11),
michael@0 1770 // both scalar
michael@0 1771 testInt(2.<11.),
michael@0 1772 testInt(20.<11.),
michael@0 1773 testInt(2.<=2.),
michael@0 1774 testInt(2.<=11.),
michael@0 1775 testInt(20.<=11.),
michael@0 1776 testInt(2.>2.),
michael@0 1777 testInt(2.>11.),
michael@0 1778 testInt(20.>11.),
michael@0 1779 testInt(2.>=2.),
michael@0 1780 testInt(2.>=11.),
michael@0 1781 testInt(20.>=11.),
michael@0 1782 testInt(2.==2.),
michael@0 1783 testInt(2.==11.),
michael@0 1784 testInt(20.==11.),
michael@0 1785 testInt(2.!=2.),
michael@0 1786 testInt(2.!=11.),
michael@0 1787 testInt(20.!=11.),
michael@0 1788 // int, string (string is int)
michael@0 1789 testFalse(2<'2'),
michael@0 1790 testTrue(2<'11'),
michael@0 1791 testFalse(20<'11'),
michael@0 1792 testTrue(2<='2'),
michael@0 1793 testTrue(2<='11'),
michael@0 1794 testFalse(20<='11'),
michael@0 1795 testFalse(2>'2'),
michael@0 1796 testFalse(2>'11'),
michael@0 1797 testTrue(20>'11'),
michael@0 1798 testTrue(2>='2'),
michael@0 1799 testFalse(2>='11'),
michael@0 1800 testTrue(20>='11'),
michael@0 1801 testTrue(2=='2'),
michael@0 1802 testFalse(2=='11'),
michael@0 1803 testFalse(2!='2'),
michael@0 1804 testTrue(2!='11'),
michael@0 1805 // int, string (string is scalar)
michael@0 1806 testFalse(2<'2.'),
michael@0 1807 testTrue(2<'11.'),
michael@0 1808 testFalse(20<'11.'),
michael@0 1809 testTrue(2=='2.'),
michael@0 1810 testFalse(2=='11.'),
michael@0 1811 // scalar, string
michael@0 1812 testFalse(2.<'2.'),
michael@0 1813 testTrue(2.<'11.'),
michael@0 1814 testFalse(20.<'11.'),
michael@0 1815 testTrue(2.=='2.'),
michael@0 1816 testFalse(2.=='11.'),
michael@0 1817 // string, int
michael@0 1818 testFalse('2'<2),
michael@0 1819 testTrue('2'<11),
michael@0 1820 testFalse('20'<11),
michael@0 1821 testTrue('2'==2),
michael@0 1822 testFalse('2'==11),
michael@0 1823 // string, scalar
michael@0 1824 testFalse('2'<2.),
michael@0 1825 testTrue('2'<11.),
michael@0 1826 testFalse('20'<11.),
michael@0 1827 testTrue('2'==2.),
michael@0 1828 testFalse('2'==11.),
michael@0 1829 // string, string
michael@0 1830 testFalse('2'<'2'),
michael@0 1831 testFalse('2'<'11'),
michael@0 1832 testFalse('20'<'11'),
michael@0 1833 testTrue('2'=='2'),
michael@0 1834 testFalse('2'=='11'),
michael@0 1835 // logic
michael@0 1836 testInt(1?2:3),
michael@0 1837 testInt(0?2:3),
michael@0 1838 testInt((1&&2)||3),
michael@0 1839 testInt((1&&0)||3),
michael@0 1840 testInt((1&&0)||0),
michael@0 1841 testInt(1||(0&&3)),
michael@0 1842 testInt(0||(0&&3)),
michael@0 1843 testInt(0||(1&&3)),
michael@0 1844 testInt(1?(2?3:4):5),
michael@0 1845 testInt(0?(2?3:4):5),
michael@0 1846 testInt(1?(0?3:4):5),
michael@0 1847 testInt(0?(0?3:4):5),
michael@0 1848 testInt(1?2?3:4:5),
michael@0 1849 testInt(0?2?3:4:5),
michael@0 1850 testInt(1?0?3:4:5),
michael@0 1851 testInt(0?0?3:4:5),
michael@0 1852
michael@0 1853 testInt(1?2:(3?4:5)),
michael@0 1854 testInt(0?2:(3?4:5)),
michael@0 1855 testInt(1?0:(3?4:5)),
michael@0 1856 testInt(0?0:(3?4:5)),
michael@0 1857 testInt(1?2:3?4:5),
michael@0 1858 testInt(0?2:3?4:5),
michael@0 1859 testInt(1?0:3?4:5),
michael@0 1860 testInt(0?0:3?4:5)
michael@0 1861 , { "123.5", SkType_Float, 0, SkIntToScalar(123) + SK_Scalar1/2, DEF_STRING_ANSWER }
michael@0 1862 };
michael@0 1863
michael@0 1864 #define SkScriptNAnswer_testCount SK_ARRAY_COUNT(scriptTests)
michael@0 1865
michael@0 1866 void SkScriptEngine::UnitTest() {
michael@0 1867 for (unsigned index = 0; index < SkScriptNAnswer_testCount; index++) {
michael@0 1868 SkScriptEngine engine(SkScriptEngine::ToOpType(scriptTests[index].fType));
michael@0 1869 SkScriptValue value;
michael@0 1870 const char* script = scriptTests[index].fScript;
michael@0 1871 SkASSERT(engine.evaluateScript(&script, &value) == true);
michael@0 1872 SkASSERT(value.fType == scriptTests[index].fType);
michael@0 1873 SkScalar error;
michael@0 1874 switch (value.fType) {
michael@0 1875 case SkType_Int:
michael@0 1876 SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer);
michael@0 1877 break;
michael@0 1878 case SkType_Float:
michael@0 1879 error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer);
michael@0 1880 SkASSERT(error < SK_Scalar1 / 10000);
michael@0 1881 break;
michael@0 1882 case SkType_String:
michael@0 1883 SkASSERT(strcmp(value.fOperand.fString->c_str(), scriptTests[index].fStringAnswer) == 0);
michael@0 1884 break;
michael@0 1885 default:
michael@0 1886 SkASSERT(0);
michael@0 1887 }
michael@0 1888 }
michael@0 1889 }
michael@0 1890 #endif

mercurial