Home | History | Annotate | Download | only in animator
      1 
      2 /*
      3  * Copyright 2006 The Android Open Source Project
      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 
      9 
     10 #include "SkAnimator.h"
     11 #include "SkAnimateMaker.h"
     12 #include "SkCanvas.h"
     13 #include "SkDisplayApply.h"
     14 #include "SkDisplayMovie.h"
     15 #include "SkDisplayTypes.h"
     16 #include "SkDisplayXMLParser.h"
     17 #include "SkStream.h"
     18 #include "SkScript.h"
     19 #include "SkScript2.h" //   compiled script experiment
     20 #include "SkSystemEventTypes.h"
     21 #include "SkTypedArray.h"
     22 #ifdef SK_BUILD_FOR_ANDROID
     23 #include "SkDrawExtraPathEffect.h"
     24 #endif
     25 #ifdef SK_DEBUG
     26 #include "SkTime.h"
     27 #endif
     28 
     29 #if defined SK_BUILD_FOR_WIN32 && defined SK_DEBUG
     30     #define _static
     31     extern const char gMathPrimerText[];
     32     extern const char gMathPrimerBinary[];
     33 #else
     34     #define _static static
     35 #endif
     36 
     37 _static const char gMathPrimerText[] =
     38 "<screenplay>"
     39     "<Math id=\"Math\"/>"
     40     "<Number id=\"Number\"/>"
     41 "</screenplay>";
     42 
     43 #define gMathPrimer gMathPrimerText
     44 
     45 SkAnimator::SkAnimator() : fMaker(NULL) {
     46     initialize();
     47 }
     48 
     49 SkAnimator::~SkAnimator() {
     50     SkDELETE(fMaker);
     51 }
     52 
     53 void SkAnimator::addExtras(SkExtras* extras) {
     54     *fMaker->fExtras.append() = extras;
     55 }
     56 
     57 bool SkAnimator::appendStream(SkStream* stream) {
     58     return decodeStream(stream);
     59 }
     60 
     61 bool SkAnimator::decodeMemory(const void* buffer, size_t size)
     62 {
     63     fMaker->fFileName.reset();
     64     SkDisplayXMLParser parser(*fMaker);
     65     return parser.parse((const char*)buffer, size);
     66 }
     67 
     68 bool SkAnimator::decodeStream(SkStream* stream)
     69 {
     70     SkDisplayXMLParser parser(*fMaker);
     71     bool result = parser.parse(*stream);
     72     fMaker->setErrorString();
     73     return result;
     74 }
     75 
     76 bool SkAnimator::decodeDOM(const SkDOM& dom, const SkDOMNode* node)
     77 {
     78     fMaker->fFileName.reset();
     79     SkDisplayXMLParser parser(*fMaker);
     80     return parser.parse(dom, node);
     81 }
     82 
     83 bool SkAnimator::decodeURI(const char uri[]) {
     84 //  SkDebugf("animator decode %s\n", uri);
     85 
     86 //    SkStream* stream = SkStream::GetURIStream(fMaker->fPrefix.c_str(), uri);
     87     SkStream* stream = new SkFILEStream(uri);
     88 
     89     SkAutoTDelete<SkStream> autoDel(stream);
     90     setURIBase(uri);
     91     return decodeStream(stream);
     92 }
     93 
     94 bool SkAnimator::doCharEvent(SkUnichar code) {
     95     if (code == 0)
     96         return false;
     97     struct SkEventState state;
     98     state.fCode = code;
     99     fMaker->fEnableTime = fMaker->getAppTime();
    100     bool result = fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kKeyChar, &state);
    101     fMaker->notifyInval();
    102     return result;
    103 }
    104 
    105 bool SkAnimator::doClickEvent(int clickState, SkScalar x, SkScalar y) {
    106     SkASSERT(clickState >= 0 && clickState <= 2);
    107     struct SkEventState state;
    108     state.fX = x;
    109     state.fY = y;
    110     fMaker->fEnableTime = fMaker->getAppTime();
    111     bool result = fMaker->fEvents.doEvent(*fMaker,
    112         clickState == 0 ? SkDisplayEvent::kMouseDown :
    113         clickState == 1 ? SkDisplayEvent::kMouseDrag :
    114         SkDisplayEvent::kMouseUp, &state);
    115     fMaker->notifyInval();
    116     return result;
    117 }
    118 
    119 bool SkAnimator::doKeyEvent(SkKey code) {
    120     if (code == 0)
    121         return false;
    122     struct SkEventState state;
    123     state.fCode = code;
    124     fMaker->fEnableTime = fMaker->getAppTime();
    125     bool result = fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kKeyPress, &state);
    126     fMaker->notifyInval();
    127     return result;
    128 }
    129 
    130 bool SkAnimator::doKeyUpEvent(SkKey code) {
    131     if (code == 0)
    132         return false;
    133     struct SkEventState state;
    134     state.fCode = code;
    135     fMaker->fEnableTime = fMaker->getAppTime();
    136     bool result = fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kKeyPressUp, &state);
    137     fMaker->notifyInval();
    138     return result;
    139 }
    140 
    141 bool SkAnimator::doUserEvent(const SkEvent& evt) {
    142     fMaker->fEnableTime = fMaker->getAppTime();
    143     return onEvent(evt);
    144 }
    145 
    146 SkAnimator::DifferenceType SkAnimator::draw(SkCanvas* canvas, SkPaint* paint, SkMSec time) {
    147     if (paint == NULL)
    148         return draw(canvas, time);
    149     fMaker->fScreenplay.time = time;
    150     fMaker->fCanvas = canvas;
    151     fMaker->fPaint = paint;
    152     fMaker->fDisplayList.fHasUnion = false;
    153     int result = fMaker->fDisplayList.draw(*fMaker, time);
    154     if (result)
    155         result += fMaker->fDisplayList.fHasUnion;
    156     return (DifferenceType) result;
    157 }
    158 
    159 SkAnimator::DifferenceType SkAnimator::draw(SkCanvas* canvas, SkMSec time) {
    160     SkPaint paint;
    161     return draw(canvas, &paint, time);
    162 }
    163 
    164 #ifdef SK_DEBUG
    165 void SkAnimator::eventDone(const SkEvent& ) {
    166 }
    167 #endif
    168 
    169 bool SkAnimator::findClickEvent(SkScalar x, SkScalar y) {
    170     struct SkEventState state;
    171     state.fDisable = true;
    172     state.fX = x;
    173     state.fY = y;
    174     fMaker->fEnableTime = fMaker->getAppTime();
    175     bool result = fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kMouseDown, &state);
    176     fMaker->notifyInval();
    177     return result;
    178 }
    179 
    180 const SkAnimator* SkAnimator::getAnimator(const SkDisplayable* displayable) const {
    181     if (displayable->getType() != SkType_Movie)
    182         return NULL;
    183     const SkDisplayMovie* movie = (const SkDisplayMovie*) displayable;
    184     return movie->getAnimator();
    185 }
    186 
    187 const SkDisplayable* SkAnimator::getElement(const char* id) {
    188     SkDisplayable* element;
    189     if (fMaker->find(id, &element) == false)
    190         return NULL;
    191     return (const SkDisplayable*) element;
    192 }
    193 
    194 SkElementType SkAnimator::getElementType(const SkDisplayable* ae) {
    195     SkDisplayable* element = (SkDisplayable*) ae;
    196     const SkMemberInfo* info = SkDisplayType::GetMembers(fMaker, element->getType(), NULL);
    197     return (SkElementType) SkDisplayType::Find(fMaker, info);
    198 }
    199 
    200 SkElementType SkAnimator::getElementType(const char* id) {
    201     const SkDisplayable* element = getElement(id);
    202     return getElementType(element);
    203 }
    204 
    205 const SkMemberInfo* SkAnimator::getField(const SkDisplayable* ae, const char* field) {
    206     SkDisplayable* element = (SkDisplayable*) ae;
    207     const SkMemberInfo* info = element->getMember(field);
    208     return (const SkMemberInfo*) info;
    209 }
    210 
    211 const SkMemberInfo* SkAnimator::getField(const char* elementID, const char* field) {
    212     const SkDisplayable* element = getElement(elementID);
    213     return getField(element, field);
    214 }
    215 
    216 SkFieldType SkAnimator::getFieldType(const SkMemberInfo* ai) {
    217     const SkMemberInfo* info = (const SkMemberInfo*) ai;
    218     return (SkFieldType) info->getType();
    219 }
    220 
    221 SkFieldType SkAnimator::getFieldType(const char* id, const char* fieldID) {
    222     const SkMemberInfo* field = getField(id, fieldID);
    223     return getFieldType(field);
    224 }
    225 
    226  static bool getArrayCommon(const SkDisplayable* ae, const SkMemberInfo* ai,
    227      int index, SkOperand* operand, SkDisplayTypes type) {
    228     const SkDisplayable* element = (const SkDisplayable*) ae;
    229     const SkMemberInfo* info = (const SkMemberInfo*) ai;
    230     SkASSERT(info->fType == SkType_Array);
    231     return info->getArrayValue(element, index, operand);
    232 }
    233 
    234 int32_t SkAnimator::getArrayInt(const SkDisplayable* ae,
    235         const SkMemberInfo* ai, int index) {
    236     SkOperand operand;
    237     bool result = getArrayCommon(ae, ai, index, &operand, SkType_Int);
    238     return result ? operand.fS32 : SK_NaN32;
    239 }
    240 
    241 int32_t SkAnimator::getArrayInt(const char* id, const char* fieldID, int index) {
    242     const SkDisplayable* element = getElement(id);
    243     if (element == NULL)
    244         return SK_NaN32;
    245     const SkMemberInfo* field = getField(element, fieldID);
    246     if (field == NULL)
    247         return SK_NaN32;
    248     return getArrayInt(element, field, index);
    249 }
    250 
    251 SkScalar SkAnimator::getArrayScalar(const SkDisplayable* ae,
    252         const SkMemberInfo* ai, int index) {
    253     SkOperand operand;
    254     bool result = getArrayCommon(ae, ai, index, &operand, SkType_Float);
    255     return result ? operand.fScalar : SK_ScalarNaN;
    256 }
    257 
    258 SkScalar SkAnimator::getArrayScalar(const char* id, const char* fieldID, int index) {
    259     const SkDisplayable* element = getElement(id);
    260     if (element == NULL)
    261         return SK_ScalarNaN;
    262     const SkMemberInfo* field = getField(element, fieldID);
    263     if (field == NULL)
    264         return SK_ScalarNaN;
    265     return getArrayScalar(element, field, index);
    266 }
    267 
    268 const char* SkAnimator::getArrayString(const SkDisplayable* ae,
    269         const SkMemberInfo* ai, int index) {
    270     SkOperand operand;
    271     bool result = getArrayCommon(ae, ai, index, &operand, SkType_String);
    272     return result ? operand.fString->c_str() : NULL;
    273 }
    274 
    275 const char* SkAnimator::getArrayString(const char* id, const char* fieldID, int index) {
    276     const SkDisplayable* element = getElement(id);
    277     if (element == NULL)
    278         return NULL;
    279     const SkMemberInfo* field = getField(element, fieldID);
    280     if (field == NULL)
    281         return NULL;
    282     return getArrayString(element, field, index);
    283 }
    284 
    285 SkMSec SkAnimator::getInterval() {
    286     return fMaker->fMinimumInterval == (SkMSec) -1 ? 0 : fMaker->fMinimumInterval;
    287 }
    288 
    289 void SkAnimator::getInvalBounds(SkRect* inval) {
    290     if (fMaker->fDisplayList.fHasUnion) {
    291         inval->fLeft = SkIntToScalar(fMaker->fDisplayList.fInvalBounds.fLeft);
    292         inval->fTop = SkIntToScalar(fMaker->fDisplayList.fInvalBounds.fTop);
    293         inval->fRight = SkIntToScalar(fMaker->fDisplayList.fInvalBounds.fRight);
    294         inval->fBottom = SkIntToScalar(fMaker->fDisplayList.fInvalBounds.fBottom);
    295     } else {
    296         inval->fLeft = inval->fTop = -SK_ScalarMax;
    297         inval->fRight = inval->fBottom = SK_ScalarMax;
    298     }
    299 }
    300 
    301 const SkXMLParserError* SkAnimator::getParserError() {
    302     return &fMaker->fError;
    303 }
    304 
    305 const char* SkAnimator::getParserErrorString() {
    306     if (fMaker->fErrorString.size() == 0 && fMaker->fError.hasError())
    307         fMaker->setErrorString();
    308     return fMaker->fErrorString.c_str();
    309 }
    310 
    311 int32_t SkAnimator::getInt(const SkDisplayable* element, const SkMemberInfo* info) {
    312     if (info->fType != SkType_MemberProperty) {
    313         SkOperand operand;
    314         if (info->getType() == SkType_Int) {
    315             info->getValue(element, &operand, 1);
    316             return operand.fS32;
    317         }
    318         return SK_NaN32;
    319     }
    320     SkScriptValue scriptValue;
    321     bool success = element->getProperty(info->propertyIndex(), &scriptValue);
    322     if (success && scriptValue.fType == SkType_Int)
    323         return scriptValue.fOperand.fS32;
    324     return SK_NaN32;
    325 }
    326 
    327 int32_t SkAnimator::getInt(const char* id, const char* fieldID) {
    328     const SkDisplayable* element = getElement(id);
    329     if (element == NULL)
    330         return SK_NaN32;
    331     const SkMemberInfo* field = getField(element, fieldID);
    332     if (field == NULL)
    333         return SK_NaN32;
    334     return getInt(element, field);
    335 }
    336 
    337 SkScalar SkAnimator::getScalar(const SkDisplayable* element, const SkMemberInfo* info) {
    338     if (info->fType != SkType_MemberProperty) {
    339         SkOperand operand;
    340         if (info->getType() == SkType_Float) {
    341             info->getValue(element, &operand, 1);
    342             return operand.fScalar;
    343         }
    344         return SK_ScalarNaN;
    345     }
    346     SkScriptValue scriptValue;
    347     bool success = element->getProperty(info->propertyIndex(), &scriptValue);
    348     if (success && scriptValue.fType == SkType_Float)
    349         return scriptValue.fOperand.fScalar;
    350     return SK_ScalarNaN;
    351 }
    352 
    353 SkScalar SkAnimator::getScalar(const char* id, const char* fieldID) {
    354     const SkDisplayable* element = getElement(id);
    355     if (element == NULL)
    356         return SK_ScalarNaN;
    357     const SkMemberInfo* field = getField(element, fieldID);
    358     if (field == NULL)
    359         return SK_ScalarNaN;
    360     return getScalar(element, field);
    361 }
    362 
    363 const char* SkAnimator::getString(const SkDisplayable* ae,
    364         const SkMemberInfo* ai) {
    365     const SkDisplayable* element = (const SkDisplayable*) ae;
    366     const SkMemberInfo* info = (const SkMemberInfo*) ai;
    367     SkString* temp;
    368     info->getString(element, &temp);
    369     return temp->c_str();
    370 }
    371 
    372 const char* SkAnimator::getString(const char* id, const char* fieldID) {
    373     const SkDisplayable* element = getElement(id);
    374     if (element == NULL)
    375         return NULL;
    376     const SkMemberInfo* field = getField(element, fieldID);
    377     if (field == NULL)
    378         return NULL;
    379     return getString(element, field);
    380 }
    381 
    382 const char* SkAnimator::getURIBase() {
    383     return fMaker->fPrefix.c_str();
    384 }
    385 
    386 void SkAnimator::initialize() {
    387     SkDELETE(fMaker);
    388     fMaker = SkNEW_ARGS(SkAnimateMaker, (this, NULL, NULL));
    389     decodeMemory(gMathPrimer, sizeof(gMathPrimer)-1);
    390 #ifdef SK_BUILD_FOR_ANDROID
    391     InitializeSkExtraPathEffects(this);
    392 #endif
    393 }
    394 
    395 
    396 #ifdef SK_DEBUG
    397 bool SkAnimator::isTrackingEvents() {
    398     return false;
    399 }
    400 #endif
    401 
    402 bool SkAnimator::onEvent(const SkEvent& evt) {
    403 #ifdef SK_DEBUG
    404     SkAnimator* root = fMaker->getRoot();
    405     if (root == NULL)
    406         root = this;
    407     if (root->isTrackingEvents())
    408         root->eventDone(evt);
    409 #endif
    410     if (evt.isType(SK_EventType_OnEnd)) {
    411         SkEventState eventState;
    412         bool success = evt.findPtr("anim", (void**) &eventState.fDisplayable);
    413         SkASSERT(success);
    414         success = evt.findS32("time", (int32_t*) &fMaker->fEnableTime);
    415         SkASSERT(success);
    416         fMaker->fAdjustedStart = fMaker->getAppTime() - fMaker->fEnableTime;
    417         fMaker->fEvents.doEvent(*fMaker, SkDisplayEvent::kOnEnd, &eventState);
    418         fMaker->fAdjustedStart = 0;
    419         goto inval;
    420     }
    421     if (evt.isType(SK_EventType_Delay)) {
    422         fMaker->doDelayedEvent();
    423         goto inval;
    424     }
    425     {
    426         const char* id = evt.findString("id");
    427         if (id == NULL)
    428             return false;
    429         SkDisplayable** firstMovie = fMaker->fMovies.begin();
    430         SkDisplayable** endMovie = fMaker->fMovies.end();
    431         for (SkDisplayable** ptr = firstMovie; ptr < endMovie; ptr++) {
    432             SkDisplayMovie* movie = (SkDisplayMovie*) *ptr;
    433             movie->doEvent(evt);
    434         }
    435         {
    436             SkDisplayable* event;
    437             if (fMaker->find(id, &event) == false)
    438                 return false;
    439     #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
    440             SkString debugOut;
    441             SkMSec realTime = fMaker->getAppTime();
    442             debugOut.appendS32(realTime - fMaker->fDebugTimeBase);
    443             debugOut.append(" onEvent id=");
    444             debugOut.append(id);
    445     #endif
    446             SkMSec time = evt.getFast32();
    447             if (time != 0) {
    448                 SkMSec app  = fMaker->getAppTime();
    449                 fMaker->setEnableTime(app, time);
    450     #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
    451                 debugOut.append(" time=");
    452                 debugOut.appendS32(time - fMaker->fDebugTimeBase);
    453                 debugOut.append(" adjust=");
    454                 debugOut.appendS32(fMaker->fAdjustedStart);
    455     #endif
    456             }
    457     #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING
    458             SkDebugf("%s\n", debugOut.c_str());
    459     #endif
    460             SkASSERT(event->isEvent());
    461             SkDisplayEvent* displayEvent = (SkDisplayEvent*) event;
    462             displayEvent->populateInput(*fMaker, evt);
    463             displayEvent->enableEvent(*fMaker);
    464         }
    465     }
    466 inval:
    467     fMaker->notifyInval();
    468     return true;
    469 }
    470 
    471 void SkAnimator::onEventPost(SkEvent* evt, SkEventSinkID sinkID)
    472 {
    473 #ifdef SK_DEBUG
    474     SkAnimator* root = fMaker->getRoot();
    475     if (root) {
    476         root->onEventPost(evt, sinkID);
    477         return;
    478     }
    479 #else
    480     SkASSERT(sinkID == this->getSinkID() || this->getHostEventSinkID() == sinkID);
    481 #endif
    482     evt->setTargetID(sinkID)->post();
    483 }
    484 
    485 void SkAnimator::onEventPostTime(SkEvent* evt, SkEventSinkID sinkID, SkMSec time)
    486 {
    487 #ifdef SK_DEBUG
    488     SkAnimator* root = fMaker->getRoot();
    489     if (root) {
    490         root->onEventPostTime(evt, sinkID, time);
    491         return;
    492     }
    493 #else
    494     SkASSERT(sinkID == this->getSinkID() || this->getHostEventSinkID() == sinkID);
    495 #endif
    496     evt->setTargetID(sinkID)->postTime(time);
    497 }
    498 
    499 void SkAnimator::reset() {
    500     fMaker->fDisplayList.reset();
    501 }
    502 
    503 SkEventSinkID SkAnimator::getHostEventSinkID() const {
    504     return fMaker->fHostEventSinkID;
    505 }
    506 
    507 void SkAnimator::setHostEventSinkID(SkEventSinkID target) {
    508     fMaker->fHostEventSinkID = target;
    509 }
    510 
    511 void SkAnimator::onSetHostHandler(Handler ) {
    512 }
    513 
    514 void SkAnimator::setJavaOwner(Handler ) {
    515 }
    516 
    517 bool SkAnimator::setArrayString(const char* id, const char* fieldID, const char** array, int num)
    518 {
    519     SkTypedArray tArray(SkType_String);
    520     tArray.setCount(num);
    521     for (int i = 0; i < num; i++) {
    522         SkOperand op;
    523         op.fString = new SkString(array[i]);
    524         tArray[i] = op;
    525     }
    526     return setArray(id, fieldID, tArray);
    527 }
    528 bool SkAnimator::setArrayInt(const char* id, const char* fieldID, const int* array, int num)
    529 {
    530     SkTypedArray tArray(SkType_Int);
    531     tArray.setCount(num);
    532     for (int i = 0; i < num; i++) {
    533         SkOperand op;
    534         op.fS32 = array[i];
    535         tArray[i] = op;
    536     }
    537     return setArray(id, fieldID, tArray);
    538 }
    539 
    540 bool SkAnimator::setArray(SkDisplayable* element, const SkMemberInfo* info, SkTypedArray array) {
    541     if (info->fType != SkType_Array)
    542         return false;   //the field is not an array
    543     //i think we can handle the case where the displayable itself is an array differently from the
    544     //case where it has an array - for one thing, if it is an array, i think we can change its type
    545     //if it's not, we cannot
    546     SkDisplayTypes type = element->getType();
    547     if (type == SkType_Array) {
    548         SkDisplayArray* dispArray = (SkDisplayArray*) element;
    549         dispArray->values = array;
    550         return true;
    551     }
    552     else
    553         return false;   //currently i don't care about this case
    554 }
    555 
    556 bool SkAnimator::setArray(const char* id, const char* fieldID, SkTypedArray array) {
    557     SkDisplayable* element = (SkDisplayable*) getElement(id);
    558     //should I go ahead and change all 'NULL's to 'NULL'?
    559     if (element == NULL)
    560         return false;
    561     const SkMemberInfo* field = getField(element, fieldID);
    562     if (field == NULL)
    563         return false;
    564     return setArray(element, field, array);
    565 }
    566 
    567 bool SkAnimator::setInt(SkDisplayable* element, const SkMemberInfo* info, int32_t s32) {
    568     if (info->fType != SkType_MemberProperty) {
    569         SkOperand operand;
    570         operand.fS32 = s32;
    571         SkASSERT(info->getType() == SkType_Int);
    572         info->setValue(element, &operand, 1);
    573     } else {
    574         SkScriptValue scriptValue;
    575         scriptValue.fType = SkType_Int;
    576         scriptValue.fOperand.fS32 = s32;
    577         element->setProperty(info->propertyIndex(), scriptValue);
    578     }
    579     return true;
    580 }
    581 
    582 bool SkAnimator::setInt(const char* id, const char* fieldID, int32_t s32) {
    583     SkDisplayable* element = (SkDisplayable*) getElement(id);
    584     if (element == NULL)
    585         return false;
    586     const SkMemberInfo* field = getField(element, fieldID);
    587     if (field == NULL)
    588         return false;
    589     return setInt(element, field, s32);
    590 }
    591 
    592 bool SkAnimator::setScalar(SkDisplayable* element, const SkMemberInfo* info, SkScalar scalar) {
    593     if (info->fType != SkType_MemberProperty) {
    594         SkOperand operand;
    595         operand.fScalar = scalar;
    596         SkASSERT(info->getType() == SkType_Float);
    597         info->setValue(element, &operand, 1);
    598     } else {
    599         SkScriptValue scriptValue;
    600         scriptValue.fType = SkType_Float;
    601         scriptValue.fOperand.fScalar = scalar;
    602         element->setProperty(info->propertyIndex(), scriptValue);
    603     }
    604     return true;
    605 }
    606 
    607 bool SkAnimator::setScalar(const char* id, const char* fieldID, SkScalar scalar) {
    608     SkDisplayable* element = (SkDisplayable*) getElement(id);
    609     if (element == NULL)
    610         return false;
    611     const SkMemberInfo* field = getField(element, fieldID);
    612     if (field == NULL)
    613         return false;
    614     return setScalar(element, field, scalar);
    615 }
    616 
    617 bool SkAnimator::setString(SkDisplayable* element,
    618         const SkMemberInfo* info, const char* str) {
    619     // !!! until this is fixed, can't call script with global references from here
    620     info->setValue(*fMaker, NULL, 0, info->fCount, element, info->getType(), str, strlen(str));
    621     return true;
    622 }
    623 
    624 bool SkAnimator::setString(const char* id, const char* fieldID, const char* str) {
    625     SkDisplayable* element = (SkDisplayable*) getElement(id);
    626     if (element == NULL)
    627         return false;
    628     const SkMemberInfo* field = getField(element, fieldID);
    629     if (field == NULL)
    630         return false;
    631     return setString(element, field, str);
    632 }
    633 
    634 void SkAnimator::setTimeline(const Timeline& timeline) {
    635     fMaker->fTimeline = &timeline;
    636 }
    637 
    638 void SkAnimator::setURIBase(const char* uri) {
    639     if (uri)
    640     {
    641         const char* tail = strrchr(uri, '/');
    642         if (tail) {
    643             SkString prefix(uri, tail - uri + 1);
    644             if (uri[0] != '.' /*SkStream::IsAbsoluteURI(uri)*/)
    645                 fMaker->fPrefix.reset();
    646             fMaker->fPrefix.append(prefix);
    647             fMaker->fFileName.set(tail + 1);
    648         } else
    649             fMaker->fFileName.set(uri);
    650     }
    651 }
    652 
    653 #ifdef SK_DEBUG
    654 bool SkAnimator::NoLeaks() {
    655 #ifdef SK_BUILD_FOR_MAC
    656     if (SkDisplayable::fAllocations.count() == 0)
    657         return true;
    658 //  return SkDisplayable::fAllocationCount == 0;
    659     SkDebugf("!!! leaked %d displayables:\n", SkDisplayable::fAllocations.count());
    660     for (SkDisplayable** leak = SkDisplayable::fAllocations.begin(); leak < SkDisplayable::fAllocations.end(); leak++)
    661         SkDebugf("%08x %s\n", *leak, (*leak)->id);
    662 #endif
    663     return false;
    664 }
    665 #endif
    666 
    667 #ifdef SK_SUPPORT_UNITTEST
    668 #include "SkAnimatorScript.h"
    669 #include "SkBase64.h"
    670 #include "SkParse.h"
    671 #include "SkMemberInfo.h"
    672 
    673 #define unittestline(type)  { #type , type::UnitTest }
    674 #endif
    675 
    676 
    677 void SkAnimator::Init(bool runUnitTests) {
    678 #ifdef SK_SUPPORT_UNITTEST
    679     if (runUnitTests == false)
    680         return;
    681     static const struct {
    682         const char* fTypeName;
    683         void (*fUnitTest)( );
    684     } gUnitTests[] = {
    685         unittestline(SkBase64),
    686         unittestline(SkDisplayType),
    687         unittestline(SkParse),
    688         unittestline(SkScriptEngine),
    689 //      unittestline(SkScriptEngine2),  // compiled script experiment
    690         unittestline(SkAnimatorScript)
    691     };
    692     for (int i = 0; i < (int)SK_ARRAY_COUNT(gUnitTests); i++)
    693     {
    694         SkDebugf("SkAnimator: Running UnitTest for %s\n", gUnitTests[i].fTypeName);
    695         gUnitTests[i].fUnitTest();
    696         SkDebugf("SkAnimator: End UnitTest for %s\n", gUnitTests[i].fTypeName);
    697     }
    698 #endif
    699 }
    700 
    701 void SkAnimator::Term() {
    702 }
    703