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