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