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