michael@0: michael@0: /* michael@0: * Copyright 2006 The Android Open Source Project michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: #include "SkAnimateMaker.h" michael@0: #include "SkAnimator.h" michael@0: #include "SkAnimatorScript.h" michael@0: #include "SkDisplayable.h" michael@0: #include "SkDisplayApply.h" michael@0: #include "SkDisplayList.h" michael@0: #include "SkDisplayMovie.h" michael@0: #include "SkDisplayType.h" michael@0: #include "SkExtras.h" michael@0: #include "SkMemberInfo.h" michael@0: #include "SkStream.h" michael@0: #include "SkSystemEventTypes.h" michael@0: #include "SkTime.h" michael@0: michael@0: class DefaultTimeline : public SkAnimator::Timeline { michael@0: virtual SkMSec getMSecs() const { michael@0: return SkTime::GetMSecs(); michael@0: } michael@0: } gDefaultTimeline; michael@0: michael@0: SkAnimateMaker::SkAnimateMaker(SkAnimator* animator, SkCanvas* canvas, SkPaint* paint) michael@0: : fActiveEvent(NULL), fAdjustedStart(0), fCanvas(canvas), fEnableTime(0), michael@0: fHostEventSinkID(0), fMinimumInterval((SkMSec) -1), fPaint(paint), fParentMaker(NULL), michael@0: fTimeline(&gDefaultTimeline), fInInclude(false), fInMovie(false), michael@0: fFirstScriptError(false), fLoaded(false), fIDs(256), fAnimator(animator) michael@0: { michael@0: fScreenplay.time = 0; michael@0: #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING michael@0: fDebugTimeBase = (SkMSec) -1; michael@0: #endif michael@0: #ifdef SK_DUMP_ENABLED michael@0: fDumpEvents = fDumpGConditions = fDumpPosts = false; michael@0: #endif michael@0: } michael@0: michael@0: SkAnimateMaker::~SkAnimateMaker() { michael@0: deleteMembers(); michael@0: } michael@0: michael@0: #if 0 michael@0: SkMSec SkAnimateMaker::adjustDelay(SkMSec expectedBase, SkMSec delay) { michael@0: SkMSec appTime = (*fTimeCallBack)(); michael@0: if (appTime) michael@0: delay -= appTime - expectedBase; michael@0: if (delay < 0) michael@0: delay = 0; michael@0: return delay; michael@0: } michael@0: #endif michael@0: michael@0: void SkAnimateMaker::appendActive(SkActive* active) { michael@0: fDisplayList.append(active); michael@0: } michael@0: michael@0: void SkAnimateMaker::clearExtraPropertyCallBack(SkDisplayTypes type) { michael@0: SkExtras** end = fExtras.end(); michael@0: for (SkExtras** extraPtr = fExtras.begin(); extraPtr < end; extraPtr++) { michael@0: SkExtras* extra = *extraPtr; michael@0: if (extra->definesType(type)) { michael@0: extra->fExtraCallBack = NULL; michael@0: extra->fExtraStorage = NULL; michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: bool SkAnimateMaker::computeID(SkDisplayable* displayable, SkDisplayable* parent, SkString* newID) { michael@0: const char* script; michael@0: if (findKey(displayable, &script) == false) michael@0: return true; michael@0: return SkAnimatorScript::EvaluateString(*this, displayable, parent, script, newID); michael@0: } michael@0: michael@0: SkDisplayable* SkAnimateMaker::createInstance(const char name[], size_t len) { michael@0: SkDisplayTypes type = SkDisplayType::GetType(this, name, len ); michael@0: if ((int)type >= 0) michael@0: return SkDisplayType::CreateInstance(this, type); michael@0: return NULL; michael@0: } michael@0: michael@0: // differs from SkAnimator::decodeStream in that it does not reset error state michael@0: bool SkAnimateMaker::decodeStream(SkStream* stream) michael@0: { michael@0: SkDisplayXMLParser parser(*this); michael@0: return parser.parse(*stream); michael@0: } michael@0: michael@0: // differs from SkAnimator::decodeURI in that it does not set URI base michael@0: bool SkAnimateMaker::decodeURI(const char uri[]) { michael@0: // SkDebugf("animator decode %s\n", uri); michael@0: michael@0: // SkStream* stream = SkStream::GetURIStream(fPrefix.c_str(), uri); michael@0: SkAutoTUnref stream(SkStream::NewFromFile(uri)); michael@0: if (stream.get()) { michael@0: bool success = decodeStream(stream); michael@0: if (hasError() && fError.hasNoun() == false) michael@0: fError.setNoun(uri); michael@0: return success; michael@0: } else { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: #if defined SK_DEBUG && 0 michael@0: //used for the if'd out section of deleteMembers michael@0: #include "SkTSearch.h" michael@0: michael@0: extern "C" { michael@0: int compare_disp(const void* a, const void* b) { michael@0: return *(const SkDisplayable**)a - *(const SkDisplayable**)b; michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: void SkAnimateMaker::delayEnable(SkApply* apply, SkMSec time) { michael@0: int index = fDelayed.find(apply); michael@0: if (index < 0) { michael@0: *fDelayed.append() = apply; michael@0: } michael@0: michael@0: (new SkEvent(SK_EventType_Delay, fAnimator->getSinkID()))->postTime(time); michael@0: } michael@0: michael@0: void SkAnimateMaker::deleteMembers() { michael@0: int index; michael@0: #if defined SK_DEBUG && 0 michael@0: //this code checks to see if helpers are among the children, but it is not complete - michael@0: //it should check the children of the children michael@0: int result; michael@0: SkTDArray children(fChildren.begin(), fChildren.count()); michael@0: SkQSort(children.begin(), children.count(), sizeof(SkDisplayable*),compare_disp); michael@0: for (index = 0; index < fHelpers.count(); index++) { michael@0: SkDisplayable* helper = fHelpers[index]; michael@0: result = SkTSearch(children.begin(), children.count(), helper, sizeof(SkDisplayable*)); michael@0: SkASSERT(result < 0); michael@0: } michael@0: #endif michael@0: for (index = 0; index < fChildren.count(); index++) { michael@0: SkDisplayable* child = fChildren[index]; michael@0: delete child; michael@0: } michael@0: for (index = 0; index < fHelpers.count(); index++) { michael@0: SkDisplayable* helper = fHelpers[index]; michael@0: delete helper; michael@0: } michael@0: for (index = 0; index < fExtras.count(); index++) { michael@0: SkExtras* extras = fExtras[index]; michael@0: delete extras; michael@0: } michael@0: } michael@0: michael@0: void SkAnimateMaker::doDelayedEvent() { michael@0: fEnableTime = getAppTime(); michael@0: for (int index = 0; index < fDelayed.count(); ) { michael@0: SkDisplayable* child = fDelayed[index]; michael@0: SkASSERT(child->isApply()); michael@0: SkApply* apply = (SkApply*) child; michael@0: apply->interpolate(*this, fEnableTime); michael@0: if (apply->hasDelayedAnimator()) michael@0: index++; michael@0: else michael@0: fDelayed.remove(index); michael@0: } michael@0: } michael@0: michael@0: bool SkAnimateMaker::doEvent(const SkEvent& event) { michael@0: return (!fInMovie || fLoaded) && fAnimator->doEvent(event); michael@0: } michael@0: michael@0: #ifdef SK_DUMP_ENABLED michael@0: void SkAnimateMaker::dump(const char* match) { michael@0: SkTDict::Iter iter(fIDs); michael@0: const char* name; michael@0: SkDisplayable* result; michael@0: while ((name = iter.next(&result)) != NULL) { michael@0: if (strcmp(match,name) == 0) michael@0: result->dump(this); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: int SkAnimateMaker::dynamicProperty(SkString& nameStr, SkDisplayable** displayablePtr ) { michael@0: const char* name = nameStr.c_str(); michael@0: const char* dot = strchr(name, '.'); michael@0: SkASSERT(dot); michael@0: SkDisplayable* displayable; michael@0: if (find(name, dot - name, &displayable) == false) { michael@0: SkASSERT(0); michael@0: return 0; michael@0: } michael@0: const char* fieldName = dot + 1; michael@0: const SkMemberInfo* memberInfo = displayable->getMember(fieldName); michael@0: *displayablePtr = displayable; michael@0: return (int) memberInfo->fOffset; michael@0: } michael@0: michael@0: SkMSec SkAnimateMaker::getAppTime() const { michael@0: return fTimeline->getMSecs(); michael@0: } michael@0: michael@0: #ifdef SK_DEBUG michael@0: SkAnimator* SkAnimateMaker::getRoot() michael@0: { michael@0: SkAnimateMaker* maker = this; michael@0: while (maker->fParentMaker) michael@0: maker = maker->fParentMaker; michael@0: return maker == this ? NULL : maker->fAnimator; michael@0: } michael@0: #endif michael@0: michael@0: void SkAnimateMaker::helperAdd(SkDisplayable* trackMe) { michael@0: SkASSERT(fHelpers.find(trackMe) < 0); michael@0: *fHelpers.append() = trackMe; michael@0: } michael@0: michael@0: void SkAnimateMaker::helperRemove(SkDisplayable* alreadyTracked) { michael@0: int helperIndex = fHelpers.find(alreadyTracked); michael@0: if (helperIndex >= 0) michael@0: fHelpers.remove(helperIndex); michael@0: } michael@0: michael@0: #if 0 michael@0: void SkAnimateMaker::loadMovies() { michael@0: for (SkDisplayable** dispPtr = fMovies.begin(); dispPtr < fMovies.end(); dispPtr++) { michael@0: SkDisplayable* displayable = *dispPtr; michael@0: SkASSERT(displayable->getType() == SkType_Movie); michael@0: SkDisplayMovie* movie = (SkDisplayMovie*) displayable; michael@0: SkAnimateMaker* movieMaker = movie->fMovie.fMaker; michael@0: movieMaker->fEvents.doEvent(*movieMaker, SkDisplayEvent::kOnload, NULL); michael@0: movieMaker->fEvents.removeEvent(SkDisplayEvent::kOnload, NULL); michael@0: movieMaker->loadMovies(); michael@0: } michael@0: } michael@0: #endif michael@0: michael@0: void SkAnimateMaker::notifyInval() { michael@0: if (fHostEventSinkID) michael@0: fAnimator->onEventPost(new SkEvent(SK_EventType_Inval), fHostEventSinkID); michael@0: } michael@0: michael@0: void SkAnimateMaker::notifyInvalTime(SkMSec time) { michael@0: if (fHostEventSinkID) michael@0: fAnimator->onEventPostTime(new SkEvent(SK_EventType_Inval), fHostEventSinkID, time); michael@0: } michael@0: michael@0: void SkAnimateMaker::postOnEnd(SkAnimateBase* animate, SkMSec end) { michael@0: SkEvent evt; michael@0: evt.setS32("time", animate->getStart() + end); michael@0: evt.setPtr("anim", animate); michael@0: evt.setType(SK_EventType_OnEnd); michael@0: SkEventSinkID sinkID = fAnimator->getSinkID(); michael@0: fAnimator->onEventPost(new SkEvent(evt), sinkID); michael@0: } michael@0: michael@0: void SkAnimateMaker::reset() { michael@0: deleteMembers(); michael@0: fChildren.reset(); michael@0: fHelpers.reset(); michael@0: fIDs.reset(); michael@0: fEvents.reset(); michael@0: fDisplayList.hardReset(); michael@0: } michael@0: michael@0: void SkAnimateMaker::removeActive(SkActive* active) { michael@0: if (active == NULL) michael@0: return; michael@0: fDisplayList.remove(active); michael@0: } michael@0: michael@0: bool SkAnimateMaker::resolveID(SkDisplayable* displayable, SkDisplayable* original) { michael@0: SkString newID; michael@0: bool success = computeID(original, NULL, &newID); michael@0: if (success) michael@0: setID(displayable, newID); michael@0: return success; michael@0: } michael@0: michael@0: void SkAnimateMaker::setErrorString() { michael@0: fErrorString.reset(); michael@0: if (fError.hasError()) { michael@0: SkString err; michael@0: if (fFileName.size() > 0) michael@0: fErrorString.set(fFileName.c_str()); michael@0: else michael@0: fErrorString.set("screenplay error"); michael@0: int line = fError.getLineNumber(); michael@0: if (line >= 0) { michael@0: fErrorString.append(", "); michael@0: fErrorString.append("line "); michael@0: fErrorString.appendS32(line); michael@0: } michael@0: fErrorString.append(": "); michael@0: fError.getErrorString(&err); michael@0: fErrorString.append(err); michael@0: #if defined SK_DEBUG michael@0: SkDebugf("%s\n", fErrorString.c_str()); michael@0: #endif michael@0: } michael@0: } michael@0: michael@0: void SkAnimateMaker::setEnableTime(SkMSec appTime, SkMSec expectedTime) { michael@0: #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING michael@0: SkString debugOut; michael@0: SkMSec time = getAppTime(); michael@0: debugOut.appendS32(time - fDebugTimeBase); michael@0: debugOut.append(" set enable old enable="); michael@0: debugOut.appendS32(fEnableTime - fDebugTimeBase); michael@0: debugOut.append(" old adjust="); michael@0: debugOut.appendS32(fAdjustedStart); michael@0: debugOut.append(" new enable="); michael@0: debugOut.appendS32(expectedTime - fDebugTimeBase); michael@0: debugOut.append(" new adjust="); michael@0: debugOut.appendS32(appTime - expectedTime); michael@0: SkDebugf("%s\n", debugOut.c_str()); michael@0: #endif michael@0: fAdjustedStart = appTime - expectedTime; michael@0: fEnableTime = expectedTime; michael@0: SkDisplayable** firstMovie = fMovies.begin(); michael@0: SkDisplayable** endMovie = fMovies.end(); michael@0: for (SkDisplayable** ptr = firstMovie; ptr < endMovie; ptr++) { michael@0: SkDisplayMovie* movie = (SkDisplayMovie*) *ptr; michael@0: movie->fMovie.fMaker->setEnableTime(appTime, expectedTime); michael@0: } michael@0: } michael@0: michael@0: void SkAnimateMaker::setExtraPropertyCallBack(SkDisplayTypes type, michael@0: SkScriptEngine::_propertyCallBack callBack, void* userStorage) { michael@0: SkExtras** end = fExtras.end(); michael@0: for (SkExtras** extraPtr = fExtras.begin(); extraPtr < end; extraPtr++) { michael@0: SkExtras* extra = *extraPtr; michael@0: if (extra->definesType(type)) { michael@0: extra->fExtraCallBack = callBack; michael@0: extra->fExtraStorage = userStorage; michael@0: break; michael@0: } michael@0: } michael@0: } michael@0: michael@0: void SkAnimateMaker::setID(SkDisplayable* displayable, const SkString& newID) { michael@0: fIDs.set(newID.c_str(), displayable); michael@0: #ifdef SK_DEBUG michael@0: displayable->_id.set(newID); michael@0: displayable->id = displayable->_id.c_str(); michael@0: #endif michael@0: } michael@0: michael@0: void SkAnimateMaker::setScriptError(const SkScriptEngine& engine) { michael@0: SkString errorString; michael@0: #ifdef SK_DEBUG michael@0: engine.getErrorString(&errorString); michael@0: #endif michael@0: setErrorNoun(errorString); michael@0: setErrorCode(SkDisplayXMLParserError::kErrorInScript); michael@0: } michael@0: michael@0: bool SkAnimateMaker::GetStep(const char* token, size_t len, void* stepPtr, SkScriptValue* value) { michael@0: if (SK_LITERAL_STR_EQUAL("step", token, len)) { michael@0: value->fOperand.fS32 = *(int32_t*) stepPtr; michael@0: value->fType = SkType_Int; michael@0: return true; michael@0: } michael@0: return false; michael@0: }