1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2011 Google Inc.
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkScript2.h"
98a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.com#include "SkData.h"
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkFloatingPoint.h"
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkMath.h"
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkParse.h"
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkScriptCallBack.h"
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkScriptRuntime.h"
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkString.h"
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkOpArray.h"
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkScriptEngine2::OperatorAttributes SkScriptEngine2::gOpAttributes[] = {
1964cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org{ SkOperand2::kNoType, SkOperand2::kNoType, kNoBias, kResultIsNotBoolean },
20d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString),
2164cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org    SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), kTowardsString, kResultIsNotBoolean },    // kAdd
2264cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org{ SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kBitAnd
2364cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org{ SkOperand2::kNoType, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kBitNot
2464cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org{ SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kBitOr
25d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar),
2664cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org    SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias, kResultIsNotBoolean }, // kDivide
27d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString),
28d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar |SkOperand2:: kString), kTowardsNumber,
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kResultIsBoolean }, // kEqual
3064cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org{ SkOperand2::kS32, SkOperand2::kNoType, kNoBias, kResultIsNotBoolean },     // kFlipOps
31d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString),
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), kTowardsNumber,
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kResultIsBoolean }, // kGreaterEqual
3464cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org{ SkOperand2::kNoType, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kLogicalAnd    (really, ToBool)
3564cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org{ SkOperand2::kNoType, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kLogicalNot
3664cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org{ SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kLogicalOr
3764cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org{ SkOperand2::kNoType, SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias, kResultIsNotBoolean }, // kMinus
38d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar),
3964cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org    SkOperand2::OpType(SkOperand2::kS32 |SkOperand2:: kScalar), kNoBias, kResultIsNotBoolean }, // kModulo
40d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar),
4164cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org    SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias, kResultIsNotBoolean }, // kMultiply
4264cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org{ SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kShiftLeft
4364cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org{ SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kShiftRight
44d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com{ SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar),
4564cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org    SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias, kResultIsNotBoolean }, // kSubtract
4664cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org{ SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean } // kXor
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define kBracketPrecedence 16
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define kIfElsePrecedence 15
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst signed char SkScriptEngine2::gPrecedence[] = {
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    17, // kUnassigned,
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    6, // kAdd,
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    10, // kBitAnd,
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    4, // kBitNot,
578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    12, // kBitOr,
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    5, // kDivide,
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    9, // kEqual,
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    -1, // kFlipOps,
618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    8, // kGreaterEqual,
628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    13, // kLogicalAnd,
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    4, // kLogicalNot,
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    14, // kLogicalOr,
658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    4, // kMinus,
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    5, // kModulo,
678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    5, // kMultiply,
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    7, // kShiftLeft,
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    7, // kShiftRight,    // signed
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    6, // kSubtract,
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    11, // kXor
728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kBracketPrecedence, // kArrayOp
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kIfElsePrecedence, // kElse
748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kIfElsePrecedence, // kIf
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kBracketPrecedence, // kParen
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comconst SkScriptEngine2::TypeOp SkScriptEngine2::gTokens[] = {
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kNop, // unassigned
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kAddInt, // kAdd,
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kBitAndInt, // kBitAnd,
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kBitNotInt, // kBitNot,
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kBitOrInt, // kBitOr,
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kDivideInt, // kDivide,
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kEqualInt, // kEqual,
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kFlipOpsOp, // kFlipOps,
878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kGreaterEqualInt, // kGreaterEqual,
888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kLogicalAndInt, // kLogicalAnd,
898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kLogicalNotInt, // kLogicalNot,
908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kLogicalOrInt, // kLogicalOr,
918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kMinusInt, // kMinus,
928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kModuloInt, // kModulo,
938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kMultiplyInt, // kMultiply,
948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kShiftLeftInt, // kShiftLeft,
958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kShiftRightInt, // kShiftRight,    // signed
968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kSubtractInt, // kSubtract,
978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    kXorInt // kXor
988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline bool is_between(int c, int min, int max)
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return (unsigned)(c - min) <= (unsigned)(max - min);
1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic inline bool is_ws(int c)
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return is_between(c, 1, 32);
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic int token_length(const char* start) {
1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    char ch = start[0];
1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (! is_between(ch, 'a' , 'z') &&  ! is_between(ch, 'A', 'Z') && ch != '_' && ch != '$')
1138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return -1;
1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int length = 0;
1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    do
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        ch = start[++length];
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (is_between(ch, 'a' , 'z') || is_between(ch, 'A', 'Z') || is_between(ch, '0', '9') ||
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com           ch == '_' || ch == '$');
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return length;
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkScriptEngine2::SkScriptEngine2(SkOperand2::OpType returnType) : fActiveStream(&fStream),
123d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.comfTokenLength(0), fReturnType(returnType), fError(kNoError),
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comfAccumulatorType(SkOperand2::kNoType),
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comfBranchPopAllowed(true), fConstExpression(true), fOperandInUse(false)
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Branch branch(kUnassigned, 0, 0);
1288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fBranchStack.push(branch);
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *fOpStack.push() = (Op) kParen;
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkScriptEngine2::~SkScriptEngine2() {
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (SkString** stringPtr = fTrackString.begin(); stringPtr < fTrackString.end(); stringPtr++)
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        delete *stringPtr;
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (SkOpArray** arrayPtr = fTrackArray.begin(); arrayPtr < fTrackArray.end(); arrayPtr++)
1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        delete *arrayPtr;
1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkScriptEngine2::addToken(SkScriptEngine2::TypeOp op) {
1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int limit = fBranchStack.count() - 1;
1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (int index = 0; index < limit; index++) {
1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        Branch& branch = fBranchStack.index(index);
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (branch.fPrimed == Branch::kIsPrimed)
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            resolveBranch(branch);
1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fBranchPopAllowed) {
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        while (fBranchStack.top().fDone == Branch::kIsDone)
1488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fBranchStack.pop();
1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned char charOp = (unsigned char) op;
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fActiveStream->write(&charOp, sizeof(charOp));
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
154d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.comvoid SkScriptEngine2::addTokenConst(SkScriptValue2* value, AddTokenRegister reg,
1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                    SkOperand2::OpType toType, SkScriptEngine2::TypeOp op) {
1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (value->fIsConstant == SkScriptValue2::kConstant && convertTo(toType, value))
1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    addTokenValue(*value, reg);
1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    addToken(op);
1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    value->fIsWritten = SkScriptValue2::kWritten;
1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    value->fType = toType;
1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkScriptEngine2::addTokenInt(int integer) {
1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fActiveStream->write(&integer, sizeof(integer));
1668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkScriptEngine2::addTokenScalar(SkScalar scalar) {
1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fActiveStream->write(&scalar, sizeof(scalar));
1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkScriptEngine2::addTokenString(const SkString& string) {
17392f93264e760b74cc706d01b2d0fcfaa3d857f51commit-bot@chromium.org    int size = SkToInt(string.size());
1748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    addTokenInt(size);
1758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fActiveStream->write(string.c_str(), size);
1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkScriptEngine2::addTokenValue(const SkScriptValue2& value, AddTokenRegister reg) {
1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (value.isConstant() == false) {
1808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (reg == kAccumulator) {
1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (fAccumulatorType == SkOperand2::kNoType)
1828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                addToken(kAccumulatorPop);
1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } else {
1848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            ; // !!! incomplete?
1858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (reg == kAccumulator && fAccumulatorType != SkOperand2::kNoType)
1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        addToken(kAccumulatorPush);
1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    switch (value.fType) {
1918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkOperand2::kS32:
1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            addToken(reg == kAccumulator ? kIntegerAccumulator : kIntegerOperand);
1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            addTokenInt(value.fOperand.fS32);
1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (reg == kAccumulator)
1958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fAccumulatorType = SkOperand2::kS32;
1968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            else
1978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fOperandInUse = true;
1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
1998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkOperand2::kScalar:
2008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            addToken(reg == kAccumulator ? kScalarAccumulator : kScalarOperand);
2018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            addTokenScalar(value.fOperand.fScalar);
2028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (reg == kAccumulator)
2038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fAccumulatorType = SkOperand2::kScalar;
2048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            else
2058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fOperandInUse = true;
2068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
2078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkOperand2::kString:
2088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            addToken(reg == kAccumulator ? kStringAccumulator : kStringOperand);
2098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            addTokenString(*value.fOperand.fString);
2108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (reg == kAccumulator)
2118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fAccumulatorType = SkOperand2::kString;
2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            else
2138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fOperandInUse = true;
2148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        default:
2168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(0); //!!! not implemented yet
2178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkScriptEngine2::arithmeticOp(char ch, char nextChar, bool lastPush) {
2218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Op op = kUnassigned;
2228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool reverseOperands = false;
2238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool negateResult = false;
2248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int advance = 1;
2258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    switch (ch) {
2268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case '+':
2278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // !!! ignoring unary plus as implemented here has the side effect of
2288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // suppressing errors like +"hi"
2298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (lastPush == false)    // unary plus, don't push an operator
230800046eba45c9e982ecfe8964b2107f7713ed639reed@android.com                return advance;
2318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            op = kAdd;
2328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
2338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case '-':
2348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            op = lastPush ? kSubtract : kMinus;
2358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
2368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case '*':
2378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            op = kMultiply;
2388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
2398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case '/':
2408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            op = kDivide;
2418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
2428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case '>':
2438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (nextChar == '>') {
2448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                op = kShiftRight;
2458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                goto twoChar;
246d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com            }
2478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            op = kGreaterEqual;
2488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (nextChar == '=')
2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                goto twoChar;
2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                reverseOperands = negateResult = true;
2518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
2528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case '<':
2538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (nextChar == '<') {
2548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                op = kShiftLeft;
2558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                goto twoChar;
2568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
2578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            op = kGreaterEqual;
2588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            reverseOperands = nextChar == '=';
2598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            negateResult = ! reverseOperands;
2608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            advance += reverseOperands;
2618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
2628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case '=':
2638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (nextChar == '=') {
2648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                op = kEqual;
2658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                goto twoChar;
2668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
2678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
2688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case '!':
2698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (nextChar == '=') {
2708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                op = kEqual;
2718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                negateResult = true;
2728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comtwoChar:
2738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    advance++;
2748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                break;
275d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com            }
2768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            op = kLogicalNot;
2778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
2788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case '?':
2798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            op =(Op)  kIf;
2808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
2818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case ':':
2828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            op = (Op) kElse;
2838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
2848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case '^':
2858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            op = kXor;
2868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
2878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case '(':
2888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            *fOpStack.push() = (Op) kParen;
289800046eba45c9e982ecfe8964b2107f7713ed639reed@android.com            return advance;
2908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case '&':
2918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(nextChar != '&');
2928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            op = kBitAnd;
2938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
2948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case '|':
2958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(nextChar != '|');
2968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            op = kBitOr;
2978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
2988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case '%':
2998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            op = kModulo;
3008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
3018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case '~':
3028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            op = kBitNot;
3038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
3048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (op == kUnassigned)
3068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return 0;
3078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    signed char precedence = gPrecedence[op];
3088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    do {
3098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int idx = 0;
3108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        Op compare;
3118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        do {
3128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            compare = fOpStack.index(idx);
3138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if ((compare & kArtificialOp) == 0)
3148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                break;
3158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            idx++;
3168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } while (true);
3178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        signed char topPrecedence = gPrecedence[compare];
3188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(topPrecedence != -1);
319d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        if (topPrecedence > precedence || (topPrecedence == precedence &&
32064cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org            gOpAttributes[op].fLeftType == SkOperand2::kNoType)) {
3218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
3228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
3238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        processOp();
3248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } while (true);
3258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (negateResult)
3268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *fOpStack.push() = (Op) (kLogicalNot | kArtificialOp);
3278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fOpStack.push(op);
3288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (reverseOperands)
3298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *fOpStack.push() = (Op) (kFlipOps | kArtificialOp);
330800046eba45c9e982ecfe8964b2107f7713ed639reed@android.com
331800046eba45c9e982ecfe8964b2107f7713ed639reed@android.com    return advance;
3328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
334d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.combool SkScriptEngine2::convertParams(SkTDArray<SkScriptValue2>* params,
3358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                    const SkOperand2::OpType* paramTypes, int paramCount) {
3368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int count = params->count();
3378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (count > paramCount) {
3388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(0);
3398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;    // too many parameters passed
3408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
341d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    for (int index = 0; index < count; index++)
3428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        convertTo(paramTypes[index], &(*params)[index]);
3438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
3448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkScriptEngine2::convertTo(SkOperand2::OpType toType, SkScriptValue2* value ) {
3478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkOperand2::OpType type = value->fType;
3488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (type == toType)
3498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return true;
3508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (type == SkOperand2::kObject) {
3518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (handleUnbox(value) == false)
3528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return false;
3538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return convertTo(toType, value);
3548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return ConvertTo(this, toType, value);
3568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
358d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.combool SkScriptEngine2::evaluateDot(const char*& script) {
3598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    size_t fieldLength = token_length(++script);        // skip dot
3608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(fieldLength > 0); // !!! add error handling
3618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char* field = script;
3628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    script += fieldLength;
3638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool success = handleProperty();
3648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (success == false) {
3658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fError = kCouldNotFindReferencedID;
3668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        goto error;
3678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
3688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return evaluateDotParam(script, field, fieldLength);
3698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comerror:
3708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
3718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
373d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.combool SkScriptEngine2::evaluateDotParam(const char*& script, const char* field, size_t fieldLength) {
3748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScriptValue2& top = fValueStack.top();
3758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (top.fType != SkOperand2::kObject)
3768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
3778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void* object = top.fOperand.fObject;
3788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fValueStack.pop();
3798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    char ch; // see if it is a simple member or a function
380d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    while (is_ws(ch = script[0]))
3818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        script++;
3828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool success = true;
3838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (ch != '(')
3848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        success = handleMember(field, fieldLength, object);
3858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    else {
3868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkTDArray<SkScriptValue2> params;
3878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *fBraceStack.push() = kFunctionBrace;
3888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        success = functionParams(&script, &params);
3898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (success)
3908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            success = handleMemberFunction(field, fieldLength, object, &params);
3918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
392d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    return success;
3938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
3948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkScriptEngine2::evaluateScript(const char** scriptPtr, SkScriptValue2* value) {
3968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    //    fArrayOffset = 0;        // no support for structures for now
3978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool success;
3988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char* inner;
3998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (strncmp(*scriptPtr, "#script:", sizeof("#script:") - 1) == 0) {
4008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *scriptPtr += sizeof("#script:") - 1;
4018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (fReturnType == SkOperand2::kNoType || fReturnType == SkOperand2::kString) {
4028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            success = innerScript(scriptPtr, value);
4038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(success);
4048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            inner = value->fOperand.fString->c_str();
4058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            scriptPtr = &inner;
4068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
4078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    success = innerScript(scriptPtr, value);
4098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char* script = *scriptPtr;
4108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    char ch;
4118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (is_ws(ch = script[0]))
4128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        script++;
4138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (ch != '\0') {
4148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // error may trigger on scripts like "50,0" that were intended to be written as "[50, 0]"
4158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
4168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return success;
4188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkScriptEngine2::forget(SkOpArray* array) {
4218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (array->getType() == SkOperand2::kString) {
4228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        for (int index = 0; index < array->count(); index++) {
4238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkString* string = (*array)[index].fString;
4248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int found = fTrackString.find(string);
4258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (found >= 0)
4268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fTrackString.remove(found);
4278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
4288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
4298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (array->getType() == SkOperand2::kArray) {
4318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        for (int index = 0; index < array->count(); index++) {
4328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkOpArray* child = (*array)[index].fArray;
4338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            forget(child);    // forgets children of child
4348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int found = fTrackArray.find(child);
4358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (found >= 0)
4368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fTrackArray.remove(found);
4378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
4388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkScriptEngine2::functionParams(const char** scriptPtr, SkTDArray<SkScriptValue2>* params) {
4428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    (*scriptPtr)++; // skip open paren
4438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *fOpStack.push() = (Op) kParen;
4448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *fBraceStack.push() = kFunctionBrace;
4458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    do {
4468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScriptValue2 value;
4478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        bool success = innerScript(scriptPtr, &value);
4488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(success);
4498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (success == false)
4508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return false;
4518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        *params->append() = value;
4528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } while ((*scriptPtr)[-1] == ',');
4538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fBraceStack.pop();
4548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fOpStack.pop(); // pop paren
4558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    (*scriptPtr)++; // advance beyond close paren
4568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
4578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comsize_t SkScriptEngine2::getTokenOffset() {
4608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return fActiveStream->getOffset();
4618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkOperand2::OpType SkScriptEngine2::getUnboxType(SkOperand2 scriptValue) {
4648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
4658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if ((*callBack)->getType() != SkScriptCallBack::kUnbox)
4668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            continue;
4678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return (*callBack)->getReturnType(0, &scriptValue);
4688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return SkOperand2::kObject;
4708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkScriptEngine2::innerScript(const char** scriptPtr, SkScriptValue2* value) {
4738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char* script = *scriptPtr;
4748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    char ch;
4758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool lastPush = false;
4768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool success = true;
4778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int opBalance = fOpStack.count();
4788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int baseBrace = fBraceStack.count();
4798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int branchBalance = fBranchStack.count();
4808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while ((ch = script[0]) != '\0') {
4818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (is_ws(ch)) {
4828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            script++;
4838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            continue;
4848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
4858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScriptValue2 operand;
4868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const char* dotCheck;
4878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (fBraceStack.count() > baseBrace) {
4888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (fBraceStack.top() == kArrayBrace) {
4898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkScriptValue2 tokenValue;
4908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                success = innerScript(&script, &tokenValue);    // terminate and return on comma, close brace
4918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(success);
4928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                {
4938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    SkOperand2::OpType type = fReturnType;
4948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    if (fReturnType == SkOperand2::kNoType) {
495d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com                        // !!! short sighted; in the future, allow each returned array component to carry
4968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        // its own type, and let caller do any needed conversions
4978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        if (value->fOperand.fArray->count() == 0)
4988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            value->fOperand.fArray->setType(type = tokenValue.fType);
4998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        else
5008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                            type = value->fOperand.fArray->getType();
5018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    }
5028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    if (tokenValue.fType != type)
5038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        convertTo(type, &tokenValue);
5048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    *value->fOperand.fArray->append() = tokenValue.fOperand;
5058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
5068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                lastPush = false;
5078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                continue;
508a7ed3cc6371e50a5beb3750c475fe23665dafa7dtomhudson@google.com            } else {
5098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(token_length(script) > 0);
510a7ed3cc6371e50a5beb3750c475fe23665dafa7dtomhudson@google.com            }
5118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
5128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (lastPush != false && fTokenLength > 0) {
5138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (ch == '(') {
5148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                *fBraceStack.push() = kFunctionBrace;
5158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkString functionName(fToken, fTokenLength);
516d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
5178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (handleFunction(&script) == false)
5188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    return false;
5198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                lastPush = true;
5208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                continue;
5218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            } else if (ch == '[') {
5228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (handleProperty() == false) {
5238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    SkASSERT(0);
5248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    return false;
5258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
5268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (handleArrayIndexer(&script) == false)
5278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    return false;
5288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                lastPush = true;
5298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                continue;
5308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            } else if (ch != '.') {
5318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (handleProperty() == false) {
5328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    SkASSERT(0);
5338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    return false;
5348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
5358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                lastPush = true;
5368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                continue;
5378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
5388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
5398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (ch == '0' && (script[1] & ~0x20) == 'X') {
5408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(lastPush == false);
5418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            script += 2;
5428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            script = SkParse::FindHex(script, (uint32_t*) &operand.fOperand.fS32);
5438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(script);
5448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            goto intCommon;
5458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
5468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (lastPush == false && ch == '.')
5478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            goto scalarCommon;
5488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (ch >= '0' && ch <= '9') {
5498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(lastPush == false);
5508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            dotCheck = SkParse::FindS32(script, &operand.fOperand.fS32);
5518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (dotCheck[0] != '.') {
5528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                script = dotCheck;
5538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comintCommon:
5548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                operand.fType = SkOperand2::kS32;
5558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            } else {
5568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comscalarCommon:
5578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                script = SkParse::FindScalar(script, &operand.fOperand.fScalar);
5588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                operand.fType = SkOperand2::kScalar;
5598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
5608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            operand.fIsConstant = SkScriptValue2::kConstant;
5618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fValueStack.push(operand);
5628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            lastPush = true;
5638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            continue;
5648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
5658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int length = token_length(script);
5668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (length > 0) {
5678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(lastPush == false);
5688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fToken = script;
5698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fTokenLength = length;
5708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            script += length;
5718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            lastPush = true;
5728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            continue;
5738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
5748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        char startQuote = ch;
5758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (startQuote == '\'' || startQuote == '\"') {
5768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(lastPush == false);
5778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            operand.fOperand.fString = new SkString();
5788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            ++script;
5798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            const char* stringStart = script;
5808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            do {    // measure string
5818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (script[0] == '\\')
5828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    ++script;
5838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                ++script;
5848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(script[0]); // !!! throw an error
5858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            } while (script[0] != startQuote);
5868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            operand.fOperand.fString->set(stringStart, script - stringStart);
5878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            script = stringStart;
5888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            char* stringWrite = operand.fOperand.fString->writable_str();
5898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            do {    // copy string
5908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (script[0] == '\\')
5918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    ++script;
5928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                *stringWrite++ = script[0];
5938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                ++script;
5948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(script[0]); // !!! throw an error
5958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            } while (script[0] != startQuote);
5968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            ++script;
5978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            track(operand.fOperand.fString);
5988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            operand.fType = SkOperand2::kString;
5998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            operand.fIsConstant = SkScriptValue2::kConstant;
6008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fValueStack.push(operand);
6018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            lastPush = true;
6028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            continue;
6038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
6048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (ch ==  '.') {
6058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (fTokenLength == 0) {
6068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                int tokenLength = token_length(++script);
6078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                const char* token = script;
6088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                script += tokenLength;
6098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(fValueStack.count() > 0); // !!! add error handling
6108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkScriptValue2 top;
6118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fValueStack.pop(&top);
612d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
6138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                addTokenInt(top.fType);
6148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                addToken(kBoxToken);
6158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                top.fType = SkOperand2::kObject;
6168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                top.fIsConstant = SkScriptValue2::kVariable;
6178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fConstExpression = false;
6188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fValueStack.push(top);
6198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                success = evaluateDotParam(script, token, tokenLength);
6208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(success);
6218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                lastPush = true;
622d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com                continue;
6238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
6248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // get next token, and evaluate immediately
6258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            success = evaluateDot(script);
6268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (success == false) {
6278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                //                SkASSERT(0);
6288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                return false;
6298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
6308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            lastPush = true;
6318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            continue;
6328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
6338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (ch == '[') {
6348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (lastPush == false) {
6358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                script++;
6368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                *fBraceStack.push() = kArrayBrace;
6378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                operand.fOperand.fArray = value->fOperand.fArray = new SkOpArray(fReturnType);
6388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                track(value->fOperand.fArray);
639d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com
6408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                operand.fType = SkOperand2::kArray;
6418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                operand.fIsConstant = SkScriptValue2::kVariable;
6428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fValueStack.push(operand);
6438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                continue;
6448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
6458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (handleArrayIndexer(&script) == false)
6468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                return false;
6478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            lastPush = true;
6488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            continue;
6498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
6508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#if 0 // structs not supported for now
6518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (ch == '{') {
6528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (lastPush == false) {
6538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                script++;
6548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                *fBraceStack.push() = kStructBrace;
6558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                operand.fS32 = 0;
6568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                *fTypeStack.push() = (SkOpType) kStruct;
6578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fOperandStack.push(operand);
6588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                continue;
6598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
6608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(0); // braces in other contexts aren't supported yet
6618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
6628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
6638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (ch == ')' && fBraceStack.count() > 0) {
664d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com            BraceStyle braceStyle = fBraceStack.top();
6658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (braceStyle == kFunctionBrace) {
6668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fBraceStack.pop();
6678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                break;
6688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
6698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
6708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (ch == ',' || ch == ']') {
6718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (ch != ',') {
6728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                BraceStyle match;
6738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fBraceStack.pop(&match);
6748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(match == kArrayBrace);
6758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
6768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            script++;
6778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // !!! see if brace or bracket is correct closer
6788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
6798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
6808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        char nextChar = script[1];
6818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int advance = logicalOp(ch, nextChar);
682d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        if (advance == 0)
6838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            advance = arithmeticOp(ch, nextChar, lastPush);
6848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (advance == 0) // unknown token
6858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return false;
6868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (advance > 0)
6878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            script += advance;
6888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        lastPush = ch == ']' || ch == ')';
6898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fTokenLength > 0) {
6918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        success = handleProperty();
6928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(success);
6938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int branchIndex = 0;
6958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    branchBalance = fBranchStack.count() - branchBalance;
6968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fBranchPopAllowed = false;
6978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (branchIndex < branchBalance) {
6988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        Branch& branch = fBranchStack.index(branchIndex++);
6998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (branch.fPrimed == Branch::kIsPrimed)
7008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
7018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        Op branchOp = branch.fOperator;
7028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkOperand2::OpType lastType = fValueStack.top().fType;
7038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        addTokenValue(fValueStack.top(), kAccumulator);
7048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fValueStack.pop();
7058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (branchOp == kLogicalAnd || branchOp == kLogicalOr) {
7068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (branch.fOperator == kLogicalAnd)
7078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                branch.prime();
7088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            addToken(kToBool);
7098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } else {
7108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            resolveBranch(branch);
7118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkScriptValue2 operand;
7128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            operand.fType = lastType;
7138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // !!! note that many branching expressions could be constant
7148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // today, we always evaluate branches as returning variables
7158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            operand.fIsConstant = SkScriptValue2::kVariable;
7168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fValueStack.push(operand);
7178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
7188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (branch.fDone == Branch::kIsNotDone)
7198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            branch.prime();
7208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fBranchPopAllowed = true;
7228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (fBranchStack.top().fDone == Branch::kIsDone)
7238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fBranchStack.pop();
7248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (fOpStack.count() > opBalance) {     // leave open paren
7258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (processOp() == false)
7268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return false;
7278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkOperand2::OpType topType = fValueStack.count() > 0 ? fValueStack.top().fType : SkOperand2::kNoType;
7298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (topType != fReturnType &&
7308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        topType == SkOperand2::kString && fReturnType != SkOperand2::kNoType) { // if result is a string, give handle property a chance to convert it to the property value
7318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkString* string = fValueStack.top().fOperand.fString;
7328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fToken = string->c_str();
7338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fTokenLength = string->size();
7348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fValueStack.pop();
7358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        success = handleProperty();
7368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (success == false) {    // if it couldn't convert, return string (error?)
7378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkScriptValue2 operand;
7388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            operand.fType = SkOperand2::kString;
7398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            operand.fOperand.fString = string;
7408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            operand.fIsConstant = SkScriptValue2::kVariable;     // !!! ?
7418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fValueStack.push(operand);
7428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
7438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fStream.getOffset() > 0) {
7458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        addToken(kEnd);
7468a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.com        SkAutoDataUnref data(fStream.copyToData());
7478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
74841f9e6e45d54c73cc0cc4f84b46b48f9480ff396robertphillips@google.com        decompile(data->bytes(), data->size());
7498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
7508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScriptRuntime runtime(fCallBackArray);
75159f46b81f8bdd1b524f5cc43bc27603f9604c71arobertphillips@google.com        runtime.executeTokens((unsigned char*) data->bytes());
7528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScriptValue2 value1;
7538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        runtime.getResult(&value1.fOperand);
7548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        value1.fType = fReturnType;
7558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fValueStack.push(value1);
7568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (value) {
7588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (fValueStack.count() == 0)
7598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return false;
7608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fValueStack.pop(value);
761d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        if (value->fType != fReturnType && value->fType == SkOperand2::kObject &&
7628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fReturnType != SkOperand2::kNoType)
7638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            convertTo(fReturnType, value);
7648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    //    if (fBranchStack.top().fOpStackDepth > fOpStack.count())
7668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    //        resolveBranch();
7678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *scriptPtr = script;
7688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true; // no error
7698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
7708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkScriptEngine2::handleArrayIndexer(const char** scriptPtr) {
7728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScriptValue2 scriptValue;
7738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    (*scriptPtr)++;
7748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *fOpStack.push() = (Op) kParen;
7758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *fBraceStack.push() = kArrayBrace;
7768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkOperand2::OpType saveType = fReturnType;
7778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fReturnType = SkOperand2::kS32;
7788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool success = innerScript(scriptPtr, &scriptValue);
7798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fReturnType = saveType;
7808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(success);
7818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    success = convertTo(SkOperand2::kS32, &scriptValue);
7828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(success);
7838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int index = scriptValue.fOperand.fS32;
7848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fValueStack.pop(&scriptValue);
7858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (scriptValue.fType == SkOperand2::kObject) {
7868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        success = handleUnbox(&scriptValue);
7878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(success);
7888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(scriptValue.fType == SkOperand2::kArray);
7898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    scriptValue.fType = scriptValue.fOperand.fArray->getType();
7918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    //    SkASSERT(index >= 0);
7928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if ((unsigned) index >= (unsigned) scriptValue.fOperand.fArray->count()) {
7938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fError = kArrayIndexOutOfBounds;
7948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return false;
7958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    scriptValue.fOperand = scriptValue.fOperand.fArray->begin()[index];
7978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    scriptValue.fIsConstant = SkScriptValue2::kVariable;
7988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fValueStack.push(scriptValue);
7998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fOpStack.pop(); // pop paren
8008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return success;
8018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkScriptEngine2::handleFunction(const char** scriptPtr) {
8048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const char* functionName = fToken;
8058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    size_t functionNameLen = fTokenLength;
8068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fTokenLength = 0;
8078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkTDArray<SkScriptValue2> params;
8088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool success = functionParams(scriptPtr, &params);
8098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (success == false)
8108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        goto done;
8118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
8128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
8138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if ((*callBack)->getType() != SkScriptCallBack::kFunction)
8148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                continue;
8158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkScriptValue2 callbackResult;
8168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            success = (*callBack)->getReference(functionName, functionNameLen, &callbackResult);
8178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (success) {
8188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                callbackResult.fType = (*callBack)->getReturnType(callbackResult.fOperand.fReference, NULL);
8198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                callbackResult.fIsConstant = SkScriptValue2::kVariable;
8208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fValueStack.push(callbackResult);
8218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                goto done;
8228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
8238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
8248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
8258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return false;
8268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comdone:
8278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fOpStack.pop();
8288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return success;
8298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkScriptEngine2::handleMember(const char* field, size_t len, void* object) {
8328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool success = true;
8338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
8348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if ((*callBack)->getType() != SkScriptCallBack::kMember)
8358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            continue;
8368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScriptValue2 callbackResult;
8378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        success = (*callBack)->getReference(field, len, &callbackResult);
8388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (success) {
8398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (callbackResult.fType == SkOperand2::kString)
8408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                track(callbackResult.fOperand.fString);
8418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            callbackResult.fIsConstant = SkScriptValue2::kVariable;
8428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fValueStack.push(callbackResult);
8438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            goto done;
8448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
8458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
8468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return false;
8478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comdone:
8488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return success;
8498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
851d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.combool SkScriptEngine2::handleMemberFunction(const char* field, size_t len, void* object,
8528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                           SkTDArray<SkScriptValue2>* params) {
8538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool success = true;
8548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
8558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if ((*callBack)->getType() != SkScriptCallBack::kMemberFunction)
8568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            continue;
8578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScriptValue2 callbackResult;
8588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        success = (*callBack)->getReference(field, len, &callbackResult);
8598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (success) {
8608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (callbackResult.fType == SkOperand2::kString)
8618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                track(callbackResult.fOperand.fString);
8628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            callbackResult.fIsConstant = SkScriptValue2::kVariable;
8638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fValueStack.push(callbackResult);
8648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            goto done;
8658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
8668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
8678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return false;
8688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comdone:
8698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return success;
8708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkScriptEngine2::handleProperty() {
8738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool success = true;
8748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
8758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if ((*callBack)->getType() != SkScriptCallBack::kProperty)
8768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            continue;
8778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScriptValue2 callbackResult;
8788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        success = (*callBack)->getReference(fToken, fTokenLength, &callbackResult);
8798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (success) {
8808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (callbackResult.fType == SkOperand2::kString && callbackResult.fOperand.fString == NULL) {
8818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                callbackResult.fOperand.fString = new SkString(fToken, fTokenLength);
8828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                track(callbackResult.fOperand.fString);
8838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
8848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            callbackResult.fIsConstant = SkScriptValue2::kVariable;
8858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fValueStack.push(callbackResult);
8868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            goto done;
8878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
8888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
8898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comdone:
8908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fTokenLength = 0;
8918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return success;
8928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
8938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkScriptEngine2::handleUnbox(SkScriptValue2* scriptValue) {
8958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool success = true;
8968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
8978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if ((*callBack)->getType() != SkScriptCallBack::kUnbox)
8988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            continue;
8998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScriptCallBackConvert* callBackConvert = (SkScriptCallBackConvert*) *callBack;
9008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        success = callBackConvert->convert(scriptValue->fType, &scriptValue->fOperand);
9018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (success) {
9028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (scriptValue->fType == SkOperand2::kString)
9038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                track(scriptValue->fOperand.fString);
9048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            goto done;
9058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
9068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
9078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return false;
9088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comdone:
9098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return success;
9108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
9118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// note that entire expression is treated as if it were enclosed in parens
9138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com// an open paren is always the first thing in the op stack
9148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comint SkScriptEngine2::logicalOp(char ch, char nextChar) {
9168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int advance = 1;
9178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Op op;
9188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    signed char precedence;
9198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    switch (ch) {
9208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case ')':
9218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            op = (Op) kParen;
9228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
9238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case ']':
9248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            op = (Op) kArrayOp;
9258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
9268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case '?':
9278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            op = (Op) kIf;
9288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
9298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case ':':
9308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            op = (Op) kElse;
9318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
9328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case '&':
9338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (nextChar != '&')
9348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                goto noMatch;
9358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            op = kLogicalAnd;
9368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            advance = 2;
9378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
9388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case '|':
9398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (nextChar != '|')
9408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                goto noMatch;
9418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            op = kLogicalOr;
9428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            advance = 2;
9438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
9448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        default:
9458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            noMatch:
9468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return 0;
9478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
9488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    precedence = gPrecedence[op];
9498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int branchIndex = 0;
9508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fBranchPopAllowed = false;
9518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    do {
9528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        while (gPrecedence[fOpStack.top() & ~kArtificialOp] < precedence)
9538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            processOp();
9548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        Branch& branch = fBranchStack.index(branchIndex++);
9558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        Op branchOp = branch.fOperator;
9568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (gPrecedence[branchOp] >= precedence)
9578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
9588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        addTokenValue(fValueStack.top(), kAccumulator);
9598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fValueStack.pop();
9608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (branchOp == kLogicalAnd || branchOp == kLogicalOr) {
9618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (branch.fOperator == kLogicalAnd)
9628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                branch.prime();
9638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            addToken(kToBool);
9648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } else
9658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            resolveBranch(branch);
9668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (branch.fDone == Branch::kIsNotDone)
9678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            branch.prime();
9688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } while (true);
9698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fBranchPopAllowed = true;
9708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    while (fBranchStack.top().fDone == Branch::kIsDone)
9718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fBranchStack.pop();
9728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    processLogicalOp(op);
9738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return advance;
9748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
9758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkScriptEngine2::processLogicalOp(Op op) {
9778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    switch (op) {
9788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case kParen:
9798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case kArrayOp:
9808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(fOpStack.count() > 1 && fOpStack.top() == op);    // !!! add error handling
981d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com            if (op == kParen)
9828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fOpStack.pop();
9838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            else {
9848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkScriptValue2 value;
9858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fValueStack.pop(&value);
9868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(value.fType == SkOperand2::kS32 || value.fType == SkOperand2::kScalar); // !!! add error handling (although, could permit strings eventually)
987e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com                int index = value.fType == SkOperand2::kScalar ? SkScalarFloorToInt(value.fOperand.fScalar) :
9888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    value.fOperand.fS32;
9898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkScriptValue2 arrayValue;
9908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fValueStack.pop(&arrayValue);
9918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(arrayValue.fType == SkOperand2::kArray);  // !!! add error handling
9928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkOpArray* array = arrayValue.fOperand.fArray;
9938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkOperand2 operand;
9940e51577a14f903ffeafa117a75954baeb173ffb9humper@google.com                SkDEBUGCODE(bool success = ) array->getIndex(index, &operand);
9958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(success); // !!! add error handling
9968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkScriptValue2 resultValue;
9978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                resultValue.fType = array->getType();
9988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                resultValue.fOperand = operand;
9998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                resultValue.fIsConstant = SkScriptValue2::kVariable;
10008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fValueStack.push(resultValue);
10018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
10028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                break;
10038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case kIf: {
10048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (fAccumulatorType == SkOperand2::kNoType) {
10058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                addTokenValue(fValueStack.top(), kAccumulator);
10068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fValueStack.pop();
10078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
10088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(fAccumulatorType != SkOperand2::kString); // !!! add error handling
10098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            addToken(kIfOp);
10108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            Branch branch(op, fOpStack.count(), getTokenOffset());
10118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            *fBranchStack.push() = branch;
10128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            addTokenInt(0); // placeholder for future branch
10138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fAccumulatorType = SkOperand2::kNoType;
10148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } break;
10158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case kElse: {
10168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            addTokenValue(fValueStack.top(), kAccumulator);
10178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fValueStack.pop();
10188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            addToken(kElseOp);
10198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            size_t newOffset = getTokenOffset();
10208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            addTokenInt(0); // placeholder for future branch
10218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            Branch& branch = fBranchStack.top();
10228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            resolveBranch(branch);
10238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            branch.fOperator = op;
10248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            branch.fDone = Branch::kIsNotDone;
10258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(branch.fOpStackDepth == fOpStack.count());
102692f93264e760b74cc706d01b2d0fcfaa3d857f51commit-bot@chromium.org            branch.fOffset = SkToU16(newOffset);
10278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fAccumulatorType = SkOperand2::kNoType;
10288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } break;
10298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case kLogicalAnd:
10308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case kLogicalOr: {
10318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            Branch& oldTop = fBranchStack.top();
10328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            Branch::Primed wasPrime = oldTop.fPrimed;
10338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            Branch::Done wasDone = oldTop.fDone;
10348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            oldTop.fPrimed = Branch::kIsNotPrimed;
10358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            oldTop.fDone = Branch::kIsNotDone;
10368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (fAccumulatorType == SkOperand2::kNoType) {
10378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(fValueStack.top().fType == SkOperand2::kS32); // !!! add error handling, and conversion to int?
10388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                addTokenValue(fValueStack.top(), kAccumulator);
10398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                fValueStack.pop();
1040a7ed3cc6371e50a5beb3750c475fe23665dafa7dtomhudson@google.com            } else {
10418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(fAccumulatorType == SkOperand2::kS32);
1042a7ed3cc6371e50a5beb3750c475fe23665dafa7dtomhudson@google.com            }
10438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // if 'and', write beq goto opcode after end of predicate (after to bool)
10448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // if 'or', write bne goto to bool
10458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            addToken(op == kLogicalAnd ? kLogicalAndInt : kLogicalOrInt);
10468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            Branch branch(op, fOpStack.count(), getTokenOffset());
1047d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com            addTokenInt(0); // placeholder for future branch
10488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            oldTop.fPrimed = wasPrime;
10498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            oldTop.fDone = wasDone;
10508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            *fBranchStack.push() = branch;
10518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fAccumulatorType = SkOperand2::kNoType;
10528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }    break;
10538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        default:
10548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(0);
10558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
10568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
10578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkScriptEngine2::processOp() {
10598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    Op op;
10608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fOpStack.pop(&op);
10618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    op = (Op) (op & ~kArtificialOp);
10628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const OperatorAttributes* attributes = &gOpAttributes[op];
106364cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org    SkScriptValue2 value1;
106464cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org    memset(&value1, 0, sizeof(SkScriptValue2));
10658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScriptValue2 value2;
10668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fValueStack.pop(&value2);
10678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    value2.fIsWritten = SkScriptValue2::kUnwritten;
10688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    //    SkScriptEngine2::SkTypeOp convert1[3];
10698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    //    SkScriptEngine2::SkTypeOp convert2[3];
10708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    //    SkScriptEngine2::SkTypeOp* convert2Ptr = convert2;
10718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool constantOperands = value2.fIsConstant == SkScriptValue2::kConstant;
10728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (attributes->fLeftType != SkOperand2::kNoType) {
10738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fValueStack.pop(&value1);
1074d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        constantOperands &= value1.fIsConstant == SkScriptValue2::kConstant;
10758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        value1.fIsWritten = SkScriptValue2::kUnwritten;
10768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (op == kFlipOps) {
10778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkTSwap(value1, value2);
10788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fOpStack.pop(&op);
10798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            op = (Op) (op & ~kArtificialOp);
10808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            attributes = &gOpAttributes[op];
10818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (constantOperands == false)
10828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                addToken(kFlipOpsOp);
10838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
10848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (value1.fType == SkOperand2::kObject && (value1.fType & attributes->fLeftType) == 0) {
10858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            value1.fType = getUnboxType(value1.fOperand);
10868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            addToken(kUnboxToken);
10878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
10888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
10898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (value2.fType == SkOperand2::kObject && (value2.fType & attributes->fLeftType) == 0) {
10908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        value1.fType = getUnboxType(value2.fOperand);
10918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        addToken(kUnboxToken2);
10928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
10938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (attributes->fLeftType != SkOperand2::kNoType) {
10948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (value1.fType != value2.fType) {
1095d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com            if ((attributes->fLeftType & SkOperand2::kString) && attributes->fBias & kTowardsString &&
10968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                ((value1.fType | value2.fType) & SkOperand2::kString)) {
10978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (value1.fType == SkOperand2::kS32 || value1.fType == SkOperand2::kScalar) {
1098d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com                    addTokenConst(&value1, kAccumulator, SkOperand2::kString,
10998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                  value1.fType == SkOperand2::kS32 ? kIntToString : kScalarToString);
11008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
11018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (value2.fType == SkOperand2::kS32 || value2.fType == SkOperand2::kScalar) {
1102d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com                    addTokenConst(&value2, kOperand, SkOperand2::kString,
11038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                  value2.fType == SkOperand2::kS32 ? kIntToString2 : kScalarToString2);
11048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                }
1105d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com            } else if (attributes->fLeftType & SkOperand2::kScalar && ((value1.fType | value2.fType) &
11068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                                                       SkOperand2::kScalar)) {
11078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (value1.fType == SkOperand2::kS32)
11088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    addTokenConst(&value1, kAccumulator, SkOperand2::kScalar, kIntToScalar);
11098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (value2.fType == SkOperand2::kS32)
11108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    addTokenConst(&value2, kOperand, SkOperand2::kScalar, kIntToScalar2);
11118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
11128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
11138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if ((value1.fType & attributes->fLeftType) == 0 || value1.fType != value2.fType) {
11148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (value1.fType == SkOperand2::kString)
11158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                addTokenConst(&value1, kAccumulator, SkOperand2::kScalar, kStringToScalar);
1116d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com            if (value1.fType == SkOperand2::kScalar && (attributes->fLeftType == SkOperand2::kS32 ||
11178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                                        value2.fType == SkOperand2::kS32))
11188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                addTokenConst(&value1, kAccumulator, SkOperand2::kS32, kScalarToInt);
11198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
11208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
11218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    AddTokenRegister rhRegister = attributes->fLeftType != SkOperand2::kNoType ?
11228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kOperand : kAccumulator;
11238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if ((value2.fType & attributes->fRightType) == 0 || value1.fType != value2.fType) {
11248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (value2.fType == SkOperand2::kString)
11258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            addTokenConst(&value2, rhRegister, SkOperand2::kScalar, kStringToScalar2);
1126d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com        if (value2.fType == SkOperand2::kScalar && (attributes->fRightType == SkOperand2::kS32 ||
11278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                                    value1.fType == SkOperand2::kS32))
11288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            addTokenConst(&value2, rhRegister, SkOperand2::kS32, kScalarToInt2);
11298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
11308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    TypeOp typeOp = gTokens[op];
11318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (value2.fType == SkOperand2::kScalar)
11328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        typeOp = (TypeOp) (typeOp + 1);
11338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    else if (value2.fType == SkOperand2::kString)
11348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        typeOp = (TypeOp) (typeOp + 2);
11358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDynamicMemoryWStream stream;
1136a7ed3cc6371e50a5beb3750c475fe23665dafa7dtomhudson@google.com    SkOperand2::OpType saveType = SkOperand2::kNoType;
1137a7ed3cc6371e50a5beb3750c475fe23665dafa7dtomhudson@google.com    SkBool saveOperand = false;
11388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (constantOperands) {
11398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fActiveStream = &stream;
11408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        saveType = fAccumulatorType;
11418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        saveOperand = fOperandInUse;
11428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fAccumulatorType = SkOperand2::kNoType;
11438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fOperandInUse = false;
11448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
11458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (attributes->fLeftType != SkOperand2::kNoType) {    // two operands
11468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (value1.fIsWritten == SkScriptValue2::kUnwritten)
11478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            addTokenValue(value1, kAccumulator);
11488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
11498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (value2.fIsWritten == SkScriptValue2::kUnwritten)
11508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        addTokenValue(value2, rhRegister);
11518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    addToken(typeOp);
11528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (constantOperands) {
11538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        addToken(kEnd);
11548a85d0c4938173476d037d7af0ee3b9436a1234ereed@google.com        SkAutoDataUnref data(fStream.copyToData());
1155d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com#ifdef SK_DEBUG
115641f9e6e45d54c73cc0cc4f84b46b48f9480ff396robertphillips@google.com        decompile(data->bytes(), data->size());
11578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
11588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScriptRuntime runtime(fCallBackArray);
115959f46b81f8bdd1b524f5cc43bc27603f9604c71arobertphillips@google.com        runtime.executeTokens((unsigned char*)data->bytes());
11608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        runtime.getResult(&value1.fOperand);
11618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (attributes->fResultIsBoolean == kResultIsBoolean)
11628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            value1.fType = SkOperand2::kS32;
11638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        else if (attributes->fLeftType == SkOperand2::kNoType) // unary operand
11648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            value1.fType = value2.fType;
11658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fValueStack.push(value1);
11668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (value1.fType == SkOperand2::kString)
11678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            runtime.untrack(value1.fOperand.fString);
11688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        else if (value1.fType == SkOperand2::kArray)
11698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            runtime.untrack(value1.fOperand.fArray);
11708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fActiveStream = &fStream;
11718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fAccumulatorType = saveType;
11728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fOperandInUse = saveOperand;
11738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return true;
11748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
11758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    value2.fIsConstant = SkScriptValue2::kVariable;
11768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fValueStack.push(value2);
11778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true;
11788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
11798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkScriptEngine2::Branch::resolve(SkDynamicMemoryWStream* stream, size_t off) {
11818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(fDone == kIsNotDone);
11828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fPrimed = kIsNotPrimed;
11838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fDone = kIsDone;
11848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(off > fOffset + sizeof(size_t));
11858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    size_t offset = off - fOffset - sizeof(offset);
11868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    stream->write(&offset, fOffset, sizeof(offset));
11878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
11888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkScriptEngine2::resolveBranch(SkScriptEngine2::Branch& branch) {
11908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    branch.resolve(fActiveStream, getTokenOffset());
11918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
11928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkScriptEngine2::ConvertTo(SkScriptEngine2* engine, SkOperand2::OpType toType, SkScriptValue2* value ) {
11948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(value);
11958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkOperand2::OpType type = value->fType;
1196d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    if (type == toType)
11978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return true;
11988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkOperand2& operand = value->fOperand;
11998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    bool success = true;
12008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    switch (toType) {
12018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkOperand2::kS32:
12028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (type == SkOperand2::kScalar)
1203e1ca705cac4b946993f6cbf798e2a0ba27e739f3reed@google.com                operand.fS32 = SkScalarFloorToInt(operand.fScalar);
12048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            else {
12058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(type == SkOperand2::kString);
12068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                success = SkParse::FindS32(operand.fString->c_str(), &operand.fS32) != NULL;
12078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
12088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                break;
12098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkOperand2::kScalar:
12108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (type == SkOperand2::kS32)
12118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                operand.fScalar = IntToScalar(operand.fS32);
12128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            else {
12138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(type == SkOperand2::kString);
12148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                success = SkParse::FindScalar(operand.fString->c_str(), &operand.fScalar) != NULL;
12158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
12168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                break;
12178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkOperand2::kString: {
12188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkString* strPtr = new SkString();
12198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(engine);
12208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            engine->track(strPtr);
12218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (type == SkOperand2::kS32)
12228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                strPtr->appendS32(operand.fS32);
12238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            else {
12248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(type == SkOperand2::kScalar);
12258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                strPtr->appendScalar(operand.fScalar);
12268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
12278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            operand.fString = strPtr;
12288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } break;
12298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkOperand2::kArray: {
12308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkOpArray* array = new SkOpArray(type);
12318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            *array->append() = operand;
12328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            engine->track(array);
12338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            operand.fArray = array;
12348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } break;
12358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        default:
12368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(0);
12378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
12388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    value->fType = toType;
12398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return success;
12408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
12418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkScalar SkScriptEngine2::IntToScalar(int32_t s32) {
12438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkScalar scalar;
124464cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org    if (s32 == (int32_t) SK_NaN32)
12458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        scalar = SK_ScalarNaN;
12468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    else if (SkAbs32(s32) == SK_MaxS32)
12478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        scalar = SkSign32(s32) * SK_ScalarMax;
12488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    else
12498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        scalar = SkIntToScalar(s32);
12508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return scalar;
12518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
12528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.combool SkScriptEngine2::ValueToString(const SkScriptValue2& value, SkString* string) {
12548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    switch (value.fType) {
12558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkOperand2::kS32:
12568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            string->reset();
12578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            string->appendS32(value.fOperand.fS32);
12588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
12598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkOperand2::kScalar:
12608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            string->reset();
12618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            string->appendScalar(value.fOperand.fScalar);
12628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
12638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        case SkOperand2::kString:
12648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            string->set(*value.fOperand.fString);
12658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            break;
12668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        default:
12678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(0);
12688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            return false;
12698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
12708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return true; // no error
12718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
12728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
12749c55f801a35b0d6c39f007fae432bd13094f3c52sugoi@google.com#if defined(SK_SUPPORT_UNITTEST)
12758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
127664cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org#define testInt(expression) { #expression, SkOperand2::kS32, expression, 0, NULL }
1277100abf49e10544bc4f436bf1f38e6929779621f4bsalomon@google.com#define testScalar(expression) { #expression, SkOperand2::kScalar, 0, (float) (expression), NULL }
1278100abf49e10544bc4f436bf1f38e6929779621f4bsalomon@google.com#define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkOperand2::kScalar, 0, fmodf((float) exp1, (float) exp2), NULL }
127964cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org#define testTrue(expression) { #expression, SkOperand2::kS32, 1, 0, NULL }
128064cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org#define testFalse(expression) { #expression, SkOperand2::kS32, 0, 0, NULL }
12818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstatic const SkScriptNAnswer2 scriptTests[]  = {
128364cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org    testInt(1||(0&&3)),
12848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testScalar(- -5.5- -1.5),
1285d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    testScalar(1.0+5),
12868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt((6+7)*8),
12878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(3*(4+5)),
12888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testScalar(1.0+2.0),
1289d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    testScalar(3.0-1.0),
1290d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    testScalar(6-1.0),
1291d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    testScalar(2.5*6.),
1292d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    testScalar(0.5*4),
1293d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    testScalar(4.5/.5),
1294d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    testScalar(9.5/19),
1295d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    testRemainder(9.5, 0.5),
1296d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com    testRemainder(9.,2),
12978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testRemainder(9,2.5),
12988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testRemainder(-9,2.5),
12998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testTrue(-9==-9.0),
13008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testTrue(-9.==-4.0-5),
13018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testTrue(-9.*1==-4-5),
13028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse(-9!=-9.0),
13038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse(-9.!=-4.0-5),
13048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse(-9.*1!=-4-5),
13058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(0x123),
13068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(0XABC),
13078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(0xdeadBEEF),
13088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {    "'123'+\"456\"", SkOperand2::kString, 0, 0, "123456" },
13098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {    "123+\"456\"", SkOperand2::kString, 0, 0, "123456" },
13108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {    "'123'+456", SkOperand2::kString, 0, 0, "123456" },
131164cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org    {    "'123'|\"456\"", SkOperand2::kS32, 123|456, 0, NULL },
131264cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org    {    "123|\"456\"", SkOperand2::kS32, 123|456, 0, NULL },
131364cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org    {    "'123'|456", SkOperand2::kS32, 123|456, 0, NULL },
131464cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org    {    "'2'<11", SkOperand2::kS32, 1, 0, NULL },
131564cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org    {    "2<'11'", SkOperand2::kS32, 1, 0, NULL },
131664cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org    {    "'2'<'11'", SkOperand2::kS32, 0, 0, NULL },
13178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(123),
13188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(-345),
13198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(+678),
13208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(1+2+3),
13218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(3*4+5),
13228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(6+7*8),
13238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(-1-2-8/4),
13248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(-9%4),
13258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(9%-4),
13268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(-9%-4),
13278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(123|978),
13288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(123&978),
13298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(123^978),
13308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2<<4),
13318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(99>>3),
13328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(~55),
13338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(~~55),
13348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(!55),
13358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(!!55),
13368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // both int
13378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2<2),
13388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2<11),
13398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20<11),
13408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2<=2),
13418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2<=11),
13428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20<=11),
13438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2>2),
13448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2>11),
13458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20>11),
13468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2>=2),
13478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2>=11),
13488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20>=11),
13498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2==2),
13508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2==11),
13518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20==11),
13528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2!=2),
13538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2!=11),
13548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20!=11),
13558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // left int, right scalar
13568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2<2.),
13578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2<11.),
13588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20<11.),
13598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2<=2.),
13608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2<=11.),
13618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20<=11.),
13628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2>2.),
13638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2>11.),
13648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20>11.),
13658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2>=2.),
13668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2>=11.),
13678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20>=11.),
13688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2==2.),
13698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2==11.),
13708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20==11.),
13718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2!=2.),
13728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2!=11.),
13738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20!=11.),
13748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // left scalar, right int
13758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2.<2),
13768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2.<11),
13778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20.<11),
13788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2.<=2),
13798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2.<=11),
13808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20.<=11),
13818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2.>2),
13828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2.>11),
13838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20.>11),
13848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2.>=2),
13858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2.>=11),
13868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20.>=11),
13878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2.==2),
13888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2.==11),
13898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20.==11),
13908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2.!=2),
13918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2.!=11),
13928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20.!=11),
13938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // both scalar
13948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2.<11.),
13958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20.<11.),
13968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2.<=2.),
13978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2.<=11.),
13988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20.<=11.),
13998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2.>2.),
14008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2.>11.),
14018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20.>11.),
14028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2.>=2.),
14038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2.>=11.),
14048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20.>=11.),
14058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2.==2.),
14068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2.==11.),
14078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20.==11.),
14088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2.!=2.),
14098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(2.!=11.),
14108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(20.!=11.),
14118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // int, string (string is int)
14128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse(2<'2'),
14138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testTrue(2<'11'),
14148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse(20<'11'),
14158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testTrue(2<='2'),
14168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testTrue(2<='11'),
14178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse(20<='11'),
14188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse(2>'2'),
14198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse(2>'11'),
14208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testTrue(20>'11'),
14218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testTrue(2>='2'),
14228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse(2>='11'),
14238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testTrue(20>='11'),
14248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testTrue(2=='2'),
14258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse(2=='11'),
14268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse(2!='2'),
14278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testTrue(2!='11'),
14288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // int, string (string is scalar)
14298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse(2<'2.'),
14308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testTrue(2<'11.'),
14318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse(20<'11.'),
14328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testTrue(2=='2.'),
14338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse(2=='11.'),
14348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // scalar, string
14358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse(2.<'2.'),
14368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testTrue(2.<'11.'),
14378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse(20.<'11.'),
14388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testTrue(2.=='2.'),
14398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse(2.=='11.'),
14408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // string, int
14418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse('2'<2),
14428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testTrue('2'<11),
14438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse('20'<11),
14448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testTrue('2'==2),
14458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse('2'==11),
14468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // string, scalar
14478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse('2'<2.),
14488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testTrue('2'<11.),
14498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse('20'<11.),
14508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testTrue('2'==2.),
14518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse('2'==11.),
14528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // string, string
14538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse('2'<'2'),
14548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse('2'<'11'),
14558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse('20'<'11'),
14568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testTrue('2'=='2'),
14578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testFalse('2'=='11'),
14588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // logic
14598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(1?2:3),
14608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(0?2:3),
146164cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org    testInt((1&&2)||3),
146264cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org    testInt((1&&0)||3),
146364cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org    testInt((1&&0)||0),
146464cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org    testInt(1||(0&&3)),
146564cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org    testInt(0||(0&&3)),
146664cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org    testInt(0||(1&&3)),
14678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    testInt(0&&1?2:3)
146864cc579efa7e416c7298ed159d76b074b283c0f9senorblanco@chromium.org    , {    "123.5", SkOperand2::kScalar, 0, SkIntToScalar(123) + SK_Scalar1/2, NULL }
14698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
14708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkScriptNAnswer_testCount    SK_ARRAY_COUNT(scriptTests)
14729c55f801a35b0d6c39f007fae432bd13094f3c52sugoi@google.com#endif  // SK_SUPPORT_UNITTEST
14738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
14748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkScriptEngine2::UnitTest() {
1475ec10d21eb9a17639688188b0defce6d757331eb4reed@android.com#if defined(SK_SUPPORT_UNITTEST)
14768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    ValidateDecompileTable();
14772dc8b96230c99cd460c02fdb69b036905d072216commit-bot@chromium.org    for (size_t index = 0; index < SkScriptNAnswer_testCount; index++) {
14788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScriptEngine2 engine(scriptTests[index].fType);
14798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScriptValue2 value;
14808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const char* script = scriptTests[index].fScript;
14818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        const char* scriptPtr = script;
14828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(engine.evaluateScript(&scriptPtr, &value) == true);
14838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(value.fType == scriptTests[index].fType);
14848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkScalar error;
14858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        switch (value.fType) {
14868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            case SkOperand2::kS32:
14878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (value.fOperand.fS32 != scriptTests[index].fIntAnswer)
14888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    SkDEBUGF(("script '%s' == value %d != expected answer %d\n", script, value.fOperand.fS32, scriptTests[index].fIntAnswer));
14898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer);
14908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                break;
14918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            case SkOperand2::kScalar:
14928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer);
14938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                if (error >= SK_Scalar1 / 10000)
14948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    SkDEBUGF(("script '%s' == value %g != expected answer %g\n", script, value.fOperand.fScalar / (1.0f * SK_Scalar1), scriptTests[index].fScalarAnswer / (1.0f * SK_Scalar1)));
14958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(error < SK_Scalar1 / 10000);
14968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                break;
14978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            case SkOperand2::kString:
14988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(value.fOperand.fString->equals(scriptTests[index].fStringAnswer));
14998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                break;
15008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            default:
15018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                SkASSERT(0);
15028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
15038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
15049c55f801a35b0d6c39f007fae432bd13094f3c52sugoi@google.com#endif  // SK_SUPPORT_UNITTEST
15058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
15069c55f801a35b0d6c39f007fae432bd13094f3c52sugoi@google.com#endif  // SK_DEBUG
1507