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, ¶ms);
381 if (success)
382 success = handleMemberFunction(field, fieldLength, object, ¶ms);
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, ¶ms);
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