summaryrefslogtreecommitdiffstats
path: root/skia/animator/SkScript.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'skia/animator/SkScript.cpp')
-rw-r--r--skia/animator/SkScript.cpp1918
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], &params[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
-