| Index: skia/animator/SkScript.cpp
|
| ===================================================================
|
| --- skia/animator/SkScript.cpp (revision 16859)
|
| +++ skia/animator/SkScript.cpp (working copy)
|
| @@ -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
|
| -
|
|
|