gfx/skia/trunk/src/animator/SkScriptTokenizer.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     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"
    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 };
    49 #define kBracketPrecedence 16
    50 #define kIfElsePrecedence 15
    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 };
    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 };
   100 static inline bool is_between(int c, int min, int max)
   101 {
   102     return (unsigned)(c - min) <= (unsigned)(max - min);
   103 }
   105 static inline bool is_ws(int c)
   106 {
   107     return is_between(c, 1, 32);
   108 }
   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 }
   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 }
   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 }
   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 }
   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 }
   164 void SkScriptEngine2::addTokenInt(int integer) {
   165     fActiveStream->write(&integer, sizeof(integer));
   166 }
   168 void SkScriptEngine2::addTokenScalar(SkScalar scalar) {
   169     fActiveStream->write(&scalar, sizeof(scalar));
   170 }
   172 void SkScriptEngine2::addTokenString(const SkString& string) {
   173     int size = string.size();
   174     addTokenInt(size);
   175     fActiveStream->write(string.c_str(), size);
   176 }
   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 }
   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);
   331     return advance;
   332 }
   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 }
   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 }
   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 }
   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 }
   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 }
   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 }
   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 }
   459 size_t SkScriptEngine2::getTokenOffset() {
   460     return fActiveStream->getOffset();
   461 }
   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 }
   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);
   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                 int tokenLength = token_length(++script);
   607                 const char* token = script;
   608                 script += tokenLength;
   609                 SkASSERT(fValueStack.count() > 0); // !!! add error handling
   610                 SkScriptValue2 top;
   611                 fValueStack.pop(&top);
   613                 addTokenInt(top.fType);
   614                 addToken(kBoxToken);
   615                 top.fType = SkOperand2::kObject;
   616                 top.fIsConstant = SkScriptValue2::kVariable;
   617                 fConstExpression = false;
   618                 fValueStack.push(top);
   619                 success = evaluateDotParam(script, token, tokenLength);
   620                 SkASSERT(success);
   621                 lastPush = true;
   622                 continue;
   623             }
   624             // get next token, and evaluate immediately
   625             success = evaluateDot(script);
   626             if (success == false) {
   627                 //                SkASSERT(0);
   628                 return false;
   629             }
   630             lastPush = true;
   631             continue;
   632         }
   633         if (ch == '[') {
   634             if (lastPush == false) {
   635                 script++;
   636                 *fBraceStack.push() = kArrayBrace;
   637                 operand.fOperand.fArray = value->fOperand.fArray = new SkOpArray(fReturnType);
   638                 track(value->fOperand.fArray);
   640                 operand.fType = SkOperand2::kArray;
   641                 operand.fIsConstant = SkScriptValue2::kVariable;
   642                 fValueStack.push(operand);
   643                 continue;
   644             }
   645             if (handleArrayIndexer(&script) == false)
   646                 return false;
   647             lastPush = true;
   648             continue;
   649         }
   650 #if 0 // structs not supported for now
   651         if (ch == '{') {
   652             if (lastPush == false) {
   653                 script++;
   654                 *fBraceStack.push() = kStructBrace;
   655                 operand.fS32 = 0;
   656                 *fTypeStack.push() = (SkOpType) kStruct;
   657                 fOperandStack.push(operand);
   658                 continue;
   659             }
   660             SkASSERT(0); // braces in other contexts aren't supported yet
   661         }
   662 #endif
   663         if (ch == ')' && fBraceStack.count() > 0) {
   664             BraceStyle braceStyle = fBraceStack.top();
   665             if (braceStyle == kFunctionBrace) {
   666                 fBraceStack.pop();
   667                 break;
   668             }
   669         }
   670         if (ch == ',' || ch == ']') {
   671             if (ch != ',') {
   672                 BraceStyle match;
   673                 fBraceStack.pop(&match);
   674                 SkASSERT(match == kArrayBrace);
   675             }
   676             script++;
   677             // !!! see if brace or bracket is correct closer
   678             break;
   679         }
   680         char nextChar = script[1];
   681         int advance = logicalOp(ch, nextChar);
   682         if (advance == 0)
   683             advance = arithmeticOp(ch, nextChar, lastPush);
   684         if (advance == 0) // unknown token
   685             return false;
   686         if (advance > 0)
   687             script += advance;
   688         lastPush = ch == ']' || ch == ')';
   689     }
   690     if (fTokenLength > 0) {
   691         success = handleProperty();
   692         SkASSERT(success);
   693     }
   694     int branchIndex = 0;
   695     branchBalance = fBranchStack.count() - branchBalance;
   696     fBranchPopAllowed = false;
   697     while (branchIndex < branchBalance) {
   698         Branch& branch = fBranchStack.index(branchIndex++);
   699         if (branch.fPrimed == Branch::kIsPrimed)
   700             break;
   701         Op branchOp = branch.fOperator;
   702         SkOperand2::OpType lastType = fValueStack.top().fType;
   703         addTokenValue(fValueStack.top(), kAccumulator);
   704         fValueStack.pop();
   705         if (branchOp == kLogicalAnd || branchOp == kLogicalOr) {
   706             if (branch.fOperator == kLogicalAnd)
   707                 branch.prime();
   708             addToken(kToBool);
   709         } else {
   710             resolveBranch(branch);
   711             SkScriptValue2 operand;
   712             operand.fType = lastType;
   713             // !!! note that many branching expressions could be constant
   714             // today, we always evaluate branches as returning variables
   715             operand.fIsConstant = SkScriptValue2::kVariable;
   716             fValueStack.push(operand);
   717         }
   718         if (branch.fDone == Branch::kIsNotDone)
   719             branch.prime();
   720     }
   721     fBranchPopAllowed = true;
   722     while (fBranchStack.top().fDone == Branch::kIsDone)
   723         fBranchStack.pop();
   724     while (fOpStack.count() > opBalance) {     // leave open paren
   725         if (processOp() == false)
   726             return false;
   727     }
   728     SkOperand2::OpType topType = fValueStack.count() > 0 ? fValueStack.top().fType : SkOperand2::kNoType;
   729     if (topType != fReturnType &&
   730         topType == SkOperand2::kString && fReturnType != SkOperand2::kNoType) { // if result is a string, give handle property a chance to convert it to the property value
   731         SkString* string = fValueStack.top().fOperand.fString;
   732         fToken = string->c_str();
   733         fTokenLength = string->size();
   734         fValueStack.pop();
   735         success = handleProperty();
   736         if (success == false) {    // if it couldn't convert, return string (error?)
   737             SkScriptValue2 operand;
   738             operand.fType = SkOperand2::kString;
   739             operand.fOperand.fString = string;
   740             operand.fIsConstant = SkScriptValue2::kVariable;     // !!! ?
   741             fValueStack.push(operand);
   742         }
   743     }
   744     if (fStream.getOffset() > 0) {
   745         addToken(kEnd);
   746         SkAutoDataUnref data(fStream.copyToData());
   747 #ifdef SK_DEBUG
   748         decompile(data->bytes(), data->size());
   749 #endif
   750         SkScriptRuntime runtime(fCallBackArray);
   751         runtime.executeTokens((unsigned char*) data->bytes());
   752         SkScriptValue2 value1;
   753         runtime.getResult(&value1.fOperand);
   754         value1.fType = fReturnType;
   755         fValueStack.push(value1);
   756     }
   757     if (value) {
   758         if (fValueStack.count() == 0)
   759             return false;
   760         fValueStack.pop(value);
   761         if (value->fType != fReturnType && value->fType == SkOperand2::kObject &&
   762             fReturnType != SkOperand2::kNoType)
   763             convertTo(fReturnType, value);
   764     }
   765     //    if (fBranchStack.top().fOpStackDepth > fOpStack.count())
   766     //        resolveBranch();
   767     *scriptPtr = script;
   768     return true; // no error
   769 }
   771 bool SkScriptEngine2::handleArrayIndexer(const char** scriptPtr) {
   772     SkScriptValue2 scriptValue;
   773     (*scriptPtr)++;
   774     *fOpStack.push() = (Op) kParen;
   775     *fBraceStack.push() = kArrayBrace;
   776     SkOperand2::OpType saveType = fReturnType;
   777     fReturnType = SkOperand2::kS32;
   778     bool success = innerScript(scriptPtr, &scriptValue);
   779     fReturnType = saveType;
   780     SkASSERT(success);
   781     success = convertTo(SkOperand2::kS32, &scriptValue);
   782     SkASSERT(success);
   783     int index = scriptValue.fOperand.fS32;
   784     fValueStack.pop(&scriptValue);
   785     if (scriptValue.fType == SkOperand2::kObject) {
   786         success = handleUnbox(&scriptValue);
   787         SkASSERT(success);
   788         SkASSERT(scriptValue.fType == SkOperand2::kArray);
   789     }
   790     scriptValue.fType = scriptValue.fOperand.fArray->getType();
   791     //    SkASSERT(index >= 0);
   792     if ((unsigned) index >= (unsigned) scriptValue.fOperand.fArray->count()) {
   793         fError = kArrayIndexOutOfBounds;
   794         return false;
   795     }
   796     scriptValue.fOperand = scriptValue.fOperand.fArray->begin()[index];
   797     scriptValue.fIsConstant = SkScriptValue2::kVariable;
   798     fValueStack.push(scriptValue);
   799     fOpStack.pop(); // pop paren
   800     return success;
   801 }
   803 bool SkScriptEngine2::handleFunction(const char** scriptPtr) {
   804     const char* functionName = fToken;
   805     size_t functionNameLen = fTokenLength;
   806     fTokenLength = 0;
   807     SkTDArray<SkScriptValue2> params;
   808     bool success = functionParams(scriptPtr, &params);
   809     if (success == false)
   810         goto done;
   811     {
   812         for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
   813             if ((*callBack)->getType() != SkScriptCallBack::kFunction)
   814                 continue;
   815             SkScriptValue2 callbackResult;
   816             success = (*callBack)->getReference(functionName, functionNameLen, &callbackResult);
   817             if (success) {
   818                 callbackResult.fType = (*callBack)->getReturnType(callbackResult.fOperand.fReference, NULL);
   819                 callbackResult.fIsConstant = SkScriptValue2::kVariable;
   820                 fValueStack.push(callbackResult);
   821                 goto done;
   822             }
   823         }
   824     }
   825     return false;
   826 done:
   827         fOpStack.pop();
   828     return success;
   829 }
   831 bool SkScriptEngine2::handleMember(const char* field, size_t len, void* object) {
   832     bool success = true;
   833     for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
   834         if ((*callBack)->getType() != SkScriptCallBack::kMember)
   835             continue;
   836         SkScriptValue2 callbackResult;
   837         success = (*callBack)->getReference(field, len, &callbackResult);
   838         if (success) {
   839             if (callbackResult.fType == SkOperand2::kString)
   840                 track(callbackResult.fOperand.fString);
   841             callbackResult.fIsConstant = SkScriptValue2::kVariable;
   842             fValueStack.push(callbackResult);
   843             goto done;
   844         }
   845     }
   846     return false;
   847 done:
   848         return success;
   849 }
   851 bool SkScriptEngine2::handleMemberFunction(const char* field, size_t len, void* object,
   852                                            SkTDArray<SkScriptValue2>* params) {
   853     bool success = true;
   854     for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
   855         if ((*callBack)->getType() != SkScriptCallBack::kMemberFunction)
   856             continue;
   857         SkScriptValue2 callbackResult;
   858         success = (*callBack)->getReference(field, len, &callbackResult);
   859         if (success) {
   860             if (callbackResult.fType == SkOperand2::kString)
   861                 track(callbackResult.fOperand.fString);
   862             callbackResult.fIsConstant = SkScriptValue2::kVariable;
   863             fValueStack.push(callbackResult);
   864             goto done;
   865         }
   866     }
   867     return false;
   868 done:
   869         return success;
   870 }
   872 bool SkScriptEngine2::handleProperty() {
   873     bool success = true;
   874     for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
   875         if ((*callBack)->getType() != SkScriptCallBack::kProperty)
   876             continue;
   877         SkScriptValue2 callbackResult;
   878         success = (*callBack)->getReference(fToken, fTokenLength, &callbackResult);
   879         if (success) {
   880             if (callbackResult.fType == SkOperand2::kString && callbackResult.fOperand.fString == NULL) {
   881                 callbackResult.fOperand.fString = new SkString(fToken, fTokenLength);
   882                 track(callbackResult.fOperand.fString);
   883             }
   884             callbackResult.fIsConstant = SkScriptValue2::kVariable;
   885             fValueStack.push(callbackResult);
   886             goto done;
   887         }
   888     }
   889 done:
   890         fTokenLength = 0;
   891     return success;
   892 }
   894 bool SkScriptEngine2::handleUnbox(SkScriptValue2* scriptValue) {
   895     bool success = true;
   896     for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallBackArray.end(); callBack++) {
   897         if ((*callBack)->getType() != SkScriptCallBack::kUnbox)
   898             continue;
   899         SkScriptCallBackConvert* callBackConvert = (SkScriptCallBackConvert*) *callBack;
   900         success = callBackConvert->convert(scriptValue->fType, &scriptValue->fOperand);
   901         if (success) {
   902             if (scriptValue->fType == SkOperand2::kString)
   903                 track(scriptValue->fOperand.fString);
   904             goto done;
   905         }
   906     }
   907     return false;
   908 done:
   909         return success;
   910 }
   912 // note that entire expression is treated as if it were enclosed in parens
   913 // an open paren is always the first thing in the op stack
   915 int SkScriptEngine2::logicalOp(char ch, char nextChar) {
   916     int advance = 1;
   917     Op op;
   918     signed char precedence;
   919     switch (ch) {
   920         case ')':
   921             op = (Op) kParen;
   922             break;
   923         case ']':
   924             op = (Op) kArrayOp;
   925             break;
   926         case '?':
   927             op = (Op) kIf;
   928             break;
   929         case ':':
   930             op = (Op) kElse;
   931             break;
   932         case '&':
   933             if (nextChar != '&')
   934                 goto noMatch;
   935             op = kLogicalAnd;
   936             advance = 2;
   937             break;
   938         case '|':
   939             if (nextChar != '|')
   940                 goto noMatch;
   941             op = kLogicalOr;
   942             advance = 2;
   943             break;
   944         default:
   945             noMatch:
   946             return 0;
   947     }
   948     precedence = gPrecedence[op];
   949     int branchIndex = 0;
   950     fBranchPopAllowed = false;
   951     do {
   952         while (gPrecedence[fOpStack.top() & ~kArtificialOp] < precedence)
   953             processOp();
   954         Branch& branch = fBranchStack.index(branchIndex++);
   955         Op branchOp = branch.fOperator;
   956         if (gPrecedence[branchOp] >= precedence)
   957             break;
   958         addTokenValue(fValueStack.top(), kAccumulator);
   959         fValueStack.pop();
   960         if (branchOp == kLogicalAnd || branchOp == kLogicalOr) {
   961             if (branch.fOperator == kLogicalAnd)
   962                 branch.prime();
   963             addToken(kToBool);
   964         } else
   965             resolveBranch(branch);
   966         if (branch.fDone == Branch::kIsNotDone)
   967             branch.prime();
   968     } while (true);
   969     fBranchPopAllowed = true;
   970     while (fBranchStack.top().fDone == Branch::kIsDone)
   971         fBranchStack.pop();
   972     processLogicalOp(op);
   973     return advance;
   974 }
   976 void SkScriptEngine2::processLogicalOp(Op op) {
   977     switch (op) {
   978         case kParen:
   979         case kArrayOp:
   980             SkASSERT(fOpStack.count() > 1 && fOpStack.top() == op);    // !!! add error handling
   981             if (op == kParen)
   982                 fOpStack.pop();
   983             else {
   984                 SkScriptValue2 value;
   985                 fValueStack.pop(&value);
   986                 SkASSERT(value.fType == SkOperand2::kS32 || value.fType == SkOperand2::kScalar); // !!! add error handling (although, could permit strings eventually)
   987                 int index = value.fType == SkOperand2::kScalar ? SkScalarFloorToInt(value.fOperand.fScalar) :
   988                     value.fOperand.fS32;
   989                 SkScriptValue2 arrayValue;
   990                 fValueStack.pop(&arrayValue);
   991                 SkASSERT(arrayValue.fType == SkOperand2::kArray);  // !!! add error handling
   992                 SkOpArray* array = arrayValue.fOperand.fArray;
   993                 SkOperand2 operand;
   994                 SkDEBUGCODE(bool success = ) array->getIndex(index, &operand);
   995                 SkASSERT(success); // !!! add error handling
   996                 SkScriptValue2 resultValue;
   997                 resultValue.fType = array->getType();
   998                 resultValue.fOperand = operand;
   999                 resultValue.fIsConstant = SkScriptValue2::kVariable;
  1000                 fValueStack.push(resultValue);
  1002                 break;
  1003         case kIf: {
  1004             if (fAccumulatorType == SkOperand2::kNoType) {
  1005                 addTokenValue(fValueStack.top(), kAccumulator);
  1006                 fValueStack.pop();
  1008             SkASSERT(fAccumulatorType != SkOperand2::kString); // !!! add error handling
  1009             addToken(kIfOp);
  1010             Branch branch(op, fOpStack.count(), getTokenOffset());
  1011             *fBranchStack.push() = branch;
  1012             addTokenInt(0); // placeholder for future branch
  1013             fAccumulatorType = SkOperand2::kNoType;
  1014         } break;
  1015         case kElse: {
  1016             addTokenValue(fValueStack.top(), kAccumulator);
  1017             fValueStack.pop();
  1018             addToken(kElseOp);
  1019             size_t newOffset = getTokenOffset();
  1020             addTokenInt(0); // placeholder for future branch
  1021             Branch& branch = fBranchStack.top();
  1022             resolveBranch(branch);
  1023             branch.fOperator = op;
  1024             branch.fDone = Branch::kIsNotDone;
  1025             SkASSERT(branch.fOpStackDepth == fOpStack.count());
  1026             branch.fOffset = newOffset;
  1027             fAccumulatorType = SkOperand2::kNoType;
  1028         } break;
  1029         case kLogicalAnd:
  1030         case kLogicalOr: {
  1031             Branch& oldTop = fBranchStack.top();
  1032             Branch::Primed wasPrime = oldTop.fPrimed;
  1033             Branch::Done wasDone = oldTop.fDone;
  1034             oldTop.fPrimed = Branch::kIsNotPrimed;
  1035             oldTop.fDone = Branch::kIsNotDone;
  1036             if (fAccumulatorType == SkOperand2::kNoType) {
  1037                 SkASSERT(fValueStack.top().fType == SkOperand2::kS32); // !!! add error handling, and conversion to int?
  1038                 addTokenValue(fValueStack.top(), kAccumulator);
  1039                 fValueStack.pop();
  1040             } else {
  1041                 SkASSERT(fAccumulatorType == SkOperand2::kS32);
  1043             // if 'and', write beq goto opcode after end of predicate (after to bool)
  1044             // if 'or', write bne goto to bool
  1045             addToken(op == kLogicalAnd ? kLogicalAndInt : kLogicalOrInt);
  1046             Branch branch(op, fOpStack.count(), getTokenOffset());
  1047             addTokenInt(0); // placeholder for future branch
  1048             oldTop.fPrimed = wasPrime;
  1049             oldTop.fDone = wasDone;
  1050             *fBranchStack.push() = branch;
  1051             fAccumulatorType = SkOperand2::kNoType;
  1052         }    break;
  1053         default:
  1054             SkASSERT(0);
  1058 bool SkScriptEngine2::processOp() {
  1059     Op op;
  1060     fOpStack.pop(&op);
  1061     op = (Op) (op & ~kArtificialOp);
  1062     const OperatorAttributes* attributes = &gOpAttributes[op];
  1063     SkScriptValue2 value1;
  1064     memset(&value1, 0, sizeof(SkScriptValue2));
  1065     SkScriptValue2 value2;
  1066     fValueStack.pop(&value2);
  1067     value2.fIsWritten = SkScriptValue2::kUnwritten;
  1068     //    SkScriptEngine2::SkTypeOp convert1[3];
  1069     //    SkScriptEngine2::SkTypeOp convert2[3];
  1070     //    SkScriptEngine2::SkTypeOp* convert2Ptr = convert2;
  1071     bool constantOperands = value2.fIsConstant == SkScriptValue2::kConstant;
  1072     if (attributes->fLeftType != SkOperand2::kNoType) {
  1073         fValueStack.pop(&value1);
  1074         constantOperands &= value1.fIsConstant == SkScriptValue2::kConstant;
  1075         value1.fIsWritten = SkScriptValue2::kUnwritten;
  1076         if (op == kFlipOps) {
  1077             SkTSwap(value1, value2);
  1078             fOpStack.pop(&op);
  1079             op = (Op) (op & ~kArtificialOp);
  1080             attributes = &gOpAttributes[op];
  1081             if (constantOperands == false)
  1082                 addToken(kFlipOpsOp);
  1084         if (value1.fType == SkOperand2::kObject && (value1.fType & attributes->fLeftType) == 0) {
  1085             value1.fType = getUnboxType(value1.fOperand);
  1086             addToken(kUnboxToken);
  1089     if (value2.fType == SkOperand2::kObject && (value2.fType & attributes->fLeftType) == 0) {
  1090         value1.fType = getUnboxType(value2.fOperand);
  1091         addToken(kUnboxToken2);
  1093     if (attributes->fLeftType != SkOperand2::kNoType) {
  1094         if (value1.fType != value2.fType) {
  1095             if ((attributes->fLeftType & SkOperand2::kString) && attributes->fBias & kTowardsString &&
  1096                 ((value1.fType | value2.fType) & SkOperand2::kString)) {
  1097                 if (value1.fType == SkOperand2::kS32 || value1.fType == SkOperand2::kScalar) {
  1098                     addTokenConst(&value1, kAccumulator, SkOperand2::kString,
  1099                                   value1.fType == SkOperand2::kS32 ? kIntToString : kScalarToString);
  1101                 if (value2.fType == SkOperand2::kS32 || value2.fType == SkOperand2::kScalar) {
  1102                     addTokenConst(&value2, kOperand, SkOperand2::kString,
  1103                                   value2.fType == SkOperand2::kS32 ? kIntToString2 : kScalarToString2);
  1105             } else if (attributes->fLeftType & SkOperand2::kScalar && ((value1.fType | value2.fType) &
  1106                                                                        SkOperand2::kScalar)) {
  1107                 if (value1.fType == SkOperand2::kS32)
  1108                     addTokenConst(&value1, kAccumulator, SkOperand2::kScalar, kIntToScalar);
  1109                 if (value2.fType == SkOperand2::kS32)
  1110                     addTokenConst(&value2, kOperand, SkOperand2::kScalar, kIntToScalar2);
  1113         if ((value1.fType & attributes->fLeftType) == 0 || value1.fType != value2.fType) {
  1114             if (value1.fType == SkOperand2::kString)
  1115                 addTokenConst(&value1, kAccumulator, SkOperand2::kScalar, kStringToScalar);
  1116             if (value1.fType == SkOperand2::kScalar && (attributes->fLeftType == SkOperand2::kS32 ||
  1117                                                         value2.fType == SkOperand2::kS32))
  1118                 addTokenConst(&value1, kAccumulator, SkOperand2::kS32, kScalarToInt);
  1121     AddTokenRegister rhRegister = attributes->fLeftType != SkOperand2::kNoType ?
  1122         kOperand : kAccumulator;
  1123     if ((value2.fType & attributes->fRightType) == 0 || value1.fType != value2.fType) {
  1124         if (value2.fType == SkOperand2::kString)
  1125             addTokenConst(&value2, rhRegister, SkOperand2::kScalar, kStringToScalar2);
  1126         if (value2.fType == SkOperand2::kScalar && (attributes->fRightType == SkOperand2::kS32 ||
  1127                                                     value1.fType == SkOperand2::kS32))
  1128             addTokenConst(&value2, rhRegister, SkOperand2::kS32, kScalarToInt2);
  1130     TypeOp typeOp = gTokens[op];
  1131     if (value2.fType == SkOperand2::kScalar)
  1132         typeOp = (TypeOp) (typeOp + 1);
  1133     else if (value2.fType == SkOperand2::kString)
  1134         typeOp = (TypeOp) (typeOp + 2);
  1135     SkDynamicMemoryWStream stream;
  1136     SkOperand2::OpType saveType = SkOperand2::kNoType;
  1137     SkBool saveOperand = false;
  1138     if (constantOperands) {
  1139         fActiveStream = &stream;
  1140         saveType = fAccumulatorType;
  1141         saveOperand = fOperandInUse;
  1142         fAccumulatorType = SkOperand2::kNoType;
  1143         fOperandInUse = false;
  1145     if (attributes->fLeftType != SkOperand2::kNoType) {    // two operands
  1146         if (value1.fIsWritten == SkScriptValue2::kUnwritten)
  1147             addTokenValue(value1, kAccumulator);
  1149     if (value2.fIsWritten == SkScriptValue2::kUnwritten)
  1150         addTokenValue(value2, rhRegister);
  1151     addToken(typeOp);
  1152     if (constantOperands) {
  1153         addToken(kEnd);
  1154         SkAutoDataUnref data(fStream.copyToData());
  1155 #ifdef SK_DEBUG
  1156         decompile(data->bytes(), data->size());
  1157 #endif
  1158         SkScriptRuntime runtime(fCallBackArray);
  1159         runtime.executeTokens((unsigned char*)data->bytes());
  1160         runtime.getResult(&value1.fOperand);
  1161         if (attributes->fResultIsBoolean == kResultIsBoolean)
  1162             value1.fType = SkOperand2::kS32;
  1163         else if (attributes->fLeftType == SkOperand2::kNoType) // unary operand
  1164             value1.fType = value2.fType;
  1165         fValueStack.push(value1);
  1166         if (value1.fType == SkOperand2::kString)
  1167             runtime.untrack(value1.fOperand.fString);
  1168         else if (value1.fType == SkOperand2::kArray)
  1169             runtime.untrack(value1.fOperand.fArray);
  1170         fActiveStream = &fStream;
  1171         fAccumulatorType = saveType;
  1172         fOperandInUse = saveOperand;
  1173         return true;
  1175     value2.fIsConstant = SkScriptValue2::kVariable;
  1176     fValueStack.push(value2);
  1177     return true;
  1180 void SkScriptEngine2::Branch::resolve(SkDynamicMemoryWStream* stream, size_t off) {
  1181     SkASSERT(fDone == kIsNotDone);
  1182     fPrimed = kIsNotPrimed;
  1183     fDone = kIsDone;
  1184     SkASSERT(off > fOffset + sizeof(size_t));
  1185     size_t offset = off - fOffset - sizeof(offset);
  1186     stream->write(&offset, fOffset, sizeof(offset));
  1189 void SkScriptEngine2::resolveBranch(SkScriptEngine2::Branch& branch) {
  1190     branch.resolve(fActiveStream, getTokenOffset());
  1193 bool SkScriptEngine2::ConvertTo(SkScriptEngine2* engine, SkOperand2::OpType toType, SkScriptValue2* value ) {
  1194     SkASSERT(value);
  1195     SkOperand2::OpType type = value->fType;
  1196     if (type == toType)
  1197         return true;
  1198     SkOperand2& operand = value->fOperand;
  1199     bool success = true;
  1200     switch (toType) {
  1201         case SkOperand2::kS32:
  1202             if (type == SkOperand2::kScalar)
  1203                 operand.fS32 = SkScalarFloorToInt(operand.fScalar);
  1204             else {
  1205                 SkASSERT(type == SkOperand2::kString);
  1206                 success = SkParse::FindS32(operand.fString->c_str(), &operand.fS32) != NULL;
  1208                 break;
  1209         case SkOperand2::kScalar:
  1210             if (type == SkOperand2::kS32)
  1211                 operand.fScalar = IntToScalar(operand.fS32);
  1212             else {
  1213                 SkASSERT(type == SkOperand2::kString);
  1214                 success = SkParse::FindScalar(operand.fString->c_str(), &operand.fScalar) != NULL;
  1216                 break;
  1217         case SkOperand2::kString: {
  1218             SkString* strPtr = new SkString();
  1219             SkASSERT(engine);
  1220             engine->track(strPtr);
  1221             if (type == SkOperand2::kS32)
  1222                 strPtr->appendS32(operand.fS32);
  1223             else {
  1224                 SkASSERT(type == SkOperand2::kScalar);
  1225                 strPtr->appendScalar(operand.fScalar);
  1227             operand.fString = strPtr;
  1228         } break;
  1229         case SkOperand2::kArray: {
  1230             SkOpArray* array = new SkOpArray(type);
  1231             *array->append() = operand;
  1232             engine->track(array);
  1233             operand.fArray = array;
  1234         } break;
  1235         default:
  1236             SkASSERT(0);
  1238     value->fType = toType;
  1239     return success;
  1242 SkScalar SkScriptEngine2::IntToScalar(int32_t s32) {
  1243     SkScalar scalar;
  1244     if (s32 == (int32_t) SK_NaN32)
  1245         scalar = SK_ScalarNaN;
  1246     else if (SkAbs32(s32) == SK_MaxS32)
  1247         scalar = SkSign32(s32) * SK_ScalarMax;
  1248     else
  1249         scalar = SkIntToScalar(s32);
  1250     return scalar;
  1253 bool SkScriptEngine2::ValueToString(const SkScriptValue2& value, SkString* string) {
  1254     switch (value.fType) {
  1255         case SkOperand2::kS32:
  1256             string->reset();
  1257             string->appendS32(value.fOperand.fS32);
  1258             break;
  1259         case SkOperand2::kScalar:
  1260             string->reset();
  1261             string->appendScalar(value.fOperand.fScalar);
  1262             break;
  1263         case SkOperand2::kString:
  1264             string->set(*value.fOperand.fString);
  1265             break;
  1266         default:
  1267             SkASSERT(0);
  1268             return false;
  1270     return true; // no error
  1273 #ifdef SK_DEBUG
  1274 #if defined(SK_SUPPORT_UNITTEST)
  1276 #define testInt(expression) { #expression, SkOperand2::kS32, expression, 0, NULL }
  1277 #define testScalar(expression) { #expression, SkOperand2::kScalar, 0, (float) (expression), NULL }
  1278 #define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkOperand2::kScalar, 0, fmodf((float) exp1, (float) exp2), NULL }
  1279 #define testTrue(expression) { #expression, SkOperand2::kS32, 1, 0, NULL }
  1280 #define testFalse(expression) { #expression, SkOperand2::kS32, 0, 0, NULL }
  1282 static const SkScriptNAnswer2 scriptTests[]  = {
  1283     testInt(1||(0&&3)),
  1284     testScalar(- -5.5- -1.5),
  1285     testScalar(1.0+5),
  1286     testInt((6+7)*8),
  1287     testInt(3*(4+5)),
  1288     testScalar(1.0+2.0),
  1289     testScalar(3.0-1.0),
  1290     testScalar(6-1.0),
  1291     testScalar(2.5*6.),
  1292     testScalar(0.5*4),
  1293     testScalar(4.5/.5),
  1294     testScalar(9.5/19),
  1295     testRemainder(9.5, 0.5),
  1296     testRemainder(9.,2),
  1297     testRemainder(9,2.5),
  1298     testRemainder(-9,2.5),
  1299     testTrue(-9==-9.0),
  1300     testTrue(-9.==-4.0-5),
  1301     testTrue(-9.*1==-4-5),
  1302     testFalse(-9!=-9.0),
  1303     testFalse(-9.!=-4.0-5),
  1304     testFalse(-9.*1!=-4-5),
  1305     testInt(0x123),
  1306     testInt(0XABC),
  1307     testInt(0xdeadBEEF),
  1308     {    "'123'+\"456\"", SkOperand2::kString, 0, 0, "123456" },
  1309     {    "123+\"456\"", SkOperand2::kString, 0, 0, "123456" },
  1310     {    "'123'+456", SkOperand2::kString, 0, 0, "123456" },
  1311     {    "'123'|\"456\"", SkOperand2::kS32, 123|456, 0, NULL },
  1312     {    "123|\"456\"", SkOperand2::kS32, 123|456, 0, NULL },
  1313     {    "'123'|456", SkOperand2::kS32, 123|456, 0, NULL },
  1314     {    "'2'<11", SkOperand2::kS32, 1, 0, NULL },
  1315     {    "2<'11'", SkOperand2::kS32, 1, 0, NULL },
  1316     {    "'2'<'11'", SkOperand2::kS32, 0, 0, NULL },
  1317     testInt(123),
  1318     testInt(-345),
  1319     testInt(+678),
  1320     testInt(1+2+3),
  1321     testInt(3*4+5),
  1322     testInt(6+7*8),
  1323     testInt(-1-2-8/4),
  1324     testInt(-9%4),
  1325     testInt(9%-4),
  1326     testInt(-9%-4),
  1327     testInt(123|978),
  1328     testInt(123&978),
  1329     testInt(123^978),
  1330     testInt(2<<4),
  1331     testInt(99>>3),
  1332     testInt(~55),
  1333     testInt(~~55),
  1334     testInt(!55),
  1335     testInt(!!55),
  1336     // both int
  1337     testInt(2<2),
  1338     testInt(2<11),
  1339     testInt(20<11),
  1340     testInt(2<=2),
  1341     testInt(2<=11),
  1342     testInt(20<=11),
  1343     testInt(2>2),
  1344     testInt(2>11),
  1345     testInt(20>11),
  1346     testInt(2>=2),
  1347     testInt(2>=11),
  1348     testInt(20>=11),
  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     // left int, right scalar
  1356     testInt(2<2.),
  1357     testInt(2<11.),
  1358     testInt(20<11.),
  1359     testInt(2<=2.),
  1360     testInt(2<=11.),
  1361     testInt(20<=11.),
  1362     testInt(2>2.),
  1363     testInt(2>11.),
  1364     testInt(20>11.),
  1365     testInt(2>=2.),
  1366     testInt(2>=11.),
  1367     testInt(20>=11.),
  1368     testInt(2==2.),
  1369     testInt(2==11.),
  1370     testInt(20==11.),
  1371     testInt(2!=2.),
  1372     testInt(2!=11.),
  1373     testInt(20!=11.),
  1374     // left scalar, right int
  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     testInt(2.==2),
  1388     testInt(2.==11),
  1389     testInt(20.==11),
  1390     testInt(2.!=2),
  1391     testInt(2.!=11),
  1392     testInt(20.!=11),
  1393     // both scalar
  1394     testInt(2.<11.),
  1395     testInt(20.<11.),
  1396     testInt(2.<=2.),
  1397     testInt(2.<=11.),
  1398     testInt(20.<=11.),
  1399     testInt(2.>2.),
  1400     testInt(2.>11.),
  1401     testInt(20.>11.),
  1402     testInt(2.>=2.),
  1403     testInt(2.>=11.),
  1404     testInt(20.>=11.),
  1405     testInt(2.==2.),
  1406     testInt(2.==11.),
  1407     testInt(20.==11.),
  1408     testInt(2.!=2.),
  1409     testInt(2.!=11.),
  1410     testInt(20.!=11.),
  1411     // int, string (string is int)
  1412     testFalse(2<'2'),
  1413     testTrue(2<'11'),
  1414     testFalse(20<'11'),
  1415     testTrue(2<='2'),
  1416     testTrue(2<='11'),
  1417     testFalse(20<='11'),
  1418     testFalse(2>'2'),
  1419     testFalse(2>'11'),
  1420     testTrue(20>'11'),
  1421     testTrue(2>='2'),
  1422     testFalse(2>='11'),
  1423     testTrue(20>='11'),
  1424     testTrue(2=='2'),
  1425     testFalse(2=='11'),
  1426     testFalse(2!='2'),
  1427     testTrue(2!='11'),
  1428     // int, string (string is scalar)
  1429     testFalse(2<'2.'),
  1430     testTrue(2<'11.'),
  1431     testFalse(20<'11.'),
  1432     testTrue(2=='2.'),
  1433     testFalse(2=='11.'),
  1434     // scalar, string
  1435     testFalse(2.<'2.'),
  1436     testTrue(2.<'11.'),
  1437     testFalse(20.<'11.'),
  1438     testTrue(2.=='2.'),
  1439     testFalse(2.=='11.'),
  1440     // string, int
  1441     testFalse('2'<2),
  1442     testTrue('2'<11),
  1443     testFalse('20'<11),
  1444     testTrue('2'==2),
  1445     testFalse('2'==11),
  1446     // string, scalar
  1447     testFalse('2'<2.),
  1448     testTrue('2'<11.),
  1449     testFalse('20'<11.),
  1450     testTrue('2'==2.),
  1451     testFalse('2'==11.),
  1452     // string, string
  1453     testFalse('2'<'2'),
  1454     testFalse('2'<'11'),
  1455     testFalse('20'<'11'),
  1456     testTrue('2'=='2'),
  1457     testFalse('2'=='11'),
  1458     // logic
  1459     testInt(1?2:3),
  1460     testInt(0?2:3),
  1461     testInt((1&&2)||3),
  1462     testInt((1&&0)||3),
  1463     testInt((1&&0)||0),
  1464     testInt(1||(0&&3)),
  1465     testInt(0||(0&&3)),
  1466     testInt(0||(1&&3)),
  1467     testInt(0&&1?2:3)
  1468     , {    "123.5", SkOperand2::kScalar, 0, SkIntToScalar(123) + SK_Scalar1/2, NULL }
  1469 };
  1471 #define SkScriptNAnswer_testCount    SK_ARRAY_COUNT(scriptTests)
  1472 #endif  // SK_SUPPORT_UNITTEST
  1474 void SkScriptEngine2::UnitTest() {
  1475 #if defined(SK_SUPPORT_UNITTEST)
  1476     ValidateDecompileTable();
  1477     for (size_t index = 0; index < SkScriptNAnswer_testCount; index++) {
  1478         SkScriptEngine2 engine(scriptTests[index].fType);
  1479         SkScriptValue2 value;
  1480         const char* script = scriptTests[index].fScript;
  1481         const char* scriptPtr = script;
  1482         SkASSERT(engine.evaluateScript(&scriptPtr, &value) == true);
  1483         SkASSERT(value.fType == scriptTests[index].fType);
  1484         SkScalar error;
  1485         switch (value.fType) {
  1486             case SkOperand2::kS32:
  1487                 if (value.fOperand.fS32 != scriptTests[index].fIntAnswer)
  1488                     SkDEBUGF(("script '%s' == value %d != expected answer %d\n", script, value.fOperand.fS32, scriptTests[index].fIntAnswer));
  1489                 SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer);
  1490                 break;
  1491             case SkOperand2::kScalar:
  1492                 error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer);
  1493                 if (error >= SK_Scalar1 / 10000)
  1494                     SkDEBUGF(("script '%s' == value %g != expected answer %g\n", script, value.fOperand.fScalar / (1.0f * SK_Scalar1), scriptTests[index].fScalarAnswer / (1.0f * SK_Scalar1)));
  1495                 SkASSERT(error < SK_Scalar1 / 10000);
  1496                 break;
  1497             case SkOperand2::kString:
  1498                 SkASSERT(value.fOperand.fString->equals(scriptTests[index].fStringAnswer));
  1499                 break;
  1500             default:
  1501                 SkASSERT(0);
  1504 #endif  // SK_SUPPORT_UNITTEST
  1506 #endif  // SK_DEBUG

mercurial