Home | History | Annotate | Download | only in animator
      1 
      2 /*
      3  * Copyright 2011 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 #include "SkAnimatorScript2.h"
      9 #include "SkAnimateBase.h"
     10 #include "SkAnimateMaker.h"
     11 #include "SkDisplayTypes.h"
     12 #include "SkExtras.h"
     13 #include "SkMemberInfo.h"
     14 #include "SkOpArray.h"
     15 #include "SkParse.h"
     16 #include "SkScript2.h"
     17 #include "SkScriptCallBack.h"
     18 
     19 static const SkDisplayEnumMap gEnumMaps[] = {
     20     { SkType_AddMode, "indirect|immediate" },
     21     { SkType_Align, "left|center|right" },
     22     { SkType_ApplyMode, "immediate|once" },
     23     { SkType_ApplyTransition, "reverse" },
     24     { SkType_BitmapEncoding, "jpeg|png" },
     25     { SkType_BitmapFormat, "none|A1|A8|Index8|RGB16|RGB32" },
     26     { SkType_Boolean, "false|true" },
     27     { SkType_Cap, "butt|round|square" },
     28     { 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" },
     29     { SkType_EventKind, "none|keyChar|keyPress|mouseDown|mouseDrag|mouseMove|mouseUp|onEnd|onLoad|user" },
     30     { SkType_EventMode, "deferred|immediate" },
     31     { SkType_FillType, "winding|evenOdd" },
     32     { SkType_FilterType, "none|bilinear" },
     33     { SkType_FromPathMode, "normal|angle|position" },
     34     { SkType_Join, "miter|round|blunt" },
     35     { SkType_MaskFilterBlurStyle, "normal|solid|outer|inner" },
     36     { SkType_PathDirection, "cw|ccw" },
     37     { SkType_Style, "fill|stroke|strokeAndFill" },
     38     { SkType_TextBoxAlign, "start|center|end" },
     39     { SkType_TextBoxMode, "oneLine|lineBreak" },
     40     { SkType_TileMode, "clamp|repeat|mirror" },
     41     { SkType_Xfermode, "clear|src|dst|srcOver|dstOver|srcIn|dstIn|srcOut|dstOut|"
     42         "srcATop|dstATop|xor|darken|lighten" },
     43 };
     44 
     45 static int gEnumMapCount = SK_ARRAY_COUNT(gEnumMaps);
     46 
     47 
     48 class SkAnimatorScript_Box : public SkScriptCallBackConvert {
     49 public:
     50     SkAnimatorScript_Box() {}
     51 
     52     ~SkAnimatorScript_Box() {
     53         for (SkDisplayable** dispPtr = fTrackDisplayable.begin(); dispPtr < fTrackDisplayable.end(); dispPtr++)
     54             delete *dispPtr;
     55     }
     56 
     57     virtual bool convert(SkOperand2::OpType type, SkOperand2* operand) {
     58         SkDisplayable* displayable;
     59         switch (type) {
     60             case SkOperand2::kArray: {
     61                 SkDisplayArray* boxedValue = new SkDisplayArray(*operand->fArray);
     62                 displayable = boxedValue;
     63                 } break;
     64             case SkOperand2::kS32: {
     65                 SkDisplayInt* boxedValue = new SkDisplayInt;
     66                 displayable = boxedValue;
     67                 boxedValue->value = operand->fS32;
     68                 } break;
     69             case SkOperand2::kScalar: {
     70                 SkDisplayFloat* boxedValue = new SkDisplayFloat;
     71                 displayable = boxedValue;
     72                 boxedValue->value = operand->fScalar;
     73                 } break;
     74             case SkOperand2::kString: {
     75                 SkDisplayString* boxedValue = new SkDisplayString(*operand->fString);
     76                 displayable = boxedValue;
     77                 } break;
     78             case SkOperand2::kObject:
     79                 return true;
     80             default:
     81                 SkASSERT(0);
     82                 return false;
     83         }
     84         track(displayable);
     85         operand->fObject = (void*) displayable;
     86         return true;
     87     }
     88 
     89     virtual SkOperand2::OpType getReturnType(int index) {
     90         return SkOperand2::kObject;
     91     }
     92 
     93     virtual Type getType() const {
     94         return kBox;
     95     }
     96 
     97     void track(SkDisplayable* displayable) {
     98         SkASSERT(fTrackDisplayable.find(displayable) < 0);
     99         *fTrackDisplayable.append() = displayable;
    100     }
    101 
    102     SkTDDisplayableArray fTrackDisplayable;
    103 };
    104 
    105 
    106 class SkAnimatorScript_Enum : public SkScriptCallBackProperty {
    107 public:
    108     SkAnimatorScript_Enum(const char* tokens) : fTokens(tokens) {}
    109 
    110     virtual bool getConstValue(const char* name, int len, SkOperand2* value) {
    111         return SkAnimatorScript2::MapEnums(fTokens, name, len, &value->fS32);
    112     }
    113 
    114 private:
    115     const char* fTokens;
    116 };
    117 
    118     // !!! if type is string, call invoke
    119     // if any other type, return original value
    120         // distinction is undone: could do this by returning index == 0 only if param is string
    121         // still, caller of getParamTypes will attempt to convert param to string (I guess)
    122 class SkAnimatorScript_Eval : public SkScriptCallBackFunction {
    123 public:
    124     SkAnimatorScript_Eval(SkAnimatorScript2* engine) : fEngine(engine) {}
    125 
    126     virtual bool getIndex(const char* name, int len, size_t* result) {
    127         if (SK_LITERAL_STR_EQUAL("eval", name, len) != 0)
    128             return false;
    129         *result = 0;
    130         return true;
    131     }
    132 
    133     virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) {
    134         types->setCount(1);
    135         SkOperand2::OpType* type = types->begin();
    136         type[0] = SkOperand2::kString;
    137     }
    138 
    139     virtual bool invoke(size_t index, SkOpArray* params, SkOperand2* answer) {
    140         SkAnimatorScript2 engine(fEngine->getMaker(), fEngine->getWorking(),
    141             SkAnimatorScript2::ToDisplayType(fEngine->getReturnType()));
    142         SkOperand2* op = params->begin();
    143         const char* script = op->fString->c_str();
    144         SkScriptValue2 value;
    145         return engine.evaluateScript(&script, &value);
    146         SkASSERT(value.fType == fEngine->getReturnType());
    147         *answer = value.fOperand;
    148         // !!! incomplete ?
    149         return true;
    150     }
    151 
    152 private:
    153     SkAnimatorScript2* fEngine;
    154 };
    155 
    156 class SkAnimatorScript_ID : public SkScriptCallBackProperty {
    157 public:
    158     SkAnimatorScript_ID(SkAnimatorScript2* engine) : fEngine(engine) {}
    159 
    160     virtual bool getIndex(const char* token, int len, size_t* result) {
    161         SkDisplayable* displayable;
    162         bool success = fEngine->getMaker().find(token, len, &displayable);
    163         if (success == false) {
    164             *result = 0;
    165         } else {
    166             *result = (size_t) displayable;
    167             SkDisplayable* working = fEngine->getWorking();
    168             if (displayable->canContainDependents() && working && working->isAnimate()) {
    169                 SkAnimateBase* animator = (SkAnimateBase*) working;
    170                 if (animator->isDynamic()) {
    171                     SkDisplayDepend* depend = (SkDisplayDepend* ) displayable;
    172                     depend->addDependent(working);
    173                 }
    174             }
    175         }
    176         return true;
    177     }
    178 
    179     virtual bool getResult(size_t ref, SkOperand2* answer) {
    180         answer->fObject = (void*) ref;
    181         return true;
    182     }
    183 
    184     virtual SkOperand2::OpType getReturnType(size_t index) {
    185         return index == 0 ? SkOperand2::kString : SkOperand2::kObject;
    186     }
    187 
    188 private:
    189     SkAnimatorScript2* fEngine;
    190 };
    191 
    192 
    193 class SkAnimatorScript_Member : public SkScriptCallBackMember {
    194 public:
    195 
    196     SkAnimatorScript_Member(SkAnimatorScript2* engine) : fEngine(engine) {}
    197 
    198     bool getMemberReference(const char* member, size_t len, void* object, SkScriptValue2* ref) {
    199         SkDisplayable* displayable = (SkDisplayable*) object;
    200         SkString name(member, len);
    201         SkDisplayable* named = displayable->contains(name);
    202         if (named) {
    203             ref->fType = SkOperand2::kObject;
    204             ref->fOperand.fObject = named;
    205             return true;
    206         }
    207         const SkMemberInfo* info = displayable->getMember(name.c_str());
    208         if (info == NULL)
    209             return false;    // !!! add additional error info?
    210         ref->fType = SkAnimatorScript2::ToOpType(info->getType());
    211         ref->fOperand.fObject = (void*) info;
    212         return true;
    213     }
    214 
    215     bool invoke(size_t ref, void* object, SkOperand2* value) {
    216         const SkMemberInfo* info = (const SkMemberInfo* ) ref;
    217         SkDisplayable* displayable = (SkDisplayable*) object;
    218         if (info->fType == SkType_MemberProperty) {
    219             if (displayable->getProperty2(info->propertyIndex(), value) == false) {
    220                 return false;
    221             }
    222         }
    223         return fEngine->evalMemberCommon(info, displayable, value);
    224     }
    225 
    226     SkAnimatorScript2* fEngine;
    227 };
    228 
    229 
    230 class SkAnimatorScript_MemberFunction : public SkScriptCallBackMemberFunction {
    231 public:
    232     SkAnimatorScript_MemberFunction(SkAnimatorScript2* engine) : fEngine(engine) {}
    233 
    234     bool getMemberReference(const char* member, size_t len, void* object, SkScriptValue2* ref) {
    235         SkDisplayable* displayable = (SkDisplayable*) object;
    236         SkString name(member, len);
    237         const SkMemberInfo* info = displayable->getMember(name.c_str());
    238         if (info == NULL || info->fType != SkType_MemberFunction)
    239             return false;    // !!! add additional error info?
    240         ref->fType = SkAnimatorScript2::ToOpType(info->getType());
    241         ref->fOperand.fObject = (void*) info;
    242         return true;
    243     }
    244 
    245     virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) {
    246         types->setCount(3);
    247         SkOperand2::OpType* type = types->begin();
    248         type[0] = type[1] = type[2] = SkOperand2::kS32;
    249     }
    250 
    251     bool invoke(size_t ref, void* object, SkOpArray* params, SkOperand2* value)
    252     {
    253         const SkMemberInfo* info = (const SkMemberInfo* ) ref;
    254         SkDisplayable* displayable = (SkDisplayable*) object;
    255         displayable->executeFunction2(displayable, info->functionIndex(), params, info->getType(),
    256             value);
    257         return fEngine->evalMemberCommon(info, displayable, value);
    258     }
    259 
    260     SkAnimatorScript2* fEngine;
    261 };
    262 
    263 
    264 class SkAnimatorScript_NamedColor : public SkScriptCallBackProperty {
    265 public:
    266     virtual bool getConstValue(const char* name, int len, SkOperand2* value) {
    267         return SkParse::FindNamedColor(name, len, (SkColor*) &value->fS32) != NULL;
    268     }
    269 };
    270 
    271 
    272 class SkAnimatorScript_RGB : public SkScriptCallBackFunction {
    273 public:
    274     virtual bool getIndex(const char* name, int len, size_t* result) {
    275         if (SK_LITERAL_STR_EQUAL("rgb", name, len) != 0)
    276             return false;
    277         *result = 0;
    278         return true;
    279     }
    280 
    281     virtual void getParamTypes(SkIntArray(SkOperand2::OpType)* types) {
    282         types->setCount(3);
    283         SkOperand2::OpType* type = types->begin();
    284         type[0] = type[1] = type[2] = SkOperand2::kS32;
    285     }
    286 
    287     virtual bool invoke(size_t index, SkOpArray* params, SkOperand2* answer) {
    288         SkASSERT(index == 0);
    289         unsigned result = 0xFF000000;
    290         int shift = 16;
    291         for (int index = 0; index < 3; index++) {
    292             result |= SkClampMax(params->begin()[index].fS32, 255) << shift;
    293             shift -= 8;
    294         }
    295         answer->fS32 = result;
    296         return true;
    297     }
    298 
    299 };
    300 
    301 
    302 class SkAnimatorScript_Unbox : public SkScriptCallBackConvert {
    303 public:
    304     SkAnimatorScript_Unbox(SkAnimatorScript2* engine) : fEngine(engine) {}
    305 
    306     virtual bool convert(SkOperand2::OpType type, SkOperand2* operand) {
    307         SkASSERT(type == SkOperand2::kObject);
    308         SkDisplayable* displayable = (SkDisplayable*) operand->fObject;
    309         switch (displayable->getType()) {
    310             case SkType_Array: {
    311                 SkDisplayArray* boxedValue = (SkDisplayArray*) displayable;
    312                 operand->fArray = new SkOpArray(SkAnimatorScript2::ToOpType(boxedValue->values.getType()));
    313                 int count = boxedValue->values.count();
    314                 operand->fArray->setCount(count);
    315                 memcpy(operand->fArray->begin(), boxedValue->values.begin(), count * sizeof(SkOperand2));
    316                 fEngine->track(operand->fArray);
    317                 } break;
    318             case SkType_Boolean: {
    319                 SkDisplayBoolean* boxedValue = (SkDisplayBoolean*) displayable;
    320                 operand->fS32 = boxedValue->value;
    321                 } break;
    322             case SkType_Int: {
    323                 SkDisplayInt* boxedValue = (SkDisplayInt*) displayable;
    324                 operand->fS32 = boxedValue->value;
    325                 } break;
    326             case SkType_Float: {
    327                 SkDisplayFloat* boxedValue = (SkDisplayFloat*) displayable;
    328                 operand->fScalar = boxedValue->value;
    329                 } break;
    330             case SkType_String: {
    331                 SkDisplayString* boxedValue = (SkDisplayString*) displayable;
    332                 operand->fString = SkNEW_ARGS(SkString, (boxedValue->value));
    333                 } break;
    334             default: {
    335                 const char* id;
    336                 bool success = fEngine->getMaker().findKey(displayable, &id);
    337                 SkASSERT(success);
    338                 operand->fString = SkNEW_ARGS(SkString, (id));
    339             }
    340         }
    341         return true;
    342     }
    343 
    344     virtual SkOperand2::OpType getReturnType(int /*index*/, SkOperand2* operand) {
    345         SkDisplayable* displayable = (SkDisplayable*) operand->fObject;
    346         switch (displayable->getType()) {
    347             case SkType_Array:
    348                 return SkOperand2::kArray;
    349             case SkType_Int:
    350                 return SkOperand2::kS32;
    351             case SkType_Float:
    352                 return SkOperand2::kScalar;
    353             case SkType_String:
    354             default:
    355                 return SkOperand2::kString;
    356         }
    357     }
    358 
    359     virtual Type getType() const {
    360         return kUnbox;
    361     }
    362 
    363     SkAnimatorScript2* fEngine;
    364 };
    365 
    366 SkAnimatorScript2::SkAnimatorScript2(SkAnimateMaker& maker, SkDisplayable* working, SkDisplayTypes type) :
    367         SkScriptEngine2(ToOpType(type)), fMaker(maker), fWorking(working) {
    368     *fCallBackArray.append() = new SkAnimatorScript_Member(this);
    369     *fCallBackArray.append() = new SkAnimatorScript_MemberFunction(this);
    370     *fCallBackArray.append() = new SkAnimatorScript_Box();
    371     *fCallBackArray.append() = new SkAnimatorScript_Unbox(this);
    372     *fCallBackArray.append() = new SkAnimatorScript_ID(this);
    373     if (type == SkType_ARGB) {
    374         *fCallBackArray.append() = new SkAnimatorScript_RGB();
    375         *fCallBackArray.append() = new SkAnimatorScript_NamedColor();
    376     }
    377     if (SkDisplayType::IsEnum(&maker, type)) {
    378         // !!! for SpiderMonkey, iterate through the enum values, and map them to globals
    379         const SkDisplayEnumMap& map = GetEnumValues(type);
    380         *fCallBackArray.append() = new SkAnimatorScript_Enum(map.fValues);
    381     }
    382     *fCallBackArray.append() = new SkAnimatorScript_Eval(this);
    383 #if 0        // !!! no extra support for now
    384     for (SkExtras** extraPtr = maker.fExtras.begin(); extraPtr < maker.fExtras.end(); extraPtr++) {
    385         SkExtras* extra = *extraPtr;
    386         if (extra->fExtraCallBack)
    387             *fCallBackArray.append() = new propertyCallBack(extra->fExtraCallBack, extra->fExtraStorage);
    388     }
    389 #endif
    390 }
    391 
    392 SkAnimatorScript2::~SkAnimatorScript2() {
    393     SkScriptCallBack** end = fCallBackArray.end();
    394     for (SkScriptCallBack** ptr = fCallBackArray.begin(); ptr < end; ptr++)
    395         delete *ptr;
    396 }
    397 
    398 bool SkAnimatorScript2::evalMemberCommon(const SkMemberInfo* info,
    399         SkDisplayable* displayable, SkOperand2* value) {
    400     SkDisplayTypes original;
    401     SkDisplayTypes type = original = (SkDisplayTypes) info->getType();
    402     if (info->fType == SkType_Array)
    403         type = SkType_Array;
    404     switch (type) {
    405         case SkType_ARGB:
    406             type = SkType_Int;
    407         case SkType_Boolean:
    408         case SkType_Int:
    409         case SkType_MSec:
    410         case SkType_Float:
    411             SkASSERT(info->getCount() == 1);
    412             if (info->fType != SkType_MemberProperty && info->fType != SkType_MemberFunction)
    413                 value->fS32 = *(int32_t*) info->memberData(displayable);    // OK for SkScalar too
    414             if (type == SkType_MSec) {
    415                 value->fScalar = SkScalarDiv((SkScalar) value->fS32, 1000); // dividing two ints is the same as dividing two scalars
    416                 type = SkType_Float;
    417             }
    418             break;
    419         case SkType_String: {
    420             SkString* displayableString;
    421             if (info->fType != SkType_MemberProperty && info->fType != SkType_MemberFunction) {
    422                 info->getString(displayable, &displayableString);
    423                 value->fString = new SkString(*displayableString);
    424             }
    425             } break;
    426         case SkType_Array: {
    427             SkASSERT(info->fType != SkType_MemberProperty); // !!! incomplete
    428             SkTDOperandArray* displayableArray = (SkTDOperandArray*) info->memberData(displayable);
    429             if (displayable->getType() == SkType_Array) {
    430                 SkDisplayArray* typedArray = (SkDisplayArray*) displayable;
    431                 original = typedArray->values.getType();
    432             }
    433             SkASSERT(original != SkType_Unknown);
    434             SkOpArray* array = value->fArray = new SkOpArray(ToOpType(original));
    435             track(array);
    436             int count = displayableArray->count();
    437             if (count > 0) {
    438                 array->setCount(count);
    439                 memcpy(array->begin(), displayableArray->begin(), count * sizeof(SkOperand2));
    440             }
    441             } break;
    442         default:
    443             SkASSERT(0); // unimplemented
    444     }
    445     return true;
    446 }
    447 
    448 const SkDisplayEnumMap& SkAnimatorScript2::GetEnumValues(SkDisplayTypes type) {
    449     int index = SkTSearch<SkDisplayTypes>(&gEnumMaps[0].fType, gEnumMapCount, type,
    450         sizeof(SkDisplayEnumMap));
    451     SkASSERT(index >= 0);
    452     return gEnumMaps[index];
    453 }
    454 
    455 SkDisplayTypes SkAnimatorScript2::ToDisplayType(SkOperand2::OpType type) {
    456     int val = type;
    457     switch (val) {
    458         case SkOperand2::kNoType:
    459             return SkType_Unknown;
    460         case SkOperand2::kS32:
    461             return SkType_Int;
    462         case SkOperand2::kScalar:
    463             return SkType_Float;
    464         case SkOperand2::kString:
    465             return SkType_String;
    466         case SkOperand2::kArray:
    467             return SkType_Array;
    468         case SkOperand2::kObject:
    469             return SkType_Displayable;
    470         default:
    471             SkASSERT(0);
    472             return SkType_Unknown;
    473     }
    474 }
    475 
    476 SkOperand2::OpType SkAnimatorScript2::ToOpType(SkDisplayTypes type) {
    477     if (SkDisplayType::IsDisplayable(NULL /* fMaker */, type))
    478         return SkOperand2::kObject;
    479     if (SkDisplayType::IsEnum(NULL /* fMaker */, type))
    480         return SkOperand2::kS32;
    481     switch (type) {
    482         case SkType_ARGB:
    483         case SkType_MSec:
    484         case SkType_Int:
    485             return SkOperand2::kS32;
    486         case SkType_Float:
    487         case SkType_Point:
    488         case SkType_3D_Point:
    489             return SkOperand2::kScalar;
    490         case SkType_Base64:
    491         case SkType_DynamicString:
    492         case SkType_String:
    493             return SkOperand2::kString;
    494         case SkType_Array:
    495             return SkOperand2::kArray;
    496         case SkType_Unknown:
    497             return SkOperand2::kNoType;
    498         default:
    499             SkASSERT(0);
    500             return SkOperand2::kNoType;
    501     }
    502 }
    503 
    504 bool SkAnimatorScript2::MapEnums(const char* ptr, const char* match, size_t len, int* value) {
    505     int index = 0;
    506     bool more = true;
    507     do {
    508         const char* last = strchr(ptr, '|');
    509         if (last == NULL) {
    510             last = &ptr[strlen(ptr)];
    511             more = false;
    512         }
    513         size_t length = last - ptr;
    514         if (len == length && strncmp(ptr, match, length) == 0) {
    515             *value = index;
    516             return true;
    517         }
    518         index++;
    519         ptr = last + 1;
    520     } while (more);
    521     return false;
    522 }
    523 
    524 #if defined SK_DEBUG
    525 
    526 #include "SkAnimator.h"
    527 
    528 static const char scriptTestSetup[]  =
    529 "<screenplay>"
    530     "<apply>"
    531         "<paint>"
    532             "<emboss id='emboss' direction='[1,1,1]'  />"
    533         "</paint>"
    534         "<animateField id='animation' field='direction' target='emboss' from='[1,1,1]' to='[-1,1,1]' dur='1'/>"
    535         "<set lval='direction[0]' target='emboss' to='-1' />"
    536     "</apply>"
    537     "<color id='testColor' color='0 ? rgb(0,0,0) : rgb(255,255,255)' />"
    538     "<color id='xColor' color='rgb(12,34,56)' />"
    539     "<typedArray id='emptyArray' />"
    540     "<typedArray id='intArray' values='[1, 4, 6]' />"
    541     "<s32 id='idx' value='2' />"
    542     "<s32 id='idy' value='2' />"
    543     "<string id='alpha' value='abc' />"
    544     "<rectangle id='testRect' left='Math.cos(0)' top='2' right='12' bottom='5' />"
    545     "<event id='evt'>"
    546         "<input name='x' />"
    547         "<apply scope='idy'>"
    548             "<set field='value' to='evt.x.s32' />"
    549         "</apply>"
    550     "</event>"
    551 "</screenplay>";
    552 
    553 static const SkScriptNAnswer scriptTests[]  = {
    554     {    "alpha+alpha", SkType_String, 0, 0, "abcabc" },
    555     {    "0 ? Math.sin(0) : 1", SkType_Int, 1 },
    556     {    "intArray[4]", SkType_Unknown },
    557     {    "emptyArray[4]", SkType_Unknown },
    558     {    "idx", SkType_Int, 2 },
    559     {    "intArray.length", SkType_Int, 3 },
    560     {    "intArray.values[0]", SkType_Int, 1 },
    561     {    "intArray[0]", SkType_Int, 1 },
    562     {    "idx.value", SkType_Int, 2 },
    563     {    "alpha.value", SkType_String, 0, 0, "abc" },
    564     {    "alpha", SkType_String, 0, 0, "abc" },
    565     {    "alpha.value+alpha.value", SkType_String, 0, 0, "abcabc" },
    566     {    "alpha+idx", SkType_String, 0, 0, "abc2" },
    567     {    "idx+alpha", SkType_String, 0, 0, "2abc" },
    568     {    "intArray[idx]", SkType_Int, 6 },
    569     {    "alpha.slice(1,2)", SkType_String, 0, 0, "b" },
    570     {    "alpha.value.slice(1,2)", SkType_String, 0, 0, "b" },
    571     {    "Math.sin(0)", SkType_Float, 0, SkIntToScalar(0) },
    572     {    "testRect.left+2", SkType_Float, 0, SkIntToScalar(3) },
    573     {    "0 ? intArray[0] : 1", SkType_Int, 1 },
    574     {    "0 ? intArray.values[0] : 1", SkType_Int, 1 },
    575     {    "0 ? idx : 1", SkType_Int, 1 },
    576     {    "0 ? idx.value : 1", SkType_Int, 1 },
    577     {    "0 ? alpha.slice(1,2) : 1", SkType_Int, 1 },
    578     {    "0 ? alpha.value.slice(1,2) : 1", SkType_Int, 1 },
    579     { "idy", SkType_Int, 3 }
    580 };
    581 
    582 #define SkScriptNAnswer_testCount    SK_ARRAY_COUNT(scriptTests)
    583 
    584 void SkAnimatorScript2::UnitTest() {
    585 #if defined(SK_SUPPORT_UNITTEST)
    586     SkAnimator animator;
    587     SkASSERT(animator.decodeMemory(scriptTestSetup, sizeof(scriptTestSetup)-1));
    588     SkEvent evt;
    589     evt.setString("id", "evt");
    590     evt.setS32("x", 3);
    591     animator.doUserEvent(evt);
    592     // set up animator with memory script above, then run value tests
    593     for (int index = 0; index < SkScriptNAnswer_testCount; index++) {
    594         SkAnimatorScript2 engine(*animator.fMaker, NULL, scriptTests[index].fType);
    595         SkScriptValue2 value;
    596         const char* script = scriptTests[index].fScript;
    597         bool success = engine.evaluateScript(&script, &value);
    598         if (success == false) {
    599             SkASSERT(scriptTests[index].fType == SkType_Unknown);
    600             continue;
    601         }
    602         SkASSERT(value.fType == ToOpType(scriptTests[index].fType));
    603         SkScalar error;
    604         switch (value.fType) {
    605             case SkOperand2::kS32:
    606                 SkASSERT(value.fOperand.fS32 == scriptTests[index].fIntAnswer);
    607                 break;
    608             case SkOperand2::kScalar:
    609                 error = SkScalarAbs(value.fOperand.fScalar - scriptTests[index].fScalarAnswer);
    610                 SkASSERT(error < SK_Scalar1 / 10000);
    611                 break;
    612             case SkOperand2::kString:
    613                 SkASSERT(value.fOperand.fString->equals(scriptTests[index].fStringAnswer));
    614                 break;
    615             default:
    616                 SkASSERT(0);
    617         }
    618     }
    619 #endif
    620 }
    621 
    622 #endif
    623