1 
2 /*
3  * Copyright 2006 The Android Open Source Project
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 
9 
10 #include "SkScript.h"
11 #include "SkMath.h"
12 #include "SkParse.h"
13 #include "SkString.h"
14 #include "SkTypedArray.h"
15 
16 /* things to do
17     ? re-enable support for struct literals (e.g., for initializing points or rects)
18         {x:1, y:2}
19     ? use standard XML / script notation like document.getElementById("canvas");
20     finish support for typed arrays
21         ? allow indexing arrays by string
22             this could map to the 'name' attribute of a given child of an array
23         ? allow multiple types in the array
24     remove SkDisplayType.h  // from SkOperand.h
25     merge type and operand arrays into scriptvalue array
26 */
27 
28 #ifdef SK_DEBUG
29 static const char* errorStrings[] = {
30         "array index of out bounds", // kArrayIndexOutOfBounds
31         "could not find reference id", // kCouldNotFindReferencedID
32         "dot operator expects object", // kDotOperatorExpectsObject
33         "error in array index", // kErrorInArrrayIndex
34         "error in function parameters", // kErrorInFunctionParameters
35         "expected array", // kExpectedArray
36         "expected boolean expression", // kExpectedBooleanExpression
37         "expected field name", // kExpectedFieldName
38         "expected hex", // kExpectedHex
39         "expected int for condition operator", // kExpectedIntForConditionOperator
40         "expected number", // kExpectedNumber
41         "expected number for array index", // kExpectedNumberForArrayIndex
42         "expected operator", // kExpectedOperator
43         "expected token", // kExpectedToken
44         "expected token before dot operator", // kExpectedTokenBeforeDotOperator
45         "expected value", // kExpectedValue
46         "handle member failed", // kHandleMemberFailed
47         "handle member function failed", // kHandleMemberFunctionFailed
48         "handle unbox failed", // kHandleUnboxFailed
49         "index out of range", // kIndexOutOfRange
50         "mismatched array brace", // kMismatchedArrayBrace
51         "mismatched brackets", // kMismatchedBrackets
52         "no function handler found", // kNoFunctionHandlerFound
53         "premature end", // kPrematureEnd
54         "too many parameters", // kTooManyParameters
55         "type conversion failed", // kTypeConversionFailed
56         "unterminated string" // kUnterminatedString
57 };
58 #endif
59 
60 const SkScriptEngine::SkOperatorAttributes SkScriptEngine::gOpAttributes[] = {
61     { kNoType, kNoType, kNoBias }, //   kUnassigned,
62     { SkOpType(kInt | kScalar | kString), SkOpType(kInt | kScalar | kString), kTowardsString }, // kAdd
63     // kAddInt = kAdd,
64     { kNoType, kNoType, kNoBias },  // kAddScalar,
65     { kNoType, kNoType, kNoBias },  // kAddString,
66     { kNoType, kNoType, kNoBias },  // kArrayOp,
67     { kInt, kInt, kNoBias }, // kBitAnd
68     { kNoType, kInt, kNoBias }, // kBitNot
69     { kInt, kInt, kNoBias }, // kBitOr
70     { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kDivide
71     // kDivideInt = kDivide
72     { kNoType, kNoType, kNoBias },  // kDivideScalar
73     { kNoType, kNoType, kNoBias },  // kElse
74     { SkOpType(kInt | kScalar | kString), SkOpType(kInt | kScalar | kString), kTowardsNumber }, // kEqual
75     // kEqualInt = kEqual
76     { kNoType, kNoType, kNoBias },  // kEqualScalar
77     { kNoType, kNoType, kNoBias },  // kEqualString
78     { kInt, kNoType, kNoBias },     // kFlipOps
79     { SkOpType(kInt | kScalar | kString), SkOpType(kInt | kScalar | kString), kTowardsNumber }, // kGreaterEqual
80     // kGreaterEqualInt = kGreaterEqual
81     { kNoType, kNoType, kNoBias },  // kGreaterEqualScalar
82     { kNoType, kNoType, kNoBias },  // kGreaterEqualString
83     { kNoType, kNoType, kNoBias },  // kIf
84     { kNoType, kInt, kNoBias }, // kLogicalAnd  (really, ToBool)
85     { kNoType, kInt, kNoBias }, // kLogicalNot
86     { kInt, kInt, kNoBias }, // kLogicalOr
87     { kNoType, SkOpType(kInt | kScalar), kNoBias }, // kMinus
88     // kMinusInt = kMinus
89     { kNoType, kNoType, kNoBias },  // kMinusScalar
90     { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kModulo
91     // kModuloInt = kModulo
92     { kNoType, kNoType, kNoBias },  // kModuloScalar
93     { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kMultiply
94     // kMultiplyInt = kMultiply
95     { kNoType, kNoType, kNoBias },  // kMultiplyScalar
96     { kNoType, kNoType, kNoBias },  // kParen
97     { kInt, kInt, kNoBias }, // kShiftLeft
98     { kInt, kInt, kNoBias }, // kShiftRight
99     { SkOpType(kInt | kScalar), SkOpType(kInt | kScalar), kNoBias }, // kSubtract
100     // kSubtractInt = kSubtract
101     { kNoType, kNoType, kNoBias },  // kSubtractScalar
102     { kInt, kInt, kNoBias } // kXor
103 };
104 
105 // Note that the real precedence for () [] is '2'
106 // but here, precedence means 'while an equal or smaller precedence than the current operator
107 // is on the stack, process it. This allows 3+5*2 to defer the add until after the multiply
108 // is preformed, since the add precedence is not smaller than multiply.
109 // But, (3*4 does not process the '(', since brackets are greater than all other precedences
110 #define kBracketPrecedence 16
111 #define kIfElsePrecedence 15
112 
113 const signed char SkScriptEngine::gPrecedence[] = {
114         -1, //  kUnassigned,
115         6, // kAdd,
116         // kAddInt = kAdd,
117         6, // kAddScalar,
118         6, // kAddString,   // string concat
119         kBracketPrecedence, // kArrayOp,
120         10, // kBitAnd,
121         4, // kBitNot,
122         12, // kBitOr,
123         5, // kDivide,
124         // kDivideInt = kDivide,
125         5, // kDivideScalar,
126         kIfElsePrecedence, // kElse,
127         9, // kEqual,
128         // kEqualInt = kEqual,
129         9, // kEqualScalar,
130         9, // kEqualString,
131         -1, // kFlipOps,
132         8, // kGreaterEqual,
133         // kGreaterEqualInt = kGreaterEqual,
134         8, // kGreaterEqualScalar,
135         8, // kGreaterEqualString,
136         kIfElsePrecedence, // kIf,
137         13, // kLogicalAnd,
138         4, // kLogicalNot,
139         14, // kLogicalOr,
140         4, // kMinus,
141         // kMinusInt = kMinus,
142         4, // kMinusScalar,
143         5, // kModulo,
144         // kModuloInt = kModulo,
145         5, // kModuloScalar,
146         5, // kMultiply,
147         // kMultiplyInt = kMultiply,
148         5, // kMultiplyScalar,
149         kBracketPrecedence, // kParen,
150         7, // kShiftLeft,
151         7, // kShiftRight,  // signed
152         6, // kSubtract,
153         // kSubtractInt = kSubtract,
154         6, // kSubtractScalar,
155         11, // kXor
156 };
157 
is_between(int c,int min,int max)158 static inline bool is_between(int c, int min, int max)
159 {
160     return (unsigned)(c - min) <= (unsigned)(max - min);
161 }
162 
is_ws(int c)163 static inline bool is_ws(int c)
164 {
165     return is_between(c, 1, 32);
166 }
167 
token_length(const char * start)168 static int token_length(const char* start) {
169     char ch = start[0];
170     if (! is_between(ch, 'a' , 'z') &&  ! is_between(ch, 'A', 'Z') && ch != '_' && ch != '$')
171         return -1;
172     int length = 0;
173     do
174         ch = start[++length];
175     while (is_between(ch, 'a' , 'z') || is_between(ch, 'A', 'Z') || is_between(ch, '0', '9') ||
176         ch == '_' || ch == '$');
177     return length;
178 }
179 
SkScriptEngine(SkOpType returnType)180 SkScriptEngine::SkScriptEngine(SkOpType returnType) :
181     fTokenLength(0), fReturnType(returnType), fError(kNoError)
182 {
183     SkSuppress noInitialSuppress;
184     noInitialSuppress.fOperator = kUnassigned;
185     noInitialSuppress.fOpStackDepth = 0;
186     noInitialSuppress.fSuppress = false;
187     noInitialSuppress.fElse = 0;
188     fSuppressStack.push(noInitialSuppress);
189     *fOpStack.push() = kParen;
190     fTrackArray.appendClear();
191     fTrackString.appendClear();
192 }
193 
~SkScriptEngine()194 SkScriptEngine::~SkScriptEngine() {
195     for (SkString** stringPtr = fTrackString.begin(); stringPtr < fTrackString.end(); stringPtr++)
196         delete *stringPtr;
197     for (SkTypedArray** arrayPtr = fTrackArray.begin(); arrayPtr < fTrackArray.end(); arrayPtr++)
198         delete *arrayPtr;
199 }
200 
arithmeticOp(char ch,char nextChar,bool lastPush)201 int SkScriptEngine::arithmeticOp(char ch, char nextChar, bool lastPush) {
202     SkOp op = kUnassigned;
203     bool reverseOperands = false;
204     bool negateResult = false;
205     int advance = 1;
206     switch (ch) {
207         case '+':
208             // !!! ignoring unary plus as implemented here has the side effect of
209             // suppressing errors like +"hi"
210             if (lastPush == false)  // unary plus, don't push an operator
211                 goto returnAdv;
212             op = kAdd;
213             break;
214         case '-':
215             op = lastPush ? kSubtract : kMinus;
216             break;
217         case '*':
218             op = kMultiply;
219             break;
220         case '/':
221             op = kDivide;
222             break;
223         case '>':
224             if (nextChar == '>') {
225                 op = kShiftRight;
226                 goto twoChar;
227             }
228             op = kGreaterEqual;
229             if (nextChar == '=')
230                 goto twoChar;
231             reverseOperands = negateResult = true;
232             break;
233         case '<':
234             if (nextChar == '<') {
235                 op = kShiftLeft;
236                 goto twoChar;
237             }
238             op = kGreaterEqual;
239             reverseOperands = nextChar == '=';
240             negateResult = ! reverseOperands;
241             advance += reverseOperands;
242             break;
243         case '=':
244             if (nextChar == '=') {
245                 op = kEqual;
246                 goto twoChar;
247             }
248             break;
249         case '!':
250             if (nextChar == '=') {
251                 op = kEqual;
252                 negateResult = true;
253 twoChar:
254                 advance++;
255                 break;
256             }
257             op = kLogicalNot;
258             break;
259         case '?':
260             op = kIf;
261             break;
262         case ':':
263             op = kElse;
264             break;
265         case '^':
266             op = kXor;
267             break;
268         case '(':
269             *fOpStack.push() = kParen;  // push even if eval is suppressed
270             goto returnAdv;
271         case '&':
272             SkASSERT(nextChar != '&');
273             op = kBitAnd;
274             break;
275         case '|':
276             SkASSERT(nextChar != '|');
277             op = kBitOr;
278             break;
279         case '%':
280             op = kModulo;
281             break;
282         case '~':
283             op = kBitNot;
284             break;
285     }
286     if (op == kUnassigned)
287         return 0;
288     if (fSuppressStack.top().fSuppress == false) {
289         signed char precedence = gPrecedence[op];
290         do {
291             int idx = 0;
292             SkOp compare;
293             do {
294                 compare = fOpStack.index(idx);
295                 if ((compare & kArtificialOp) == 0)
296                     break;
297                 idx++;
298             } while (true);
299             signed char topPrecedence = gPrecedence[compare];
300             SkASSERT(topPrecedence != -1);
301             if (topPrecedence > precedence || (topPrecedence == precedence &&
302                     gOpAttributes[op].fLeftType == kNoType)) {
303                 break;
304             }
305             if (processOp() == false)
306                 return 0;   // error
307         } while (true);
308         if (negateResult)
309             *fOpStack.push() = (SkOp) (kLogicalNot | kArtificialOp);
310         fOpStack.push(op);
311         if (reverseOperands)
312             *fOpStack.push() = (SkOp) (kFlipOps | kArtificialOp);
313     }
314 returnAdv:
315     return advance;
316 }
317 
boxCallBack(_boxCallBack func,void * userStorage)318 void SkScriptEngine::boxCallBack(_boxCallBack func, void* userStorage) {
319     UserCallBack callBack;
320     callBack.fBoxCallBack = func;
321     commonCallBack(kBox, callBack, userStorage);
322 }
323 
commonCallBack(CallBackType type,UserCallBack & callBack,void * userStorage)324 void SkScriptEngine::commonCallBack(CallBackType type, UserCallBack& callBack, void* userStorage) {
325     callBack.fCallBackType = type;
326     callBack.fUserStorage = userStorage;
327     *fUserCallBacks.prepend() = callBack;
328 }
329 
convertParams(SkTDArray<SkScriptValue> & params,const SkFunctionParamType * paramTypes,int paramCount)330 bool SkScriptEngine::convertParams(SkTDArray<SkScriptValue>& params,
331         const SkFunctionParamType* paramTypes, int paramCount) {
332     if (params.count() > paramCount) {
333         fError = kTooManyParameters;
334         return false;   // too many parameters passed
335     }
336     for (int index = 0; index < params.count(); index++) {
337         if (convertTo((SkDisplayTypes) paramTypes[index], &params[index]) == false)
338             return false;
339     }
340     return true;
341 }
342 
convertTo(SkDisplayTypes toType,SkScriptValue * value)343 bool SkScriptEngine::convertTo(SkDisplayTypes toType, SkScriptValue* value ) {
344     SkDisplayTypes type = value->fType;
345     if (type == toType)
346         return true;
347     if (ToOpType(type) == kObject) {
348 #if 0   // !!! I want object->string to get string from displaystringtype, not id
349         if (ToOpType(toType) == kString) {
350             bool success = handleObjectToString(value->fOperand.fObject);
351             if (success == false)
352                 return false;
353             SkOpType type;
354             fTypeStack.pop(&type);
355             value->fType = ToDisplayType(type);
356             fOperandStack.pop(&value->fOperand);
357             return true;
358         }
359 #endif
360         if (handleUnbox(value) == false) {
361             fError = kHandleUnboxFailed;
362             return false;
363         }
364         return convertTo(toType, value);
365     }
366     return ConvertTo(this, toType, value);
367 }
368 
evaluateDot(const char * & script,bool suppressed)369 bool SkScriptEngine::evaluateDot(const char*& script, bool suppressed) {
370     size_t fieldLength = token_length(++script);        // skip dot
371     if (fieldLength == 0) {
372         fError = kExpectedFieldName;
373         return false;
374     }
375     const char* field = script;
376     script += fieldLength;
377     bool success = handleProperty(suppressed);
378     if (success == false) {
379         fError = kCouldNotFindReferencedID; // note: never generated by standard animator plugins
380         return false;
381     }
382     return evaluateDotParam(script, suppressed, field, fieldLength);
383 }
384 
evaluateDotParam(const char * & script,bool suppressed,const char * field,size_t fieldLength)385 bool SkScriptEngine::evaluateDotParam(const char*& script, bool suppressed,
386         const char* field, size_t fieldLength) {
387     void* object;
388     if (suppressed)
389         object = nullptr;
390     else {
391         if (fTypeStack.top() != kObject) {
392             fError = kDotOperatorExpectsObject;
393             return false;
394         }
395         object = fOperandStack.top().fObject;
396         fTypeStack.pop();
397         fOperandStack.pop();
398     }
399     char ch; // see if it is a simple member or a function
400     while (is_ws(ch = script[0]))
401         script++;
402     bool success = true;
403     if (ch != '(') {
404             if (suppressed == false) {
405                 if ((success = handleMember(field, fieldLength, object)) == false)
406                     fError = kHandleMemberFailed;
407             }
408     } else {
409         SkTDArray<SkScriptValue> params;
410         *fBraceStack.push() = kFunctionBrace;
411         success = functionParams(&script, params);
412         if (success && suppressed == false &&
413                 (success = handleMemberFunction(field, fieldLength, object, params)) == false)
414             fError = kHandleMemberFunctionFailed;
415     }
416     return success;
417 }
418 
evaluateScript(const char ** scriptPtr,SkScriptValue * value)419 bool SkScriptEngine::evaluateScript(const char** scriptPtr, SkScriptValue* value) {
420 #ifdef SK_DEBUG
421     const char** original = scriptPtr;
422 #endif
423     bool success;
424     const char* inner;
425     if (strncmp(*scriptPtr, "#script:", sizeof("#script:") - 1) == 0) {
426         *scriptPtr += sizeof("#script:") - 1;
427         if (fReturnType == kNoType || fReturnType == kString) {
428             success = innerScript(scriptPtr, value);
429             if (success == false)
430                 goto end;
431             inner = value->fOperand.fString->c_str();
432             scriptPtr = &inner;
433         }
434     }
435     {
436         success = innerScript(scriptPtr, value);
437         if (success == false)
438             goto end;
439         const char* script = *scriptPtr;
440         char ch;
441         while (is_ws(ch = script[0]))
442             script++;
443         if (ch != '\0') {
444             // error may trigger on scripts like "50,0" that were intended to be written as "[50, 0]"
445             fError = kPrematureEnd;
446             success = false;
447         }
448     }
449 end:
450 #ifdef SK_DEBUG
451     if (success == false) {
452         SkDebugf("script failed: %s", *original);
453         if (fError)
454             SkDebugf(" %s", errorStrings[fError - 1]);
455         SkDebugf("\n");
456     }
457 #endif
458     return success;
459 }
460 
forget(SkTypedArray * array)461 void SkScriptEngine::forget(SkTypedArray* array) {
462     if (array->getType() == SkType_String) {
463         for (int index = 0; index < array->count(); index++) {
464             SkString* string = (*array)[index].fString;
465             int found = fTrackString.find(string);
466             if (found >= 0)
467                 fTrackString.remove(found);
468         }
469         return;
470     }
471     if (array->getType() == SkType_Array) {
472         for (int index = 0; index < array->count(); index++) {
473             SkTypedArray* child = (*array)[index].fArray;
474             forget(child);  // forgets children of child
475             int found = fTrackArray.find(child);
476             if (found >= 0)
477                 fTrackArray.remove(found);
478         }
479     }
480 }
481 
functionCallBack(_functionCallBack func,void * userStorage)482 void SkScriptEngine::functionCallBack(_functionCallBack func, void* userStorage) {
483     UserCallBack callBack;
484     callBack.fFunctionCallBack = func;
485     commonCallBack(kFunction, callBack, userStorage);
486 }
487 
functionParams(const char ** scriptPtr,SkTDArray<SkScriptValue> & params)488 bool SkScriptEngine::functionParams(const char** scriptPtr, SkTDArray<SkScriptValue>& params) {
489     (*scriptPtr)++; // skip open paren
490     *fOpStack.push() = kParen;
491     *fBraceStack.push() = kFunctionBrace;
492     SkBool suppressed = fSuppressStack.top().fSuppress;
493     do {
494         SkScriptValue value;
495         bool success = innerScript(scriptPtr, suppressed ? nullptr : &value);
496         if (success == false) {
497             fError = kErrorInFunctionParameters;
498             return false;
499         }
500         if (suppressed)
501             continue;
502         *params.append() = value;
503     } while ((*scriptPtr)[-1] == ',');
504     fBraceStack.pop();
505     fOpStack.pop(); // pop paren
506     (*scriptPtr)++; // advance beyond close paren
507     return true;
508 }
509 
510 #ifdef SK_DEBUG
getErrorString(SkString * str) const511 bool SkScriptEngine::getErrorString(SkString* str) const {
512     if (fError)
513         str->set(errorStrings[fError - 1]);
514     return fError != 0;
515 }
516 #endif
517 
innerScript(const char ** scriptPtr,SkScriptValue * value)518 bool SkScriptEngine::innerScript(const char** scriptPtr, SkScriptValue* value) {
519     const char* script = *scriptPtr;
520     char ch;
521     bool lastPush = false;
522     bool success = true;
523     int opBalance = fOpStack.count();
524     int baseBrace = fBraceStack.count();
525     int suppressBalance = fSuppressStack.count();
526     while ((ch = script[0]) != '\0') {
527         if (is_ws(ch)) {
528             script++;
529             continue;
530         }
531         SkBool suppressed = fSuppressStack.top().fSuppress;
532         SkOperand operand;
533         const char* dotCheck;
534         if (fBraceStack.count() > baseBrace) {
535 #if 0   // disable support for struct brace
536             if (ch == ':') {
537                 SkASSERT(fTokenLength > 0);
538                 SkASSERT(fBraceStack.top() == kStructBrace);
539                 ++script;
540                 SkASSERT(fDisplayable);
541                 SkString token(fToken, fTokenLength);
542                 fTokenLength = 0;
543                 const char* tokenName = token.c_str();
544                 const SkMemberInfo* tokenInfo SK_INIT_TO_AVOID_WARNING;
545                 if (suppressed == false) {
546                     SkDisplayTypes type = fInfo->getType();
547                     tokenInfo = SkDisplayType::GetMember(type, &tokenName);
548                     SkASSERT(tokenInfo);
549                 }
550                 SkScriptValue tokenValue;
551                 success = innerScript(&script, &tokenValue);    // terminate and return on comma, close brace
552                 SkASSERT(success);
553                 if (suppressed == false) {
554                     if (tokenValue.fType == SkType_Displayable) {
555                         SkASSERT(SkDisplayType::IsDisplayable(tokenInfo->getType()));
556                         fDisplayable->setReference(tokenInfo, tokenValue.fOperand.fDisplayable);
557                     } else {
558                         if (tokenValue.fType != tokenInfo->getType()) {
559                             if (convertTo(tokenInfo->getType(), &tokenValue) == false)
560                                 return false;
561                         }
562                         tokenInfo->writeValue(fDisplayable, nullptr, 0, 0,
563                             (void*) ((char*) fInfo->memberData(fDisplayable) + tokenInfo->fOffset + fArrayOffset),
564                             tokenInfo->getType(), tokenValue);
565                     }
566                 }
567                 lastPush = false;
568                 continue;
569             } else
570 #endif
571             if (fBraceStack.top() == kArrayBrace) {
572                 SkScriptValue tokenValue;
573                 success = innerScript(&script, &tokenValue);    // terminate and return on comma, close brace
574                 if (success == false) {
575                     fError = kErrorInArrrayIndex;
576                     return false;
577                 }
578                 if (suppressed == false) {
579 #if 0 // no support for structures for now
580                     if (tokenValue.fType == SkType_Structure) {
581                         fArrayOffset += (int) fInfo->getSize(fDisplayable);
582                     } else
583 #endif
584                     {
585                         SkDisplayTypes type = ToDisplayType(fReturnType);
586                         if (fReturnType == kNoType) {
587                             // !!! short sighted; in the future, allow each returned array component to carry
588                             // its own type, and let caller do any needed conversions
589                             if (value->fOperand.fArray->count() == 0)
590                                 value->fOperand.fArray->setType(type = tokenValue.fType);
591                             else
592                                 type = value->fOperand.fArray->getType();
593                         }
594                         if (tokenValue.fType != type) {
595                             if (convertTo(type, &tokenValue) == false)
596                                 return false;
597                         }
598                         *value->fOperand.fArray->append() = tokenValue.fOperand;
599                     }
600                 }
601                 lastPush = false;
602                 continue;
603             } else {
604                 if (token_length(script) == 0) {
605                     fError = kExpectedToken;
606                     return false;
607                 }
608             }
609         }
610         if (lastPush != false && fTokenLength > 0) {
611             if (ch == '(') {
612                 *fBraceStack.push() = kFunctionBrace;
613                 if (handleFunction(&script, SkToBool(suppressed)) == false)
614                     return false;
615                 lastPush = true;
616                 continue;
617             } else if (ch == '[') {
618                 if (handleProperty(SkToBool(suppressed)) == false)
619                     return false;   // note: never triggered by standard animator plugins
620                 if (handleArrayIndexer(&script, SkToBool(suppressed)) == false)
621                     return false;
622                 lastPush = true;
623                 continue;
624             } else if (ch != '.') {
625                 if (handleProperty(SkToBool(suppressed)) == false)
626                     return false;   // note: never triggered by standard animator plugins
627                 lastPush = true;
628                 continue;
629             }
630         }
631         if (ch == '0' && (script[1] & ~0x20) == 'X') {
632             if (lastPush != false) {
633                 fError = kExpectedOperator;
634                 return false;
635             }
636             script += 2;
637             script = SkParse::FindHex(script, (uint32_t*)&operand.fS32);
638             if (script == nullptr) {
639                 fError = kExpectedHex;
640                 return false;
641             }
642             goto intCommon;
643         }
644         if (lastPush == false && ch == '.')
645             goto scalarCommon;
646         if (ch >= '0' && ch <= '9') {
647             if (lastPush != false) {
648                 fError = kExpectedOperator;
649                 return false;
650             }
651             dotCheck = SkParse::FindS32(script, &operand.fS32);
652             if (dotCheck[0] != '.') {
653                 script = dotCheck;
654 intCommon:
655                 if (suppressed == false)
656                     *fTypeStack.push() = kInt;
657             } else {
658 scalarCommon:
659                 script = SkParse::FindScalar(script, &operand.fScalar);
660                 if (suppressed == false)
661                     *fTypeStack.push() = kScalar;
662             }
663             if (suppressed == false)
664                 fOperandStack.push(operand);
665             lastPush = true;
666             continue;
667         }
668         int length = token_length(script);
669         if (length > 0) {
670             if (lastPush != false) {
671                 fError = kExpectedOperator;
672                 return false;
673             }
674             fToken = script;
675             fTokenLength = length;
676             script += length;
677             lastPush = true;
678             continue;
679         }
680         char startQuote = ch;
681         if (startQuote == '\'' || startQuote == '\"') {
682             if (lastPush != false) {
683                 fError = kExpectedOperator;
684                 return false;
685             }
686             operand.fString = new SkString();
687             track(operand.fString);
688             ++script;
689 
690             // <mrr> this is a lot of calls to append() one char at at time
691             // how hard to preflight script so we know how much to grow fString by?
692             do {
693                 if (script[0] == '\\')
694                     ++script;
695                 operand.fString->append(script, 1);
696                 ++script;
697                 if (script[0] == '\0') {
698                     fError = kUnterminatedString;
699                     return false;
700                 }
701             } while (script[0] != startQuote);
702             ++script;
703             if (suppressed == false) {
704                 *fTypeStack.push() = kString;
705                 fOperandStack.push(operand);
706             }
707             lastPush = true;
708             continue;
709         }
710         ;
711         if (ch ==  '.') {
712             if (fTokenLength == 0) {
713                 SkScriptValue scriptValue;
714                 SkDEBUGCODE(scriptValue.fOperand.fObject = nullptr);
715                 int tokenLength = token_length(++script);
716                 const char* token = script;
717                 script += tokenLength;
718                 if (suppressed == false) {
719                     if (fTypeStack.count() == 0) {
720                         fError = kExpectedTokenBeforeDotOperator;
721                         return false;
722                     }
723                     SkOpType topType;
724                     fTypeStack.pop(&topType);
725                     fOperandStack.pop(&scriptValue.fOperand);
726                     scriptValue.fType = ToDisplayType(topType);
727                     handleBox(&scriptValue);
728                 }
729                 success = evaluateDotParam(script, SkToBool(suppressed), token, tokenLength);
730                 if (success == false)
731                     return false;
732                 lastPush = true;
733                 continue;
734             }
735             // get next token, and evaluate immediately
736             success = evaluateDot(script, SkToBool(suppressed));
737             if (success == false)
738                 return false;
739             lastPush = true;
740             continue;
741         }
742         if (ch == '[') {
743             if (lastPush == false) {
744                 script++;
745                 *fBraceStack.push() = kArrayBrace;
746                 if (suppressed)
747                     continue;
748                 operand.fArray = value->fOperand.fArray = new SkTypedArray(ToDisplayType(fReturnType));
749                 track(value->fOperand.fArray);
750                 *fTypeStack.push() = (SkOpType) kArray;
751                 fOperandStack.push(operand);
752                 continue;
753             }
754             if (handleArrayIndexer(&script, SkToBool(suppressed)) == false)
755                 return false;
756             lastPush = true;
757             continue;
758         }
759 #if 0 // structs not supported for now
760         if (ch == '{') {
761             if (lastPush == false) {
762                 script++;
763                 *fBraceStack.push() = kStructBrace;
764                 if (suppressed)
765                     continue;
766                 operand.fS32 = 0;
767                 *fTypeStack.push() = (SkOpType) kStruct;
768                 fOperandStack.push(operand);
769                 continue;
770             }
771             SkASSERT(0); // braces in other contexts aren't supported yet
772         }
773 #endif
774         if (ch == ')' && fBraceStack.count() > 0) {
775             SkBraceStyle braceStyle = fBraceStack.top();
776             if (braceStyle == kFunctionBrace) {
777                 fBraceStack.pop();
778                 break;
779             }
780         }
781         if (ch == ',' || ch == ']') {
782             if (ch != ',') {
783                 SkBraceStyle match;
784                 fBraceStack.pop(&match);
785                 if (match != kArrayBrace) {
786                     fError = kMismatchedArrayBrace;
787                     return false;
788                 }
789             }
790             script++;
791             // !!! see if brace or bracket is correct closer
792             break;
793         }
794         char nextChar = script[1];
795         int advance = logicalOp(ch, nextChar);
796         if (advance < 0)     // error
797             return false;
798         if (advance == 0)
799             advance = arithmeticOp(ch, nextChar, lastPush);
800         if (advance == 0) // unknown token
801             return false;
802         if (advance > 0)
803             script += advance;
804         lastPush = ch == ']' || ch == ')';
805     }
806     bool suppressed = SkToBool(fSuppressStack.top().fSuppress);
807     if (fTokenLength > 0) {
808         success = handleProperty(suppressed);
809         if (success == false)
810             return false;   // note: never triggered by standard animator plugins
811     }
812     while (fOpStack.count() > opBalance) {   // leave open paren
813         if ((fError = opError()) != kNoError)
814             return false;
815         if (processOp() == false)
816             return false;
817     }
818     SkOpType topType = fTypeStack.count() > 0 ? fTypeStack.top() : kNoType;
819     if (suppressed == false && topType != fReturnType &&
820             topType == kString && fReturnType != kNoType) { // if result is a string, give handle property a chance to convert it to the property value
821         SkString* string = fOperandStack.top().fString;
822         fToken = string->c_str();
823         fTokenLength = string->size();
824         fOperandStack.pop();
825         fTypeStack.pop();
826         success = handleProperty(SkToBool(fSuppressStack.top().fSuppress));
827         if (success == false) { // if it couldn't convert, return string (error?)
828             SkOperand operand;
829             operand.fS32 = 0;
830             *fTypeStack.push() = kString;
831             operand.fString = string;
832             fOperandStack.push(operand);
833         }
834     }
835     if (value) {
836         if (fOperandStack.count() == 0)
837             return false;
838         SkASSERT(fOperandStack.count() >= 1);
839         SkASSERT(fTypeStack.count() >= 1);
840         fOperandStack.pop(&value->fOperand);
841         SkOpType type;
842         fTypeStack.pop(&type);
843         value->fType = ToDisplayType(type);
844 //      SkASSERT(value->fType != SkType_Unknown);
845         if (topType != fReturnType && topType == kObject && fReturnType != kNoType) {
846             if (convertTo(ToDisplayType(fReturnType), value) == false)
847                 return false;
848         }
849     }
850     while (fSuppressStack.count() > suppressBalance)
851         fSuppressStack.pop();
852     *scriptPtr = script;
853     return true; // no error
854 }
855 
memberCallBack(_memberCallBack member,void * userStorage)856 void SkScriptEngine::memberCallBack(_memberCallBack member , void* userStorage) {
857     UserCallBack callBack;
858     callBack.fMemberCallBack = member;
859     commonCallBack(kMember, callBack, userStorage);
860 }
861 
memberFunctionCallBack(_memberFunctionCallBack func,void * userStorage)862 void SkScriptEngine::memberFunctionCallBack(_memberFunctionCallBack func, void* userStorage) {
863     UserCallBack callBack;
864     callBack.fMemberFunctionCallBack = func;
865     commonCallBack(kMemberFunction, callBack, userStorage);
866 }
867 
868 #if 0
869 void SkScriptEngine::objectToStringCallBack(_objectToStringCallBack func, void* userStorage) {
870     UserCallBack callBack;
871     callBack.fObjectToStringCallBack = func;
872     commonCallBack(kObjectToString, callBack, userStorage);
873 }
874 #endif
875 
handleArrayIndexer(const char ** scriptPtr,bool suppressed)876 bool SkScriptEngine::handleArrayIndexer(const char** scriptPtr, bool suppressed) {
877     SkScriptValue scriptValue;
878     (*scriptPtr)++;
879     *fOpStack.push() = kParen;
880     *fBraceStack.push() = kArrayBrace;
881     SkOpType saveType = fReturnType;
882     fReturnType = kInt;
883     bool success = innerScript(scriptPtr, suppressed == false ? &scriptValue : nullptr);
884     if (success == false)
885         return false;
886     fReturnType = saveType;
887     if (suppressed == false) {
888         if (convertTo(SkType_Int, &scriptValue) == false)
889             return false;
890         int index = scriptValue.fOperand.fS32;
891         SkScriptValue scriptValue;
892         SkOpType type;
893         fTypeStack.pop(&type);
894         fOperandStack.pop(&scriptValue.fOperand);
895         scriptValue.fType = ToDisplayType(type);
896         if (type == kObject) {
897             success = handleUnbox(&scriptValue);
898             if (success == false)
899                 return false;
900             if (ToOpType(scriptValue.fType) != kArray) {
901                 fError = kExpectedArray;
902                 return false;
903             }
904         }
905         *fTypeStack.push() = scriptValue.fOperand.fArray->getOpType();
906 //      SkASSERT(index >= 0);
907         if ((unsigned) index >= (unsigned) scriptValue.fOperand.fArray->count()) {
908             fError = kArrayIndexOutOfBounds;
909             return false;
910         }
911         scriptValue.fOperand = scriptValue.fOperand.fArray->begin()[index];
912         fOperandStack.push(scriptValue.fOperand);
913     }
914     fOpStack.pop(); // pop paren
915     return success;
916 }
917 
handleBox(SkScriptValue * scriptValue)918 bool SkScriptEngine::handleBox(SkScriptValue* scriptValue) {
919     bool success = true;
920     for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) {
921         if (callBack->fCallBackType != kBox)
922             continue;
923         success = (*callBack->fBoxCallBack)(callBack->fUserStorage, scriptValue);
924         if (success) {
925             fOperandStack.push(scriptValue->fOperand);
926             *fTypeStack.push() = ToOpType(scriptValue->fType);
927             goto done;
928         }
929     }
930 done:
931     return success;
932 }
933 
handleFunction(const char ** scriptPtr,bool suppressed)934 bool SkScriptEngine::handleFunction(const char** scriptPtr, bool suppressed) {
935     SkScriptValue callbackResult;
936     SkTDArray<SkScriptValue> params;
937     SkString functionName(fToken, fTokenLength);
938     fTokenLength = 0;
939     bool success = functionParams(scriptPtr, params);
940     if (success == false)
941         goto done;
942     if (suppressed == true)
943         return true;
944     {
945         for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) {
946             if (callBack->fCallBackType != kFunction)
947                 continue;
948             success = (*callBack->fFunctionCallBack)(functionName.c_str(), functionName.size(), params,
949                 callBack->fUserStorage, &callbackResult);
950             if (success) {
951                 fOperandStack.push(callbackResult.fOperand);
952                 *fTypeStack.push() = ToOpType(callbackResult.fType);
953                 goto done;
954             }
955         }
956     }
957     fError = kNoFunctionHandlerFound;
958     return false;
959 done:
960     return success;
961 }
962 
handleMember(const char * field,size_t len,void * object)963 bool SkScriptEngine::handleMember(const char* field, size_t len, void* object) {
964     SkScriptValue callbackResult;
965     bool success = true;
966     for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) {
967         if (callBack->fCallBackType != kMember)
968             continue;
969         success = (*callBack->fMemberCallBack)(field, len, object, callBack->fUserStorage, &callbackResult);
970         if (success) {
971             if (callbackResult.fType == SkType_String)
972                 track(callbackResult.fOperand.fString);
973             fOperandStack.push(callbackResult.fOperand);
974             *fTypeStack.push() = ToOpType(callbackResult.fType);
975             goto done;
976         }
977     }
978     return false;
979 done:
980     return success;
981 }
982 
handleMemberFunction(const char * field,size_t len,void * object,SkTDArray<SkScriptValue> & params)983 bool SkScriptEngine::handleMemberFunction(const char* field, size_t len, void* object, SkTDArray<SkScriptValue>& params) {
984     SkScriptValue callbackResult;
985     bool success = true;
986     for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) {
987         if (callBack->fCallBackType != kMemberFunction)
988             continue;
989         success = (*callBack->fMemberFunctionCallBack)(field, len, object, params,
990             callBack->fUserStorage, &callbackResult);
991         if (success) {
992             if (callbackResult.fType == SkType_String)
993                 track(callbackResult.fOperand.fString);
994             fOperandStack.push(callbackResult.fOperand);
995             *fTypeStack.push() = ToOpType(callbackResult.fType);
996             goto done;
997         }
998     }
999     return false;
1000 done:
1001     return success;
1002 }
1003 
1004 #if 0
1005 bool SkScriptEngine::handleObjectToString(void* object) {
1006     SkScriptValue callbackResult;
1007     bool success = true;
1008     for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) {
1009         if (callBack->fCallBackType != kObjectToString)
1010             continue;
1011         success = (*callBack->fObjectToStringCallBack)(object,
1012             callBack->fUserStorage, &callbackResult);
1013         if (success) {
1014             if (callbackResult.fType == SkType_String)
1015                 track(callbackResult.fOperand.fString);
1016             fOperandStack.push(callbackResult.fOperand);
1017             *fTypeStack.push() = ToOpType(callbackResult.fType);
1018             goto done;
1019         }
1020     }
1021     return false;
1022 done:
1023     return success;
1024 }
1025 #endif
1026 
handleProperty(bool suppressed)1027 bool SkScriptEngine::handleProperty(bool suppressed) {
1028     SkScriptValue callbackResult;
1029     bool success = true;
1030     if (suppressed)
1031         goto done;
1032     success = false; // note that with standard animator-script plugins, callback never returns false
1033     {
1034         for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) {
1035             if (callBack->fCallBackType != kProperty)
1036                 continue;
1037             success = (*callBack->fPropertyCallBack)(fToken, fTokenLength,
1038                 callBack->fUserStorage, &callbackResult);
1039             if (success) {
1040                 if (callbackResult.fType == SkType_String && callbackResult.fOperand.fString == nullptr) {
1041                     callbackResult.fOperand.fString = new SkString(fToken, fTokenLength);
1042                     track(callbackResult.fOperand.fString);
1043                 }
1044                 fOperandStack.push(callbackResult.fOperand);
1045                 *fTypeStack.push() = ToOpType(callbackResult.fType);
1046                 goto done;
1047             }
1048         }
1049     }
1050 done:
1051     fTokenLength = 0;
1052     return success;
1053 }
1054 
handleUnbox(SkScriptValue * scriptValue)1055 bool SkScriptEngine::handleUnbox(SkScriptValue* scriptValue) {
1056     bool success = true;
1057     for (UserCallBack* callBack = fUserCallBacks.begin(); callBack < fUserCallBacks.end(); callBack++) {
1058         if (callBack->fCallBackType != kUnbox)
1059             continue;
1060         success = (*callBack->fUnboxCallBack)(callBack->fUserStorage, scriptValue);
1061         if (success) {
1062             if (scriptValue->fType == SkType_String)
1063                 track(scriptValue->fOperand.fString);
1064             goto done;
1065         }
1066     }
1067     return false;
1068 done:
1069     return success;
1070 }
1071 
1072 // note that entire expression is treated as if it were enclosed in parens
1073 // an open paren is always the first thing in the op stack
1074 
logicalOp(char ch,char nextChar)1075 int SkScriptEngine::logicalOp(char ch, char nextChar) {
1076     int advance = 1;
1077     SkOp match;
1078     signed char precedence;
1079     switch (ch) {
1080         case ')':
1081             match = kParen;
1082             break;
1083         case ']':
1084             match = kArrayOp;
1085             break;
1086         case '?':
1087             match = kIf;
1088             break;
1089         case ':':
1090             match = kElse;
1091             break;
1092         case '&':
1093             if (nextChar != '&')
1094                 goto noMatch;
1095             match = kLogicalAnd;
1096             advance = 2;
1097             break;
1098         case '|':
1099             if (nextChar != '|')
1100                 goto noMatch;
1101             match = kLogicalOr;
1102             advance = 2;
1103             break;
1104         default:
1105 noMatch:
1106             return 0;
1107     }
1108     SkSuppress suppress;
1109     precedence = gPrecedence[match];
1110     if (fSuppressStack.top().fSuppress) {
1111         if (fSuppressStack.top().fOpStackDepth < fOpStack.count()) {
1112             SkOp topOp = fOpStack.top();
1113             if (gPrecedence[topOp] <= precedence)
1114                 fOpStack.pop();
1115             goto goHome;
1116         }
1117         bool changedPrecedence = gPrecedence[fSuppressStack.top().fOperator] < precedence;
1118         if (changedPrecedence)
1119             fSuppressStack.pop();
1120         if (precedence == kIfElsePrecedence) {
1121             if (match == kIf) {
1122                 if (changedPrecedence)
1123                     fOpStack.pop();
1124                 else
1125                     *fOpStack.push() = kIf;
1126             } else {
1127                 if (fSuppressStack.top().fOpStackDepth == fOpStack.count()) {
1128                     goto flipSuppress;
1129                 }
1130                 fOpStack.pop();
1131             }
1132         }
1133         if (changedPrecedence == false)
1134             goto goHome;
1135     }
1136     while (gPrecedence[fOpStack.top() & ~kArtificialOp] < precedence) {
1137         if (processOp() == false)
1138             return false;
1139     }
1140     if (fSuppressStack.top().fOpStackDepth > fOpStack.count())
1141         fSuppressStack.pop();
1142     switch (match) {
1143         case kParen:
1144         case kArrayOp:
1145             if (fOpStack.count() <= 1 || fOpStack.top() != match) {
1146                 fError = kMismatchedBrackets;
1147                 return -1;
1148             }
1149             if (match == kParen)
1150                 fOpStack.pop();
1151             else {
1152                 SkOpType indexType;
1153                 fTypeStack.pop(&indexType);
1154                 if (indexType != kInt && indexType != kScalar) {
1155                     fError = kExpectedNumberForArrayIndex; // (although, could permit strings eventually)
1156                     return -1;
1157                 }
1158                 SkOperand indexOperand;
1159                 fOperandStack.pop(&indexOperand);
1160                 int index = indexType == kScalar ? SkScalarFloorToInt(indexOperand.fScalar) :
1161                     indexOperand.fS32;
1162                 SkOpType arrayType;
1163                 fTypeStack.pop(&arrayType);
1164                 if ((unsigned)arrayType != (unsigned)kArray) {
1165                     fError = kExpectedArray;
1166                     return -1;
1167                 }
1168                 SkOperand arrayOperand;
1169                 fOperandStack.pop(&arrayOperand);
1170                 SkTypedArray* array = arrayOperand.fArray;
1171                 SkOperand operand;
1172                 if (array->getIndex(index, &operand) == false) {
1173                     fError = kIndexOutOfRange;
1174                     return -1;
1175                 }
1176                 SkOpType resultType = array->getOpType();
1177                 fTypeStack.push(resultType);
1178                 fOperandStack.push(operand);
1179             }
1180             break;
1181         case kIf: {
1182             SkScriptValue ifValue;
1183             SkOpType ifType;
1184             fTypeStack.pop(&ifType);
1185             ifValue.fType = ToDisplayType(ifType);
1186             fOperandStack.pop(&ifValue.fOperand);
1187             if (convertTo(SkType_Int, &ifValue) == false)
1188                 return -1;
1189             if (ifValue.fType != SkType_Int) {
1190                 fError = kExpectedIntForConditionOperator;
1191                 return -1;
1192             }
1193             suppress.fSuppress = ifValue.fOperand.fS32 == 0;
1194             suppress.fOperator = kIf;
1195             suppress.fOpStackDepth = fOpStack.count();
1196             suppress.fElse = false;
1197             fSuppressStack.push(suppress);
1198             // if left is true, do only up to colon
1199             // if left is false, do only after colon
1200             } break;
1201         case kElse:
1202 flipSuppress:
1203             if (fSuppressStack.top().fElse)
1204                 fSuppressStack.pop();
1205             fSuppressStack.top().fElse = true;
1206             fSuppressStack.top().fSuppress ^= true;
1207             // flip last do / don't do consideration from last '?'
1208             break;
1209         case kLogicalAnd:
1210         case kLogicalOr: {
1211             if (fTypeStack.top() != kInt) {
1212                 fError = kExpectedBooleanExpression;
1213                 return -1;
1214             }
1215             int32_t topInt = fOperandStack.top().fS32;
1216             if (fOpStack.top() != kLogicalAnd)
1217                 *fOpStack.push() = kLogicalAnd; // really means 'to bool', and is appropriate for 'or'
1218             if (match == kLogicalOr ? topInt != 0 : topInt == 0) {
1219                 suppress.fSuppress = true;
1220                 suppress.fOperator = match;
1221                 suppress.fOpStackDepth = fOpStack.count();
1222                 suppress.fElse = false;
1223                 fSuppressStack.push(suppress);
1224             } else {
1225                 fTypeStack.pop();
1226                 fOperandStack.pop();
1227             }
1228         }   break;
1229         default:
1230             SkASSERT(0);
1231     }
1232 goHome:
1233     return advance;
1234 }
1235 
opError()1236 SkScriptEngine::Error SkScriptEngine::opError() {
1237     int opCount = fOpStack.count();
1238     int operandCount = fOperandStack.count();
1239     if (opCount == 0) {
1240         if (operandCount != 1)
1241             return kExpectedOperator;
1242         return kNoError;
1243     }
1244     SkOp op = (SkOp) (fOpStack.top() & ~kArtificialOp);
1245     const SkOperatorAttributes* attributes = &gOpAttributes[op];
1246     if (attributes->fLeftType != kNoType && operandCount < 2)
1247         return kExpectedValue;
1248     if (attributes->fLeftType == kNoType && operandCount < 1)
1249         return kExpectedValue;
1250     return kNoError;
1251 }
1252 
processOp()1253 bool SkScriptEngine::processOp() {
1254     SkOp op;
1255     fOpStack.pop(&op);
1256     op = (SkOp) (op & ~kArtificialOp);
1257     const SkOperatorAttributes* attributes = &gOpAttributes[op];
1258     SkOpType type2;
1259     fTypeStack.pop(&type2);
1260     SkOpType type1 = type2;
1261     SkOperand operand2;
1262     fOperandStack.pop(&operand2);
1263     SkOperand operand1 = operand2; // !!! not really needed, suppresses warning
1264     if (attributes->fLeftType != kNoType) {
1265         fTypeStack.pop(&type1);
1266         fOperandStack.pop(&operand1);
1267         if (op == kFlipOps) {
1268             SkTSwap(type1, type2);
1269             SkTSwap(operand1, operand2);
1270             fOpStack.pop(&op);
1271             op = (SkOp) (op & ~kArtificialOp);
1272             attributes = &gOpAttributes[op];
1273         }
1274         if (type1 == kObject && (type1 & attributes->fLeftType) == 0) {
1275             SkScriptValue val;
1276             val.fType = ToDisplayType(type1);
1277             val.fOperand = operand1;
1278             bool success = handleUnbox(&val);
1279             if (success == false)
1280                 return false;
1281             type1 = ToOpType(val.fType);
1282             operand1 = val.fOperand;
1283         }
1284     }
1285     if (type2 == kObject && (type2 & attributes->fLeftType) == 0) {
1286         SkScriptValue val;
1287         val.fType = ToDisplayType(type2);
1288         val.fOperand = operand2;
1289         bool success = handleUnbox(&val);
1290         if (success == false)
1291             return false;
1292         type2 = ToOpType(val.fType);
1293         operand2 = val.fOperand;
1294     }
1295     if (attributes->fLeftType != kNoType) {
1296         if (type1 != type2) {
1297             if ((attributes->fLeftType & kString) && attributes->fBias & kTowardsString && ((type1 | type2) & kString)) {
1298                 if (type1 == kInt || type1 == kScalar) {
1299                     convertToString(operand1, type1 == kInt ? SkType_Int : SkType_Float);
1300                     type1 = kString;
1301                 }
1302                 if (type2 == kInt || type2 == kScalar) {
1303                     convertToString(operand2, type2 == kInt ? SkType_Int : SkType_Float);
1304                     type2 = kString;
1305                 }
1306             } else if (attributes->fLeftType & kScalar && ((type1 | type2) & kScalar)) {
1307                 if (type1 == kInt) {
1308                     operand1.fScalar = IntToScalar(operand1.fS32);
1309                     type1 = kScalar;
1310                 }
1311                 if (type2 == kInt) {
1312                     operand2.fScalar = IntToScalar(operand2.fS32);
1313                      type2 = kScalar;
1314                 }
1315             }
1316         }
1317         if ((type1 & attributes->fLeftType) == 0 || type1 != type2) {
1318             if (type1 == kString) {
1319                 const char* result = SkParse::FindScalar(operand1.fString->c_str(), &operand1.fScalar);
1320                 if (result == nullptr) {
1321                     fError = kExpectedNumber;
1322                     return false;
1323                 }
1324                 type1 = kScalar;
1325             }
1326             if (type1 == kScalar && (attributes->fLeftType == kInt || type2 == kInt)) {
1327                 operand1.fS32 = SkScalarFloorToInt(operand1.fScalar);
1328                 type1 = kInt;
1329             }
1330         }
1331     }
1332     if ((type2 & attributes->fRightType) == 0 || type1 != type2) {
1333         if (type2 == kString) {
1334             const char* result = SkParse::FindScalar(operand2.fString->c_str(), &operand2.fScalar);
1335             if (result == nullptr) {
1336                 fError = kExpectedNumber;
1337                 return false;
1338             }
1339             type2 = kScalar;
1340         }
1341         if (type2 == kScalar && (attributes->fRightType == kInt || type1 == kInt)) {
1342             operand2.fS32 = SkScalarFloorToInt(operand2.fScalar);
1343             type2 = kInt;
1344         }
1345     }
1346     if (type2 == kScalar)
1347         op = (SkOp) (op + 1);
1348     else if (type2 == kString)
1349         op = (SkOp) (op + 2);
1350     switch(op) {
1351         case kAddInt:
1352             operand2.fS32 += operand1.fS32;
1353             break;
1354         case kAddScalar:
1355             operand2.fScalar += operand1.fScalar;
1356             break;
1357         case kAddString:
1358             if (fTrackString.find(operand1.fString) < 0) {
1359                 operand1.fString = new SkString(*operand1.fString);
1360                 track(operand1.fString);
1361             }
1362             operand1.fString->append(*operand2.fString);
1363             operand2 = operand1;
1364             break;
1365         case kBitAnd:
1366             operand2.fS32 &= operand1.fS32;
1367             break;
1368         case kBitNot:
1369             operand2.fS32 = ~operand2.fS32;
1370             break;
1371         case kBitOr:
1372             operand2.fS32 |= operand1.fS32;
1373             break;
1374         case kDivideInt:
1375             if (operand2.fS32 == 0) {
1376                 operand2.fS32 = operand1.fS32 == 0 ? SK_NaN32 : operand1.fS32 > 0 ? SK_MaxS32 : -SK_MaxS32;
1377                 break;
1378             } else {
1379                 int32_t original = operand2.fS32;
1380                 operand2.fS32 = operand1.fS32 / operand2.fS32;
1381                 if (original * operand2.fS32 == operand1.fS32)
1382                     break;    // integer divide was good enough
1383                 operand2.fS32 = original;
1384                 type2 = kScalar;
1385             }
1386         case kDivideScalar:
1387             if (operand2.fScalar == 0)
1388                 operand2.fScalar = operand1.fScalar == 0 ? SK_ScalarNaN : operand1.fScalar > 0 ? SK_ScalarMax : -SK_ScalarMax;
1389             else
1390                 operand2.fScalar = operand1.fScalar / operand2.fScalar;
1391             break;
1392         case kEqualInt:
1393             operand2.fS32 = operand1.fS32 == operand2.fS32;
1394             break;
1395         case kEqualScalar:
1396             operand2.fS32 = operand1.fScalar == operand2.fScalar;
1397             type2 = kInt;
1398             break;
1399         case kEqualString:
1400             operand2.fS32 = *operand1.fString == *operand2.fString;
1401             type2 = kInt;
1402             break;
1403         case kGreaterEqualInt:
1404             operand2.fS32 = operand1.fS32 >= operand2.fS32;
1405             break;
1406         case kGreaterEqualScalar:
1407             operand2.fS32 = operand1.fScalar >= operand2.fScalar;
1408             type2 = kInt;
1409             break;
1410         case kGreaterEqualString:
1411             operand2.fS32 = strcmp(operand1.fString->c_str(), operand2.fString->c_str()) >= 0;
1412             type2 = kInt;
1413             break;
1414         case kLogicalAnd:
1415             operand2.fS32 = !! operand2.fS32;   // really, ToBool
1416             break;
1417         case kLogicalNot:
1418             operand2.fS32 = ! operand2.fS32;
1419             break;
1420         case kLogicalOr:
1421             SkASSERT(0);    // should have already been processed
1422             break;
1423         case kMinusInt:
1424             operand2.fS32 = -operand2.fS32;
1425             break;
1426         case kMinusScalar:
1427             operand2.fScalar = -operand2.fScalar;
1428             break;
1429         case kModuloInt:
1430             operand2.fS32 = operand1.fS32 % operand2.fS32;
1431             break;
1432         case kModuloScalar:
1433             operand2.fScalar = SkScalarMod(operand1.fScalar, operand2.fScalar);
1434             break;
1435         case kMultiplyInt:
1436             operand2.fS32 *= operand1.fS32;
1437             break;
1438         case kMultiplyScalar:
1439             operand2.fScalar = SkScalarMul(operand1.fScalar, operand2.fScalar);
1440             break;
1441         case kShiftLeft:
1442             operand2.fS32 = operand1.fS32 << operand2.fS32;
1443             break;
1444         case kShiftRight:
1445             operand2.fS32 = operand1.fS32 >> operand2.fS32;
1446             break;
1447         case kSubtractInt:
1448             operand2.fS32 = operand1.fS32 - operand2.fS32;
1449             break;
1450         case kSubtractScalar:
1451             operand2.fScalar = operand1.fScalar - operand2.fScalar;
1452             break;
1453         case kXor:
1454             operand2.fS32 ^= operand1.fS32;
1455             break;
1456         default:
1457             SkASSERT(0);
1458     }
1459     fTypeStack.push(type2);
1460     fOperandStack.push(operand2);
1461     return true;
1462 }
1463 
propertyCallBack(_propertyCallBack prop,void * userStorage)1464 void SkScriptEngine::propertyCallBack(_propertyCallBack prop, void* userStorage) {
1465     UserCallBack callBack;
1466     callBack.fPropertyCallBack = prop;
1467     commonCallBack(kProperty, callBack, userStorage);
1468 }
1469 
track(SkTypedArray * array)1470 void SkScriptEngine::track(SkTypedArray* array) {
1471     SkASSERT(fTrackArray.find(array) < 0);
1472     *(fTrackArray.end() - 1) = array;
1473     fTrackArray.appendClear();
1474 }
1475 
track(SkString * string)1476 void SkScriptEngine::track(SkString* string) {
1477     SkASSERT(fTrackString.find(string) < 0);
1478     *(fTrackString.end() - 1) = string;
1479     fTrackString.appendClear();
1480 }
1481 
unboxCallBack(_unboxCallBack func,void * userStorage)1482 void SkScriptEngine::unboxCallBack(_unboxCallBack func, void* userStorage) {
1483     UserCallBack callBack;
1484     callBack.fUnboxCallBack = func;
1485     commonCallBack(kUnbox, callBack, userStorage);
1486 }
1487 
ConvertTo(SkScriptEngine * engine,SkDisplayTypes toType,SkScriptValue * value)1488 bool SkScriptEngine::ConvertTo(SkScriptEngine* engine, SkDisplayTypes toType, SkScriptValue* value ) {
1489     SkASSERT(value);
1490     if (SkDisplayType::IsEnum(nullptr /* fMaker */, toType))
1491         toType = SkType_Int;
1492     if (toType == SkType_Point || toType == SkType_3D_Point)
1493         toType = SkType_Float;
1494     if (toType == SkType_Drawable)
1495         toType = SkType_Displayable;
1496     SkDisplayTypes type = value->fType;
1497     if (type == toType)
1498         return true;
1499     SkOperand& operand = value->fOperand;
1500     bool success = true;
1501     switch (toType) {
1502         case SkType_Int:
1503             if (type == SkType_Boolean)
1504                 break;
1505             if (type == SkType_Float)
1506                 operand.fS32 = SkScalarFloorToInt(operand.fScalar);
1507             else {
1508                 if (type != SkType_String) {
1509                     success = false;
1510                     break; // error
1511                 }
1512                 success = SkParse::FindS32(operand.fString->c_str(), &operand.fS32) != nullptr;
1513             }
1514             break;
1515         case SkType_Float:
1516             if (type == SkType_Int) {
1517                 if (operand.fS32 == SK_NaN32)
1518                     operand.fScalar = SK_ScalarNaN;
1519                 else if (SkAbs32(operand.fS32) == SK_MaxS32)
1520                     operand.fScalar = SkSign32(operand.fS32) * SK_ScalarMax;
1521                 else
1522                     operand.fScalar = SkIntToScalar(operand.fS32);
1523             } else {
1524                 if (type != SkType_String) {
1525                     success = false;
1526                     break; // error
1527                 }
1528                 success = SkParse::FindScalar(operand.fString->c_str(), &operand.fScalar) != nullptr;
1529             }
1530             break;
1531         case SkType_String: {
1532             SkString* strPtr = new SkString();
1533             SkASSERT(engine);
1534             engine->track(strPtr);
1535             if (type == SkType_Int) {
1536                 strPtr->appendS32(operand.fS32);
1537             } else if (type == SkType_Displayable) {
1538                 SkASSERT(0); // must call through instance version instead of static version
1539             } else {
1540                 if (type != SkType_Float) {
1541                     success = false;
1542                     break;
1543                 }
1544                 strPtr->appendScalar(operand.fScalar);
1545             }
1546             operand.fString = strPtr;
1547             } break;
1548         case SkType_Array: {
1549             SkTypedArray* array = new SkTypedArray(type);
1550             *array->append() = operand;
1551             engine->track(array);
1552             operand.fArray = array;
1553             } break;
1554         default:
1555             SkASSERT(0);
1556     }
1557     value->fType = toType;
1558     if (success == false)
1559         engine->fError = kTypeConversionFailed;
1560     return success;
1561 }
1562 
IntToScalar(int32_t s32)1563 SkScalar SkScriptEngine::IntToScalar(int32_t s32) {
1564     SkScalar scalar;
1565     if (s32 == SK_NaN32)
1566         scalar = SK_ScalarNaN;
1567     else if (SkAbs32(s32) == SK_MaxS32)
1568         scalar = SkSign32(s32) * SK_ScalarMax;
1569     else
1570         scalar = SkIntToScalar(s32);
1571     return scalar;
1572 }
1573 
ToDisplayType(SkOpType type)1574 SkDisplayTypes SkScriptEngine::ToDisplayType(SkOpType type) {
1575     int val = type;
1576     switch (val) {
1577         case kNoType:
1578             return SkType_Unknown;
1579         case kInt:
1580             return SkType_Int;
1581         case kScalar:
1582             return SkType_Float;
1583         case kString:
1584             return SkType_String;
1585         case kArray:
1586             return SkType_Array;
1587         case kObject:
1588             return SkType_Displayable;
1589 //      case kStruct:
1590 //          return SkType_Structure;
1591         default:
1592             SkASSERT(0);
1593             return SkType_Unknown;
1594     }
1595 }
1596 
ToOpType(SkDisplayTypes type)1597 SkScriptEngine::SkOpType SkScriptEngine::ToOpType(SkDisplayTypes type) {
1598     if (SkDisplayType::IsDisplayable(nullptr /* fMaker */, type))
1599         return (SkOpType) kObject;
1600     if (SkDisplayType::IsEnum(nullptr /* fMaker */, type))
1601         return kInt;
1602     switch (type) {
1603         case SkType_ARGB:
1604         case SkType_MSec:
1605         case SkType_Int:
1606             return kInt;
1607         case SkType_Float:
1608         case SkType_Point:
1609         case SkType_3D_Point:
1610             return kScalar;
1611         case SkType_Base64:
1612         case SkType_DynamicString:
1613         case SkType_String:
1614             return kString;
1615         case SkType_Array:
1616             return (SkOpType) kArray;
1617         case SkType_Unknown:
1618             return kNoType;
1619         default:
1620             SkASSERT(0);
1621             return kNoType;
1622     }
1623 }
1624 
ValueToString(SkScriptValue value,SkString * string)1625 bool SkScriptEngine::ValueToString(SkScriptValue value, SkString* string) {
1626     switch (value.fType) {
1627         case kInt:
1628             string->reset();
1629             string->appendS32(value.fOperand.fS32);
1630             break;
1631         case kScalar:
1632             string->reset();
1633             string->appendScalar(value.fOperand.fScalar);
1634             break;
1635         case kString:
1636             string->set(*value.fOperand.fString);
1637             break;
1638         default:
1639             SkASSERT(0);
1640             return false;
1641     }
1642     return true; // no error
1643 }
1644 
1645 #ifdef SK_SUPPORT_UNITTEST
1646 
1647 #include "SkFloatingPoint.h"
1648 
1649 #define DEF_SCALAR_ANSWER   0
1650 #define DEF_STRING_ANSWER   nullptr
1651 
1652 #define testInt(expression) { #expression, SkType_Int, expression, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }
1653     #define testScalar(expression) { #expression, SkType_Float, 0, (float) expression, DEF_STRING_ANSWER }
1654     #define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkType_Float, 0, sk_float_mod(exp1, exp2), DEF_STRING_ANSWER }
1655 #define testTrue(expression) { #expression, SkType_Int, 1, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }
1656 #define testFalse(expression) { #expression, SkType_Int, 0, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER }
1657 
1658 static const SkScriptNAnswer scriptTests[]  = {
1659     testInt(1>1/2),
1660     testInt((6+7)*8),
1661     testInt(0&&1?2:3),
1662     testInt(3*(4+5)),
1663     testScalar(1.0+2.0),
1664     testScalar(1.0+5),
1665     testScalar(3.0-1.0),
1666     testScalar(6-1.0),
1667     testScalar(- -5.5- -1.5),
1668     testScalar(2.5*6.),
1669     testScalar(0.5*4),
1670     testScalar(4.5/.5),
1671     testScalar(9.5/19),
1672     testRemainder(9.5, 0.5),
1673     testRemainder(9.,2),
1674     testRemainder(9,2.5),
1675     testRemainder(-9,2.5),
1676     testTrue(-9==-9.0),
1677     testTrue(-9.==-4.0-5),
1678     testTrue(-9.*1==-4-5),
1679     testFalse(-9!=-9.0),
1680     testFalse(-9.!=-4.0-5),
1681     testFalse(-9.*1!=-4-5),
1682     testInt(0x123),
1683     testInt(0XABC),
1684     testInt(0xdeadBEEF),
1685     {   "'123'+\"456\"", SkType_String, 0, 0, "123456" },
1686     {   "123+\"456\"", SkType_String, 0, 0, "123456" },
1687     {   "'123'+456", SkType_String, 0, 0, "123456" },
1688     {   "'123'|\"456\"", SkType_Int, 123|456, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER },
1689     {   "123|\"456\"", SkType_Int, 123|456, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER },
1690     {   "'123'|456", SkType_Int, 123|456, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER },
1691     {   "'2'<11", SkType_Int, 1, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER },
1692     {   "2<'11'", SkType_Int, 1, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER },
1693     {   "'2'<'11'", SkType_Int, 0, DEF_SCALAR_ANSWER, DEF_STRING_ANSWER },
1694     testInt(123),
1695     testInt(-345),
1696     testInt(+678),
1697     testInt(1+2+3),
1698     testInt(3*4+5),
1699     testInt(6+7*8),
1700     testInt(-1-2-8/4),
1701     testInt(-9%4),
1702     testInt(9%-4),
1703     testInt(-9%-4),
1704     testInt(123|978),
1705     testInt(123&978),
1706     testInt(123^978),
1707     testInt(2<<4),
1708     testInt(99>>3),
1709     testInt(~55),
1710     testInt(~~55),
1711     testInt(!55),
1712     testInt(!!55),
1713     // both int
1714     testInt(2<2),
1715     testInt(2<11),
1716     testInt(20<11),
1717     testInt(2<=2),
1718     testInt(2<=11),
1719     testInt(20<=11),
1720     testInt(2>2),
1721     testInt(2>11),
1722     testInt(20>11),
1723     testInt(2>=2),
1724     testInt(2>=11),
1725     testInt(20>=11),
1726     testInt(2==2),
1727     testInt(2==11),
1728     testInt(20==11),
1729     testInt(2!=2),
1730     testInt(2!=11),
1731     testInt(20!=11),
1732     // left int, right scalar
1733     testInt(2<2.),
1734     testInt(2<11.),
1735     testInt(20<11.),
1736     testInt(2<=2.),
1737     testInt(2<=11.),
1738     testInt(20<=11.),
1739     testInt(2>2.),
1740     testInt(2>11.),
1741     testInt(20>11.),
1742     testInt(2>=2.),
1743     testInt(2>=11.),
1744     testInt(20>=11.),
1745     testInt(2==2.),
1746     testInt(2==11.),
1747     testInt(20==11.),
1748     testInt(2!=2.),
1749     testInt(2!=11.),
1750     testInt(20!=11.),
1751     // left scalar, right int
1752         testInt(2.<2),
1753     testInt(2.<11),
1754     testInt(20.<11),
1755     testInt(2.<=2),
1756     testInt(2.<=11),
1757     testInt(20.<=11),
1758     testInt(2.>2),
1759     testInt(2.>11),
1760     testInt(20.>11),
1761     testInt(2.>=2),
1762     testInt(2.>=11),
1763     testInt(20.>=11),
1764     testInt(2.==2),
1765     testInt(2.==11),
1766     testInt(20.==11),
1767     testInt(2.!=2),
1768     testInt(2.!=11),
1769     testInt(20.!=11),
1770     // both scalar
1771     testInt(2.<11.),
1772     testInt(20.<11.),
1773     testInt(2.<=2.),
1774     testInt(2.<=11.),
1775     testInt(20.<=11.),
1776     testInt(2.>2.),
1777     testInt(2.>11.),
1778     testInt(20.>11.),
1779     testInt(2.>=2.),
1780     testInt(2.>=11.),
1781     testInt(20.>=11.),
1782     testInt(2.==2.),
1783     testInt(2.==11.),
1784     testInt(20.==11.),
1785     testInt(2.!=2.),
1786     testInt(2.!=11.),
1787     testInt(20.!=11.),
1788     // int, string (string is int)
1789     testFalse(2<'2'),
1790     testTrue(2<'11'),
1791     testFalse(20<'11'),
1792     testTrue(2<='2'),
1793     testTrue(2<='11'),
1794     testFalse(20<='11'),
1795     testFalse(2>'2'),
1796     testFalse(2>'11'),
1797     testTrue(20>'11'),
1798     testTrue(2>='2'),
1799     testFalse(2>='11'),
1800     testTrue(20>='11'),
1801     testTrue(2=='2'),
1802     testFalse(2=='11'),
1803     testFalse(2!='2'),
1804     testTrue(2!='11'),
1805     // int, string (string is scalar)
1806     testFalse(2<'2.'),
1807     testTrue(2<'11.'),
1808     testFalse(20<'11.'),
1809     testTrue(2=='2.'),
1810     testFalse(2=='11.'),
1811     // scalar, string
1812     testFalse(2.<'2.'),
1813     testTrue(2.<'11.'),
1814     testFalse(20.<'11.'),
1815     testTrue(2.=='2.'),
1816     testFalse(2.=='11.'),
1817     // string, int
1818     testFalse('2'<2),
1819     testTrue('2'<11),
1820     testFalse('20'<11),
1821     testTrue('2'==2),
1822     testFalse('2'==11),
1823     // string, scalar
1824     testFalse('2'<2.),
1825     testTrue('2'<11.),
1826     testFalse('20'<11.),
1827     testTrue('2'==2.),
1828     testFalse('2'==11.),
1829     // string, string
1830     testFalse('2'<'2'),
1831     testFalse('2'<'11'),
1832     testFalse('20'<'11'),
1833     testTrue('2'=='2'),
1834     testFalse('2'=='11'),
1835     // logic
1836     testInt(1?2:3),
1837     testInt(0?2:3),
1838     testInt((1&&2)||3),
1839     testInt((1&&0)||3),
1840     testInt((1&&0)||0),
1841     testInt(1||(0&&3)),
1842     testInt(0||(0&&3)),
1843     testInt(0||(1&&3)),
1844     testInt(1?(2?3:4):5),
1845     testInt(0?(2?3:4):5),
1846     testInt(1?(0?3:4):5),
1847     testInt(0?(0?3:4):5),
1848     testInt(1?2?3:4:5),
1849     testInt(0?2?3:4:5),
1850     testInt(1?0?3:4:5),
1851     testInt(0?0?3:4:5),
1852 
1853     testInt(1?2:(3?4:5)),
1854     testInt(0?2:(3?4:5)),
1855     testInt(1?0:(3?4:5)),
1856     testInt(0?0:(3?4:5)),
1857     testInt(1?2:3?4:5),
1858     testInt(0?2:3?4:5),
1859     testInt(1?0:3?4:5),
1860     testInt(0?0:3?4:5)
1861     , { "123.5", SkType_Float, 0, SkIntToScalar(123) + SK_Scalar1/2, DEF_STRING_ANSWER }
1862 };
1863 
1864 #define SkScriptNAnswer_testCount   SK_ARRAY_COUNT(scriptTests)
1865 
UnitTest()1866 void SkScriptEngine::UnitTest() {
1867     for (unsigned index = 0; index < SkScriptNAnswer_testCount; index++) {
1868         SkScriptEngine engine(SkScriptEngine::ToOpType(scriptTests[index].fType));
1869         SkScriptValue value;
1870         const char* script = scriptTests[index].fScript;
1871         SkASSERT(engine.evaluateScript(&script, &value) == true);
1872         SkASSERT(value.fType == scriptTests[index].fType);
1873         SkScalar error;
1874         switch (value.fType) {
1875             case SkType_Int:
1876                 SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer);
1877                 break;
1878             case SkType_Float:
1879                 error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer);
1880                 SkASSERT(error < SK_Scalar1 / 10000);
1881                 break;
1882             case SkType_String:
1883                 SkASSERT(strcmp(value.fOperand.fString->c_str(), scriptTests[index].fStringAnswer) == 0);
1884                 break;
1885             default:
1886                 SkASSERT(0);
1887         }
1888     }
1889 }
1890 #endif
1891