| OLD | NEW |
| (Empty) |
| 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::kStrin
g), | |
| 13 SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kStr
ing), 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 }, // kD
ivide | |
| 19 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kStrin
g), | |
| 20 SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar |SkOperand2:: kStr
ing), kTowardsNumber, | |
| 21 kResultIsBoolean }, // kEqual | |
| 22 { SkOperand2::kS32 }, // kFlipOps | |
| 23 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kStrin
g), | |
| 24 SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar | SkOperand2::kStr
ing), kTowardsNumber, | |
| 25 kResultIsBoolean }, // kGreaterEqual | |
| 26 { SkOperand2::kNoType, SkOperand2::kS32, kNoBias }, // kLogicalAnd (really, T
oBool) | |
| 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 }, // kM
odulo | |
| 32 { SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), | |
| 33 SkOperand2::OpType(SkOperand2::kS32 | SkOperand2::kScalar), kNoBias }, // kM
ultiply | |
| 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 }, // kS
ubtract | |
| 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 | |
| 92 static inline bool is_between(int c, int min, int max) | |
| 93 { | |
| 94 return (unsigned)(c - min) <= (unsigned)(max - min); | |
| 95 } | |
| 96 | |
| 97 static inline bool is_ws(int c) | |
| 98 { | |
| 99 return is_between(c, 1, 32); | |
| 100 } | |
| 101 | |
| 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(c
h, '0', '9') || | |
| 110 ch == '_' || ch == '$'); | |
| 111 return length; | |
| 112 } | |
| 113 | |
| 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 | |
| 124 SkScriptEngine2::~SkScriptEngine2() { | |
| 125 for (SkString** stringPtr = fTrackString.begin(); stringPtr < fTrackString.e
nd(); stringPtr++) | |
| 126 delete *stringPtr; | |
| 127 for (SkOpArray** arrayPtr = fTrackArray.begin(); arrayPtr < fTrackArray.end(
); arrayPtr++) | |
| 128 delete *arrayPtr; | |
| 129 } | |
| 130 | |
| 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 | |
| 146 void SkScriptEngine2::addTokenConst(SkScriptValue2* value, AddTokenRegister reg,
| |
| 147 SkOperand2::OpType toType, SkScriptEngine2::
TypeOp op) { | |
| 148 if (value->fIsConstant == SkScriptValue2::kConstant && convertTo(toType, val
ue)) | |
| 149 return; | |
| 150 addTokenValue(*value, reg); | |
| 151 addToken(op); | |
| 152 value->fIsWritten = SkScriptValue2::kWritten; | |
| 153 value->fType = toType; | |
| 154 } | |
| 155 | |
| 156 void SkScriptEngine2::addTokenInt(int integer) { | |
| 157 fActiveStream->write(&integer, sizeof(integer)); | |
| 158 } | |
| 159 | |
| 160 void SkScriptEngine2::addTokenScalar(SkScalar scalar) { | |
| 161 fActiveStream->write(&scalar, sizeof(scalar)); | |
| 162 } | |
| 163 | |
| 164 void SkScriptEngine2::addTokenString(const SkString& string) { | |
| 165 int size = string.size(); | |
| 166 addTokenInt(size); | |
| 167 fActiveStream->write(string.c_str(), size); | |
| 168 } | |
| 169 | |
| 170 void SkScriptEngine2::addTokenValue(const SkScriptValue2& value, AddTokenRegiste
r 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 | |
| 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 o
f | |
| 220 // suppressing errors like +"hi" | |
| 221 if (lastPush == false) // unary plus, don't push an operator | |
| 222 goto returnAdv; | |
| 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 goto returnAdv; | |
| 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 returnAdv: | |
| 323 return advance; | |
| 324 } | |
| 325 | |
| 326 bool SkScriptEngine2::convertParams(SkTDArray<SkScriptValue2>* params, | |
| 327 const SkOperand2::OpType* paramTypes, int pa
ramCount) { | |
| 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 | |
| 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 | |
| 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 | |
| 365 bool SkScriptEngine2::evaluateDotParam(const char*& script, const char* field, s
ize_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 | |
| 387 bool SkScriptEngine2::evaluateScript(const char** scriptPtr, SkScriptValue2* val
ue) { | |
| 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::kSt
ring) { | |
| 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 wri
tten as "[50, 0]" | |
| 407 return false; | |
| 408 } | |
| 409 return success; | |
| 410 } | |
| 411 | |
| 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 | |
| 433 bool SkScriptEngine2::functionParams(const char** scriptPtr, SkTDArray<SkScriptV
alue2>* 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 | |
| 451 size_t SkScriptEngine2::getTokenOffset() { | |
| 452 return fActiveStream->getOffset(); | |
| 453 } | |
| 454 | |
| 455 SkOperand2::OpType SkScriptEngine2::getUnboxType(SkOperand2 scriptValue) { | |
| 456 for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallB
ackArray.end(); callBack++) { | |
| 457 if ((*callBack)->getType() != SkScriptCallBack::kUnbox) | |
| 458 continue; | |
| 459 return (*callBack)->getReturnType(0, &scriptValue); | |
| 460 } | |
| 461 return SkOperand2::kObject; | |
| 462 } | |
| 463 | |
| 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 conversion
s | |
| 489 if (value->fOperand.fArray->count() == 0) | |
| 490 value->fOperand.fArray->setType(type = tokenValue.fT
ype); | |
| 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().fTy
pe : 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 pro
perty 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 (err
or?) | |
| 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 | |
| 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 | |
| 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 < fC
allBackArray.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 | |
| 823 bool SkScriptEngine2::handleMember(const char* field, size_t len, void* object)
{ | |
| 824 bool success = true; | |
| 825 for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallB
ackArray.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 | |
| 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 < fCallB
ackArray.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 | |
| 864 bool SkScriptEngine2::handleProperty() { | |
| 865 bool success = true; | |
| 866 for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallB
ackArray.end(); callBack++) { | |
| 867 if ((*callBack)->getType() != SkScriptCallBack::kProperty) | |
| 868 continue; | |
| 869 SkScriptValue2 callbackResult; | |
| 870 success = (*callBack)->getReference(fToken, fTokenLength, &callbackResul
t); | |
| 871 if (success) { | |
| 872 if (callbackResult.fType == SkOperand2::kString && callbackResult.fO
perand.fString == NULL) { | |
| 873 callbackResult.fOperand.fString = new SkString(fToken, fTokenLen
gth); | |
| 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 | |
| 886 bool SkScriptEngine2::handleUnbox(SkScriptValue2* scriptValue) { | |
| 887 bool success = true; | |
| 888 for (SkScriptCallBack** callBack = fCallBackArray.begin(); callBack < fCallB
ackArray.end(); callBack++) { | |
| 889 if ((*callBack)->getType() != SkScriptCallBack::kUnbox) | |
| 890 continue; | |
| 891 SkScriptCallBackConvert* callBackConvert = (SkScriptCallBackConvert*) *c
allBack; | |
| 892 success = callBackConvert->convert(scriptValue->fType, &scriptValue->fOp
erand); | |
| 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 | |
| 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 | |
| 968 void SkScriptEngine2::processLogicalOp(Op op) { | |
| 969 switch (op) { | |
| 970 case kParen: | |
| 971 case kArrayOp: | |
| 972 SkASSERT(fOpStack.count() > 1 && fOpStack.top() == op); // !!! ad
d 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 == SkOpe
rand2::kScalar); // !!! add error handling (although, could permit strings event
ually) | |
| 979 int index = value.fType == SkOperand2::kScalar ? SkScalarFloor(v
alue.fOperand.fScalar) : | |
| 980 value.fOperand.fS32; | |
| 981 SkScriptValue2 arrayValue; | |
| 982 fValueStack.pop(&arrayValue); | |
| 983 SkASSERT(arrayValue.fType == SkOperand2::kArray); // !!! add er
ror 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); // !!! ad
d 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 | |
| 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->f
LeftType) == 0) { | |
| 1075 value1.fType = getUnboxType(value1.fOperand); | |
| 1076 addToken(kUnboxToken); | |
| 1077 } | |
| 1078 } | |
| 1079 if (value2.fType == SkOperand2::kObject && (value2.fType & attributes->fLeft
Type) == 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->fBi
as & kTowardsString && | |
| 1086 ((value1.fType | value2.fType) & SkOperand2::kString)) { | |
| 1087 if (value1.fType == SkOperand2::kS32 || value1.fType == SkOperan
d2::kScalar) { | |
| 1088 addTokenConst(&value1, kAccumulator, SkOperand2::kString, | |
| 1089 value1.fType == SkOperand2::kS32 ? kIntToStrin
g : kScalarToString); | |
| 1090 } | |
| 1091 if (value2.fType == SkOperand2::kS32 || value2.fType == SkOperan
d2::kScalar) { | |
| 1092 addTokenConst(&value2, kOperand, SkOperand2::kString, | |
| 1093 value2.fType == SkOperand2::kS32 ? kIntToStrin
g2 : kScalarToString2); | |
| 1094 } | |
| 1095 } else if (attributes->fLeftType & SkOperand2::kScalar && ((value1.f
Type | value2.fType) & | |
| 1096 SkOperand
2::kScalar)) { | |
| 1097 if (value1.fType == SkOperand2::kS32) | |
| 1098 addTokenConst(&value1, kAccumulator, SkOperand2::kScalar, kI
ntToScalar); | |
| 1099 if (value2.fType == SkOperand2::kS32) | |
| 1100 addTokenConst(&value2, kOperand, SkOperand2::kScalar, kIntTo
Scalar2); | |
| 1101 } | |
| 1102 } | |
| 1103 if ((value1.fType & attributes->fLeftType) == 0 || value1.fType != value
2.fType) { | |
| 1104 if (value1.fType == SkOperand2::kString) | |
| 1105 addTokenConst(&value1, kAccumulator, SkOperand2::kScalar, kStrin
gToScalar); | |
| 1106 if (value1.fType == SkOperand2::kScalar && (attributes->fLeftType ==
SkOperand2::kS32 || | |
| 1107 value2.fType == SkOperan
d2::kS32)) | |
| 1108 addTokenConst(&value1, kAccumulator, SkOperand2::kS32, kScalarTo
Int); | |
| 1109 } | |
| 1110 } | |
| 1111 AddTokenRegister rhRegister = attributes->fLeftType != SkOperand2::kNoType ? | |
| 1112 kOperand : kAccumulator; | |
| 1113 if ((value2.fType & attributes->fRightType) == 0 || value1.fType != value2.f
Type) { | |
| 1114 if (value2.fType == SkOperand2::kString) | |
| 1115 addTokenConst(&value2, rhRegister, SkOperand2::kScalar, kStringToSca
lar2); | |
| 1116 if (value2.fType == SkOperand2::kScalar && (attributes->fRightType == Sk
Operand2::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 | |
| 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 | |
| 1178 void SkScriptEngine2::resolveBranch(SkScriptEngine2::Branch& branch) { | |
| 1179 branch.resolve(fActiveStream, getTokenOffset()); | |
| 1180 } | |
| 1181 | |
| 1182 bool SkScriptEngine2::ConvertTo(SkScriptEngine2* engine, SkOperand2::OpType toTy
pe, 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.fS
32) != 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 | |
| 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 | |
| 1242 bool SkScriptEngine2::ValueToString(const SkScriptValue2& value, SkString* strin
g) { | |
| 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) ex
pression } | |
| 1267 #define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkOperand2::kScalar, 0, fmo
df(exp1, exp2) } | |
| 1268 #else | |
| 1269 #ifdef SK_CAN_USE_FLOAT | |
| 1270 #define testScalar(expression) { #expression, SkOperand2::kScalar, 0, (int) ((ex
pression) * 65536.0f) } | |
| 1271 #define testRemainder(exp1, exp2) { #exp1 "%" #exp2, SkOperand2::kScalar, 0, (in
t) (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 #if !defined(SK_BUILD_FOR_BREW) | |
| 1278 static const SkScriptNAnswer2 scriptTests[] = { | |
| 1279 testInt(1||0&&3), | |
| 1280 #ifdef SK_CAN_USE_FLOAT | |
| 1281 testScalar(- -5.5- -1.5), | |
| 1282 testScalar(1.0+5), | |
| 1283 #endif | |
| 1284 testInt((6+7)*8), | |
| 1285 testInt(3*(4+5)), | |
| 1286 #ifdef SK_CAN_USE_FLOAT | |
| 1287 testScalar(1.0+2.0), | |
| 1288 testScalar(3.0-1.0), | |
| 1289 testScalar(6-1.0), | |
| 1290 testScalar(2.5*6.), | |
| 1291 testScalar(0.5*4), | |
| 1292 testScalar(4.5/.5), | |
| 1293 testScalar(9.5/19), | |
| 1294 testRemainder(9.5, 0.5), | |
| 1295 testRemainder(9.,2), | |
| 1296 testRemainder(9,2.5), | |
| 1297 testRemainder(-9,2.5), | |
| 1298 testTrue(-9==-9.0), | |
| 1299 testTrue(-9.==-4.0-5), | |
| 1300 testTrue(-9.*1==-4-5), | |
| 1301 testFalse(-9!=-9.0), | |
| 1302 testFalse(-9.!=-4.0-5), | |
| 1303 testFalse(-9.*1!=-4-5), | |
| 1304 #endif | |
| 1305 testInt(0x123), | |
| 1306 testInt(0XABC), | |
| 1307 testInt(0xdeadBEEF), | |
| 1308 { "'123'+\"456\"", SkOperand2::kString, 0, 0, "123456" }, | |
| 1309 { "123+\"456\"", SkOperand2::kString, 0, 0, "123456" }, | |
| 1310 { "'123'+456", SkOperand2::kString, 0, 0, "123456" }, | |
| 1311 { "'123'|\"456\"", SkOperand2::kS32, 123|456 }, | |
| 1312 { "123|\"456\"", SkOperand2::kS32, 123|456 }, | |
| 1313 { "'123'|456", SkOperand2::kS32, 123|456 }, | |
| 1314 { "'2'<11", SkOperand2::kS32, 1 }, | |
| 1315 { "2<'11'", SkOperand2::kS32, 1 }, | |
| 1316 { "'2'<'11'", SkOperand2::kS32, 0 }, | |
| 1317 testInt(123), | |
| 1318 testInt(-345), | |
| 1319 testInt(+678), | |
| 1320 testInt(1+2+3), | |
| 1321 testInt(3*4+5), | |
| 1322 testInt(6+7*8), | |
| 1323 testInt(-1-2-8/4), | |
| 1324 testInt(-9%4), | |
| 1325 testInt(9%-4), | |
| 1326 testInt(-9%-4), | |
| 1327 testInt(123|978), | |
| 1328 testInt(123&978), | |
| 1329 testInt(123^978), | |
| 1330 testInt(2<<4), | |
| 1331 testInt(99>>3), | |
| 1332 testInt(~55), | |
| 1333 testInt(~~55), | |
| 1334 testInt(!55), | |
| 1335 testInt(!!55), | |
| 1336 // both int | |
| 1337 testInt(2<2), | |
| 1338 testInt(2<11), | |
| 1339 testInt(20<11), | |
| 1340 testInt(2<=2), | |
| 1341 testInt(2<=11), | |
| 1342 testInt(20<=11), | |
| 1343 testInt(2>2), | |
| 1344 testInt(2>11), | |
| 1345 testInt(20>11), | |
| 1346 testInt(2>=2), | |
| 1347 testInt(2>=11), | |
| 1348 testInt(20>=11), | |
| 1349 testInt(2==2), | |
| 1350 testInt(2==11), | |
| 1351 testInt(20==11), | |
| 1352 testInt(2!=2), | |
| 1353 testInt(2!=11), | |
| 1354 testInt(20!=11), | |
| 1355 #ifdef SK_CAN_USE_FLOAT | |
| 1356 // left int, right scalar | |
| 1357 testInt(2<2.), | |
| 1358 testInt(2<11.), | |
| 1359 testInt(20<11.), | |
| 1360 testInt(2<=2.), | |
| 1361 testInt(2<=11.), | |
| 1362 testInt(20<=11.), | |
| 1363 testInt(2>2.), | |
| 1364 testInt(2>11.), | |
| 1365 testInt(20>11.), | |
| 1366 testInt(2>=2.), | |
| 1367 testInt(2>=11.), | |
| 1368 testInt(20>=11.), | |
| 1369 testInt(2==2.), | |
| 1370 testInt(2==11.), | |
| 1371 testInt(20==11.), | |
| 1372 testInt(2!=2.), | |
| 1373 testInt(2!=11.), | |
| 1374 testInt(20!=11.), | |
| 1375 // left scalar, right int | |
| 1376 testInt(2.<2), | |
| 1377 testInt(2.<11), | |
| 1378 testInt(20.<11), | |
| 1379 testInt(2.<=2), | |
| 1380 testInt(2.<=11), | |
| 1381 testInt(20.<=11), | |
| 1382 testInt(2.>2), | |
| 1383 testInt(2.>11), | |
| 1384 testInt(20.>11), | |
| 1385 testInt(2.>=2), | |
| 1386 testInt(2.>=11), | |
| 1387 testInt(20.>=11), | |
| 1388 testInt(2.==2), | |
| 1389 testInt(2.==11), | |
| 1390 testInt(20.==11), | |
| 1391 testInt(2.!=2), | |
| 1392 testInt(2.!=11), | |
| 1393 testInt(20.!=11), | |
| 1394 // both scalar | |
| 1395 testInt(2.<11.), | |
| 1396 testInt(20.<11.), | |
| 1397 testInt(2.<=2.), | |
| 1398 testInt(2.<=11.), | |
| 1399 testInt(20.<=11.), | |
| 1400 testInt(2.>2.), | |
| 1401 testInt(2.>11.), | |
| 1402 testInt(20.>11.), | |
| 1403 testInt(2.>=2.), | |
| 1404 testInt(2.>=11.), | |
| 1405 testInt(20.>=11.), | |
| 1406 testInt(2.==2.), | |
| 1407 testInt(2.==11.), | |
| 1408 testInt(20.==11.), | |
| 1409 testInt(2.!=2.), | |
| 1410 testInt(2.!=11.), | |
| 1411 testInt(20.!=11.), | |
| 1412 #endif | |
| 1413 // int, string (string is int) | |
| 1414 testFalse(2<'2'), | |
| 1415 testTrue(2<'11'), | |
| 1416 testFalse(20<'11'), | |
| 1417 testTrue(2<='2'), | |
| 1418 testTrue(2<='11'), | |
| 1419 testFalse(20<='11'), | |
| 1420 testFalse(2>'2'), | |
| 1421 testFalse(2>'11'), | |
| 1422 testTrue(20>'11'), | |
| 1423 testTrue(2>='2'), | |
| 1424 testFalse(2>='11'), | |
| 1425 testTrue(20>='11'), | |
| 1426 testTrue(2=='2'), | |
| 1427 testFalse(2=='11'), | |
| 1428 testFalse(2!='2'), | |
| 1429 testTrue(2!='11'), | |
| 1430 // int, string (string is scalar) | |
| 1431 testFalse(2<'2.'), | |
| 1432 testTrue(2<'11.'), | |
| 1433 testFalse(20<'11.'), | |
| 1434 testTrue(2=='2.'), | |
| 1435 testFalse(2=='11.'), | |
| 1436 #ifdef SK_CAN_USE_FLOAT | |
| 1437 // scalar, string | |
| 1438 testFalse(2.<'2.'), | |
| 1439 testTrue(2.<'11.'), | |
| 1440 testFalse(20.<'11.'), | |
| 1441 testTrue(2.=='2.'), | |
| 1442 testFalse(2.=='11.'), | |
| 1443 // string, int | |
| 1444 testFalse('2'<2), | |
| 1445 testTrue('2'<11), | |
| 1446 testFalse('20'<11), | |
| 1447 testTrue('2'==2), | |
| 1448 testFalse('2'==11), | |
| 1449 // string, scalar | |
| 1450 testFalse('2'<2.), | |
| 1451 testTrue('2'<11.), | |
| 1452 testFalse('20'<11.), | |
| 1453 testTrue('2'==2.), | |
| 1454 testFalse('2'==11.), | |
| 1455 #endif | |
| 1456 // string, string | |
| 1457 testFalse('2'<'2'), | |
| 1458 testFalse('2'<'11'), | |
| 1459 testFalse('20'<'11'), | |
| 1460 testTrue('2'=='2'), | |
| 1461 testFalse('2'=='11'), | |
| 1462 // logic | |
| 1463 testInt(1?2:3), | |
| 1464 testInt(0?2:3), | |
| 1465 testInt(1&&2||3), | |
| 1466 testInt(1&&0||3), | |
| 1467 testInt(1&&0||0), | |
| 1468 testInt(1||0&&3), | |
| 1469 testInt(0||0&&3), | |
| 1470 testInt(0||1&&3), | |
| 1471 testInt(0&&1?2:3) | |
| 1472 #ifdef SK_CAN_USE_FLOAT | |
| 1473 , { "123.5", SkOperand2::kScalar, 0, SkIntToScalar(123) + SK_Scalar1/2 } | |
| 1474 #endif | |
| 1475 }; | |
| 1476 #endif // build for brew | |
| 1477 | |
| 1478 #define SkScriptNAnswer_testCount SK_ARRAY_COUNT(scriptTests) | |
| 1479 | |
| 1480 void SkScriptEngine2::UnitTest() { | |
| 1481 #if !defined(SK_BUILD_FOR_BREW) && defined(SK_SUPPORT_UNITTEST) | |
| 1482 ValidateDecompileTable(); | |
| 1483 for (int index = 0; index < SkScriptNAnswer_testCount; index++) { | |
| 1484 SkScriptEngine2 engine(scriptTests[index].fType); | |
| 1485 SkScriptValue2 value; | |
| 1486 const char* script = scriptTests[index].fScript; | |
| 1487 const char* scriptPtr = script; | |
| 1488 SkASSERT(engine.evaluateScript(&scriptPtr, &value) == true); | |
| 1489 SkASSERT(value.fType == scriptTests[index].fType); | |
| 1490 SkScalar error; | |
| 1491 switch (value.fType) { | |
| 1492 case SkOperand2::kS32: | |
| 1493 if (value.fOperand.fS32 != scriptTests[index].fIntAnswer) | |
| 1494 SkDEBUGF(("script '%s' == value %d != expected answer %d\n",
script, value.fOperand.fS32, scriptTests[index].fIntAnswer)); | |
| 1495 SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer); | |
| 1496 break; | |
| 1497 case SkOperand2::kScalar: | |
| 1498 error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].
fScalarAnswer); | |
| 1499 #ifdef SK_CAN_USE_FLOAT | |
| 1500 if (error >= SK_Scalar1 / 10000) | |
| 1501 SkDEBUGF(("script '%s' == value %g != expected answer %g\n",
script, value.fOperand.fScalar / (1.0f * SK_Scalar1), scriptTests[index].fScala
rAnswer / (1.0f * SK_Scalar1))); | |
| 1502 #endif | |
| 1503 SkASSERT(error < SK_Scalar1 / 10000); | |
| 1504 break; | |
| 1505 case SkOperand2::kString: | |
| 1506 SkASSERT(value.fOperand.fString->equals(scriptTests[index].fStri
ngAnswer)); | |
| 1507 break; | |
| 1508 default: | |
| 1509 SkASSERT(0); | |
| 1510 } | |
| 1511 } | |
| 1512 #endif | |
| 1513 } | |
| 1514 #endif | |
| OLD | NEW |