Home | History | Annotate | Download | only in animator
      1 
      2 /*
      3  * Copyright 2011 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 #include "SkScript2.h"
      9 #include "SkData.h"
     10 #include "SkFloatingPoint.h"
     11 #include "SkMath.h"
     12 #include "SkParse.h"
     13 #include "SkScriptCallBack.h"
     14 #include "SkScriptRuntime.h"
     15 #include "SkString.h"
     16 #include "SkOpArray.h"
     17 
     18 const SkScriptEngine2::OperatorAttributes SkScriptEngine2::gOpAttributes[] = {
     19 { SkOperand2::kNoType, SkOperand2::kNoType, kNoBias, kResultIsNotBoolean },
     20 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString),
     21     SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), kTowardsString, kResultIsNotBoolean },    // kAdd
     22 { SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kBitAnd
     23 { SkOperand2::kNoType, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kBitNot
     24 { SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kBitOr
     25 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar),
     26     SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias, kResultIsNotBoolean }, // kDivide
     27 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString),
     28     SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar |SkOperand2:: kString), kTowardsNumber,
     29     kResultIsBoolean }, // kEqual
     30 { SkOperand2::kS32, SkOperand2::kNoType, kNoBias, kResultIsNotBoolean },     // kFlipOps
     31 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString),
     32     SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kString), kTowardsNumber,
     33     kResultIsBoolean }, // kGreaterEqual
     34 { SkOperand2::kNoType, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kLogicalAnd    (really, ToBool)
     35 { SkOperand2::kNoType, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kLogicalNot
     36 { SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kLogicalOr
     37 { SkOperand2::kNoType, SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias, kResultIsNotBoolean }, // kMinus
     38 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar),
     39     SkOperand2::OpType(SkOperand2::kS32 |SkOperand2:: kScalar), kNoBias, kResultIsNotBoolean }, // kModulo
     40 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar),
     41     SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias, kResultIsNotBoolean }, // kMultiply
     42 { SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kShiftLeft
     43 { SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean }, // kShiftRight
     44 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar),
     45     SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias, kResultIsNotBoolean }, // kSubtract
     46 { SkOperand2::kS32, SkOperand2::kS32, kNoBias, kResultIsNotBoolean } // kXor
     47 };
     48 
     49 #define kBracketPrecedence 16
     50 #define kIfElsePrecedence 15
     51 
     52 const signed char SkScriptEngine2::gPrecedence[] = {
     53     17, // kUnassigned,
     54     6, // kAdd,
     55     10, // kBitAnd,
     56     4, // kBitNot,
     57     12, // kBitOr,
     58     5, // kDivide,
     59     9, // kEqual,
     60     -1, // kFlipOps,
     61     8, // kGreaterEqual,
     62     13, // kLogicalAnd,
     63     4, // kLogicalNot,
     64     14, // kLogicalOr,
     65     4, // kMinus,
     66     5, // kModulo,
     67     5, // kMultiply,
     68     7, // kShiftLeft,
     69     7, // kShiftRight,    // signed
     70     6, // kSubtract,
     71     11, // kXor
     72     kBracketPrecedence, // kArrayOp
     73     kIfElsePrecedence, // kElse
     74     kIfElsePrecedence, // kIf
     75     kBracketPrecedence, // kParen
     76 };
     77 
     78 const SkScriptEngine2::TypeOp SkScriptEngine2::gTokens[] = {
     79     kNop, // unassigned
     80     kAddInt, // kAdd,
     81     kBitAndInt, // kBitAnd,
     82     kBitNotInt, // kBitNot,
     83     kBitOrInt, // kBitOr,
     84     kDivideInt, // kDivide,
     85     kEqualInt, // kEqual,
     86     kFlipOpsOp, // kFlipOps,
     87     kGreaterEqualInt, // kGreaterEqual,
     88     kLogicalAndInt, // kLogicalAnd,
     89     kLogicalNotInt, // kLogicalNot,
     90     kLogicalOrInt, // kLogicalOr,
     91     kMinusInt, // kMinus,
     92     kModuloInt, // kModulo,
     93     kMultiplyInt, // kMultiply,
     94     kShiftLeftInt, // kShiftLeft,
     95     kShiftRightInt, // kShiftRight,    // signed
     96     kSubtractInt, // kSubtract,
     97     kXorInt // kXor
     98 };
     99 
    100 static inline bool is_between(int c, int min, int max)
    101 {
    102     return (unsigned)(c - min) <= (unsigned)(max - min);
    103 }
    104 
    105 static inline bool is_ws(int c)
    106 {
    107     return is_between(c, 1, 32);
    108 }
    109 
    110 static int token_length(const char* start) {
    111     char ch = start[0];
    112     if (! is_between(ch, 'a' , 'z') &&  ! is_between(ch, 'A', 'Z') && ch != '_' && ch != '$')
    113         return -1;
    114     int length = 0;
    115     do
    116         ch = start[++length];
    117     while (is_between(ch, 'a' , 'z') || is_between(ch, 'A', 'Z') || is_between(ch, '0', '9') ||
    118            ch == '_' || ch == '$');
    119     return length;
    120 }
    121 
    122 SkScriptEngine2::SkScriptEngine2(SkOperand2::OpType returnType) : fActiveStream(&fStream),
    123 fTokenLength(0), fReturnType(returnType), fError(kNoError),
    124 fAccumulatorType(SkOperand2::kNoType),
    125 fBranchPopAllowed(true), fConstExpression(true), fOperandInUse(false)
    126 {
    127     Branch branch(kUnassigned, 0, 0);
    128     fBranchStack.push(branch);
    129     *fOpStack.push() = (Op) kParen;
    130 }
    131 
    132 SkScriptEngine2::~SkScriptEngine2() {
    133     for (SkString** stringPtr = fTrackString.begin(); stringPtr < fTrackString.end(); stringPtr++)
    134         delete *stringPtr;
    135     for (SkOpArray** arrayPtr = fTrackArray.begin(); arrayPtr < fTrackArray.end(); arrayPtr++)
    136         delete *arrayPtr;
    137 }
    138 
    139 void SkScriptEngine2::addToken(SkScriptEngine2::TypeOp op) {
    140     int limit = fBranchStack.count() - 1;
    141     for (int index = 0; index < limit; index++) {
    142         Branch& branch = fBranchStack.index(index);
    143         if (branch.fPrimed == Branch::kIsPrimed)
    144             resolveBranch(branch);
    145     }
    146     if (fBranchPopAllowed) {
    147         while (fBranchStack.top().fDone == Branch::kIsDone)
    148             fBranchStack.pop();
    149     }
    150     unsigned char charOp = (unsigned char) op;
    151     fActiveStream->write(&charOp, sizeof(charOp));
    152 }
    153 
    154 void SkScriptEngine2::addTokenConst(SkScriptValue2* value, AddTokenRegister reg,
    155                                     SkOperand2::OpType toType, SkScriptEngine2::TypeOp op) {
    156     if (value->fIsConstant == SkScriptValue2::kConstant && convertTo(toType, value))
    157         return;
    158     addTokenValue(*value, reg);
    159     addToken(op);
    160     value->fIsWritten = SkScriptValue2::kWritten;
    161     value->fType = toType;
    162 }
    163 
    164 void SkScriptEngine2::addTokenInt(int integer) {
    165     fActiveStream->write(&integer, sizeof(integer));
    166 }
    167 
    168 void SkScriptEngine2::addTokenScalar(SkScalar scalar) {
    169     fActiveStream->write(&scalar, sizeof(scalar));
    170 }
    171 
    172 void SkScriptEngine2::addTokenString(const SkString& string) {
    173     int size = string.size();
    174     addTokenInt(size);
    175     fActiveStream->write(string.c_str(), size);
    176 }
    177 
    178 void SkScriptEngine2::addTokenValue(const SkScriptValue2& value, AddTokenRegister reg) {
    179     if (value.isConstant() == false) {
    180         if (reg == kAccumulator) {
    181             if (fAccumulatorType == SkOperand2::kNoType)
    182                 addToken(kAccumulatorPop);
    183         } else {
    184             ; // !!! incomplete?
    185         }
    186         return;
    187     }
    188     if (reg == kAccumulator && fAccumulatorType != SkOperand2::kNoType)
    189         addToken(kAccumulatorPush);
    190     switch (value.fType) {
    191         case SkOperand2::kS32:
    192             addToken(reg == kAccumulator ? kIntegerAccumulator : kIntegerOperand);
    193             addTokenInt(value.fOperand.fS32);
    194             if (reg == kAccumulator)
    195                 fAccumulatorType = SkOperand2::kS32;
    196             else
    197                 fOperandInUse = true;
    198             break;
    199         case SkOperand2::kScalar:
    200             addToken(reg == kAccumulator ? kScalarAccumulator : kScalarOperand);
    201             addTokenScalar(value.fOperand.fScalar);
    202             if (reg == kAccumulator)
    203                 fAccumulatorType = SkOperand2::kScalar;
    204             else
    205                 fOperandInUse = true;
    206             break;
    207         case SkOperand2::kString:
    208             addToken(reg == kAccumulator ? kStringAccumulator : kStringOperand);
    209             addTokenString(*value.fOperand.fString);
    210             if (reg == kAccumulator)
    211                 fAccumulatorType = SkOperand2::kString;
    212             else
    213                 fOperandInUse = true;
    214             break;
    215         default:
    216             SkASSERT(0); //!!! not implemented yet
    217     }
    218 }
    219 
    220 int SkScriptEngine2::arithmeticOp(char ch, char nextChar, bool lastPush) {
    221     Op op = kUnassigned;
    222     bool reverseOperands = false;
    223     bool negateResult = false;
    224     int advance = 1;
    225     switch (ch) {
    226         case '+':
    227             // !!! ignoring unary plus as implemented here has the side effect of
    228             // suppressing errors like +"hi"
    229             if (lastPush == false)    // unary plus, don't push an operator
    230                 return advance;
    231             op = kAdd;
    232             break;
    233         case '-':
    234             op = lastPush ? kSubtract : kMinus;
    235             break;
    236         case '*':
    237             op = kMultiply;
    238             break;
    239         case '/':
    240             op = kDivide;
    241             break;
    242         case '>':
    243             if (nextChar == '>') {
    244                 op = kShiftRight;
    245                 goto twoChar;
    246             }
    247             op = kGreaterEqual;
    248             if (nextChar == '=')
    249                 goto twoChar;
    250                 reverseOperands = negateResult = true;
    251             break;
    252         case '<':
    253             if (nextChar == '<') {
    254                 op = kShiftLeft;
    255                 goto twoChar;
    256             }
    257             op = kGreaterEqual;
    258             reverseOperands = nextChar == '=';
    259             negateResult = ! reverseOperands;
    260             advance += reverseOperands;
    261             break;
    262         case '=':
    263             if (nextChar == '=') {
    264                 op = kEqual;
    265                 goto twoChar;
    266             }
    267             break;
    268         case '!':
    269             if (nextChar == '=') {
    270                 op = kEqual;
    271                 negateResult = true;
    272 twoChar:
    273                     advance++;
    274                 break;
    275             }
    276             op = kLogicalNot;
    277             break;
    278         case '?':
    279             op =(Op)  kIf;
    280             break;
    281         case ':':
    282             op = (Op) kElse;
    283             break;
    284         case '^':
    285             op = kXor;
    286             break;
    287         case '(':
    288             *fOpStack.push() = (Op) kParen;
    289             return advance;
    290         case '&':
    291             SkASSERT(nextChar != '&');
    292             op = kBitAnd;
    293             break;
    294         case '|':
    295             SkASSERT(nextChar != '|');
    296             op = kBitOr;
    297             break;
    298         case '%':
    299             op = kModulo;
    300             break;
    301         case '~':
    302             op = kBitNot;
    303             break;
    304     }
    305     if (op == kUnassigned)
    306         return 0;
    307     signed char precedence = gPrecedence[op];
    308     do {
    309         int idx = 0;
    310         Op compare;
    311         do {
    312             compare = fOpStack.index(idx);
    313             if ((compare & kArtificialOp) == 0)
    314                 break;
    315             idx++;
    316         } while (true);
    317         signed char topPrecedence = gPrecedence[compare];
    318         SkASSERT(topPrecedence != -1);
    319         if (topPrecedence > precedence || (topPrecedence == precedence &&
    320             gOpAttributes[op].fLeftType == SkOperand2::kNoType)) {
    321             break;
    322         }
    323         processOp();
    324     } while (true);
    325     if (negateResult)
    326         *fOpStack.push() = (Op) (kLogicalNot | kArtificialOp);
    327     fOpStack.push(op);
    328     if (reverseOperands)
    329         *fOpStack.push() = (Op) (kFlipOps | kArtificialOp);
    330 
    331     return advance;
    332 }
    333 
    334 bool SkScriptEngine2::convertParams(SkTDArray<SkScriptValue2>* params,
    335                                     const SkOperand2::OpType* paramTypes, int paramCount) {
    336     int count = params->count();
    337     if (count > paramCount) {
    338         SkASSERT(0);
    339         return false;    // too many parameters passed
    340     }
    341     for (int index = 0; index < count; index++)
    342         convertTo(paramTypes[index], &(*params)[index]);
    343     return true;
    344 }
    345 
    346 bool SkScriptEngine2::convertTo(SkOperand2::OpType toType, SkScriptValue2* value ) {
    347     SkOperand2::OpType type = value->fType;
    348     if (type == toType)
    349         return true;
    350     if (type == SkOperand2::kObject) {
    351         if (handleUnbox(value) == false)
    352             return false;
    353         return convertTo(toType, value);
    354     }
    355     return ConvertTo(this, toType, value);
    356 }
    357 
    358 bool SkScriptEngine2::evaluateDot(const char*& script) {
    359     size_t fieldLength = token_length(++script);        // skip dot
    360     SkASSERT(fieldLength > 0); // !!! add error handling
    361     const char* field = script;
    362     script += fieldLength;
    363     bool success = handleProperty();
    364     if (success == false) {
    365         fError = kCouldNotFindReferencedID;
    366         goto error;
    367     }
    368     return evaluateDotParam(script, field, fieldLength);
    369 error:
    370         return false;
    371 }
    372 
    373 bool SkScriptEngine2::evaluateDotParam(const char*& script, const char* field, size_t fieldLength) {
    374     SkScriptValue2& top = fValueStack.top();
    375     if (top.fType != SkOperand2::kObject)
    376         return false;
    377     void* object = top.fOperand.fObject;
    378     fValueStack.pop();
    379     char ch; // see if it is a simple member or a function
    380     while (is_ws(ch = script[0]))
    381         script++;
    382     bool success = true;
    383     if (ch != '(')
    384         success = handleMember(field, fieldLength, object);
    385     else {
    386         SkTDArray<SkScriptValue2> params;
    387         *fBraceStack.push() = kFunctionBrace;
    388         success = functionParams(&script, &params);
    389         if (success)
    390             success = handleMemberFunction(field, fieldLength, object, &params);
    391     }
    392     return success;
    393 }
    394 
    395 bool SkScriptEngine2::evaluateScript(const char** scriptPtr, SkScriptValue2* value) {
    396     //    fArrayOffset = 0;        // no support for structures for now
    397     bool success;
    398     const char* inner;
    399     if (strncmp(*scriptPtr, "#script:", sizeof("#script:") - 1) == 0) {
    400         *scriptPtr += sizeof("#script:") - 1;
    401         if (fReturnType == SkOperand2::kNoType || fReturnType == SkOperand2::kString) {
    402             success = innerScript(scriptPtr, value);
    403             SkASSERT(success);
    404             inner = value->fOperand.fString->c_str();
    405             scriptPtr = &inner;
    406         }
    407     }
    408     success = innerScript(scriptPtr, value);
    409     const char* script = *scriptPtr;
    410     char ch;
    411     while (is_ws(ch = script[0]))
    412         script++;
    413     if (ch != '\0') {
    414         // error may trigger on scripts like "50,0" that were intended to be written as "[50, 0]"
    415         return false;
    416     }
    417     return success;
    418 }
    419 
    420 void SkScriptEngine2::forget(SkOpArray* array) {
    421     if (array->getType() == SkOperand2::kString) {
    422         for (int index = 0; index < array->count(); index++) {
    423             SkString* string = (*array)[index].fString;
    424             int found = fTrackString.find(string);
    425             if (found >= 0)
    426                 fTrackString.remove(found);
    427         }
    428         return;
    429     }
    430     if (array->getType() == SkOperand2::kArray) {
    431         for (int index = 0; index < array->count(); index++) {
    432             SkOpArray* child = (*array)[index].fArray;
    433             forget(child);    // forgets children of child
    434             int found = fTrackArray.find(child);
    435             if (found >= 0)
    436                 fTrackArray.remove(found);
    437         }
    438     }
    439 }
    440 
    441 bool SkScriptEngine2::functionParams(const char** scriptPtr, SkTDArray<SkScriptValue2>* params) {
    442     (*scriptPtr)++; // skip open paren
    443     *fOpStack.push() = (Op) kParen;
    444     *fBraceStack.push() = kFunctionBrace;
    445     do {
    446         SkScriptValue2 value;
    447         bool success = innerScript(scriptPtr, &value);
    448         SkASSERT(success);
    449         if (success == false)
    450             return false;
    451         *params->append() = value;
    452     } while ((*scriptPtr)[-1] == ',');
    453     fBraceStack.pop();
    454     fOpStack.pop(); // pop paren
    455     (*scriptPtr)++; // advance beyond close paren
    456     return true;
    457 }
    458 
    459 size_t SkScriptEngine2::getTokenOffset() {
    460     return fActiveStream->getOffset();
    461 }
    462 
    463 SkOperand2::OpType SkScriptEngine2::getUnboxType(SkOperand2 scriptValue) {
    464     for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
    465         if ((*callBack)->getType() != SkScriptCallBack::kUnbox)
    466             continue;
    467         return (*callBack)->getReturnType(0, &scriptValue);
    468     }
    469     return SkOperand2::kObject;
    470 }
    471 
    472 bool SkScriptEngine2::innerScript(const char** scriptPtr, SkScriptValue2* value) {
    473     const char* script = *scriptPtr;
    474     char ch;
    475     bool lastPush = false;
    476     bool success = true;
    477     int opBalance = fOpStack.count();
    478     int baseBrace = fBraceStack.count();
    479     int branchBalance = fBranchStack.count();
    480     while ((ch = script[0]) != '\0') {
    481         if (is_ws(ch)) {
    482             script++;
    483             continue;
    484         }
    485         SkScriptValue2 operand;
    486         const char* dotCheck;
    487         if (fBraceStack.count() > baseBrace) {
    488             if (fBraceStack.top() == kArrayBrace) {
    489                 SkScriptValue2 tokenValue;
    490                 success = innerScript(&script, &tokenValue);    // terminate and return on comma, close brace
    491                 SkASSERT(success);
    492                 {
    493                     SkOperand2::OpType type = fReturnType;
    494                     if (fReturnType == SkOperand2::kNoType) {
    495                         // !!! short sighted; in the future, allow each returned array component to carry
    496                         // its own type, and let caller do any needed conversions
    497                         if (value->fOperand.fArray->count() == 0)
    498                             value->fOperand.fArray->setType(type = tokenValue.fType);
    499                         else
    500                             type = value->fOperand.fArray->getType();
    501                     }
    502                     if (tokenValue.fType != type)
    503                         convertTo(type, &tokenValue);
    504                     *value->fOperand.fArray->append() = tokenValue.fOperand;
    505                 }
    506                 lastPush = false;
    507                 continue;
    508             } else {
    509                 SkASSERT(token_length(script) > 0);
    510             }
    511         }
    512         if (lastPush != false && fTokenLength > 0) {
    513             if (ch == '(') {
    514                 *fBraceStack.push() = kFunctionBrace;
    515                 SkString functionName(fToken, fTokenLength);
    516 
    517                 if (handleFunction(&script) == false)
    518                     return false;
    519                 lastPush = true;
    520                 continue;
    521             } else if (ch == '[') {
    522                 if (handleProperty() == false) {
    523                     SkASSERT(0);
    524                     return false;
    525                 }
    526                 if (handleArrayIndexer(&script) == false)
    527                     return false;
    528                 lastPush = true;
    529                 continue;
    530             } else if (ch != '.') {
    531                 if (handleProperty() == false) {
    532                     SkASSERT(0);
    533                     return false;
    534                 }
    535                 lastPush = true;
    536                 continue;
    537             }
    538         }
    539         if (ch == '0' && (script[1] & ~0x20) == 'X') {
    540             SkASSERT(lastPush == false);
    541             script += 2;
    542             script = SkParse::FindHex(script, (uint32_t*) &operand.fOperand.fS32);
    543             SkASSERT(script);
    544             goto intCommon;
    545         }
    546         if (lastPush == false && ch == '.')
    547             goto scalarCommon;
    548         if (ch >= '0' && ch <= '9') {
    549             SkASSERT(lastPush == false);
    550             dotCheck = SkParse::FindS32(script, &operand.fOperand.fS32);
    551             if (dotCheck[0] != '.') {
    552                 script = dotCheck;
    553 intCommon:
    554                 operand.fType = SkOperand2::kS32;
    555             } else {
    556 scalarCommon:
    557                 script = SkParse::FindScalar(script, &operand.fOperand.fScalar);
    558                 operand.fType = SkOperand2::kScalar;
    559             }
    560             operand.fIsConstant = SkScriptValue2::kConstant;
    561             fValueStack.push(operand);
    562             lastPush = true;
    563             continue;
    564         }
    565         int length = token_length(script);
    566         if (length > 0) {
    567             SkASSERT(lastPush == false);
    568             fToken = script;
    569             fTokenLength = length;
    570             script += length;
    571             lastPush = true;
    572             continue;
    573         }
    574         char startQuote = ch;
    575         if (startQuote == '\'' || startQuote == '\"') {
    576             SkASSERT(lastPush == false);
    577             operand.fOperand.fString = new SkString();
    578             ++script;
    579             const char* stringStart = script;
    580             do {    // measure string
    581                 if (script[0] == '\\')
    582                     ++script;
    583                 ++script;
    584                 SkASSERT(script[0]); // !!! throw an error
    585             } while (script[0] != startQuote);
    586             operand.fOperand.fString->set(stringStart, script - stringStart);
    587             script = stringStart;
    588             char* stringWrite = operand.fOperand.fString->writable_str();
    589             do {    // copy string
    590                 if (script[0] == '\\')
    591                     ++script;
    592                 *stringWrite++ = script[0];
    593                 ++script;
    594                 SkASSERT(script[0]); // !!! throw an error
    595             } while (script[0] != startQuote);
    596             ++script;
    597             track(operand.fOperand.fString);
    598             operand.fType = SkOperand2::kString;
    599             operand.fIsConstant = SkScriptValue2::kConstant;
    600             fValueStack.push(operand);
    601             lastPush = true;
    602             continue;
    603         }
    604         if (ch ==  '.') {
    605             if (fTokenLength == 0) {
    606                 SkDEBUGCODE(SkScriptValue2 scriptValue;)
    607                 SkDEBUGCODE(scriptValue.fOperand.fObject = NULL);
    608                 int tokenLength = token_length(++script);
    609                 const char* token = script;
    610                 script += tokenLength;
    611                 SkASSERT(fValueStack.count() > 0); // !!! add error handling
    612                 SkScriptValue2 top;
    613                 fValueStack.pop(&top);
    614 
    615                 addTokenInt(top.fType);
    616                 addToken(kBoxToken);
    617                 top.fType = SkOperand2::kObject;
    618                 top.fIsConstant = SkScriptValue2::kVariable;
    619                 fConstExpression = false;
    620                 fValueStack.push(top);
    621                 success = evaluateDotParam(script, token, tokenLength);
    622                 SkASSERT(success);
    623                 lastPush = true;
    624                 continue;
    625             }
    626             // get next token, and evaluate immediately
    627             success = evaluateDot(script);
    628             if (success == false) {
    629                 //                SkASSERT(0);
    630                 return false;
    631             }
    632             lastPush = true;
    633             continue;
    634         }
    635         if (ch == '[') {
    636             if (lastPush == false) {
    637                 script++;
    638                 *fBraceStack.push() = kArrayBrace;
    639                 operand.fOperand.fArray = value->fOperand.fArray = new SkOpArray(fReturnType);
    640                 track(value->fOperand.fArray);
    641 
    642                 operand.fType = SkOperand2::kArray;
    643                 operand.fIsConstant = SkScriptValue2::kVariable;
    644                 fValueStack.push(operand);
    645                 continue;
    646             }
    647             if (handleArrayIndexer(&script) == false)
    648                 return false;
    649             lastPush = true;
    650             continue;
    651         }
    652 #if 0 // structs not supported for now
    653         if (ch == '{') {
    654             if (lastPush == false) {
    655                 script++;
    656                 *fBraceStack.push() = kStructBrace;
    657                 operand.fS32 = 0;
    658                 *fTypeStack.push() = (SkOpType) kStruct;
    659                 fOperandStack.push(operand);
    660                 continue;
    661             }
    662             SkASSERT(0); // braces in other contexts aren't supported yet
    663         }
    664 #endif
    665         if (ch == ')' && fBraceStack.count() > 0) {
    666             BraceStyle braceStyle = fBraceStack.top();
    667             if (braceStyle == kFunctionBrace) {
    668                 fBraceStack.pop();
    669                 break;
    670             }
    671         }
    672         if (ch == ',' || ch == ']') {
    673             if (ch != ',') {
    674                 BraceStyle match;
    675                 fBraceStack.pop(&match);
    676                 SkASSERT(match == kArrayBrace);
    677             }
    678             script++;
    679             // !!! see if brace or bracket is correct closer
    680             break;
    681         }
    682         char nextChar = script[1];
    683         int advance = logicalOp(ch, nextChar);
    684         if (advance == 0)
    685             advance = arithmeticOp(ch, nextChar, lastPush);
    686         if (advance == 0) // unknown token
    687             return false;
    688         if (advance > 0)
    689             script += advance;
    690         lastPush = ch == ']' || ch == ')';
    691     }
    692     if (fTokenLength > 0) {
    693         success = handleProperty();
    694         SkASSERT(success);
    695     }
    696     int branchIndex = 0;
    697     branchBalance = fBranchStack.count() - branchBalance;
    698     fBranchPopAllowed = false;
    699     while (branchIndex < branchBalance) {
    700         Branch& branch = fBranchStack.index(branchIndex++);
    701         if (branch.fPrimed == Branch::kIsPrimed)
    702             break;
    703         Op branchOp = branch.fOperator;
    704         SkOperand2::OpType lastType = fValueStack.top().fType;
    705         addTokenValue(fValueStack.top(), kAccumulator);
    706         fValueStack.pop();
    707         if (branchOp == kLogicalAnd || branchOp == kLogicalOr) {
    708             if (branch.fOperator == kLogicalAnd)
    709                 branch.prime();
    710             addToken(kToBool);
    711         } else {
    712             resolveBranch(branch);
    713             SkScriptValue2 operand;
    714             operand.fType = lastType;
    715             // !!! note that many branching expressions could be constant
    716             // today, we always evaluate branches as returning variables
    717             operand.fIsConstant = SkScriptValue2::kVariable;
    718             fValueStack.push(operand);
    719         }
    720         if (branch.fDone == Branch::kIsNotDone)
    721             branch.prime();
    722     }
    723     fBranchPopAllowed = true;
    724     while (fBranchStack.top().fDone == Branch::kIsDone)
    725         fBranchStack.pop();
    726     while (fOpStack.count() > opBalance) {     // leave open paren
    727         if (processOp() == false)
    728             return false;
    729     }
    730     SkOperand2::OpType topType = fValueStack.count() > 0 ? fValueStack.top().fType : SkOperand2::kNoType;
    731     if (topType != fReturnType &&
    732         topType == SkOperand2::kString && fReturnType != SkOperand2::kNoType) { // if result is a string, give handle property a chance to convert it to the property value
    733         SkString* string = fValueStack.top().fOperand.fString;
    734         fToken = string->c_str();
    735         fTokenLength = string->size();
    736         fValueStack.pop();
    737         success = handleProperty();
    738         if (success == false) {    // if it couldn't convert, return string (error?)
    739             SkScriptValue2 operand;
    740             operand.fType = SkOperand2::kString;
    741             operand.fOperand.fString = string;
    742             operand.fIsConstant = SkScriptValue2::kVariable;     // !!! ?
    743             fValueStack.push(operand);
    744         }
    745     }
    746     if (fStream.getOffset() > 0) {
    747         addToken(kEnd);
    748         SkAutoDataUnref data(fStream.copyToData());
    749 #ifdef SK_DEBUG
    750         decompile(data.bytes(), data.size());
    751 #endif
    752         SkScriptRuntime runtime(fCallBackArray);
    753         runtime.executeTokens((unsigned char*) data.bytes());
    754         SkScriptValue2 value1;
    755         runtime.getResult(&value1.fOperand);
    756         value1.fType = fReturnType;
    757         fValueStack.push(value1);
    758     }
    759     if (value) {
    760         if (fValueStack.count() == 0)
    761             return false;
    762         fValueStack.pop(value);
    763         if (value->fType != fReturnType && value->fType == SkOperand2::kObject &&
    764             fReturnType != SkOperand2::kNoType)
    765             convertTo(fReturnType, value);
    766     }
    767     //    if (fBranchStack.top().fOpStackDepth > fOpStack.count())
    768     //        resolveBranch();
    769     *scriptPtr = script;
    770     return true; // no error
    771 }
    772 
    773 bool SkScriptEngine2::handleArrayIndexer(const char** scriptPtr) {
    774     SkScriptValue2 scriptValue;
    775     (*scriptPtr)++;
    776     *fOpStack.push() = (Op) kParen;
    777     *fBraceStack.push() = kArrayBrace;
    778     SkOperand2::OpType saveType = fReturnType;
    779     fReturnType = SkOperand2::kS32;
    780     bool success = innerScript(scriptPtr, &scriptValue);
    781     fReturnType = saveType;
    782     SkASSERT(success);
    783     success = convertTo(SkOperand2::kS32, &scriptValue);
    784     SkASSERT(success);
    785     int index = scriptValue.fOperand.fS32;
    786     fValueStack.pop(&scriptValue);
    787     if (scriptValue.fType == SkOperand2::kObject) {
    788         success = handleUnbox(&scriptValue);
    789         SkASSERT(success);
    790         SkASSERT(scriptValue.fType == SkOperand2::kArray);
    791     }
    792     scriptValue.fType = scriptValue.fOperand.fArray->getType();
    793     //    SkASSERT(index >= 0);
    794     if ((unsigned) index >= (unsigned) scriptValue.fOperand.fArray->count()) {
    795         fError = kArrayIndexOutOfBounds;
    796         return false;
    797     }
    798     scriptValue.fOperand = scriptValue.fOperand.fArray->begin()[index];
    799     scriptValue.fIsConstant = SkScriptValue2::kVariable;
    800     fValueStack.push(scriptValue);
    801     fOpStack.pop(); // pop paren
    802     return success;
    803 }
    804 
    805 bool SkScriptEngine2::handleFunction(const char** scriptPtr) {
    806     const char* functionName = fToken;
    807     size_t functionNameLen = fTokenLength;
    808     fTokenLength = 0;
    809     SkTDArray<SkScriptValue2> params;
    810     bool success = functionParams(scriptPtr, &params);
    811     if (success == false)
    812         goto done;
    813     {
    814         for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
    815             if ((*callBack)->getType() != SkScriptCallBack::kFunction)
    816                 continue;
    817             SkScriptValue2 callbackResult;
    818             success = (*callBack)->getReference(functionName, functionNameLen, &callbackResult);
    819             if (success) {
    820                 callbackResult.fType = (*callBack)->getReturnType(callbackResult.fOperand.fReference, NULL);
    821                 callbackResult.fIsConstant = SkScriptValue2::kVariable;
    822                 fValueStack.push(callbackResult);
    823                 goto done;
    824             }
    825         }
    826     }
    827     return false;
    828 done:
    829         fOpStack.pop();
    830     return success;
    831 }
    832 
    833 bool SkScriptEngine2::handleMember(const char* field, size_t len, void* object) {
    834     bool success = true;
    835     for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
    836         if ((*callBack)->getType() != SkScriptCallBack::kMember)
    837             continue;
    838         SkScriptValue2 callbackResult;
    839         success = (*callBack)->getReference(field, len, &callbackResult);
    840         if (success) {
    841             if (callbackResult.fType == SkOperand2::kString)
    842                 track(callbackResult.fOperand.fString);
    843             callbackResult.fIsConstant = SkScriptValue2::kVariable;
    844             fValueStack.push(callbackResult);
    845             goto done;
    846         }
    847     }
    848     return false;
    849 done:
    850         return success;
    851 }
    852 
    853 bool SkScriptEngine2::handleMemberFunction(const char* field, size_t len, void* object,
    854                                            SkTDArray<SkScriptValue2>* params) {
    855     bool success = true;
    856     for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
    857         if ((*callBack)->getType() != SkScriptCallBack::kMemberFunction)
    858             continue;
    859         SkScriptValue2 callbackResult;
    860         success = (*callBack)->getReference(field, len, &callbackResult);
    861         if (success) {
    862             if (callbackResult.fType == SkOperand2::kString)
    863                 track(callbackResult.fOperand.fString);
    864             callbackResult.fIsConstant = SkScriptValue2::kVariable;
    865             fValueStack.push(callbackResult);
    866             goto done;
    867         }
    868     }
    869     return false;
    870 done:
    871         return success;
    872 }
    873 
    874 bool SkScriptEngine2::handleProperty() {
    875     bool success = true;
    876     for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
    877         if ((*callBack)->getType() != SkScriptCallBack::kProperty)
    878             continue;
    879         SkScriptValue2 callbackResult;
    880         success = (*callBack)->getReference(fToken, fTokenLength, &callbackResult);
    881         if (success) {
    882             if (callbackResult.fType == SkOperand2::kString && callbackResult.fOperand.fString == NULL) {
    883                 callbackResult.fOperand.fString = new SkString(fToken, fTokenLength);
    884                 track(callbackResult.fOperand.fString);
    885             }
    886             callbackResult.fIsConstant = SkScriptValue2::kVariable;
    887             fValueStack.push(callbackResult);
    888             goto done;
    889         }
    890     }
    891 done:
    892         fTokenLength = 0;
    893     return success;
    894 }
    895 
    896 bool SkScriptEngine2::handleUnbox(SkScriptValue2* scriptValue) {
    897     bool success = true;
    898     for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
    899         if ((*callBack)->getType() != SkScriptCallBack::kUnbox)
    900             continue;
    901         SkScriptCallBackConvert* callBackConvert = (SkScriptCallBackConvert*) *callBack;
    902         success = callBackConvert->convert(scriptValue->fType, &scriptValue->fOperand);
    903         if (success) {
    904             if (scriptValue->fType == SkOperand2::kString)
    905                 track(scriptValue->fOperand.fString);
    906             goto done;
    907         }
    908     }
    909     return false;
    910 done:
    911         return success;
    912 }
    913 
    914 // note that entire expression is treated as if it were enclosed in parens
    915 // an open paren is always the first thing in the op stack
    916 
    917 int SkScriptEngine2::logicalOp(char ch, char nextChar) {
    918     int advance = 1;
    919     Op op;
    920     signed char precedence;
    921     switch (ch) {
    922         case ')':
    923             op = (Op) kParen;
    924             break;
    925         case ']':
    926             op = (Op) kArrayOp;
    927             break;
    928         case '?':
    929             op = (Op) kIf;
    930             break;
    931         case ':':
    932             op = (Op) kElse;
    933             break;
    934         case '&':
    935             if (nextChar != '&')
    936                 goto noMatch;
    937             op = kLogicalAnd;
    938             advance = 2;
    939             break;
    940         case '|':
    941             if (nextChar != '|')
    942                 goto noMatch;
    943             op = kLogicalOr;
    944             advance = 2;
    945             break;
    946         default:
    947             noMatch:
    948             return 0;
    949     }
    950     precedence = gPrecedence[op];
    951     int branchIndex = 0;
    952     fBranchPopAllowed = false;
    953     do {
    954         while (gPrecedence[fOpStack.top() & ~kArtificialOp] < precedence)
    955             processOp();
    956         Branch& branch = fBranchStack.index(branchIndex++);
    957         Op branchOp = branch.fOperator;
    958         if (gPrecedence[branchOp] >= precedence)
    959             break;
    960         addTokenValue(fValueStack.top(), kAccumulator);
    961         fValueStack.pop();
    962         if (branchOp == kLogicalAnd || branchOp == kLogicalOr) {
    963             if (branch.fOperator == kLogicalAnd)
    964                 branch.prime();
    965             addToken(kToBool);
    966         } else
    967             resolveBranch(branch);
    968         if (branch.fDone == Branch::kIsNotDone)
    969             branch.prime();
    970     } while (true);
    971     fBranchPopAllowed = true;
    972     while (fBranchStack.top().fDone == Branch::kIsDone)
    973         fBranchStack.pop();
    974     processLogicalOp(op);
    975     return advance;
    976 }
    977 
    978 void SkScriptEngine2::processLogicalOp(Op op) {
    979     switch (op) {
    980         case kParen:
    981         case kArrayOp:
    982             SkASSERT(fOpStack.count() > 1 && fOpStack.top() == op);    // !!! add error handling
    983             if (op == kParen)
    984                 fOpStack.pop();
    985             else {
    986                 SkScriptValue2 value;
    987                 fValueStack.pop(&value);
    988                 SkASSERT(value.fType == SkOperand2::kS32 || value.fType == SkOperand2::kScalar); // !!! add error handling (although, could permit strings eventually)
    989                 int index = value.fType == SkOperand2::kScalar ? SkScalarFloor(value.fOperand.fScalar) :
    990                     value.fOperand.fS32;
    991                 SkScriptValue2 arrayValue;
    992                 fValueStack.pop(&arrayValue);
    993                 SkASSERT(arrayValue.fType == SkOperand2::kArray);  // !!! add error handling
    994                 SkOpArray* array = arrayValue.fOperand.fArray;
    995                 SkOperand2 operand;
    996                 bool success = array->getIndex(index, &operand);
    997                 SkASSERT(success); // !!! add error handling
    998                 SkScriptValue2 resultValue;
    999                 resultValue.fType = array->getType();
   1000                 resultValue.fOperand = operand;
   1001                 resultValue.fIsConstant = SkScriptValue2::kVariable;
   1002                 fValueStack.push(resultValue);
   1003             }
   1004                 break;
   1005         case kIf: {
   1006             if (fAccumulatorType == SkOperand2::kNoType) {
   1007                 addTokenValue(fValueStack.top(), kAccumulator);
   1008                 fValueStack.pop();
   1009             }
   1010             SkASSERT(fAccumulatorType != SkOperand2::kString); // !!! add error handling
   1011             addToken(kIfOp);
   1012             Branch branch(op, fOpStack.count(), getTokenOffset());
   1013             *fBranchStack.push() = branch;
   1014             addTokenInt(0); // placeholder for future branch
   1015             fAccumulatorType = SkOperand2::kNoType;
   1016         } break;
   1017         case kElse: {
   1018             addTokenValue(fValueStack.top(), kAccumulator);
   1019             fValueStack.pop();
   1020             addToken(kElseOp);
   1021             size_t newOffset = getTokenOffset();
   1022             addTokenInt(0); // placeholder for future branch
   1023             Branch& branch = fBranchStack.top();
   1024             resolveBranch(branch);
   1025             branch.fOperator = op;
   1026             branch.fDone = Branch::kIsNotDone;
   1027             SkASSERT(branch.fOpStackDepth == fOpStack.count());
   1028             branch.fOffset = newOffset;
   1029             fAccumulatorType = SkOperand2::kNoType;
   1030         } break;
   1031         case kLogicalAnd:
   1032         case kLogicalOr: {
   1033             Branch& oldTop = fBranchStack.top();
   1034             Branch::Primed wasPrime = oldTop.fPrimed;
   1035             Branch::Done wasDone = oldTop.fDone;
   1036             oldTop.fPrimed = Branch::kIsNotPrimed;
   1037             oldTop.fDone = Branch::kIsNotDone;
   1038             if (fAccumulatorType == SkOperand2::kNoType) {
   1039                 SkASSERT(fValueStack.top().fType == SkOperand2::kS32); // !!! add error handling, and conversion to int?
   1040                 addTokenValue(fValueStack.top(), kAccumulator);
   1041                 fValueStack.pop();
   1042             } else {
   1043                 SkASSERT(fAccumulatorType == SkOperand2::kS32);
   1044             }
   1045             // if 'and', write beq goto opcode after end of predicate (after to bool)
   1046             // if 'or', write bne goto to bool
   1047             addToken(op == kLogicalAnd ? kLogicalAndInt : kLogicalOrInt);
   1048             Branch branch(op, fOpStack.count(), getTokenOffset());
   1049             addTokenInt(0); // placeholder for future branch
   1050             oldTop.fPrimed = wasPrime;
   1051             oldTop.fDone = wasDone;
   1052             *fBranchStack.push() = branch;
   1053             fAccumulatorType = SkOperand2::kNoType;
   1054         }    break;
   1055         default:
   1056             SkASSERT(0);
   1057     }
   1058 }
   1059 
   1060 bool SkScriptEngine2::processOp() {
   1061     Op op;
   1062     fOpStack.pop(&op);
   1063     op = (Op) (op & ~kArtificialOp);
   1064     const OperatorAttributes* attributes = &gOpAttributes[op];
   1065     SkScriptValue2 value1;
   1066     memset(&value1, 0, sizeof(SkScriptValue2));
   1067     SkScriptValue2 value2;
   1068     fValueStack.pop(&value2);
   1069     value2.fIsWritten = SkScriptValue2::kUnwritten;
   1070     //    SkScriptEngine2::SkTypeOp convert1[3];
   1071     //    SkScriptEngine2::SkTypeOp convert2[3];
   1072     //    SkScriptEngine2::SkTypeOp* convert2Ptr = convert2;
   1073     bool constantOperands = value2.fIsConstant == SkScriptValue2::kConstant;
   1074     if (attributes->fLeftType != SkOperand2::kNoType) {
   1075         fValueStack.pop(&value1);
   1076         constantOperands &= value1.fIsConstant == SkScriptValue2::kConstant;
   1077         value1.fIsWritten = SkScriptValue2::kUnwritten;
   1078         if (op == kFlipOps) {
   1079             SkTSwap(value1, value2);
   1080             fOpStack.pop(&op);
   1081             op = (Op) (op & ~kArtificialOp);
   1082             attributes = &gOpAttributes[op];
   1083             if (constantOperands == false)
   1084                 addToken(kFlipOpsOp);
   1085         }
   1086         if (value1.fType == SkOperand2::kObject && (value1.fType & attributes->fLeftType) == 0) {
   1087             value1.fType = getUnboxType(value1.fOperand);
   1088             addToken(kUnboxToken);
   1089         }
   1090     }
   1091     if (value2.fType == SkOperand2::kObject && (value2.fType & attributes->fLeftType) == 0) {
   1092         value1.fType = getUnboxType(value2.fOperand);
   1093         addToken(kUnboxToken2);
   1094     }
   1095     if (attributes->fLeftType != SkOperand2::kNoType) {
   1096         if (value1.fType != value2.fType) {
   1097             if ((attributes->fLeftType & SkOperand2::kString) && attributes->fBias & kTowardsString &&
   1098                 ((value1.fType | value2.fType) & SkOperand2::kString)) {
   1099                 if (value1.fType == SkOperand2::kS32 || value1.fType == SkOperand2::kScalar) {
   1100                     addTokenConst(&value1, kAccumulator, SkOperand2::kString,
   1101                                   value1.fType == SkOperand2::kS32 ? kIntToString : kScalarToString);
   1102                 }
   1103                 if (value2.fType == SkOperand2::kS32 || value2.fType == SkOperand2::kScalar) {
   1104                     addTokenConst(&value2, kOperand, SkOperand2::kString,
   1105                                   value2.fType == SkOperand2::kS32 ? kIntToString2 : kScalarToString2);
   1106                 }
   1107             } else if (attributes->fLeftType & SkOperand2::kScalar && ((value1.fType | value2.fType) &
   1108                                                                        SkOperand2::kScalar)) {
   1109                 if (value1.fType == SkOperand2::kS32)
   1110                     addTokenConst(&value1, kAccumulator, SkOperand2::kScalar, kIntToScalar);
   1111                 if (value2.fType == SkOperand2::kS32)
   1112                     addTokenConst(&value2, kOperand, SkOperand2::kScalar, kIntToScalar2);
   1113             }
   1114         }
   1115         if ((value1.fType & attributes->fLeftType) == 0 || value1.fType != value2.fType) {
   1116             if (value1.fType == SkOperand2::kString)
   1117                 addTokenConst(&value1, kAccumulator, SkOperand2::kScalar, kStringToScalar);
   1118             if (value1.fType == SkOperand2::kScalar && (attributes->fLeftType == SkOperand2::kS32 ||
   1119                                                         value2.fType == SkOperand2::kS32))
   1120                 addTokenConst(&value1, kAccumulator, SkOperand2::kS32, kScalarToInt);
   1121         }
   1122     }
   1123     AddTokenRegister rhRegister = attributes->fLeftType != SkOperand2::kNoType ?
   1124         kOperand : kAccumulator;
   1125     if ((value2.fType & attributes->fRightType) == 0 || value1.fType != value2.fType) {
   1126         if (value2.fType == SkOperand2::kString)
   1127             addTokenConst(&value2, rhRegister, SkOperand2::kScalar, kStringToScalar2);
   1128         if (value2.fType == SkOperand2::kScalar && (attributes->fRightType == SkOperand2::kS32 ||
   1129                                                     value1.fType == SkOperand2::kS32))
   1130             addTokenConst(&value2, rhRegister, SkOperand2::kS32, kScalarToInt2);
   1131     }
   1132     TypeOp typeOp = gTokens[op];
   1133     if (value2.fType == SkOperand2::kScalar)
   1134         typeOp = (TypeOp) (typeOp + 1);
   1135     else if (value2.fType == SkOperand2::kString)
   1136         typeOp = (TypeOp) (typeOp + 2);
   1137     SkDynamicMemoryWStream stream;
   1138     SkOperand2::OpType saveType = SkOperand2::kNoType;
   1139     SkBool saveOperand = false;
   1140     if (constantOperands) {
   1141         fActiveStream = &stream;
   1142         saveType = fAccumulatorType;
   1143         saveOperand = fOperandInUse;
   1144         fAccumulatorType = SkOperand2::kNoType;
   1145         fOperandInUse = false;
   1146     }
   1147     if (attributes->fLeftType != SkOperand2::kNoType) {    // two operands
   1148         if (value1.fIsWritten == SkScriptValue2::kUnwritten)
   1149             addTokenValue(value1, kAccumulator);
   1150     }
   1151     if (value2.fIsWritten == SkScriptValue2::kUnwritten)
   1152         addTokenValue(value2, rhRegister);
   1153     addToken(typeOp);
   1154     if (constantOperands) {
   1155         addToken(kEnd);
   1156         SkAutoDataUnref data(fStream.copyToData());
   1157 #ifdef SK_DEBUG
   1158         decompile(data.bytes(), data.size());
   1159 #endif
   1160         SkScriptRuntime runtime(fCallBackArray);
   1161         runtime.executeTokens((unsigned char*)data.bytes());
   1162         runtime.getResult(&value1.fOperand);
   1163         if (attributes->fResultIsBoolean == kResultIsBoolean)
   1164             value1.fType = SkOperand2::kS32;
   1165         else if (attributes->fLeftType == SkOperand2::kNoType) // unary operand
   1166             value1.fType = value2.fType;
   1167         fValueStack.push(value1);
   1168         if (value1.fType == SkOperand2::kString)
   1169             runtime.untrack(value1.fOperand.fString);
   1170         else if (value1.fType == SkOperand2::kArray)
   1171             runtime.untrack(value1.fOperand.fArray);
   1172         fActiveStream = &fStream;
   1173         fAccumulatorType = saveType;
   1174         fOperandInUse = saveOperand;
   1175         return true;
   1176     }
   1177     value2.fIsConstant = SkScriptValue2::kVariable;
   1178     fValueStack.push(value2);
   1179     return true;
   1180 }
   1181 
   1182 void SkScriptEngine2::Branch::resolve(SkDynamicMemoryWStream* stream, size_t off) {
   1183     SkASSERT(fDone == kIsNotDone);
   1184     fPrimed = kIsNotPrimed;
   1185     fDone = kIsDone;
   1186     SkASSERT(off > fOffset + sizeof(size_t));
   1187     size_t offset = off - fOffset - sizeof(offset);
   1188     stream->write(&offset, fOffset, sizeof(offset));
   1189 }
   1190 
   1191 void SkScriptEngine2::resolveBranch(SkScriptEngine2::Branch& branch) {
   1192     branch.resolve(fActiveStream, getTokenOffset());
   1193 }
   1194 
   1195 bool SkScriptEngine2::ConvertTo(SkScriptEngine2* engine, SkOperand2::OpType toType, SkScriptValue2* value ) {
   1196     SkASSERT(value);
   1197     SkOperand2::OpType type = value->fType;
   1198     if (type == toType)
   1199         return true;
   1200     SkOperand2& operand = value->fOperand;
   1201     bool success = true;
   1202     switch (toType) {
   1203         case SkOperand2::kS32:
   1204             if (type == SkOperand2::kScalar)
   1205                 operand.fS32 = SkScalarFloor(operand.fScalar);
   1206             else {
   1207                 SkASSERT(type == SkOperand2::kString);
   1208                 success = SkParse::FindS32(operand.fString->c_str(), &operand.fS32) != NULL;
   1209             }
   1210                 break;
   1211         case SkOperand2::kScalar:
   1212             if (type == SkOperand2::kS32)
   1213                 operand.fScalar = IntToScalar(operand.fS32);
   1214             else {
   1215                 SkASSERT(type == SkOperand2::kString);
   1216                 success = SkParse::FindScalar(operand.fString->c_str(), &operand.fScalar) != NULL;
   1217             }
   1218                 break;
   1219         case SkOperand2::kString: {
   1220             SkString* strPtr = new SkString();
   1221             SkASSERT(engine);
   1222             engine->track(strPtr);
   1223             if (type == SkOperand2::kS32)
   1224                 strPtr->appendS32(operand.fS32);
   1225             else {
   1226                 SkASSERT(type == SkOperand2::kScalar);
   1227                 strPtr->appendScalar(operand.fScalar);
   1228             }
   1229             operand.fString = strPtr;
   1230         } break;
   1231         case SkOperand2::kArray: {
   1232             SkOpArray* array = new SkOpArray(type);
   1233             *array->append() = operand;
   1234             engine->track(array);
   1235             operand.fArray = array;
   1236         } break;
   1237         default:
   1238             SkASSERT(0);
   1239     }
   1240     value->fType = toType;
   1241     return success;
   1242 }
   1243 
   1244 SkScalar SkScriptEngine2::IntToScalar(int32_t s32) {
   1245     SkScalar scalar;
   1246     if (s32 == (int32_t) SK_NaN32)
   1247         scalar = SK_ScalarNaN;
   1248     else if (SkAbs32(s32) == SK_MaxS32)
   1249         scalar = SkSign32(s32) * SK_ScalarMax;
   1250     else
   1251         scalar = SkIntToScalar(s32);
   1252     return scalar;
   1253 }
   1254 
   1255 bool SkScriptEngine2::ValueToString(const SkScriptValue2& value, SkString* string) {
   1256     switch (value.fType) {
   1257         case SkOperand2::kS32:
   1258             string->reset();
   1259             string->appendS32(value.fOperand.fS32);
   1260             break;
   1261         case SkOperand2::kScalar:
   1262             string->reset();
   1263             string->appendScalar(value.fOperand.fScalar);
   1264             break;
   1265         case SkOperand2::kString:
   1266             string->set(*value.fOperand.fString);
   1267             break;
   1268         default:
   1269             SkASSERT(0);
   1270             return false;
   1271     }
   1272     return true; // no error
   1273 }
   1274 
   1275 #ifdef SK_DEBUG
   1276 
   1277 #define testInt(expression) { #expression, SkOperand2::kS32, expression, 0, NULL }
   1278 #ifdef SK_SCALAR_IS_FLOAT
   1279 #define testScalar(expression) { #expression, SkOperand2::kScalar, 0, (float) expression, NULL }
   1280 #define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkOperand2::kScalar, 0, fmodf(exp1, exp2), NULL }
   1281 #else
   1282 #ifdef SK_CAN_USE_FLOAT
   1283 #define testScalar(expression) { #expression, SkOperand2::kScalar, 0, (int) ((expression) * 65536.0f), NULL }
   1284 #define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkOperand2::kScalar, 0, (int) (fmod(exp1, exp2)  * 65536.0f), NULL }
   1285 #endif
   1286 #endif
   1287 #define testTrue(expression) { #expression, SkOperand2::kS32, 1, 0, NULL }
   1288 #define testFalse(expression) { #expression, SkOperand2::kS32, 0, 0, NULL }
   1289 
   1290 static const SkScriptNAnswer2 scriptTests[]  = {
   1291     testInt(1||(0&&3)),
   1292 #ifdef SK_CAN_USE_FLOAT
   1293     testScalar(- -5.5- -1.5),
   1294     testScalar(1.0+5),
   1295 #endif
   1296     testInt((6+7)*8),
   1297     testInt(3*(4+5)),
   1298 #ifdef SK_CAN_USE_FLOAT
   1299     testScalar(1.0+2.0),
   1300     testScalar(3.0-1.0),
   1301     testScalar(6-1.0),
   1302     testScalar(2.5*6.),
   1303     testScalar(0.5*4),
   1304     testScalar(4.5/.5),
   1305     testScalar(9.5/19),
   1306     testRemainder(9.5, 0.5),
   1307     testRemainder(9.,2),
   1308     testRemainder(9,2.5),
   1309     testRemainder(-9,2.5),
   1310     testTrue(-9==-9.0),
   1311     testTrue(-9.==-4.0-5),
   1312     testTrue(-9.*1==-4-5),
   1313     testFalse(-9!=-9.0),
   1314     testFalse(-9.!=-4.0-5),
   1315     testFalse(-9.*1!=-4-5),
   1316 #endif
   1317     testInt(0x123),
   1318     testInt(0XABC),
   1319     testInt(0xdeadBEEF),
   1320     {    "'123'+\"456\"", SkOperand2::kString, 0, 0, "123456" },
   1321     {    "123+\"456\"", SkOperand2::kString, 0, 0, "123456" },
   1322     {    "'123'+456", SkOperand2::kString, 0, 0, "123456" },
   1323     {    "'123'|\"456\"", SkOperand2::kS32, 123|456, 0, NULL },
   1324     {    "123|\"456\"", SkOperand2::kS32, 123|456, 0, NULL },
   1325     {    "'123'|456", SkOperand2::kS32, 123|456, 0, NULL },
   1326     {    "'2'<11", SkOperand2::kS32, 1, 0, NULL },
   1327     {    "2<'11'", SkOperand2::kS32, 1, 0, NULL },
   1328     {    "'2'<'11'", SkOperand2::kS32, 0, 0, NULL },
   1329     testInt(123),
   1330     testInt(-345),
   1331     testInt(+678),
   1332     testInt(1+2+3),
   1333     testInt(3*4+5),
   1334     testInt(6+7*8),
   1335     testInt(-1-2-8/4),
   1336     testInt(-9%4),
   1337     testInt(9%-4),
   1338     testInt(-9%-4),
   1339     testInt(123|978),
   1340     testInt(123&978),
   1341     testInt(123^978),
   1342     testInt(2<<4),
   1343     testInt(99>>3),
   1344     testInt(~55),
   1345     testInt(~~55),
   1346     testInt(!55),
   1347     testInt(!!55),
   1348     // both int
   1349     testInt(2<2),
   1350     testInt(2<11),
   1351     testInt(20<11),
   1352     testInt(2<=2),
   1353     testInt(2<=11),
   1354     testInt(20<=11),
   1355     testInt(2>2),
   1356     testInt(2>11),
   1357     testInt(20>11),
   1358     testInt(2>=2),
   1359     testInt(2>=11),
   1360     testInt(20>=11),
   1361     testInt(2==2),
   1362     testInt(2==11),
   1363     testInt(20==11),
   1364     testInt(2!=2),
   1365     testInt(2!=11),
   1366     testInt(20!=11),
   1367 #ifdef SK_CAN_USE_FLOAT
   1368     // left int, right scalar
   1369     testInt(2<2.),
   1370     testInt(2<11.),
   1371     testInt(20<11.),
   1372     testInt(2<=2.),
   1373     testInt(2<=11.),
   1374     testInt(20<=11.),
   1375     testInt(2>2.),
   1376     testInt(2>11.),
   1377     testInt(20>11.),
   1378     testInt(2>=2.),
   1379     testInt(2>=11.),
   1380     testInt(20>=11.),
   1381     testInt(2==2.),
   1382     testInt(2==11.),
   1383     testInt(20==11.),
   1384     testInt(2!=2.),
   1385     testInt(2!=11.),
   1386     testInt(20!=11.),
   1387     // left scalar, right int
   1388     testInt(2.<2),
   1389     testInt(2.<11),
   1390     testInt(20.<11),
   1391     testInt(2.<=2),
   1392     testInt(2.<=11),
   1393     testInt(20.<=11),
   1394     testInt(2.>2),
   1395     testInt(2.>11),
   1396     testInt(20.>11),
   1397     testInt(2.>=2),
   1398     testInt(2.>=11),
   1399     testInt(20.>=11),
   1400     testInt(2.==2),
   1401     testInt(2.==11),
   1402     testInt(20.==11),
   1403     testInt(2.!=2),
   1404     testInt(2.!=11),
   1405     testInt(20.!=11),
   1406     // both scalar
   1407     testInt(2.<11.),
   1408     testInt(20.<11.),
   1409     testInt(2.<=2.),
   1410     testInt(2.<=11.),
   1411     testInt(20.<=11.),
   1412     testInt(2.>2.),
   1413     testInt(2.>11.),
   1414     testInt(20.>11.),
   1415     testInt(2.>=2.),
   1416     testInt(2.>=11.),
   1417     testInt(20.>=11.),
   1418     testInt(2.==2.),
   1419     testInt(2.==11.),
   1420     testInt(20.==11.),
   1421     testInt(2.!=2.),
   1422     testInt(2.!=11.),
   1423     testInt(20.!=11.),
   1424 #endif
   1425     // int, string (string is int)
   1426     testFalse(2<'2'),
   1427     testTrue(2<'11'),
   1428     testFalse(20<'11'),
   1429     testTrue(2<='2'),
   1430     testTrue(2<='11'),
   1431     testFalse(20<='11'),
   1432     testFalse(2>'2'),
   1433     testFalse(2>'11'),
   1434     testTrue(20>'11'),
   1435     testTrue(2>='2'),
   1436     testFalse(2>='11'),
   1437     testTrue(20>='11'),
   1438     testTrue(2=='2'),
   1439     testFalse(2=='11'),
   1440     testFalse(2!='2'),
   1441     testTrue(2!='11'),
   1442     // int, string (string is scalar)
   1443     testFalse(2<'2.'),
   1444     testTrue(2<'11.'),
   1445     testFalse(20<'11.'),
   1446     testTrue(2=='2.'),
   1447     testFalse(2=='11.'),
   1448 #ifdef SK_CAN_USE_FLOAT
   1449     // scalar, string
   1450     testFalse(2.<'2.'),
   1451     testTrue(2.<'11.'),
   1452     testFalse(20.<'11.'),
   1453     testTrue(2.=='2.'),
   1454     testFalse(2.=='11.'),
   1455     // string, int
   1456     testFalse('2'<2),
   1457     testTrue('2'<11),
   1458     testFalse('20'<11),
   1459     testTrue('2'==2),
   1460     testFalse('2'==11),
   1461     // string, scalar
   1462     testFalse('2'<2.),
   1463     testTrue('2'<11.),
   1464     testFalse('20'<11.),
   1465     testTrue('2'==2.),
   1466     testFalse('2'==11.),
   1467 #endif
   1468     // string, string
   1469     testFalse('2'<'2'),
   1470     testFalse('2'<'11'),
   1471     testFalse('20'<'11'),
   1472     testTrue('2'=='2'),
   1473     testFalse('2'=='11'),
   1474     // logic
   1475     testInt(1?2:3),
   1476     testInt(0?2:3),
   1477     testInt((1&&2)||3),
   1478     testInt((1&&0)||3),
   1479     testInt((1&&0)||0),
   1480     testInt(1||(0&&3)),
   1481     testInt(0||(0&&3)),
   1482     testInt(0||(1&&3)),
   1483     testInt(0&&1?2:3)
   1484 #ifdef SK_CAN_USE_FLOAT
   1485     , {    "123.5", SkOperand2::kScalar, 0, SkIntToScalar(123) + SK_Scalar1/2, NULL }
   1486 #endif
   1487 };
   1488 
   1489 #define SkScriptNAnswer_testCount    SK_ARRAY_COUNT(scriptTests)
   1490 
   1491 void SkScriptEngine2::UnitTest() {
   1492 #if defined(SK_SUPPORT_UNITTEST)
   1493     ValidateDecompileTable();
   1494     for (int index = 0; index < SkScriptNAnswer_testCount; index++) {
   1495         SkScriptEngine2 engine(scriptTests[index].fType);
   1496         SkScriptValue2 value;
   1497         const char* script = scriptTests[index].fScript;
   1498         const char* scriptPtr = script;
   1499         SkASSERT(engine.evaluateScript(&scriptPtr, &value) == true);
   1500         SkASSERT(value.fType == scriptTests[index].fType);
   1501         SkScalar error;
   1502         switch (value.fType) {
   1503             case SkOperand2::kS32:
   1504                 if (value.fOperand.fS32 != scriptTests[index].fIntAnswer)
   1505                     SkDEBUGF(("script '%s' == value %d != expected answer %d\n", script, value.fOperand.fS32, scriptTests[index].fIntAnswer));
   1506                 SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer);
   1507                 break;
   1508             case SkOperand2::kScalar:
   1509                 error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer);
   1510 #ifdef SK_CAN_USE_FLOAT
   1511                 if (error >= SK_Scalar1 / 10000)
   1512                     SkDEBUGF(("script '%s' == value %g != expected answer %g\n", script, value.fOperand.fScalar / (1.0f * SK_Scalar1), scriptTests[index].fScalarAnswer / (1.0f * SK_Scalar1)));
   1513 #endif
   1514                 SkASSERT(error < SK_Scalar1 / 10000);
   1515                 break;
   1516             case SkOperand2::kString:
   1517                 SkASSERT(value.fOperand.fString->equals(scriptTests[index].fStringAnswer));
   1518                 break;
   1519             default:
   1520                 SkASSERT(0);
   1521         }
   1522     }
   1523 #endif
   1524 }
   1525 #endif
   1526