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