1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/animator/SkAnimatorScript2.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,622 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2011 Google Inc. 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 +#include "SkAnimatorScript2.h" 1.12 +#include "SkAnimateBase.h" 1.13 +#include "SkAnimateMaker.h" 1.14 +#include "SkDisplayTypes.h" 1.15 +#include "SkExtras.h" 1.16 +#include "SkMemberInfo.h" 1.17 +#include "SkOpArray.h" 1.18 +#include "SkParse.h" 1.19 +#include "SkScript2.h" 1.20 +#include "SkScriptCallBack.h" 1.21 + 1.22 +static const SkDisplayEnumMap gEnumMaps[] = { 1.23 + { SkType_AddMode, "indirect|immediate" }, 1.24 + { SkType_Align, "left|center|right" }, 1.25 + { SkType_ApplyMode, "immediate|once" }, 1.26 + { SkType_ApplyTransition, "reverse" }, 1.27 + { SkType_BitmapEncoding, "jpeg|png" }, 1.28 + { SkType_BitmapFormat, "none|A1|A8|Index8|RGB16|RGB32" }, 1.29 + { SkType_Boolean, "false|true" }, 1.30 + { SkType_Cap, "butt|round|square" }, 1.31 + { SkType_EventCode, "none|up|down|left|right|back|end|OK|send|leftSoftKey|rightSoftKey|key0|key1|key2|key3|key4|key5|key6|key7|key8|key9|star|hash" }, 1.32 + { SkType_EventKind, "none|keyChar|keyPress|mouseDown|mouseDrag|mouseMove|mouseUp|onEnd|onLoad|user" }, 1.33 + { SkType_EventMode, "deferred|immediate" }, 1.34 + { SkType_FillType, "winding|evenOdd" }, 1.35 + { SkType_FilterType, "none|bilinear" }, 1.36 + { SkType_FromPathMode, "normal|angle|position" }, 1.37 + { SkType_Join, "miter|round|blunt" }, 1.38 + { SkType_MaskFilterBlurStyle, "normal|solid|outer|inner" }, 1.39 + { SkType_PathDirection, "cw|ccw" }, 1.40 + { SkType_Style, "fill|stroke|strokeAndFill" }, 1.41 + { SkType_TextBoxAlign, "start|center|end" }, 1.42 + { SkType_TextBoxMode, "oneLine|lineBreak" }, 1.43 + { SkType_TileMode, "clamp|repeat|mirror" }, 1.44 + { SkType_Xfermode, "clear|src|dst|srcOver|dstOver|srcIn|dstIn|srcOut|dstOut|" 1.45 + "srcATop|dstATop|xor|darken|lighten" }, 1.46 +}; 1.47 + 1.48 +static int gEnumMapCount = SK_ARRAY_COUNT(gEnumMaps); 1.49 + 1.50 + 1.51 +class SkAnimatorScript_Box : public SkScriptCallBackConvert { 1.52 +public: 1.53 + SkAnimatorScript_Box() {} 1.54 + 1.55 + ~SkAnimatorScript_Box() { 1.56 + for (SkDisplayable** dispPtr = fTrackDisplayable.begin(); dispPtr < fTrackDisplayable.end(); dispPtr++) 1.57 + delete *dispPtr; 1.58 + } 1.59 + 1.60 + virtual bool convert(SkOperand2::OpType type, SkOperand2* operand) { 1.61 + SkDisplayable* displayable; 1.62 + switch (type) { 1.63 + case SkOperand2::kArray: { 1.64 + SkDisplayArray* boxedValue = new SkDisplayArray(*operand->fArray); 1.65 + displayable = boxedValue; 1.66 + } break; 1.67 + case SkOperand2::kS32: { 1.68 + SkDisplayInt* boxedValue = new SkDisplayInt; 1.69 + displayable = boxedValue; 1.70 + boxedValue->value = operand->fS32; 1.71 + } break; 1.72 + case SkOperand2::kScalar: { 1.73 + SkDisplayFloat* boxedValue = new SkDisplayFloat; 1.74 + displayable = boxedValue; 1.75 + boxedValue->value = operand->fScalar; 1.76 + } break; 1.77 + case SkOperand2::kString: { 1.78 + SkDisplayString* boxedValue = new SkDisplayString(*operand->fString); 1.79 + displayable = boxedValue; 1.80 + } break; 1.81 + case SkOperand2::kObject: 1.82 + return true; 1.83 + default: 1.84 + SkASSERT(0); 1.85 + return false; 1.86 + } 1.87 + track(displayable); 1.88 + operand->fObject = (void*) displayable; 1.89 + return true; 1.90 + } 1.91 + 1.92 + virtual SkOperand2::OpType getReturnType(int index) { 1.93 + return SkOperand2::kObject; 1.94 + } 1.95 + 1.96 + virtual Type getType() const { 1.97 + return kBox; 1.98 + } 1.99 + 1.100 + void track(SkDisplayable* displayable) { 1.101 + SkASSERT(fTrackDisplayable.find(displayable) < 0); 1.102 + *fTrackDisplayable.append() = displayable; 1.103 + } 1.104 + 1.105 + SkTDDisplayableArray fTrackDisplayable; 1.106 +}; 1.107 + 1.108 + 1.109 +class SkAnimatorScript_Enum : public SkScriptCallBackProperty { 1.110 +public: 1.111 + SkAnimatorScript_Enum(const char* tokens) : fTokens(tokens) {} 1.112 + 1.113 + virtual bool getConstValue(const char* name, int len, SkOperand2* value) { 1.114 + return SkAnimatorScript2::MapEnums(fTokens, name, len, &value->fS32); 1.115 + } 1.116 + 1.117 +private: 1.118 + const char* fTokens; 1.119 +}; 1.120 + 1.121 + // !!! if type is string, call invoke 1.122 + // if any other type, return original value 1.123 + // distinction is undone: could do this by returning index == 0 only if param is string 1.124 + // still, caller of getParamTypes will attempt to convert param to string (I guess) 1.125 +class SkAnimatorScript_Eval : public SkScriptCallBackFunction { 1.126 +public: 1.127 + SkAnimatorScript_Eval(SkAnimatorScript2* engine) : fEngine(engine) {} 1.128 + 1.129 + virtual bool getIndex(const char* name, int len, size_t* result) { 1.130 + if (SK_LITERAL_STR_EQUAL("eval", name, len) != 0) 1.131 + return false; 1.132 + *result = 0; 1.133 + return true; 1.134 + } 1.135 + 1.136 + virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) { 1.137 + types->setCount(1); 1.138 + SkOperand2::OpType* type = types->begin(); 1.139 + type[0] = SkOperand2::kString; 1.140 + } 1.141 + 1.142 + virtual bool invoke(size_t index, SkOpArray* params, SkOperand2* answer) { 1.143 + SkAnimatorScript2 engine(fEngine->getMaker(), fEngine->getWorking(), 1.144 + SkAnimatorScript2::ToDisplayType(fEngine->getReturnType())); 1.145 + SkOperand2* op = params->begin(); 1.146 + const char* script = op->fString->c_str(); 1.147 + SkScriptValue2 value; 1.148 + return engine.evaluateScript(&script, &value); 1.149 + SkASSERT(value.fType == fEngine->getReturnType()); 1.150 + *answer = value.fOperand; 1.151 + // !!! incomplete ? 1.152 + return true; 1.153 + } 1.154 + 1.155 +private: 1.156 + SkAnimatorScript2* fEngine; 1.157 +}; 1.158 + 1.159 +class SkAnimatorScript_ID : public SkScriptCallBackProperty { 1.160 +public: 1.161 + SkAnimatorScript_ID(SkAnimatorScript2* engine) : fEngine(engine) {} 1.162 + 1.163 + virtual bool getIndex(const char* token, int len, size_t* result) { 1.164 + SkDisplayable* displayable; 1.165 + bool success = fEngine->getMaker().find(token, len, &displayable); 1.166 + if (success == false) { 1.167 + *result = 0; 1.168 + } else { 1.169 + *result = (size_t) displayable; 1.170 + SkDisplayable* working = fEngine->getWorking(); 1.171 + if (displayable->canContainDependents() && working && working->isAnimate()) { 1.172 + SkAnimateBase* animator = (SkAnimateBase*) working; 1.173 + if (animator->isDynamic()) { 1.174 + SkDisplayDepend* depend = (SkDisplayDepend* ) displayable; 1.175 + depend->addDependent(working); 1.176 + } 1.177 + } 1.178 + } 1.179 + return true; 1.180 + } 1.181 + 1.182 + virtual bool getResult(size_t ref, SkOperand2* answer) { 1.183 + answer->fObject = (void*) ref; 1.184 + return true; 1.185 + } 1.186 + 1.187 + virtual SkOperand2::OpType getReturnType(size_t index) { 1.188 + return index == 0 ? SkOperand2::kString : SkOperand2::kObject; 1.189 + } 1.190 + 1.191 +private: 1.192 + SkAnimatorScript2* fEngine; 1.193 +}; 1.194 + 1.195 + 1.196 +class SkAnimatorScript_Member : public SkScriptCallBackMember { 1.197 +public: 1.198 + 1.199 + SkAnimatorScript_Member(SkAnimatorScript2* engine) : fEngine(engine) {} 1.200 + 1.201 + bool getMemberReference(const char* member, size_t len, void* object, SkScriptValue2* ref) { 1.202 + SkDisplayable* displayable = (SkDisplayable*) object; 1.203 + SkString name(member, len); 1.204 + SkDisplayable* named = displayable->contains(name); 1.205 + if (named) { 1.206 + ref->fType = SkOperand2::kObject; 1.207 + ref->fOperand.fObject = named; 1.208 + return true; 1.209 + } 1.210 + const SkMemberInfo* info = displayable->getMember(name.c_str()); 1.211 + if (info == NULL) 1.212 + return false; // !!! add additional error info? 1.213 + ref->fType = SkAnimatorScript2::ToOpType(info->getType()); 1.214 + ref->fOperand.fObject = (void*) info; 1.215 + return true; 1.216 + } 1.217 + 1.218 + bool invoke(size_t ref, void* object, SkOperand2* value) { 1.219 + const SkMemberInfo* info = (const SkMemberInfo* ) ref; 1.220 + SkDisplayable* displayable = (SkDisplayable*) object; 1.221 + if (info->fType == SkType_MemberProperty) { 1.222 + if (displayable->getProperty2(info->propertyIndex(), value) == false) { 1.223 + return false; 1.224 + } 1.225 + } 1.226 + return fEngine->evalMemberCommon(info, displayable, value); 1.227 + } 1.228 + 1.229 + SkAnimatorScript2* fEngine; 1.230 +}; 1.231 + 1.232 + 1.233 +class SkAnimatorScript_MemberFunction : public SkScriptCallBackMemberFunction { 1.234 +public: 1.235 + SkAnimatorScript_MemberFunction(SkAnimatorScript2* engine) : fEngine(engine) {} 1.236 + 1.237 + bool getMemberReference(const char* member, size_t len, void* object, SkScriptValue2* ref) { 1.238 + SkDisplayable* displayable = (SkDisplayable*) object; 1.239 + SkString name(member, len); 1.240 + const SkMemberInfo* info = displayable->getMember(name.c_str()); 1.241 + if (info == NULL || info->fType != SkType_MemberFunction) 1.242 + return false; // !!! add additional error info? 1.243 + ref->fType = SkAnimatorScript2::ToOpType(info->getType()); 1.244 + ref->fOperand.fObject = (void*) info; 1.245 + return true; 1.246 + } 1.247 + 1.248 + virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) { 1.249 + types->setCount(3); 1.250 + SkOperand2::OpType* type = types->begin(); 1.251 + type[0] = type[1] = type[2] = SkOperand2::kS32; 1.252 + } 1.253 + 1.254 + bool invoke(size_t ref, void* object, SkOpArray* params, SkOperand2* value) 1.255 + { 1.256 + const SkMemberInfo* info = (const SkMemberInfo* ) ref; 1.257 + SkDisplayable* displayable = (SkDisplayable*) object; 1.258 + displayable->executeFunction2(displayable, info->functionIndex(), params, info->getType(), 1.259 + value); 1.260 + return fEngine->evalMemberCommon(info, displayable, value); 1.261 + } 1.262 + 1.263 + SkAnimatorScript2* fEngine; 1.264 +}; 1.265 + 1.266 + 1.267 +class SkAnimatorScript_NamedColor : public SkScriptCallBackProperty { 1.268 +public: 1.269 + virtual bool getConstValue(const char* name, int len, SkOperand2* value) { 1.270 + return SkParse::FindNamedColor(name, len, (SkColor*) &value->fS32) != NULL; 1.271 + } 1.272 +}; 1.273 + 1.274 + 1.275 +class SkAnimatorScript_RGB : public SkScriptCallBackFunction { 1.276 +public: 1.277 + virtual bool getIndex(const char* name, int len, size_t* result) { 1.278 + if (SK_LITERAL_STR_EQUAL("rgb", name, len) != 0) 1.279 + return false; 1.280 + *result = 0; 1.281 + return true; 1.282 + } 1.283 + 1.284 + virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) { 1.285 + types->setCount(3); 1.286 + SkOperand2::OpType* type = types->begin(); 1.287 + type[0] = type[1] = type[2] = SkOperand2::kS32; 1.288 + } 1.289 + 1.290 + virtual bool invoke(size_t index, SkOpArray* params, SkOperand2* answer) { 1.291 + SkASSERT(index == 0); 1.292 + unsigned result = 0xFF000000; 1.293 + int shift = 16; 1.294 + for (int index = 0; index < 3; index++) { 1.295 + result |= SkClampMax(params->begin()[index].fS32, 255) << shift; 1.296 + shift -= 8; 1.297 + } 1.298 + answer->fS32 = result; 1.299 + return true; 1.300 + } 1.301 + 1.302 +}; 1.303 + 1.304 + 1.305 +class SkAnimatorScript_Unbox : public SkScriptCallBackConvert { 1.306 +public: 1.307 + SkAnimatorScript_Unbox(SkAnimatorScript2* engine) : fEngine(engine) {} 1.308 + 1.309 + virtual bool convert(SkOperand2::OpType type, SkOperand2* operand) { 1.310 + SkASSERT(type == SkOperand2::kObject); 1.311 + SkDisplayable* displayable = (SkDisplayable*) operand->fObject; 1.312 + switch (displayable->getType()) { 1.313 + case SkType_Array: { 1.314 + SkDisplayArray* boxedValue = (SkDisplayArray*) displayable; 1.315 + operand->fArray = new SkOpArray(SkAnimatorScript2::ToOpType(boxedValue->values.getType())); 1.316 + int count = boxedValue->values.count(); 1.317 + operand->fArray->setCount(count); 1.318 + memcpy(operand->fArray->begin(), boxedValue->values.begin(), count * sizeof(SkOperand2)); 1.319 + fEngine->track(operand->fArray); 1.320 + } break; 1.321 + case SkType_Boolean: { 1.322 + SkDisplayBoolean* boxedValue = (SkDisplayBoolean*) displayable; 1.323 + operand->fS32 = boxedValue->value; 1.324 + } break; 1.325 + case SkType_Int: { 1.326 + SkDisplayInt* boxedValue = (SkDisplayInt*) displayable; 1.327 + operand->fS32 = boxedValue->value; 1.328 + } break; 1.329 + case SkType_Float: { 1.330 + SkDisplayFloat* boxedValue = (SkDisplayFloat*) displayable; 1.331 + operand->fScalar = boxedValue->value; 1.332 + } break; 1.333 + case SkType_String: { 1.334 + SkDisplayString* boxedValue = (SkDisplayString*) displayable; 1.335 + operand->fString = SkNEW_ARGS(SkString, (boxedValue->value)); 1.336 + } break; 1.337 + default: { 1.338 + const char* id; 1.339 + bool success = fEngine->getMaker().findKey(displayable, &id); 1.340 + SkASSERT(success); 1.341 + operand->fString = SkNEW_ARGS(SkString, (id)); 1.342 + } 1.343 + } 1.344 + return true; 1.345 + } 1.346 + 1.347 + virtual SkOperand2::OpType getReturnType(int /*index*/, SkOperand2* operand) { 1.348 + SkDisplayable* displayable = (SkDisplayable*) operand->fObject; 1.349 + switch (displayable->getType()) { 1.350 + case SkType_Array: 1.351 + return SkOperand2::kArray; 1.352 + case SkType_Int: 1.353 + return SkOperand2::kS32; 1.354 + case SkType_Float: 1.355 + return SkOperand2::kScalar; 1.356 + case SkType_String: 1.357 + default: 1.358 + return SkOperand2::kString; 1.359 + } 1.360 + } 1.361 + 1.362 + virtual Type getType() const { 1.363 + return kUnbox; 1.364 + } 1.365 + 1.366 + SkAnimatorScript2* fEngine; 1.367 +}; 1.368 + 1.369 +SkAnimatorScript2::SkAnimatorScript2(SkAnimateMaker& maker, SkDisplayable* working, SkDisplayTypes type) : 1.370 + SkScriptEngine2(ToOpType(type)), fMaker(maker), fWorking(working) { 1.371 + *fCallBackArray.append() = new SkAnimatorScript_Member(this); 1.372 + *fCallBackArray.append() = new SkAnimatorScript_MemberFunction(this); 1.373 + *fCallBackArray.append() = new SkAnimatorScript_Box(); 1.374 + *fCallBackArray.append() = new SkAnimatorScript_Unbox(this); 1.375 + *fCallBackArray.append() = new SkAnimatorScript_ID(this); 1.376 + if (type == SkType_ARGB) { 1.377 + *fCallBackArray.append() = new SkAnimatorScript_RGB(); 1.378 + *fCallBackArray.append() = new SkAnimatorScript_NamedColor(); 1.379 + } 1.380 + if (SkDisplayType::IsEnum(&maker, type)) { 1.381 + // !!! for SpiderMonkey, iterate through the enum values, and map them to globals 1.382 + const SkDisplayEnumMap& map = GetEnumValues(type); 1.383 + *fCallBackArray.append() = new SkAnimatorScript_Enum(map.fValues); 1.384 + } 1.385 + *fCallBackArray.append() = new SkAnimatorScript_Eval(this); 1.386 +#if 0 // !!! no extra support for now 1.387 + for (SkExtras** extraPtr = maker.fExtras.begin(); extraPtr < maker.fExtras.end(); extraPtr++) { 1.388 + SkExtras* extra = *extraPtr; 1.389 + if (extra->fExtraCallBack) 1.390 + *fCallBackArray.append() = new propertyCallBack(extra->fExtraCallBack, extra->fExtraStorage); 1.391 + } 1.392 +#endif 1.393 +} 1.394 + 1.395 +SkAnimatorScript2::~SkAnimatorScript2() { 1.396 + SkScriptCallBack** end = fCallBackArray.end(); 1.397 + for (SkScriptCallBack** ptr = fCallBackArray.begin(); ptr < end; ptr++) 1.398 + delete *ptr; 1.399 +} 1.400 + 1.401 +bool SkAnimatorScript2::evalMemberCommon(const SkMemberInfo* info, 1.402 + SkDisplayable* displayable, SkOperand2* value) { 1.403 + SkDisplayTypes original; 1.404 + SkDisplayTypes type = original = (SkDisplayTypes) info->getType(); 1.405 + if (info->fType == SkType_Array) 1.406 + type = SkType_Array; 1.407 + switch (type) { 1.408 + case SkType_ARGB: 1.409 + type = SkType_Int; 1.410 + case SkType_Boolean: 1.411 + case SkType_Int: 1.412 + case SkType_MSec: 1.413 + case SkType_Float: 1.414 + SkASSERT(info->getCount() == 1); 1.415 + if (info->fType != SkType_MemberProperty && info->fType != SkType_MemberFunction) 1.416 + value->fS32 = *(int32_t*) info->memberData(displayable); // OK for SkScalar too 1.417 + if (type == SkType_MSec) { 1.418 + value->fScalar = SkScalarDiv((SkScalar) value->fS32, 1000); // dividing two ints is the same as dividing two scalars 1.419 + type = SkType_Float; 1.420 + } 1.421 + break; 1.422 + case SkType_String: { 1.423 + SkString* displayableString; 1.424 + if (info->fType != SkType_MemberProperty && info->fType != SkType_MemberFunction) { 1.425 + info->getString(displayable, &displayableString); 1.426 + value->fString = new SkString(*displayableString); 1.427 + } 1.428 + } break; 1.429 + case SkType_Array: { 1.430 + SkASSERT(info->fType != SkType_MemberProperty); // !!! incomplete 1.431 + SkTDOperandArray* displayableArray = (SkTDOperandArray*) info->memberData(displayable); 1.432 + if (displayable->getType() == SkType_Array) { 1.433 + SkDisplayArray* typedArray = (SkDisplayArray*) displayable; 1.434 + original = typedArray->values.getType(); 1.435 + } 1.436 + SkASSERT(original != SkType_Unknown); 1.437 + SkOpArray* array = value->fArray = new SkOpArray(ToOpType(original)); 1.438 + track(array); 1.439 + int count = displayableArray->count(); 1.440 + if (count > 0) { 1.441 + array->setCount(count); 1.442 + memcpy(array->begin(), displayableArray->begin(), count * sizeof(SkOperand2)); 1.443 + } 1.444 + } break; 1.445 + default: 1.446 + SkASSERT(0); // unimplemented 1.447 + } 1.448 + return true; 1.449 +} 1.450 + 1.451 +const SkDisplayEnumMap& SkAnimatorScript2::GetEnumValues(SkDisplayTypes type) { 1.452 + int index = SkTSearch<SkDisplayTypes>(&gEnumMaps[0].fType, gEnumMapCount, type, 1.453 + sizeof(SkDisplayEnumMap)); 1.454 + SkASSERT(index >= 0); 1.455 + return gEnumMaps[index]; 1.456 +} 1.457 + 1.458 +SkDisplayTypes SkAnimatorScript2::ToDisplayType(SkOperand2::OpType type) { 1.459 + int val = type; 1.460 + switch (val) { 1.461 + case SkOperand2::kNoType: 1.462 + return SkType_Unknown; 1.463 + case SkOperand2::kS32: 1.464 + return SkType_Int; 1.465 + case SkOperand2::kScalar: 1.466 + return SkType_Float; 1.467 + case SkOperand2::kString: 1.468 + return SkType_String; 1.469 + case SkOperand2::kArray: 1.470 + return SkType_Array; 1.471 + case SkOperand2::kObject: 1.472 + return SkType_Displayable; 1.473 + default: 1.474 + SkASSERT(0); 1.475 + return SkType_Unknown; 1.476 + } 1.477 +} 1.478 + 1.479 +SkOperand2::OpType SkAnimatorScript2::ToOpType(SkDisplayTypes type) { 1.480 + if (SkDisplayType::IsDisplayable(NULL /* fMaker */, type)) 1.481 + return SkOperand2::kObject; 1.482 + if (SkDisplayType::IsEnum(NULL /* fMaker */, type)) 1.483 + return SkOperand2::kS32; 1.484 + switch (type) { 1.485 + case SkType_ARGB: 1.486 + case SkType_MSec: 1.487 + case SkType_Int: 1.488 + return SkOperand2::kS32; 1.489 + case SkType_Float: 1.490 + case SkType_Point: 1.491 + case SkType_3D_Point: 1.492 + return SkOperand2::kScalar; 1.493 + case SkType_Base64: 1.494 + case SkType_DynamicString: 1.495 + case SkType_String: 1.496 + return SkOperand2::kString; 1.497 + case SkType_Array: 1.498 + return SkOperand2::kArray; 1.499 + case SkType_Unknown: 1.500 + return SkOperand2::kNoType; 1.501 + default: 1.502 + SkASSERT(0); 1.503 + return SkOperand2::kNoType; 1.504 + } 1.505 +} 1.506 + 1.507 +bool SkAnimatorScript2::MapEnums(const char* ptr, const char* match, size_t len, int* value) { 1.508 + int index = 0; 1.509 + bool more = true; 1.510 + do { 1.511 + const char* last = strchr(ptr, '|'); 1.512 + if (last == NULL) { 1.513 + last = &ptr[strlen(ptr)]; 1.514 + more = false; 1.515 + } 1.516 + size_t length = last - ptr; 1.517 + if (len == length && strncmp(ptr, match, length) == 0) { 1.518 + *value = index; 1.519 + return true; 1.520 + } 1.521 + index++; 1.522 + ptr = last + 1; 1.523 + } while (more); 1.524 + return false; 1.525 +} 1.526 + 1.527 +#if defined SK_DEBUG 1.528 + 1.529 +#include "SkAnimator.h" 1.530 + 1.531 +static const char scriptTestSetup[] = 1.532 +"<screenplay>" 1.533 + "<apply>" 1.534 + "<paint>" 1.535 + "<emboss id='emboss' direction='[1,1,1]' />" 1.536 + "</paint>" 1.537 + "<animateField id='animation' field='direction' target='emboss' from='[1,1,1]' to='[-1,1,1]' dur='1'/>" 1.538 + "<set lval='direction[0]' target='emboss' to='-1' />" 1.539 + "</apply>" 1.540 + "<color id='testColor' color='0 ? rgb(0,0,0) : rgb(255,255,255)' />" 1.541 + "<color id='xColor' color='rgb(12,34,56)' />" 1.542 + "<typedArray id='emptyArray' />" 1.543 + "<typedArray id='intArray' values='[1, 4, 6]' />" 1.544 + "<s32 id='idx' value='2' />" 1.545 + "<s32 id='idy' value='2' />" 1.546 + "<string id='alpha' value='abc' />" 1.547 + "<rectangle id='testRect' left='Math.cos(0)' top='2' right='12' bottom='5' />" 1.548 + "<event id='evt'>" 1.549 + "<input name='x' />" 1.550 + "<apply scope='idy'>" 1.551 + "<set field='value' to='evt.x.s32' />" 1.552 + "</apply>" 1.553 + "</event>" 1.554 +"</screenplay>"; 1.555 + 1.556 +static const SkScriptNAnswer scriptTests[] = { 1.557 + { "alpha+alpha", SkType_String, 0, 0, "abcabc" }, 1.558 + { "0 ? Math.sin(0) : 1", SkType_Int, 1 }, 1.559 + { "intArray[4]", SkType_Unknown }, 1.560 + { "emptyArray[4]", SkType_Unknown }, 1.561 + { "idx", SkType_Int, 2 }, 1.562 + { "intArray.length", SkType_Int, 3 }, 1.563 + { "intArray.values[0]", SkType_Int, 1 }, 1.564 + { "intArray[0]", SkType_Int, 1 }, 1.565 + { "idx.value", SkType_Int, 2 }, 1.566 + { "alpha.value", SkType_String, 0, 0, "abc" }, 1.567 + { "alpha", SkType_String, 0, 0, "abc" }, 1.568 + { "alpha.value+alpha.value", SkType_String, 0, 0, "abcabc" }, 1.569 + { "alpha+idx", SkType_String, 0, 0, "abc2" }, 1.570 + { "idx+alpha", SkType_String, 0, 0, "2abc" }, 1.571 + { "intArray[idx]", SkType_Int, 6 }, 1.572 + { "alpha.slice(1,2)", SkType_String, 0, 0, "b" }, 1.573 + { "alpha.value.slice(1,2)", SkType_String, 0, 0, "b" }, 1.574 + { "Math.sin(0)", SkType_Float, 0, SkIntToScalar(0) }, 1.575 + { "testRect.left+2", SkType_Float, 0, SkIntToScalar(3) }, 1.576 + { "0 ? intArray[0] : 1", SkType_Int, 1 }, 1.577 + { "0 ? intArray.values[0] : 1", SkType_Int, 1 }, 1.578 + { "0 ? idx : 1", SkType_Int, 1 }, 1.579 + { "0 ? idx.value : 1", SkType_Int, 1 }, 1.580 + { "0 ? alpha.slice(1,2) : 1", SkType_Int, 1 }, 1.581 + { "0 ? alpha.value.slice(1,2) : 1", SkType_Int, 1 }, 1.582 + { "idy", SkType_Int, 3 } 1.583 +}; 1.584 + 1.585 +#define SkScriptNAnswer_testCount SK_ARRAY_COUNT(scriptTests) 1.586 + 1.587 +void SkAnimatorScript2::UnitTest() { 1.588 +#if defined(SK_SUPPORT_UNITTEST) 1.589 + SkAnimator animator; 1.590 + SkASSERT(animator.decodeMemory(scriptTestSetup, sizeof(scriptTestSetup)-1)); 1.591 + SkEvent evt; 1.592 + evt.setString("id", "evt"); 1.593 + evt.setS32("x", 3); 1.594 + animator.doUserEvent(evt); 1.595 + // set up animator with memory script above, then run value tests 1.596 + for (int index = 0; index < SkScriptNAnswer_testCount; index++) { 1.597 + SkAnimatorScript2 engine(*animator.fMaker, NULL, scriptTests[index].fType); 1.598 + SkScriptValue2 value; 1.599 + const char* script = scriptTests[index].fScript; 1.600 + bool success = engine.evaluateScript(&script, &value); 1.601 + if (success == false) { 1.602 + SkASSERT(scriptTests[index].fType == SkType_Unknown); 1.603 + continue; 1.604 + } 1.605 + SkASSERT(value.fType == ToOpType(scriptTests[index].fType)); 1.606 + SkScalar error; 1.607 + switch (value.fType) { 1.608 + case SkOperand2::kS32: 1.609 + SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer); 1.610 + break; 1.611 + case SkOperand2::kScalar: 1.612 + error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer); 1.613 + SkASSERT(error < SK_Scalar1 / 10000); 1.614 + break; 1.615 + case SkOperand2::kString: 1.616 + SkASSERT(value.fOperand.fString->equals(scriptTests[index].fStringAnswer)); 1.617 + break; 1.618 + default: 1.619 + SkASSERT(0); 1.620 + } 1.621 + } 1.622 +#endif 1.623 +} 1.624 + 1.625 +#endif