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