• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
is_between(int c,int min,int max)100 static inline bool is_between(int c, int min, int max)
101 {
102     return (unsigned)(c - min) <= (unsigned)(max - min);
103 }
104 
is_ws(int c)105 static inline bool is_ws(int c)
106 {
107     return is_between(c, 1, 32);
108 }
109 
token_length(const char * start)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 
SkScriptEngine2(SkOperand2::OpType returnType)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 
~SkScriptEngine2()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 
addToken(SkScriptEngine2::TypeOp op)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 
addTokenConst(SkScriptValue2 * value,AddTokenRegister reg,SkOperand2::OpType toType,SkScriptEngine2::TypeOp op)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 
addTokenInt(int integer)164 void SkScriptEngine2::addTokenInt(int integer) {
165     fActiveStream->write(&integer, sizeof(integer));
166 }
167 
addTokenScalar(SkScalar scalar)168 void SkScriptEngine2::addTokenScalar(SkScalar scalar) {
169     fActiveStream->write(&scalar, sizeof(scalar));
170 }
171 
addTokenString(const SkString & string)172 void SkScriptEngine2::addTokenString(const SkString& string) {
173     int size = string.size();
174     addTokenInt(size);
175     fActiveStream->write(string.c_str(), size);
176 }
177 
addTokenValue(const SkScriptValue2 & value,AddTokenRegister reg)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 
arithmeticOp(char ch,char nextChar,bool lastPush)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 
convertParams(SkTDArray<SkScriptValue2> * params,const SkOperand2::OpType * paramTypes,int paramCount)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 
convertTo(SkOperand2::OpType toType,SkScriptValue2 * value)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 
evaluateDot(const char * & script)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 
evaluateDotParam(const char * & script,const char * field,size_t fieldLength)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 
evaluateScript(const char ** scriptPtr,SkScriptValue2 * value)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 
forget(SkOpArray * array)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 
functionParams(const char ** scriptPtr,SkTDArray<SkScriptValue2> * params)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 
getTokenOffset()459 size_t SkScriptEngine2::getTokenOffset() {
460     return fActiveStream->getOffset();
461 }
462 
getUnboxType(SkOperand2 scriptValue)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 
innerScript(const char ** scriptPtr,SkScriptValue2 * value)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 
handleArrayIndexer(const char ** scriptPtr)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 
handleFunction(const char ** scriptPtr)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 
handleMember(const char * field,size_t len,void * object)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 
handleMemberFunction(const char * field,size_t len,void * object,SkTDArray<SkScriptValue2> * params)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 
handleProperty()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 
handleUnbox(SkScriptValue2 * scriptValue)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 
logicalOp(char ch,char nextChar)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 
processLogicalOp(Op op)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 
processOp()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 
resolve(SkDynamicMemoryWStream * stream,size_t off)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 
resolveBranch(SkScriptEngine2::Branch & branch)1191 void SkScriptEngine2::resolveBranch(SkScriptEngine2::Branch& branch) {
1192     branch.resolve(fActiveStream, getTokenOffset());
1193 }
1194 
ConvertTo(SkScriptEngine2 * engine,SkOperand2::OpType toType,SkScriptValue2 * value)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 
IntToScalar(int32_t s32)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 
ValueToString(const SkScriptValue2 & value,SkString * string)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 
UnitTest()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