diff options
Diffstat (limited to 'skia/animator/SkScript.cpp')
-rw-r--r-- | skia/animator/SkScript.cpp | 1918 |
1 files changed, 0 insertions, 1918 deletions
diff --git a/skia/animator/SkScript.cpp b/skia/animator/SkScript.cpp deleted file mode 100644 index 3b67d7b..0000000 --- a/skia/animator/SkScript.cpp +++ /dev/null @@ -1,1918 +0,0 @@ -/* libs/graphics/animator/SkScript.cpp -** -** Copyright 2006, The Android Open Source Project -** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at -** -** http://www.apache.org/licenses/LICENSE-2.0 -** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and -** limitations under the License. -*/ - -#include "SkScript.h" -#include "SkMath.h" -#include "SkParse.h" -#include "SkString.h" -#include "SkTypedArray.h" - -/* things to do - ? re-enable support for struct literals (e.g., for initializing points or rects) - {x:1, y:2} - ? use standard XML / script notation like document.getElementById("canvas"); - finish support for typed arrays - ? allow indexing arrays by string - this could map to the 'name' attribute of a given child of an array - ? allow multiple types in the array - remove SkDisplayType.h // from SkOperand.h - merge type and operand arrays into scriptvalue array -*/ - -#ifdef SK_DEBUG -static const char* errorStrings[] = { - "array index of out bounds", // kArrayIndexOutOfBounds - "could not find reference id", // kCouldNotFindReferencedID - "dot operator expects object", // kDotOperatorExpectsObject - "error in array index", // kErrorInArrrayIndex - "error in function parameters", // kErrorInFunctionParameters - "expected array", // kExpectedArray - "expected boolean expression", // kExpectedBooleanExpression - "expected field name", // kExpectedFieldName - "expected hex", // kExpectedHex - "expected int for condition operator", // kExpectedIntForConditionOperator - "expected number", // kExpectedNumber - "expected number for array index", // kExpectedNumberForArrayIndex - "expected operator", // kExpectedOperator - "expected token", // kExpectedToken - "expected token before dot operator", // kExpectedTokenBeforeDotOperator - "expected value", // kExpectedValue - "handle member failed", // kHandleMemberFailed - "handle member function failed", // kHandleMemberFunctionFailed - "handle unbox failed", // kHandleUnboxFailed - "index out of range", // kIndexOutOfRange - "mismatched array brace", // kMismatchedArrayBrace - "mismatched brackets", // kMismatchedBrackets - "no function handler found", // kNoFunctionHandlerFound - "premature end", // kPrematureEnd - "too many parameters", // kTooManyParameters - "type conversion failed", // kTypeConversionFailed - "unterminated string" // kUnterminatedString -}; -#endif - -const SkScriptEngine::SkOperatorAttributes SkScriptEngine::gOpAttributes[] = { - { kNoType, kNoType, kNoBias }, // kUnassigned, - { SkOpType(kInt | kScalar | kString), SkOpType(kInt | kScalar | kString), kTowardsString }, // kAdd - // kAddInt = kAdd, - { kNoType, kNoType, kNoBias }, // kAddScalar, - { kNoType, kNoType, kNoBias }, // kAddString, - { kNoType, kNoType, kNoBias }, // kArrayOp, - { kInt, kInt, kNoBias }, // kBitAnd - { kNoType, kInt, kNoBias }, // kBitNot - { kInt, kInt, kNoBias }, // kBitOr - { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kDivide - // kDivideInt = kDivide - { kNoType, kNoType, kNoBias }, // kDivideScalar - { kNoType, kNoType, kNoBias }, // kElse - { SkOpType(kInt | kScalar | kString), SkOpType(kInt | kScalar | kString), kTowardsNumber }, // kEqual - // kEqualInt = kEqual - { kNoType, kNoType, kNoBias }, // kEqualScalar - { kNoType, kNoType, kNoBias }, // kEqualString - { kInt, kNoType, kNoBias }, // kFlipOps - { SkOpType(kInt | kScalar | kString), SkOpType(kInt | kScalar | kString), kTowardsNumber }, // kGreaterEqual - // kGreaterEqualInt = kGreaterEqual - { kNoType, kNoType, kNoBias }, // kGreaterEqualScalar - { kNoType, kNoType, kNoBias }, // kGreaterEqualString - { kNoType, kNoType, kNoBias }, // kIf - { kNoType, kInt, kNoBias }, // kLogicalAnd (really, ToBool) - { kNoType, kInt, kNoBias }, // kLogicalNot - { kInt, kInt, kNoBias }, // kLogicalOr - { kNoType, SkOpType(kInt | kScalar), kNoBias }, // kMinus - // kMinusInt = kMinus - { kNoType, kNoType, kNoBias }, // kMinusScalar - { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kModulo - // kModuloInt = kModulo - { kNoType, kNoType, kNoBias }, // kModuloScalar - { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kMultiply - // kMultiplyInt = kMultiply - { kNoType, kNoType, kNoBias }, // kMultiplyScalar - { kNoType, kNoType, kNoBias }, // kParen - { kInt, kInt, kNoBias }, // kShiftLeft - { kInt, kInt, kNoBias }, // kShiftRight - { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kSubtract - // kSubtractInt = kSubtract - { kNoType, kNoType, kNoBias }, // kSubtractScalar - { kInt, kInt, kNoBias } // kXor -}; - -// Note that the real precedence for () [] is '2' -// but here, precedence means 'while an equal or smaller precedence than the current operator -// is on the stack, process it. This allows 3+5*2 to defer the add until after the multiply -// is preformed, since the add precedence is not smaller than multiply. -// But, (3*4 does not process the '(', since brackets are greater than all other precedences -#define kBracketPrecedence 16 -#define kIfElsePrecedence 15 - -const signed char SkScriptEngine::gPrecedence[] = { - -1, // kUnassigned, - 6, // kAdd, - // kAddInt = kAdd, - 6, // kAddScalar, - 6, // kAddString, // string concat - kBracketPrecedence, // kArrayOp, - 10, // kBitAnd, - 4, // kBitNot, - 12, // kBitOr, - 5, // kDivide, - // kDivideInt = kDivide, - 5, // kDivideScalar, - kIfElsePrecedence, // kElse, - 9, // kEqual, - // kEqualInt = kEqual, - 9, // kEqualScalar, - 9, // kEqualString, - -1, // kFlipOps, - 8, // kGreaterEqual, - // kGreaterEqualInt = kGreaterEqual, - 8, // kGreaterEqualScalar, - 8, // kGreaterEqualString, - kIfElsePrecedence, // kIf, - 13, // kLogicalAnd, - 4, // kLogicalNot, - 14, // kLogicalOr, - 4, // kMinus, - // kMinusInt = kMinus, - 4, // kMinusScalar, - 5, // kModulo, - // kModuloInt = kModulo, - 5, // kModuloScalar, - 5, // kMultiply, - // kMultiplyInt = kMultiply, - 5, // kMultiplyScalar, - kBracketPrecedence, // kParen, - 7, // kShiftLeft, - 7, // kShiftRight, // signed - 6, // kSubtract, - // kSubtractInt = kSubtract, - 6, // kSubtractScalar, - 11, // kXor -}; - -static inline bool is_between(int c, int min, int max) -{ - return (unsigned)(c - min) <= (unsigned)(max - min); -} - -static inline bool is_ws(int c) -{ - return is_between(c, 1, 32); -} - -static int token_length(const char* start) { - char ch = start[0]; - if (! is_between(ch, 'a' , 'z') && ! is_between(ch, 'A', 'Z') && ch != '_' && ch != '$') - return -1; - int length = 0; - do - ch = start[++length]; - while (is_between(ch, 'a' , 'z') || is_between(ch, 'A', 'Z') || is_between(ch, '0', '9') || - ch == '_' || ch == '$'); - return length; -} - -SkScriptEngine::SkScriptEngine(SkOpType returnType) : - fTokenLength(0), fReturnType(returnType), fError(kNoError) -{ - SkSuppress noInitialSuppress; - noInitialSuppress.fOperator = kUnassigned; - noInitialSuppress.fOpStackDepth = 0; - noInitialSuppress.fSuppress = false; - fSuppressStack.push(noInitialSuppress); - *fOpStack.push() = kParen; - fTrackArray.appendClear(); - fTrackString.appendClear(); -} - -SkScriptEngine::~SkScriptEngine() { - for (SkString** stringPtr = fTrackString.begin(); stringPtr < fTrackString.end(); stringPtr++) - delete *stringPtr; - for (SkTypedArray** arrayPtr = fTrackArray.begin(); arrayPtr < fTrackArray.end(); arrayPtr++) - delete *arrayPtr; -} - -int SkScriptEngine::arithmeticOp(char ch, char nextChar, bool lastPush) { - SkOp op = kUnassigned; - bool reverseOperands = false; - bool negateResult = false; - int advance = 1; - switch (ch) { - case '+': - // !!! ignoring unary plus as implemented here has the side effect of - // suppressing errors like +"hi" - if (lastPush == false) // unary plus, don't push an operator - goto returnAdv; - op = kAdd; - break; - case '-': - op = lastPush ? kSubtract : kMinus; - break; - case '*': - op = kMultiply; - break; - case '/': - op = kDivide; - break; - case '>': - if (nextChar == '>') { - op = kShiftRight; - goto twoChar; - } - op = kGreaterEqual; - if (nextChar == '=') - goto twoChar; - reverseOperands = negateResult = true; - break; - case '<': - if (nextChar == '<') { - op = kShiftLeft; - goto twoChar; - } - op = kGreaterEqual; - reverseOperands = nextChar == '='; - negateResult = ! reverseOperands; - advance += reverseOperands; - break; - case '=': - if (nextChar == '=') { - op = kEqual; - goto twoChar; - } - break; - case '!': - if (nextChar == '=') { - op = kEqual; - negateResult = true; -twoChar: - advance++; - break; - } - op = kLogicalNot; - break; - case '?': - op = kIf; - break; - case ':': - op = kElse; - break; - case '^': - op = kXor; - break; - case '(': - *fOpStack.push() = kParen; // push even if eval is suppressed - goto returnAdv; - case '&': - SkASSERT(nextChar != '&'); - op = kBitAnd; - break; - case '|': - SkASSERT(nextChar != '|'); - op = kBitOr; - break; - case '%': - op = kModulo; - break; - case '~': - op = kBitNot; - break; - } - if (op == kUnassigned) - return 0; - if (fSuppressStack.top().fSuppress == false) { - signed char precedence = gPrecedence[op]; - do { - int idx = 0; - SkOp compare; - do { - compare = fOpStack.index(idx); - if ((compare & kArtificialOp) == 0) - break; - idx++; - } while (true); - signed char topPrecedence = gPrecedence[compare]; - SkASSERT(topPrecedence != -1); - if (topPrecedence > precedence || topPrecedence == precedence && - gOpAttributes[op].fLeftType == kNoType) { - break; - } - if (processOp() == false) - return 0; // error - } while (true); - if (negateResult) - *fOpStack.push() = (SkOp) (kLogicalNot | kArtificialOp); - fOpStack.push(op); - if (reverseOperands) - *fOpStack.push() = (SkOp) (kFlipOps | kArtificialOp); - } -returnAdv: - return advance; -} - -void SkScriptEngine::boxCallBack(_boxCallBack func, void* userStorage) { - UserCallBack callBack; - callBack.fBoxCallBack = func; - commonCallBack(kBox, callBack, userStorage); -} - -void SkScriptEngine::commonCallBack(CallBackType type, UserCallBack& callBack, void* userStorage) { - callBack.fCallBackType = type; - callBack.fUserStorage = userStorage; - *fUserCallBacks.prepend() = callBack; -} - -bool SkScriptEngine::convertParams(SkTDArray<SkScriptValue>& params, - const SkFunctionParamType* paramTypes, int paramCount) { - if (params.count() > paramCount) { - fError = kTooManyParameters; - return false; // too many parameters passed - } - for (int index = 0; index < params.count(); index++) { - if (convertTo((SkDisplayTypes) paramTypes[index], ¶ms[index]) == false) - return false; - } - return true; -} - -bool SkScriptEngine::convertTo(SkDisplayTypes toType, SkScriptValue* value ) { - SkDisplayTypes type = value->fType; - if (type == toType) - return true; - if (ToOpType(type) == kObject) { -#if 0 // !!! I want object->string to get string from displaystringtype, not id - if (ToOpType(toType) == kString) { - bool success = handleObjectToString(value->fOperand.fObject); - if (success == false) - return false; - SkOpType type; - fTypeStack.pop(&type); - value->fType = ToDisplayType(type); - fOperandStack.pop(&value->fOperand); - return true; - } -#endif - if (handleUnbox(value) == false) { - fError = kHandleUnboxFailed; - return false; - } - return convertTo(toType, value); - } - return ConvertTo(this, toType, value); -} - -bool SkScriptEngine::evaluateDot(const char*& script, bool suppressed) { - size_t fieldLength = token_length(++script); // skip dot - if (fieldLength == 0) { - fError = kExpectedFieldName; - return false; - } - const char* field = script; - script += fieldLength; - bool success = handleProperty(suppressed); - if (success == false) { - fError = kCouldNotFindReferencedID; // note: never generated by standard animator plugins - return false; - } - return evaluateDotParam(script, suppressed, field, fieldLength); -} - -bool SkScriptEngine::evaluateDotParam(const char*& script, bool suppressed, - const char* field, size_t fieldLength) { - void* object; - if (suppressed) - object = NULL; - else { - if (fTypeStack.top() != kObject) { - fError = kDotOperatorExpectsObject; - return false; - } - object = fOperandStack.top().fObject; - fTypeStack.pop(); - fOperandStack.pop(); - } - char ch; // see if it is a simple member or a function - while (is_ws(ch = script[0])) - script++; - bool success = true; - if (ch != '(') { - if (suppressed == false) { - if ((success = handleMember(field, fieldLength, object)) == false) - fError = kHandleMemberFailed; - } - } else { - SkTDArray<SkScriptValue> params; - *fBraceStack.push() = kFunctionBrace; - success = functionParams(&script, params); - if (success && suppressed == false && - (success = handleMemberFunction(field, fieldLength, object, params)) == false) - fError = kHandleMemberFunctionFailed; - } - return success; -} - -bool SkScriptEngine::evaluateScript(const char** scriptPtr, SkScriptValue* value) { -#ifdef SK_DEBUG - const char** original = scriptPtr; -#endif - bool success; - const char* inner; - if (strncmp(*scriptPtr, "#script:", sizeof("#script:") - 1) == 0) { - *scriptPtr += sizeof("#script:") - 1; - if (fReturnType == kNoType || fReturnType == kString) { - success = innerScript(scriptPtr, value); - if (success == false) - goto end; - inner = value->fOperand.fString->c_str(); - scriptPtr = &inner; - } - } - { - success = innerScript(scriptPtr, value); - if (success == false) - goto end; - const char* script = *scriptPtr; - char ch; - while (is_ws(ch = script[0])) - script++; - if (ch != '\0') { - // error may trigger on scripts like "50,0" that were intended to be written as "[50, 0]" - fError = kPrematureEnd; - success = false; - } - } -end: -#ifdef SK_DEBUG - if (success == false) { - SkDebugf("script failed: %s", *original); - if (fError) - SkDebugf(" %s", errorStrings[fError - 1]); - SkDebugf("\n"); - } -#endif - return success; -} - -void SkScriptEngine::forget(SkTypedArray* array) { - if (array->getType() == SkType_String) { - for (int index = 0; index < array->count(); index++) { - SkString* string = (*array)[index].fString; - int found = fTrackString.find(string); - if (found >= 0) - fTrackString.remove(found); - } - return; - } - if (array->getType() == SkType_Array) { - for (int index = 0; index < array->count(); index++) { - SkTypedArray* child = (*array)[index].fArray; - forget(child); // forgets children of child - int found = fTrackArray.find(child); - if (found >= 0) - fTrackArray.remove(found); - } - } -} - -void SkScriptEngine::functionCallBack(_functionCallBack func, void* userStorage) { - UserCallBack callBack; - callBack.fFunctionCallBack = func; - commonCallBack(kFunction, callBack, userStorage); -} - -bool SkScriptEngine::functionParams(const char** scriptPtr, SkTDArray<SkScriptValue>& params) { - (*scriptPtr)++; // skip open paren - *fOpStack.push() = kParen; - *fBraceStack.push() = kFunctionBrace; - SkBool suppressed = fSuppressStack.top().fSuppress; - do { - SkScriptValue value; - bool success = innerScript(scriptPtr, suppressed ? NULL : &value); - if (success == false) { - fError = kErrorInFunctionParameters; - return false; - } - if (suppressed) - continue; - *params.append() = value; - } while ((*scriptPtr)[-1] == ','); - fBraceStack.pop(); - fOpStack.pop(); // pop paren - (*scriptPtr)++; // advance beyond close paren - return true; -} - -#ifdef SK_DEBUG -bool SkScriptEngine::getErrorString(SkString* str) const { - if (fError) - str->set(errorStrings[fError - 1]); - return fError != 0; -} -#endif - -bool SkScriptEngine::innerScript(const char** scriptPtr, SkScriptValue* value) { - const char* script = *scriptPtr; - char ch; - bool lastPush = false; - bool success = true; - int opBalance = fOpStack.count(); - int baseBrace = fBraceStack.count(); - int suppressBalance = fSuppressStack.count(); - while ((ch = script[0]) != '\0') { - if (is_ws(ch)) { - script++; - continue; - } - SkBool suppressed = fSuppressStack.top().fSuppress; - SkOperand operand; - const char* dotCheck; - if (fBraceStack.count() > baseBrace) { -#if 0 // disable support for struct brace - if (ch == ':') { - SkASSERT(fTokenLength > 0); - SkASSERT(fBraceStack.top() == kStructBrace); - ++script; - SkASSERT(fDisplayable); - SkString token(fToken, fTokenLength); - fTokenLength = 0; - const char* tokenName = token.c_str(); - const SkMemberInfo* tokenInfo SK_INIT_TO_AVOID_WARNING; - if (suppressed == false) { - SkDisplayTypes type = fInfo->getType(); - tokenInfo = SkDisplayType::GetMember(type, &tokenName); - SkASSERT(tokenInfo); - } - SkScriptValue tokenValue; - success = innerScript(&script, &tokenValue); // terminate and return on comma, close brace - SkASSERT(success); - if (suppressed == false) { - if (tokenValue.fType == SkType_Displayable) { - SkASSERT(SkDisplayType::IsDisplayable(tokenInfo->getType())); - fDisplayable->setReference(tokenInfo, tokenValue.fOperand.fDisplayable); - } else { - if (tokenValue.fType != tokenInfo->getType()) { - if (convertTo(tokenInfo->getType(), &tokenValue) == false) - return false; - } - tokenInfo->writeValue(fDisplayable, NULL, 0, 0, - (void*) ((char*) fInfo->memberData(fDisplayable) + tokenInfo->fOffset + fArrayOffset), - tokenInfo->getType(), tokenValue); - } - } - lastPush = false; - continue; - } else -#endif - if (fBraceStack.top() == kArrayBrace) { - SkScriptValue tokenValue; - success = innerScript(&script, &tokenValue); // terminate and return on comma, close brace - if (success == false) { - fError = kErrorInArrrayIndex; - return false; - } - if (suppressed == false) { -#if 0 // no support for structures for now - if (tokenValue.fType == SkType_Structure) { - fArrayOffset += (int) fInfo->getSize(fDisplayable); - } else -#endif - { - SkDisplayTypes type = ToDisplayType(fReturnType); - if (fReturnType == kNoType) { - // !!! short sighted; in the future, allow each returned array component to carry - // its own type, and let caller do any needed conversions - if (value->fOperand.fArray->count() == 0) - value->fOperand.fArray->setType(type = tokenValue.fType); - else - type = value->fOperand.fArray->getType(); - } - if (tokenValue.fType != type) { - if (convertTo(type, &tokenValue) == false) - return false; - } - *value->fOperand.fArray->append() = tokenValue.fOperand; - } - } - lastPush = false; - continue; - } else { - if (token_length(script) == 0) { - fError = kExpectedToken; - return false; - } - } - } - if (lastPush != false && fTokenLength > 0) { - if (ch == '(') { - *fBraceStack.push() = kFunctionBrace; - if (handleFunction(&script, SkToBool(suppressed)) == false) - return false; - lastPush = true; - continue; - } else if (ch == '[') { - if (handleProperty(SkToBool(suppressed)) == false) - return false; // note: never triggered by standard animator plugins - if (handleArrayIndexer(&script, SkToBool(suppressed)) == false) - return false; - lastPush = true; - continue; - } else if (ch != '.') { - if (handleProperty(SkToBool(suppressed)) == false) - return false; // note: never triggered by standard animator plugins - lastPush = true; - continue; - } - } - if (ch == '0' && (script[1] & ~0x20) == 'X') { - if (lastPush != false) { - fError = kExpectedOperator; - return false; - } - script += 2; - script = SkParse::FindHex(script, (uint32_t*)&operand.fS32); - if (script == NULL) { - fError = kExpectedHex; - return false; - } - goto intCommon; - } - if (lastPush == false && ch == '.') - goto scalarCommon; - if (ch >= '0' && ch <= '9') { - if (lastPush != false) { - fError = kExpectedOperator; - return false; - } - dotCheck = SkParse::FindS32(script, &operand.fS32); - if (dotCheck[0] != '.') { - script = dotCheck; -intCommon: - if (suppressed == false) - *fTypeStack.push() = kInt; - } else { -scalarCommon: - script = SkParse::FindScalar(script, &operand.fScalar); - if (suppressed == false) - *fTypeStack.push() = kScalar; - } - if (suppressed == false) - fOperandStack.push(operand); - lastPush = true; - continue; - } - int length = token_length(script); - if (length > 0) { - if (lastPush != false) { - fError = kExpectedOperator; - return false; - } - fToken = script; - fTokenLength = length; - script += length; - lastPush = true; - continue; - } - char startQuote = ch; - if (startQuote == '\'' || startQuote == '\"') { - if (lastPush != false) { - fError = kExpectedOperator; - return false; - } - operand.fString = new SkString(); - track(operand.fString); - ++script; - - // <mrr> this is a lot of calls to append() one char at at time - // how hard to preflight script so we know how much to grow fString by? - do { - if (script[0] == '\\') - ++script; - operand.fString->append(script, 1); - ++script; - if (script[0] == '\0') { - fError = kUnterminatedString; - return false; - } - } while (script[0] != startQuote); - ++script; - if (suppressed == false) { - *fTypeStack.push() = kString; - fOperandStack.push(operand); - } - lastPush = true; - continue; - } - ; - if (ch == '.') { - if (fTokenLength == 0) { - SkScriptValue scriptValue; - SkDEBUGCODE(scriptValue.fOperand.fObject = NULL); - int tokenLength = token_length(++script); - const char* token = script; - script += tokenLength; - if (suppressed == false) { - if (fTypeStack.count() == 0) { - fError = kExpectedTokenBeforeDotOperator; - return false; - } - SkOpType topType; - fTypeStack.pop(&topType); - fOperandStack.pop(&scriptValue.fOperand); - scriptValue.fType = ToDisplayType(topType); - handleBox(&scriptValue); - } - success = evaluateDotParam(script, SkToBool(suppressed), token, tokenLength); - if (success == false) - return false; - lastPush = true; - continue; - } - // get next token, and evaluate immediately - success = evaluateDot(script, SkToBool(suppressed)); - if (success == false) - return false; - lastPush = true; - continue; - } - if (ch == '[') { - if (lastPush == false) { - script++; - *fBraceStack.push() = kArrayBrace; - if (suppressed) - continue; - operand.fArray = value->fOperand.fArray = new SkTypedArray(ToDisplayType(fReturnType)); - track(value->fOperand.fArray); - *fTypeStack.push() = (SkOpType) kArray; - fOperandStack.push(operand); - continue; - } - if (handleArrayIndexer(&script, SkToBool(suppressed)) == false) - return false; - lastPush = true; - continue; - } -#if 0 // structs not supported for now - if (ch == '{') { - if (lastPush == false) { - script++; - *fBraceStack.push() = kStructBrace; - if (suppressed) - continue; - operand.fS32 = 0; - *fTypeStack.push() = (SkOpType) kStruct; - fOperandStack.push(operand); - continue; - } - SkASSERT(0); // braces in other contexts aren't supported yet - } -#endif - if (ch == ')' && fBraceStack.count() > 0) { - SkBraceStyle braceStyle = fBraceStack.top(); - if (braceStyle == kFunctionBrace) { - fBraceStack.pop(); - break; - } - } - if (ch == ',' || ch == ']') { - if (ch != ',') { - SkBraceStyle match; - fBraceStack.pop(&match); - if (match != kArrayBrace) { - fError = kMismatchedArrayBrace; - return false; - } - } - script++; - // !!! see if brace or bracket is correct closer - break; - } - char nextChar = script[1]; - int advance = logicalOp(ch, nextChar); - if (advance < 0) // error - return false; - if (advance == 0) - advance = arithmeticOp(ch, nextChar, lastPush); - if (advance == 0) // unknown token - return false; - if (advance > 0) - script += advance; - lastPush = ch == ']' || ch == ')'; - } - bool suppressed = SkToBool(fSuppressStack.top().fSuppress); - if (fTokenLength > 0) { - success = handleProperty(suppressed); - if (success == false) - return false; // note: never triggered by standard animator plugins - } - while (fOpStack.count() > opBalance) { // leave open paren - if ((fError = opError()) != kNoError) - return false; - if (processOp() == false) - return false; - } - SkOpType topType = fTypeStack.count() > 0 ? fTypeStack.top() : kNoType; - if (suppressed == false && topType != fReturnType && - topType == kString && fReturnType != kNoType) { // if result is a string, give handle property a chance to convert it to the property value - SkString* string = fOperandStack.top().fString; - fToken = string->c_str(); - fTokenLength = string->size(); - fOperandStack.pop(); - fTypeStack.pop(); - success = handleProperty(SkToBool(fSuppressStack.top().fSuppress)); - if (success == false) { // if it couldn't convert, return string (error?) - SkOperand operand; - operand.fS32 = 0; - *fTypeStack.push() = kString; - operand.fString = string; - fOperandStack.push(operand); - } - } - if (value) { - if (fOperandStack.count() == 0) - return false; - SkASSERT(fOperandStack.count() >= 1); - SkASSERT(fTypeStack.count() >= 1); - fOperandStack.pop(&value->fOperand); - SkOpType type; - fTypeStack.pop(&type); - value->fType = ToDisplayType(type); -// SkASSERT(value->fType != SkType_Unknown); - if (topType != fReturnType && topType == kObject && fReturnType != kNoType) { - if (convertTo(ToDisplayType(fReturnType), value) == false) - return false; - } - } - while (fSuppressStack.count() > suppressBalance) - fSuppressStack.pop(); - *scriptPtr = script; - return true; // no error -} - -void SkScriptEngine::memberCallBack(_memberCallBack member , void* userStorage) { - UserCallBack callBack; - callBack.fMemberCallBack = member; - commonCallBack(kMember, callBack, userStorage); -} - -void SkScriptEngine::memberFunctionCallBack(_memberFunctionCallBack func, void* userStorage) { - UserCallBack callBack; - callBack.fMemberFunctionCallBack = func; - commonCallBack(kMemberFunction, callBack, userStorage); -} - -#if 0 -void SkScriptEngine::objectToStringCallBack(_objectToStringCallBack func, void* userStorage) { - UserCallBack callBack; - callBack.fObjectToStringCallBack = func; - commonCallBack(kObjectToString, callBack, userStorage); -} -#endif - -bool SkScriptEngine::handleArrayIndexer(const char** scriptPtr, bool suppressed) { - SkScriptValue scriptValue; - (*scriptPtr)++; - *fOpStack.push() = kParen; - *fBraceStack.push() = kArrayBrace; - SkOpType saveType = fReturnType; - fReturnType = kInt; - bool success = innerScript(scriptPtr, suppressed == false ? &scriptValue : NULL); - if (success == false) - return false; - fReturnType = saveType; - if (suppressed == false) { - if (convertTo(SkType_Int, &scriptValue) == false) - return false; - int index = scriptValue.fOperand.fS32; - SkScriptValue scriptValue; - SkOpType type; - fTypeStack.pop(&type); - fOperandStack.pop(&scriptValue.fOperand); - scriptValue.fType = ToDisplayType(type); - if (type == kObject) { - success = handleUnbox(&scriptValue); - if (success == false) - return false; - if (ToOpType(scriptValue.fType) != kArray) { - fError = kExpectedArray; - return false; - } - } - *fTypeStack.push() = scriptValue.fOperand.fArray->getOpType(); -// SkASSERT(index >= 0); - if ((unsigned) index >= (unsigned) scriptValue.fOperand.fArray->count()) { - fError = kArrayIndexOutOfBounds; - return false; - } - scriptValue.fOperand = scriptValue.fOperand.fArray->begin()[index]; - fOperandStack.push(scriptValue.fOperand); - } - fOpStack.pop(); // pop paren - return success; -} - -bool SkScriptEngine::handleBox(SkScriptValue* scriptValue) { - bool success = true; - for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) { - if (callBack->fCallBackType != kBox) - continue; - success = (*callBack->fBoxCallBack)(callBack->fUserStorage, scriptValue); - if (success) { - fOperandStack.push(scriptValue->fOperand); - *fTypeStack.push() = ToOpType(scriptValue->fType); - goto done; - } - } -done: - return success; -} - -bool SkScriptEngine::handleFunction(const char** scriptPtr, bool suppressed) { - SkScriptValue callbackResult; - SkTDArray<SkScriptValue> params; - SkString functionName(fToken, fTokenLength); - fTokenLength = 0; - bool success = functionParams(scriptPtr, params); - if (success == false) - goto done; - if (suppressed == true) - return true; - { - for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) { - if (callBack->fCallBackType != kFunction) - continue; - success = (*callBack->fFunctionCallBack)(functionName.c_str(), functionName.size(), params, - callBack->fUserStorage, &callbackResult); - if (success) { - fOperandStack.push(callbackResult.fOperand); - *fTypeStack.push() = ToOpType(callbackResult.fType); - goto done; - } - } - } - fError = kNoFunctionHandlerFound; - return false; -done: - return success; -} - -bool SkScriptEngine::handleMember(const char* field, size_t len, void* object) { - SkScriptValue callbackResult; - bool success = true; - for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) { - if (callBack->fCallBackType != kMember) - continue; - success = (*callBack->fMemberCallBack)(field, len, object, callBack->fUserStorage, &callbackResult); - if (success) { - if (callbackResult.fType == SkType_String) - track(callbackResult.fOperand.fString); - fOperandStack.push(callbackResult.fOperand); - *fTypeStack.push() = ToOpType(callbackResult.fType); - goto done; - } - } - return false; -done: - return success; -} - -bool SkScriptEngine::handleMemberFunction(const char* field, size_t len, void* object, SkTDArray<SkScriptValue>& params) { - SkScriptValue callbackResult; - bool success = true; - for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) { - if (callBack->fCallBackType != kMemberFunction) - continue; - success = (*callBack->fMemberFunctionCallBack)(field, len, object, params, - callBack->fUserStorage, &callbackResult); - if (success) { - if (callbackResult.fType == SkType_String) - track(callbackResult.fOperand.fString); - fOperandStack.push(callbackResult.fOperand); - *fTypeStack.push() = ToOpType(callbackResult.fType); - goto done; - } - } - return false; -done: - return success; -} - -#if 0 -bool SkScriptEngine::handleObjectToString(void* object) { - SkScriptValue callbackResult; - bool success = true; - for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) { - if (callBack->fCallBackType != kObjectToString) - continue; - success = (*callBack->fObjectToStringCallBack)(object, - callBack->fUserStorage, &callbackResult); - if (success) { - if (callbackResult.fType == SkType_String) - track(callbackResult.fOperand.fString); - fOperandStack.push(callbackResult.fOperand); - *fTypeStack.push() = ToOpType(callbackResult.fType); - goto done; - } - } - return false; -done: - return success; -} -#endif - -bool SkScriptEngine::handleProperty(bool suppressed) { - SkScriptValue callbackResult; - bool success = true; - if (suppressed) - goto done; - success = false; // note that with standard animator-script plugins, callback never returns false - { - for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) { - if (callBack->fCallBackType != kProperty) - continue; - success = (*callBack->fPropertyCallBack)(fToken, fTokenLength, - callBack->fUserStorage, &callbackResult); - if (success) { - if (callbackResult.fType == SkType_String && callbackResult.fOperand.fString == NULL) { - callbackResult.fOperand.fString = new SkString(fToken, fTokenLength); - track(callbackResult.fOperand.fString); - } - fOperandStack.push(callbackResult.fOperand); - *fTypeStack.push() = ToOpType(callbackResult.fType); - goto done; - } - } - } -done: - fTokenLength = 0; - return success; -} - -bool SkScriptEngine::handleUnbox(SkScriptValue* scriptValue) { - bool success = true; - for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) { - if (callBack->fCallBackType != kUnbox) - continue; - success = (*callBack->fUnboxCallBack)(callBack->fUserStorage, scriptValue); - if (success) { - if (scriptValue->fType == SkType_String) - track(scriptValue->fOperand.fString); - goto done; - } - } - return false; -done: - return success; -} - -// note that entire expression is treated as if it were enclosed in parens -// an open paren is always the first thing in the op stack - -int SkScriptEngine::logicalOp(char ch, char nextChar) { - int advance = 1; - SkOp match; - signed char precedence; - switch (ch) { - case ')': - match = kParen; - break; - case ']': - match = kArrayOp; - break; - case '?': - match = kIf; - break; - case ':': - match = kElse; - break; - case '&': - if (nextChar != '&') - goto noMatch; - match = kLogicalAnd; - advance = 2; - break; - case '|': - if (nextChar != '|') - goto noMatch; - match = kLogicalOr; - advance = 2; - break; - default: -noMatch: - return 0; - } - SkSuppress suppress; - precedence = gPrecedence[match]; - if (fSuppressStack.top().fSuppress) { - if (fSuppressStack.top().fOpStackDepth < fOpStack.count()) { - SkOp topOp = fOpStack.top(); - if (gPrecedence[topOp] <= precedence) - fOpStack.pop(); - goto goHome; - } - bool changedPrecedence = gPrecedence[fSuppressStack.top().fOperator] < precedence; - if (changedPrecedence) - fSuppressStack.pop(); - if (precedence == kIfElsePrecedence) { - if (match == kIf) { - if (changedPrecedence) - fOpStack.pop(); - else - *fOpStack.push() = kIf; - } else { - if (fSuppressStack.top().fOpStackDepth == fOpStack.count()) { - goto flipSuppress; - } - fOpStack.pop(); - } - } - if (changedPrecedence == false) - goto goHome; - } - while (gPrecedence[fOpStack.top() & ~kArtificialOp] < precedence) { - if (processOp() == false) - return false; - } - if (fSuppressStack.top().fOpStackDepth > fOpStack.count()) - fSuppressStack.pop(); - switch (match) { - case kParen: - case kArrayOp: - if (fOpStack.count() <= 1 || fOpStack.top() != match) { - fError = kMismatchedBrackets; - return -1; - } - if (match == kParen) - fOpStack.pop(); - else { - SkOpType indexType; - fTypeStack.pop(&indexType); - if (indexType != kInt && indexType != kScalar) { - fError = kExpectedNumberForArrayIndex; // (although, could permit strings eventually) - return -1; - } - SkOperand indexOperand; - fOperandStack.pop(&indexOperand); - int index = indexType == kScalar ? SkScalarFloor(indexOperand.fScalar) : - indexOperand.fS32; - SkOpType arrayType; - fTypeStack.pop(&arrayType); - if ((unsigned)arrayType != (unsigned)kArray) { - fError = kExpectedArray; - return -1; - } - SkOperand arrayOperand; - fOperandStack.pop(&arrayOperand); - SkTypedArray* array = arrayOperand.fArray; - SkOperand operand; - if (array->getIndex(index, &operand) == false) { - fError = kIndexOutOfRange; - return -1; - } - SkOpType resultType = array->getOpType(); - fTypeStack.push(resultType); - fOperandStack.push(operand); - } - break; - case kIf: { - SkScriptValue ifValue; - SkOpType ifType; - fTypeStack.pop(&ifType); - ifValue.fType = ToDisplayType(ifType); - fOperandStack.pop(&ifValue.fOperand); - if (convertTo(SkType_Int, &ifValue) == false) - return -1; - if (ifValue.fType != SkType_Int) { - fError = kExpectedIntForConditionOperator; - return -1; - } - suppress.fSuppress = ifValue.fOperand.fS32 == 0; - suppress.fOperator = kIf; - suppress.fOpStackDepth = fOpStack.count(); - suppress.fElse = false; - fSuppressStack.push(suppress); - // if left is true, do only up to colon - // if left is false, do only after colon - } break; - case kElse: -flipSuppress: - if (fSuppressStack.top().fElse == true) - fSuppressStack.pop(); - fSuppressStack.top().fElse = true; - fSuppressStack.top().fSuppress ^= true; - // flip last do / don't do consideration from last '?' - break; - case kLogicalAnd: - case kLogicalOr: { - if (fTypeStack.top() != kInt) { - fError = kExpectedBooleanExpression; - return -1; - } - int32_t topInt = fOperandStack.top().fS32; - if (fOpStack.top() != kLogicalAnd) - *fOpStack.push() = kLogicalAnd; // really means 'to bool', and is appropriate for 'or' - if (match == kLogicalOr ? topInt != 0 : topInt == 0) { - suppress.fSuppress = true; - suppress.fOperator = match; - suppress.fOpStackDepth = fOpStack.count(); - fSuppressStack.push(suppress); - } else { - fTypeStack.pop(); - fOperandStack.pop(); - } - } break; - default: - SkASSERT(0); - } -goHome: - return advance; -} - -SkScriptEngine::Error SkScriptEngine::opError() { - int opCount = fOpStack.count(); - int operandCount = fOperandStack.count(); - if (opCount == 0) { - if (operandCount != 1) - return kExpectedOperator; - return kNoError; - } - SkOp op = (SkOp) (fOpStack.top() & ~kArtificialOp); - const SkOperatorAttributes* attributes = &gOpAttributes[op]; - if (attributes->fLeftType != kNoType && operandCount < 2) - return kExpectedValue; - if (attributes->fLeftType == kNoType && operandCount < 1) - return kExpectedValue; - return kNoError; -} - -bool SkScriptEngine::processOp() { - SkOp op; - fOpStack.pop(&op); - op = (SkOp) (op & ~kArtificialOp); - const SkOperatorAttributes* attributes = &gOpAttributes[op]; - SkOpType type2; - fTypeStack.pop(&type2); - SkOpType type1 = type2; - SkOperand operand2; - fOperandStack.pop(&operand2); - SkOperand operand1 = operand2; // !!! not really needed, suppresses warning - if (attributes->fLeftType != kNoType) { - fTypeStack.pop(&type1); - fOperandStack.pop(&operand1); - if (op == kFlipOps) { - SkTSwap(type1, type2); - SkTSwap(operand1, operand2); - fOpStack.pop(&op); - op = (SkOp) (op & ~kArtificialOp); - attributes = &gOpAttributes[op]; - } - if (type1 == kObject && (type1 & attributes->fLeftType) == 0) { - SkScriptValue val; - val.fType = ToDisplayType(type1); - val.fOperand = operand1; - bool success = handleUnbox(&val); - if (success == false) - return false; - type1 = ToOpType(val.fType); - operand1 = val.fOperand; - } - } - if (type2 == kObject && (type2 & attributes->fLeftType) == 0) { - SkScriptValue val; - val.fType = ToDisplayType(type2); - val.fOperand = operand2; - bool success = handleUnbox(&val); - if (success == false) - return false; - type2 = ToOpType(val.fType); - operand2 = val.fOperand; - } - if (attributes->fLeftType != kNoType) { - if (type1 != type2) { - if ((attributes->fLeftType & kString) && attributes->fBias & kTowardsString && ((type1 | type2) & kString)) { - if (type1 == kInt || type1 == kScalar) { - convertToString(operand1, type1 == kInt ? SkType_Int : SkType_Float); - type1 = kString; - } - if (type2 == kInt || type2 == kScalar) { - convertToString(operand2, type2 == kInt ? SkType_Int : SkType_Float); - type2 = kString; - } - } else if (attributes->fLeftType & kScalar && ((type1 | type2) & kScalar)) { - if (type1 == kInt) { - operand1.fScalar = IntToScalar(operand1.fS32); - type1 = kScalar; - } - if (type2 == kInt) { - operand2.fScalar = IntToScalar(operand2.fS32); - type2 = kScalar; - } - } - } - if ((type1 & attributes->fLeftType) == 0 || type1 != type2) { - if (type1 == kString) { - const char* result = SkParse::FindScalar(operand1.fString->c_str(), &operand1.fScalar); - if (result == NULL) { - fError = kExpectedNumber; - return false; - } - type1 = kScalar; - } - if (type1 == kScalar && (attributes->fLeftType == kInt || type2 == kInt)) { - operand1.fS32 = SkScalarFloor(operand1.fScalar); - type1 = kInt; - } - } - } - if ((type2 & attributes->fRightType) == 0 || type1 != type2) { - if (type2 == kString) { - const char* result = SkParse::FindScalar(operand2.fString->c_str(), &operand2.fScalar); - if (result == NULL) { - fError = kExpectedNumber; - return false; - } - type2 = kScalar; - } - if (type2 == kScalar && (attributes->fRightType == kInt || type1 == kInt)) { - operand2.fS32 = SkScalarFloor(operand2.fScalar); - type2 = kInt; - } - } - if (type2 == kScalar) - op = (SkOp) (op + 1); - else if (type2 == kString) - op = (SkOp) (op + 2); - switch(op) { - case kAddInt: - operand2.fS32 += operand1.fS32; - break; - case kAddScalar: - operand2.fScalar += operand1.fScalar; - break; - case kAddString: - if (fTrackString.find(operand1.fString) < 0) { - operand1.fString = SkNEW_ARGS(SkString, (*operand1.fString)); - track(operand1.fString); - } - operand1.fString->append(*operand2.fString); - operand2 = operand1; - break; - case kBitAnd: - operand2.fS32 &= operand1.fS32; - break; - case kBitNot: - operand2.fS32 = ~operand2.fS32; - break; - case kBitOr: - operand2.fS32 |= operand1.fS32; - break; - case kDivideInt: - if (operand2.fS32 == 0) { - operand2.fS32 = operand1.fS32 == 0 ? SK_NaN32 : operand1.fS32 > 0 ? SK_MaxS32 : -SK_MaxS32; - break; - } else { - int32_t original = operand2.fS32; - operand2.fS32 = operand1.fS32 / operand2.fS32; - if (original * operand2.fS32 == operand1.fS32) - break; // integer divide was good enough - operand2.fS32 = original; - type2 = kScalar; - } - case kDivideScalar: - if (operand2.fScalar == 0) - operand2.fScalar = operand1.fScalar == 0 ? SK_ScalarNaN : operand1.fScalar > 0 ? SK_ScalarMax : -SK_ScalarMax; - else - operand2.fScalar = SkScalarDiv(operand1.fScalar, operand2.fScalar); - break; - case kEqualInt: - operand2.fS32 = operand1.fS32 == operand2.fS32; - break; - case kEqualScalar: - operand2.fS32 = operand1.fScalar == operand2.fScalar; - type2 = kInt; - break; - case kEqualString: - operand2.fS32 = *operand1.fString == *operand2.fString; - type2 = kInt; - break; - case kGreaterEqualInt: - operand2.fS32 = operand1.fS32 >= operand2.fS32; - break; - case kGreaterEqualScalar: - operand2.fS32 = operand1.fScalar >= operand2.fScalar; - type2 = kInt; - break; - case kGreaterEqualString: - operand2.fS32 = strcmp(operand1.fString->c_str(), operand2.fString->c_str()) >= 0; - type2 = kInt; - break; - case kLogicalAnd: - operand2.fS32 = !! operand2.fS32; // really, ToBool - break; - case kLogicalNot: - operand2.fS32 = ! operand2.fS32; - break; - case kLogicalOr: - SkASSERT(0); // should have already been processed - break; - case kMinusInt: - operand2.fS32 = -operand2.fS32; - break; - case kMinusScalar: - operand2.fScalar = -operand2.fScalar; - break; - case kModuloInt: - operand2.fS32 = operand1.fS32 % operand2.fS32; - break; - case kModuloScalar: - operand2.fScalar = SkScalarMod(operand1.fScalar, operand2.fScalar); - break; - case kMultiplyInt: - operand2.fS32 *= operand1.fS32; - break; - case kMultiplyScalar: - operand2.fScalar = SkScalarMul(operand1.fScalar, operand2.fScalar); - break; - case kShiftLeft: - operand2.fS32 = operand1.fS32 << operand2.fS32; - break; - case kShiftRight: - operand2.fS32 = operand1.fS32 >> operand2.fS32; - break; - case kSubtractInt: - operand2.fS32 = operand1.fS32 - operand2.fS32; - break; - case kSubtractScalar: - operand2.fScalar = operand1.fScalar - operand2.fScalar; - break; - case kXor: - operand2.fS32 ^= operand1.fS32; - break; - default: - SkASSERT(0); - } - fTypeStack.push(type2); - fOperandStack.push(operand2); - return true; -} - -void SkScriptEngine::propertyCallBack(_propertyCallBack prop, void* userStorage) { - UserCallBack callBack; - callBack.fPropertyCallBack = prop; - commonCallBack(kProperty, callBack, userStorage); -} - -void SkScriptEngine::track(SkTypedArray* array) { - SkASSERT(fTrackArray.find(array) < 0); - *(fTrackArray.end() - 1) = array; - fTrackArray.appendClear(); -} - -void SkScriptEngine::track(SkString* string) { - SkASSERT(fTrackString.find(string) < 0); - *(fTrackString.end() - 1) = string; - fTrackString.appendClear(); -} - -void SkScriptEngine::unboxCallBack(_unboxCallBack func, void* userStorage) { - UserCallBack callBack; - callBack.fUnboxCallBack = func; - commonCallBack(kUnbox, callBack, userStorage); -} - -bool SkScriptEngine::ConvertTo(SkScriptEngine* engine, SkDisplayTypes toType, SkScriptValue* value ) { - SkASSERT(value); - if (SkDisplayType::IsEnum(NULL /* fMaker */, toType)) - toType = SkType_Int; - if (toType == SkType_Point || toType == SkType_3D_Point) - toType = SkType_Float; - if (toType == SkType_Drawable) - toType = SkType_Displayable; - SkDisplayTypes type = value->fType; - if (type == toType) - return true; - SkOperand& operand = value->fOperand; - bool success = true; - switch (toType) { - case SkType_Int: - if (type == SkType_Boolean) - break; - if (type == SkType_Float) - operand.fS32 = SkScalarFloor(operand.fScalar); - else { - if (type != SkType_String) { - success = false; - break; // error - } - success = SkParse::FindS32(operand.fString->c_str(), &operand.fS32) != NULL; - } - break; - case SkType_Float: - if (type == SkType_Int) { - if ((uint32_t)operand.fS32 == SK_NaN32) - operand.fScalar = SK_ScalarNaN; - else if (SkAbs32(operand.fS32) == SK_MaxS32) - operand.fScalar = SkSign32(operand.fS32) * SK_ScalarMax; - else - operand.fScalar = SkIntToScalar(operand.fS32); - } else { - if (type != SkType_String) { - success = false; - break; // error - } - success = SkParse::FindScalar(operand.fString->c_str(), &operand.fScalar) != NULL; - } - break; - case SkType_String: { - SkString* strPtr = new SkString(); - SkASSERT(engine); - engine->track(strPtr); - if (type == SkType_Int) - strPtr->appendS32(operand.fS32); - else if (type == SkType_Displayable) - SkASSERT(0); // must call through instance version instead of static version - else { - if (type != SkType_Float) { - success = false; - break; - } - strPtr->appendScalar(operand.fScalar); - } - operand.fString = strPtr; - } break; - case SkType_Array: { - SkTypedArray* array = new SkTypedArray(type); - *array->append() = operand; - engine->track(array); - operand.fArray = array; - } break; - default: - SkASSERT(0); - } - value->fType = toType; - if (success == false) - engine->fError = kTypeConversionFailed; - return success; -} - -SkScalar SkScriptEngine::IntToScalar(int32_t s32) { - SkScalar scalar; - if ((uint32_t)s32 == SK_NaN32) - scalar = SK_ScalarNaN; - else if (SkAbs32(s32) == SK_MaxS32) - scalar = SkSign32(s32) * SK_ScalarMax; - else - scalar = SkIntToScalar(s32); - return scalar; -} - -SkDisplayTypes SkScriptEngine::ToDisplayType(SkOpType type) { - int val = type; - switch (val) { - case kNoType: - return SkType_Unknown; - case kInt: - return SkType_Int; - case kScalar: - return SkType_Float; - case kString: - return SkType_String; - case kArray: - return SkType_Array; - case kObject: - return SkType_Displayable; -// case kStruct: -// return SkType_Structure; - default: - SkASSERT(0); - return SkType_Unknown; - } -} - -SkScriptEngine::SkOpType SkScriptEngine::ToOpType(SkDisplayTypes type) { - if (SkDisplayType::IsDisplayable(NULL /* fMaker */, type)) - return (SkOpType) kObject; - if (SkDisplayType::IsEnum(NULL /* fMaker */, type)) - return kInt; - switch (type) { - case SkType_ARGB: - case SkType_MSec: - case SkType_Int: - return kInt; - case SkType_Float: - case SkType_Point: - case SkType_3D_Point: - return kScalar; - case SkType_Base64: - case SkType_DynamicString: - case SkType_String: - return kString; - case SkType_Array: - return (SkOpType) kArray; - case SkType_Unknown: - return kNoType; - default: - SkASSERT(0); - return kNoType; - } -} - -bool SkScriptEngine::ValueToString(SkScriptValue value, SkString* string) { - switch (value.fType) { - case kInt: - string->reset(); - string->appendS32(value.fOperand.fS32); - break; - case kScalar: - string->reset(); - string->appendScalar(value.fOperand.fScalar); - break; - case kString: - string->set(*value.fOperand.fString); - break; - default: - SkASSERT(0); - return false; - } - return true; // no error -} - -#ifdef SK_SUPPORT_UNITTEST - -#ifdef SK_CAN_USE_FLOAT - #include "SkFloatingPoint.h" -#endif - -#define DEF_SCALAR_ANSWER 0 -#define DEF_STRING_ANSWER NULL - -#define testInt(expression) { #expression, SkType_Int, expression, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER } -#ifdef SK_SCALAR_IS_FLOAT - #define testScalar(expression) { #expression, SkType_Float, 0, (float) expression, DEF_STRING_ANSWER } - #define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkType_Float, 0, sk_float_mod(exp1, exp2), DEF_STRING_ANSWER } -#else - #ifdef SK_CAN_USE_FLOAT - #define testScalar(expression) { #expression, SkType_Float, 0, (int) ((expression) * 65536.0f), DEF_STRING_ANSWER } - #define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkType_Float, 0, (int) (sk_float_mod(exp1, exp2) * 65536.0f), DEF_STRING_ANSWER } - #endif -#endif -#define testTrue(expression) { #expression, SkType_Int, 1, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER } -#define testFalse(expression) { #expression, SkType_Int, 0, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER } - -#if !defined(SK_BUILD_FOR_BREW) -static const SkScriptNAnswer scriptTests[] = { - testInt(1>1/2), - testInt((6+7)*8), - testInt(0&&1?2:3), - testInt(3*(4+5)), -#ifdef SK_CAN_USE_FLOAT - testScalar(1.0+2.0), - testScalar(1.0+5), - testScalar(3.0-1.0), - testScalar(6-1.0), - testScalar(- -5.5- -1.5), - testScalar(2.5*6.), - testScalar(0.5*4), - testScalar(4.5/.5), - testScalar(9.5/19), - testRemainder(9.5, 0.5), - testRemainder(9.,2), - testRemainder(9,2.5), - testRemainder(-9,2.5), - testTrue(-9==-9.0), - testTrue(-9.==-4.0-5), - testTrue(-9.*1==-4-5), - testFalse(-9!=-9.0), - testFalse(-9.!=-4.0-5), - testFalse(-9.*1!=-4-5), -#endif - testInt(0x123), - testInt(0XABC), - testInt(0xdeadBEEF), - { "'123'+\"456\"", SkType_String, 0, 0, "123456" }, - { "123+\"456\"", SkType_String, 0, 0, "123456" }, - { "'123'+456", SkType_String, 0, 0, "123456" }, - { "'123'|\"456\"", SkType_Int, 123|456, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }, - { "123|\"456\"", SkType_Int, 123|456, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }, - { "'123'|456", SkType_Int, 123|456, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }, - { "'2'<11", SkType_Int, 1, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }, - { "2<'11'", SkType_Int, 1, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }, - { "'2'<'11'", SkType_Int, 0, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }, - testInt(123), - testInt(-345), - testInt(+678), - testInt(1+2+3), - testInt(3*4+5), - testInt(6+7*8), - testInt(-1-2-8/4), - testInt(-9%4), - testInt(9%-4), - testInt(-9%-4), - testInt(123|978), - testInt(123&978), - testInt(123^978), - testInt(2<<4), - testInt(99>>3), - testInt(~55), - testInt(~~55), - testInt(!55), - testInt(!!55), - // both int - testInt(2<2), - testInt(2<11), - testInt(20<11), - testInt(2<=2), - testInt(2<=11), - testInt(20<=11), - testInt(2>2), - testInt(2>11), - testInt(20>11), - testInt(2>=2), - testInt(2>=11), - testInt(20>=11), - testInt(2==2), - testInt(2==11), - testInt(20==11), - testInt(2!=2), - testInt(2!=11), - testInt(20!=11), -#ifdef SK_CAN_USE_FLOAT - // left int, right scalar - testInt(2<2.), - testInt(2<11.), - testInt(20<11.), - testInt(2<=2.), - testInt(2<=11.), - testInt(20<=11.), - testInt(2>2.), - testInt(2>11.), - testInt(20>11.), - testInt(2>=2.), - testInt(2>=11.), - testInt(20>=11.), - testInt(2==2.), - testInt(2==11.), - testInt(20==11.), - testInt(2!=2.), - testInt(2!=11.), - testInt(20!=11.), - // left scalar, right int - testInt(2.<2), - testInt(2.<11), - testInt(20.<11), - testInt(2.<=2), - testInt(2.<=11), - testInt(20.<=11), - testInt(2.>2), - testInt(2.>11), - testInt(20.>11), - testInt(2.>=2), - testInt(2.>=11), - testInt(20.>=11), - testInt(2.==2), - testInt(2.==11), - testInt(20.==11), - testInt(2.!=2), - testInt(2.!=11), - testInt(20.!=11), - // both scalar - testInt(2.<11.), - testInt(20.<11.), - testInt(2.<=2.), - testInt(2.<=11.), - testInt(20.<=11.), - testInt(2.>2.), - testInt(2.>11.), - testInt(20.>11.), - testInt(2.>=2.), - testInt(2.>=11.), - testInt(20.>=11.), - testInt(2.==2.), - testInt(2.==11.), - testInt(20.==11.), - testInt(2.!=2.), - testInt(2.!=11.), - testInt(20.!=11.), -#endif - // int, string (string is int) - testFalse(2<'2'), - testTrue(2<'11'), - testFalse(20<'11'), - testTrue(2<='2'), - testTrue(2<='11'), - testFalse(20<='11'), - testFalse(2>'2'), - testFalse(2>'11'), - testTrue(20>'11'), - testTrue(2>='2'), - testFalse(2>='11'), - testTrue(20>='11'), - testTrue(2=='2'), - testFalse(2=='11'), - testFalse(2!='2'), - testTrue(2!='11'), - // int, string (string is scalar) - testFalse(2<'2.'), - testTrue(2<'11.'), - testFalse(20<'11.'), - testTrue(2=='2.'), - testFalse(2=='11.'), -#ifdef SK_CAN_USE_FLOAT - // scalar, string - testFalse(2.<'2.'), - testTrue(2.<'11.'), - testFalse(20.<'11.'), - testTrue(2.=='2.'), - testFalse(2.=='11.'), - // string, int - testFalse('2'<2), - testTrue('2'<11), - testFalse('20'<11), - testTrue('2'==2), - testFalse('2'==11), - // string, scalar - testFalse('2'<2.), - testTrue('2'<11.), - testFalse('20'<11.), - testTrue('2'==2.), - testFalse('2'==11.), -#endif - // string, string - testFalse('2'<'2'), - testFalse('2'<'11'), - testFalse('20'<'11'), - testTrue('2'=='2'), - testFalse('2'=='11'), - // logic - testInt(1?2:3), - testInt(0?2:3), - testInt(1&&2||3), - testInt(1&&0||3), - testInt(1&&0||0), - testInt(1||0&&3), - testInt(0||0&&3), - testInt(0||1&&3), - testInt(1?(2?3:4):5), - testInt(0?(2?3:4):5), - testInt(1?(0?3:4):5), - testInt(0?(0?3:4):5), - testInt(1?2?3:4:5), - testInt(0?2?3:4:5), - testInt(1?0?3:4:5), - testInt(0?0?3:4:5), - - testInt(1?2:(3?4:5)), - testInt(0?2:(3?4:5)), - testInt(1?0:(3?4:5)), - testInt(0?0:(3?4:5)), - testInt(1?2:3?4:5), - testInt(0?2:3?4:5), - testInt(1?0:3?4:5), - testInt(0?0:3?4:5) -#ifdef SK_CAN_USE_FLOAT - , { "123.5", SkType_Float, 0, SkIntToScalar(123) + SK_Scalar1/2, DEF_STRING_ANSWER } -#endif -}; -#endif // build for brew - -#define SkScriptNAnswer_testCount SK_ARRAY_COUNT(scriptTests) - -void SkScriptEngine::UnitTest() { -#if !defined(SK_BUILD_FOR_BREW) - for (unsigned index = 0; index < SkScriptNAnswer_testCount; index++) { - SkScriptEngine engine(SkScriptEngine::ToOpType(scriptTests[index].fType)); - SkScriptValue value; - const char* script = scriptTests[index].fScript; - SkASSERT(engine.evaluateScript(&script, &value) == true); - SkASSERT(value.fType == scriptTests[index].fType); - SkScalar error; - switch (value.fType) { - case SkType_Int: - SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer); - break; - case SkType_Float: - error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer); - SkASSERT(error < SK_Scalar1 / 10000); - break; - case SkType_String: - SkASSERT(strcmp(value.fOperand.fString->c_str(), scriptTests[index].fStringAnswer) == 0); - break; - default: - SkASSERT(0); - } - } -#endif -} -#endif - |