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