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 "SkDisplayApply.h" michael@0: #include "SkAnimateActive.h" michael@0: #include "SkAnimateMaker.h" michael@0: #include "SkAnimateSet.h" michael@0: #include "SkAnimatorScript.h" michael@0: #include "SkDisplayType.h" michael@0: #include "SkDrawGroup.h" michael@0: #include "SkParse.h" michael@0: #include "SkScript.h" michael@0: #include "SkSystemEventTypes.h" michael@0: #ifdef SK_DEBUG michael@0: #include "SkTime.h" michael@0: #endif michael@0: #include michael@0: michael@0: enum SkApply_Properties { michael@0: SK_PROPERTY(animator), michael@0: SK_PROPERTY(step), michael@0: SK_PROPERTY(steps), michael@0: SK_PROPERTY(time) michael@0: }; michael@0: michael@0: #if SK_USE_CONDENSED_INFO == 0 michael@0: michael@0: // if no attibutes, enclosed displayable is both scope & target michael@0: // only if both scope & target are specified, or if target and enclosed displayable, are scope and target different michael@0: const SkMemberInfo SkApply::fInfo[] = { michael@0: SK_MEMBER_PROPERTY(animator, Animate), michael@0: SK_MEMBER(begin, MSec), michael@0: SK_MEMBER(dontDraw, Boolean), michael@0: SK_MEMBER(dynamicScope, String), michael@0: SK_MEMBER(interval, MSec), // recommended redraw interval michael@0: SK_MEMBER(mode, ApplyMode), michael@0: #if 0 michael@0: SK_MEMBER(pickup, Boolean), michael@0: #endif michael@0: SK_MEMBER(restore, Boolean), michael@0: SK_MEMBER(scope, Drawable), // thing that scopes animation (unnamed enclosed displayable goes here) michael@0: SK_MEMBER_PROPERTY(step, Int), michael@0: SK_MEMBER_PROPERTY(steps, Int), michael@0: SK_MEMBER_PROPERTY(time, MSec), michael@0: SK_MEMBER(transition, ApplyTransition) michael@0: }; michael@0: michael@0: #endif michael@0: michael@0: DEFINE_GET_MEMBER(SkApply); michael@0: michael@0: SkApply::SkApply() : begin(0), dontDraw(false), interval((SkMSec) -1), mode((Mode) -1), /*pickup(false), */ michael@0: restore(false), scope(NULL), steps(-1), transition((Transition) -1), fActive(NULL), /*fCurrentScope(NULL),*/ michael@0: fLastTime(0), fAppended(false), fContainsScope(false), fDeleteScope(false), fEmbedded(false), michael@0: fEnabled(false), fEnabling(false) { michael@0: } michael@0: michael@0: SkApply::~SkApply() { michael@0: for (SkDrawable** curPtr = fScopes.begin(); curPtr < fScopes.end(); curPtr++) michael@0: delete *curPtr; michael@0: if (fDeleteScope) michael@0: delete scope; michael@0: // !!! caller must call maker.removeActive(fActive) michael@0: delete fActive; michael@0: } michael@0: michael@0: void SkApply::activate(SkAnimateMaker& maker) { michael@0: if (fActive != NULL) { michael@0: if (fActive->fDrawIndex == 0 && fActive->fDrawMax == 0) michael@0: return; // if only one use, nothing more to do michael@0: if (restore == false) michael@0: return; // all share same state, regardless of instance number michael@0: bool save = fActive->initializeSave(); michael@0: fActive->fixInterpolator(save); michael@0: } else { michael@0: fActive = new SkActive(*this, maker); michael@0: fActive->init(); michael@0: maker.appendActive(fActive); michael@0: if (restore) { michael@0: fActive->initializeSave(); michael@0: int animators = fAnimators.count(); michael@0: for (int index = 0; index < animators; index++) michael@0: fActive->saveInterpolatorValues(index); michael@0: } michael@0: } michael@0: } michael@0: michael@0: void SkApply::append(SkApply* apply) { michael@0: if (fActive == NULL) michael@0: return; michael@0: int oldCount = fActive->fAnimators.count(); michael@0: fActive->append(apply); michael@0: if (restore) { michael@0: fActive->appendSave(oldCount); michael@0: int newCount = fActive->fAnimators.count(); michael@0: for (int index = oldCount; index < newCount; index++) michael@0: fActive->saveInterpolatorValues(index); michael@0: } michael@0: } michael@0: michael@0: void SkApply::applyValues(int animatorIndex, SkOperand* values, int count, michael@0: SkDisplayTypes valuesType, SkMSec time) michael@0: { michael@0: SkAnimateBase* animator = fActive->fAnimators[animatorIndex]; michael@0: const SkMemberInfo * info = animator->fFieldInfo; michael@0: SkASSERT(animator); michael@0: SkASSERT(info != NULL); michael@0: SkDisplayTypes type = (SkDisplayTypes) info->fType; michael@0: SkDisplayable* target = getTarget(animator); michael@0: if (animator->hasExecute() || type == SkType_MemberFunction || type == SkType_MemberProperty) { michael@0: SkDisplayable* executor = animator->hasExecute() ? animator : target; michael@0: if (type != SkType_MemberProperty) { michael@0: SkTDArray typedValues; michael@0: for (int index = 0; index < count; index++) { michael@0: SkScriptValue temp; michael@0: temp.fType = valuesType; michael@0: temp.fOperand = values[index]; michael@0: *typedValues.append() = temp; michael@0: } michael@0: executor->executeFunction(target, info->functionIndex(), typedValues, info->getType(), NULL); michael@0: } else { michael@0: SkScriptValue scriptValue; michael@0: scriptValue.fOperand = values[0]; michael@0: scriptValue.fType = info->getType(); michael@0: target->setProperty(info->propertyIndex(), scriptValue); michael@0: } michael@0: } else { michael@0: SkTypedArray converted; michael@0: if (type == SkType_ARGB) { michael@0: if (count == 4) { michael@0: // !!! assert that it is SkType_Float ? michael@0: animator->packARGB(&values->fScalar, count, &converted); michael@0: values = converted.begin(); michael@0: count = converted.count(); michael@0: } else { michael@0: SkASSERT(count == 1); michael@0: } michael@0: } michael@0: // SkASSERT(type == SkType_ARGB || type == SkType_String ||info->isSettable()); michael@0: if (type == SkType_String || type == SkType_DynamicString) michael@0: info->setString(target, values->fString); michael@0: else if (type == SkType_Drawable || type == SkType_Displayable) michael@0: target->setReference(info, values->fDisplayable); michael@0: else michael@0: info->setValue(target, values, count); michael@0: } michael@0: } michael@0: michael@0: bool SkApply::contains(SkDisplayable* child) { michael@0: for (SkDrawable** curPtr = fScopes.begin(); curPtr < fScopes.end(); curPtr++) { michael@0: if (*curPtr == child || (*curPtr)->contains(child)) michael@0: return true; michael@0: } michael@0: return fDeleteScope && scope == child; michael@0: } michael@0: michael@0: SkDisplayable* SkApply::deepCopy(SkAnimateMaker* maker) { michael@0: SkDrawable* saveScope = scope; michael@0: scope = NULL; michael@0: SkApply* result = (SkApply*) INHERITED::deepCopy(maker); michael@0: result->scope = scope = saveScope; michael@0: SkAnimateBase** end = fAnimators.end(); michael@0: for (SkAnimateBase** animPtr = fAnimators.begin(); animPtr < end; animPtr++) { michael@0: SkAnimateBase* anim = (SkAnimateBase*) (*animPtr)->deepCopy(maker); michael@0: *result->fAnimators.append() = anim; michael@0: maker->helperAdd(anim); michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: void SkApply::disable() { michael@0: //!!! this is the right thing to do, but has bad side effects because of other problems michael@0: // currently, if an apply is in a g and scopes a statement in another g, it ends up as members michael@0: // of both containers. The disabling here incorrectly disables both instances michael@0: // maybe the fEnabled flag needs to be moved to the fActive data so that both michael@0: // instances are not affected. michael@0: // fEnabled = false; michael@0: } michael@0: michael@0: bool SkApply::draw(SkAnimateMaker& maker) { michael@0: if (scope ==NULL) michael@0: return false; michael@0: if (scope->isApply() || scope->isDrawable() == false) michael@0: return false; michael@0: if (fEnabled == false) michael@0: enable(maker); michael@0: SkASSERT(scope); michael@0: activate(maker); michael@0: if (mode == kMode_immediate) michael@0: return fActive->draw(); michael@0: bool result = interpolate(maker, maker.getInTime()); michael@0: if (dontDraw == false) { michael@0: // if (scope->isDrawable()) michael@0: result |= scope->draw(maker); michael@0: } michael@0: if (restore) { michael@0: for (int index = 0; index < fActive->fAnimators.count(); index++) michael@0: endSave(index); michael@0: fActive->advance(); michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: #ifdef SK_DUMP_ENABLED michael@0: void SkApply::dump(SkAnimateMaker* maker) { michael@0: dumpBase(maker); michael@0: if (dynamicScope.isEmpty() == false) michael@0: SkDebugf("dynamicScope=\"%s\" ", dynamicScope.c_str()); michael@0: if (dontDraw) michael@0: SkDebugf("dontDraw=\"true\" "); michael@0: if (begin != 0) //perhaps we want this no matter what? michael@0: SkDebugf("begin=\"%g\" ", (float) begin/1000.0f); //is this correct? michael@0: if (interval != (SkMSec) -1) michael@0: SkDebugf("interval=\"%g\" ", (float) interval/1000.0f); michael@0: if (steps != -1) michael@0: SkDebugf("steps=\"%d\" ", steps); michael@0: if (restore) michael@0: SkDebugf("restore=\"true\" "); michael@0: if (transition == kTransition_reverse) michael@0: SkDebugf("transition=\"reverse\" "); michael@0: if (mode == kMode_immediate) { michael@0: SkDebugf("mode=\"immediate\" "); michael@0: } michael@0: else if (mode == kMode_create) { michael@0: SkDebugf("mode=\"create\" "); michael@0: } michael@0: bool closedYet = false; michael@0: SkDisplayList::fIndent += 4; michael@0: int save = SkDisplayList::fDumpIndex; michael@0: if (scope) { michael@0: if (closedYet == false) { michael@0: SkDebugf(">\n"); michael@0: closedYet = true; michael@0: } michael@0: scope->dump(maker); michael@0: } michael@0: int index; michael@0: // if (fActive) { michael@0: for (index = 0; index < fAnimators.count(); index++) { michael@0: if (closedYet == false) { michael@0: SkDebugf(">\n"); michael@0: closedYet = true; michael@0: } michael@0: SkAnimateBase* animator = fAnimators[index]; michael@0: animator->dump(maker); michael@0: // } michael@0: } michael@0: SkDisplayList::fIndent -= 4; michael@0: SkDisplayList::fDumpIndex = save; michael@0: if (closedYet) michael@0: dumpEnd(maker); michael@0: else michael@0: SkDebugf("/>\n"); michael@0: } michael@0: #endif michael@0: michael@0: bool SkApply::enable(SkAnimateMaker& maker) { michael@0: fEnabled = true; michael@0: bool initialized = fActive != NULL; michael@0: if (dynamicScope.size() > 0) michael@0: enableDynamic(maker); michael@0: if (maker.fError.hasError()) michael@0: return false; michael@0: int animators = fAnimators.count(); michael@0: int index; michael@0: for (index = 0; index < animators; index++) { michael@0: SkAnimateBase* animator = fAnimators[index]; michael@0: animator->fStart = maker.fEnableTime; michael@0: animator->fResetPending = animator->fReset; michael@0: } michael@0: if (scope && scope->isApply()) michael@0: ((SkApply*) scope)->setEmbedded(); michael@0: /* if (mode == kMode_once) { michael@0: if (scope) { michael@0: activate(maker); michael@0: interpolate(maker, maker.fEnableTime); michael@0: inactivate(maker); michael@0: } michael@0: return true; michael@0: }*/ michael@0: if ((mode == kMode_immediate || mode == kMode_create) && scope == NULL) michael@0: return false; // !!! error? michael@0: bool enableMe = scope && (scope->hasEnable() || scope->isApply() || scope->isDrawable() == false); michael@0: if ((mode == kMode_immediate && enableMe) || mode == kMode_create) michael@0: activate(maker); // for non-drawables like post, prime them here michael@0: if (mode == kMode_immediate && enableMe) michael@0: fActive->enable(); michael@0: if (mode == kMode_create && scope != NULL) { michael@0: enableCreate(maker); michael@0: return true; michael@0: } michael@0: if (mode == kMode_immediate) { michael@0: return scope->isApply() || scope->isDrawable() == false; michael@0: } michael@0: refresh(maker); michael@0: SkDisplayList& displayList = maker.fDisplayList; michael@0: SkDrawable* drawable; michael@0: #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING michael@0: SkString debugOut; michael@0: SkMSec time = maker.getAppTime(); michael@0: debugOut.appendS32(time - maker.fDebugTimeBase); michael@0: debugOut.append(" apply enable id="); michael@0: debugOut.append(_id); michael@0: debugOut.append("; start="); michael@0: debugOut.appendS32(maker.fEnableTime - maker.fDebugTimeBase); michael@0: SkDebugf("%s\n", debugOut.c_str()); michael@0: #endif michael@0: if (scope == NULL || scope->isApply() || scope->getType() == SkType_Movie || scope->isDrawable() == false) { michael@0: activate(maker); // for non-drawables like post, prime them here michael@0: if (initialized) { michael@0: append(this); michael@0: } michael@0: fEnabling = true; michael@0: interpolate(maker, maker.fEnableTime); michael@0: fEnabling = false; michael@0: if (scope != NULL && dontDraw == false) michael@0: scope->enable(maker); michael@0: return true; michael@0: } else if (initialized && restore == false) michael@0: append(this); michael@0: #if 0 michael@0: bool wasActive = inactivate(maker); // start fresh michael@0: if (wasActive) { michael@0: activate(maker); michael@0: interpolate(maker, maker.fEnableTime); michael@0: return true; michael@0: } michael@0: #endif michael@0: // start here; michael@0: // now that one apply might embed another, only the parent apply should replace the scope michael@0: // or get appended to the display list michael@0: // similarly, an apply added by an add immediate has already been located in the display list michael@0: // and should not get moved or added again here michael@0: if (fEmbedded) { michael@0: return false; // already added to display list by embedder michael@0: } michael@0: drawable = (SkDrawable*) scope; michael@0: SkTDDrawableArray* parentList; michael@0: SkTDDrawableArray* grandList; michael@0: SkGroup* parentGroup; michael@0: SkGroup* thisGroup; michael@0: int old = displayList.findGroup(drawable, &parentList, &parentGroup, &thisGroup, &grandList); michael@0: if (old < 0) michael@0: goto append; michael@0: else if (fContainsScope) { michael@0: if ((*parentList)[old] != this || restore) { michael@0: append: michael@0: if (parentGroup) michael@0: parentGroup->markCopySize(old); michael@0: if (parentList->count() < 10000) { michael@0: fAppended = true; michael@0: *parentList->append() = this; michael@0: } else michael@0: maker.setErrorCode(SkDisplayXMLParserError::kDisplayTreeTooDeep); michael@0: old = -1; michael@0: } else michael@0: reset(); michael@0: } else { michael@0: SkASSERT(old < parentList->count()); michael@0: if ((*parentList)[old]->isApply()) { michael@0: SkApply* apply = (SkApply*) (*parentList)[old]; michael@0: if (apply != this && apply->fActive == NULL) michael@0: apply->activate(maker); michael@0: apply->append(this); michael@0: parentGroup = NULL; michael@0: } else { michael@0: if (parentGroup) michael@0: parentGroup->markCopySize(old); michael@0: SkDrawable** newApplyLocation = &(*parentList)[old]; michael@0: SkGroup* pGroup; michael@0: int oldApply = displayList.findGroup(this, &parentList, &pGroup, &thisGroup, &grandList); michael@0: if (oldApply >= 0) { michael@0: (*parentList)[oldApply] = (SkDrawable*) SkDisplayType::CreateInstance(&maker, SkType_Apply); michael@0: parentGroup = NULL; michael@0: fDeleteScope = true; michael@0: } michael@0: *newApplyLocation = this; michael@0: } michael@0: } michael@0: if (parentGroup) { michael@0: parentGroup->markCopySet(old); michael@0: fDeleteScope = dynamicScope.size() == 0; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: void SkApply::enableCreate(SkAnimateMaker& maker) { michael@0: SkString newID; michael@0: for (int step = 0; step <= steps; step++) { michael@0: fLastTime = step * SK_MSec1; michael@0: bool success = maker.computeID(scope, this, &newID); michael@0: if (success == false) michael@0: return; michael@0: if (maker.find(newID.c_str(), NULL)) michael@0: continue; michael@0: SkApply* copy = (SkApply*) deepCopy(&maker); // work on copy of animator state michael@0: if (mode == kMode_create) michael@0: copy->mode = (Mode) -1; michael@0: SkDrawable* copyScope = copy->scope = (SkDrawable*) scope->deepCopy(&maker); michael@0: *fScopes.append() = copyScope; michael@0: if (copyScope->resolveIDs(maker, scope, this)) { michael@0: step = steps; // quit michael@0: goto next; // resolveIDs failed michael@0: } michael@0: if (newID.size() > 0) michael@0: maker.setID(copyScope, newID); michael@0: if (copy->resolveIDs(maker, this, this)) { // fix up all fields, including target michael@0: step = steps; // quit michael@0: goto next; // resolveIDs failed michael@0: } michael@0: copy->activate(maker); michael@0: copy->interpolate(maker, step * SK_MSec1); michael@0: maker.removeActive(copy->fActive); michael@0: next: michael@0: delete copy; michael@0: } michael@0: } michael@0: michael@0: void SkApply::enableDynamic(SkAnimateMaker& maker) { michael@0: SkASSERT(mode != kMode_create); // create + dynamic are not currently compatible michael@0: SkDisplayable* newScope; michael@0: bool success = SkAnimatorScript::EvaluateDisplayable(maker, this, dynamicScope.c_str(), michael@0: &newScope); michael@0: if (success && scope != newScope) { michael@0: SkTDDrawableArray* pList, * gList; michael@0: SkGroup* pGroup = NULL, * found = NULL; michael@0: int old = maker.fDisplayList.findGroup(scope, &pList, &pGroup, &found, &gList); michael@0: if (pList && old >= 0 && (*pList)[old]->isApply() && (*pList)[old] != this) { michael@0: if (fAppended == false) { michael@0: if (found != NULL) { michael@0: SkDisplayable* oldChild = (*pList)[old]; michael@0: if (oldChild->isApply() && found->copySet(old)) { michael@0: found->markCopyClear(old); michael@0: // delete oldChild; michael@0: } michael@0: } michael@0: (*pList)[old] = scope; michael@0: } else michael@0: pList->remove(old); michael@0: } michael@0: scope = (SkDrawable*) newScope; michael@0: onEndElement(maker); michael@0: } michael@0: maker.removeActive(fActive); michael@0: delete fActive; michael@0: fActive = NULL; michael@0: } michael@0: michael@0: void SkApply::endSave(int index) { michael@0: SkAnimateBase* animate = fActive->fAnimators[index]; michael@0: const SkMemberInfo* info = animate->fFieldInfo; michael@0: SkDisplayTypes type = (SkDisplayTypes) info->fType; michael@0: if (type == SkType_MemberFunction) michael@0: return; michael@0: SkDisplayable* target = getTarget(animate); michael@0: size_t size = info->getSize(target); michael@0: int count = (int) (size / sizeof(SkScalar)); michael@0: int activeIndex = fActive->fDrawIndex + index; michael@0: SkOperand* last = new SkOperand[count]; michael@0: SkAutoTDelete autoLast(last); michael@0: if (type != SkType_MemberProperty) { michael@0: info->getValue(target, last, count); michael@0: SkOperand* saveOperand = fActive->fSaveRestore[activeIndex]; michael@0: if (saveOperand) michael@0: info->setValue(target, fActive->fSaveRestore[activeIndex], count); michael@0: } else { michael@0: SkScriptValue scriptValue; michael@0: SkDEBUGCODE(bool success = ) target->getProperty(info->propertyIndex(), &scriptValue); michael@0: SkASSERT(success == true); michael@0: last[0] = scriptValue.fOperand; michael@0: scriptValue.fOperand = fActive->fSaveRestore[activeIndex][0]; michael@0: target->setProperty(info->propertyIndex(), scriptValue); michael@0: } michael@0: SkOperand* save = fActive->fSaveRestore[activeIndex]; michael@0: if (save) michael@0: memcpy(save, last, count * sizeof(SkOperand)); michael@0: } michael@0: michael@0: bool SkApply::getProperty(int index, SkScriptValue* value) const { michael@0: switch (index) { michael@0: case SK_PROPERTY(step): michael@0: value->fType = SkType_Int; michael@0: value->fOperand.fS32 = fLastTime / SK_MSec1; michael@0: break; michael@0: case SK_PROPERTY(steps): michael@0: value->fType = SkType_Int; michael@0: value->fOperand.fS32 = steps; michael@0: break; michael@0: case SK_PROPERTY(time): michael@0: value->fType = SkType_MSec; michael@0: value->fOperand.fS32 = fLastTime; michael@0: break; michael@0: default: michael@0: // SkASSERT(0); michael@0: return false; michael@0: } michael@0: return true; michael@0: } michael@0: michael@0: void SkApply::getStep(SkScriptValue* value) { michael@0: getProperty(SK_PROPERTY(step), value); michael@0: } michael@0: michael@0: SkDrawable* SkApply::getTarget(SkAnimateBase* animate) { michael@0: if (animate->fTargetIsScope == false || mode != kMode_create) michael@0: return animate->fTarget; michael@0: return scope; michael@0: } michael@0: michael@0: bool SkApply::hasDelayedAnimator() const { michael@0: SkAnimateBase* const* animEnd = fAnimators.end(); michael@0: for (SkAnimateBase* const* animPtr = fAnimators.begin(); animPtr < animEnd; animPtr++) { michael@0: SkAnimateBase* const animator = *animPtr; michael@0: if (animator->fDelayed) michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: bool SkApply::hasEnable() const { michael@0: return true; michael@0: } michael@0: michael@0: bool SkApply::inactivate(SkAnimateMaker& maker) { michael@0: if (fActive == NULL) michael@0: return false; michael@0: maker.removeActive(fActive); michael@0: delete fActive; michael@0: fActive = NULL; michael@0: return true; michael@0: } michael@0: michael@0: #ifdef SK_DEBUG michael@0: SkMSec lastTime = (SkMSec) -1; michael@0: #endif michael@0: michael@0: bool SkApply::interpolate(SkAnimateMaker& maker, SkMSec rawTime) { michael@0: if (fActive == NULL) michael@0: return false; michael@0: bool result = false; michael@0: #if defined SK_DEBUG && defined SK_DEBUG_ANIMATION_TIMING michael@0: SkMSec time = maker.getAppTime(); michael@0: if (lastTime == (SkMSec) -1) michael@0: lastTime = rawTime - 1; michael@0: if (fActive != NULL && michael@0: strcmp(id, "a3") == 0 && rawTime > lastTime) { michael@0: lastTime += 1000; michael@0: SkString debugOut; michael@0: debugOut.appendS32(time - maker.fDebugTimeBase); michael@0: debugOut.append(" apply id="); michael@0: debugOut.append(_id); michael@0: debugOut.append("; "); michael@0: debugOut.append(fActive->fAnimators[0]->_id); michael@0: debugOut.append("="); michael@0: debugOut.appendS32(rawTime - fActive->fState[0].fStartTime); michael@0: debugOut.append(")"); michael@0: SkDebugf("%s\n", debugOut.c_str()); michael@0: } michael@0: #endif michael@0: fActive->start(); michael@0: if (restore) michael@0: fActive->initializeSave(); michael@0: int animators = fActive->fAnimators.count(); michael@0: for (int inner = 0; inner < animators; inner++) { michael@0: SkAnimateBase* animate = fActive->fAnimators[inner]; michael@0: if (animate->fChanged) { michael@0: animate->fChanged = false; michael@0: animate->fStart = rawTime; michael@0: // SkTypedArray values; michael@0: // int count = animate->fValues.count(); michael@0: // values.setCount(count); michael@0: // memcpy(values.begin(), animate->fValues.begin(), sizeof(SkOperand) * count); michael@0: animate->onEndElement(maker); michael@0: // if (memcmp(values.begin(), animate->fValues.begin(), sizeof(SkOperand) * count) != 0) { michael@0: fActive->append(this); michael@0: fActive->start(); michael@0: // } michael@0: } michael@0: SkMSec time = fActive->getTime(rawTime, inner); michael@0: SkActive::SkState& state = fActive->fState[inner]; michael@0: if (SkMSec_LT(rawTime, state.fStartTime)) { michael@0: if (fEnabling) { michael@0: animate->fDelayed = true; michael@0: maker.delayEnable(this, state.fStartTime); michael@0: } michael@0: continue; michael@0: } else michael@0: animate->fDelayed = false; michael@0: SkMSec innerTime = fLastTime = state.getRelativeTime(time); michael@0: if (restore) michael@0: fActive->restoreInterpolatorValues(inner); michael@0: if (animate->fReset) { michael@0: if (transition != SkApply::kTransition_reverse) { michael@0: if (SkMSec_LT(state.fBegin + state.fDuration, innerTime)) { michael@0: if (animate->fResetPending) { michael@0: innerTime = 0; michael@0: animate->fResetPending = false; michael@0: } else michael@0: continue; michael@0: } michael@0: } else if (innerTime == 0) { michael@0: if (animate->fResetPending) { michael@0: innerTime = state.fBegin + state.fDuration; michael@0: animate->fResetPending = false; michael@0: } else michael@0: continue; michael@0: } michael@0: } michael@0: int count = animate->components(); michael@0: SkAutoSTMalloc<16, SkOperand> values(count); michael@0: SkInterpolatorBase::Result interpResult = fActive->fInterpolators[inner]->timeToValues( michael@0: innerTime, values.get()); michael@0: result |= (interpResult != SkInterpolatorBase::kFreezeEnd_Result); michael@0: if (((transition != SkApply::kTransition_reverse && interpResult == SkInterpolatorBase::kFreezeEnd_Result) || michael@0: (transition == SkApply::kTransition_reverse && fLastTime == 0)) && state.fUnpostedEndEvent) { michael@0: // SkDEBUGF(("interpolate: post on end\n")); michael@0: state.fUnpostedEndEvent = false; michael@0: maker.postOnEnd(animate, state.fBegin + state.fDuration); michael@0: maker.fAdjustedStart = 0; // !!! left over from synchronizing animation days, undoubtably out of date (and broken) michael@0: } michael@0: if (animate->formula.size() > 0) { michael@0: if (fLastTime > animate->dur) michael@0: fLastTime = animate->dur; michael@0: SkTypedArray formulaValues; michael@0: formulaValues.setCount(count); michael@0: SkDEBUGCODE(bool success = ) animate->fFieldInfo->setValue(maker, &formulaValues, 0, 0, NULL, michael@0: animate->getValuesType(), animate->formula); michael@0: SkASSERT(success); michael@0: if (restore) michael@0: save(inner); // save existing value michael@0: applyValues(inner, formulaValues.begin(), count, animate->getValuesType(), innerTime); michael@0: } else { michael@0: if (restore) michael@0: save(inner); // save existing value michael@0: applyValues(inner, values.get(), count, animate->getValuesType(), innerTime); michael@0: } michael@0: } michael@0: return result; michael@0: } michael@0: michael@0: void SkApply::initialize() { michael@0: if (scope == NULL) michael@0: return; michael@0: if (scope->isApply() || scope->isDrawable() == false) michael@0: return; michael@0: scope->initialize(); michael@0: } michael@0: michael@0: void SkApply::onEndElement(SkAnimateMaker& maker) michael@0: { michael@0: SkDrawable* scopePtr = scope; michael@0: while (scopePtr && scopePtr->isApply()) { michael@0: SkApply* scopedApply = (SkApply*) scopePtr; michael@0: if (scopedApply->scope == this) { michael@0: maker.setErrorCode(SkDisplayXMLParserError::kApplyScopesItself); michael@0: return; michael@0: } michael@0: scopePtr = scopedApply->scope; michael@0: } michael@0: if (mode == kMode_create) michael@0: return; michael@0: if (scope != NULL && steps >= 0 && scope->isApply() == false && scope->isDrawable()) michael@0: scope->setSteps(steps); michael@0: for (SkAnimateBase** animPtr = fAnimators.begin(); animPtr < fAnimators.end(); animPtr++) { michael@0: SkAnimateBase* anim = *animPtr; michael@0: //for reusing apply statements with dynamic scope michael@0: if (anim->fTarget == NULL || anim->fTargetIsScope) { michael@0: anim->fTargetIsScope = true; michael@0: if (scope) michael@0: anim->fTarget = scope; michael@0: else michael@0: anim->setTarget(maker); michael@0: anim->onEndElement(maker); // allows animate->fFieldInfo to be set michael@0: } michael@0: if (scope != NULL && steps >= 0 && anim->fTarget != scope && anim->fTarget->isDrawable()) michael@0: anim->fTarget->setSteps(steps); michael@0: } michael@0: } michael@0: michael@0: const SkMemberInfo* SkApply::preferredChild(SkDisplayTypes type) { michael@0: SkASSERT(SkDisplayType::IsAnimate(type) == false); michael@0: fContainsScope = true; michael@0: return getMember("scope"); // !!! cwap! need to refer to member through enum like kScope instead michael@0: } michael@0: michael@0: void SkApply::refresh(SkAnimateMaker& maker) { michael@0: for (SkAnimateBase** animPtr = fAnimators.begin(); animPtr < fAnimators.end(); animPtr++) { michael@0: SkAnimateBase* animate = *animPtr; michael@0: animate->onEndElement(maker); michael@0: } michael@0: if (fActive) michael@0: fActive->resetInterpolators(); michael@0: } michael@0: michael@0: void SkApply::reset() { michael@0: if (fActive) michael@0: fActive->resetState(); michael@0: } michael@0: michael@0: bool SkApply::resolveIDs(SkAnimateMaker& maker, SkDisplayable* original, SkApply* apply) { // replace to/formula strings in animators of the form xxx.step with the step value, if xxx.step is in scope michael@0: if (resolveField(maker, apply, &dynamicScope) == false) michael@0: return true; // failed michael@0: SkAnimateBase** endPtr = fAnimators.end(); michael@0: SkAnimateBase** origPtr = ((SkApply*) original)->fAnimators.begin(); michael@0: for (SkAnimateBase** animPtr = fAnimators.begin(); animPtr < endPtr; ) { michael@0: SkAnimateBase* animator = *animPtr++; michael@0: maker.resolveID(animator, *origPtr++); michael@0: if (resolveField(maker, this, &animator->target) == false) michael@0: return true; michael@0: if (resolveField(maker, this, &animator->from) == false) michael@0: return true; michael@0: if (resolveField(maker, this, &animator->to) == false) michael@0: return true; michael@0: if (resolveField(maker, this, &animator->formula) == false) michael@0: return true; michael@0: } michael@0: // setEmbedded(); michael@0: onEndElement(maker); michael@0: return false; // succeeded michael@0: } michael@0: michael@0: bool SkApply::resolveField(SkAnimateMaker& maker, SkDisplayable* parent, SkString* str) { michael@0: const char* script = str->c_str(); michael@0: if (str->startsWith("#string:") == false) michael@0: return true; michael@0: script += sizeof("#string:") - 1; michael@0: return SkAnimatorScript::EvaluateString(maker, this, parent, script, str); michael@0: } michael@0: michael@0: void SkApply::save(int index) { michael@0: SkAnimateBase* animate = fActive->fAnimators[index]; michael@0: const SkMemberInfo * info = animate->fFieldInfo; michael@0: SkDisplayable* target = getTarget(animate); michael@0: // if (animate->hasExecute()) michael@0: // info = animate->getResolvedInfo(); michael@0: SkDisplayTypes type = (SkDisplayTypes) info->fType; michael@0: if (type == SkType_MemberFunction) michael@0: return; // nothing to save michael@0: size_t size = info->getSize(target); michael@0: int count = (int) (size / sizeof(SkScalar)); michael@0: bool useLast = true; michael@0: // !!! this all may be unneeded, at least in the dynamic case ?? michael@0: int activeIndex = fActive->fDrawIndex + index; michael@0: SkTDOperandArray last; michael@0: if (fActive->fSaveRestore[activeIndex] == NULL) { michael@0: fActive->fSaveRestore[activeIndex] = new SkOperand[count]; michael@0: useLast = false; michael@0: } else { michael@0: last.setCount(count); michael@0: memcpy(last.begin(), fActive->fSaveRestore[activeIndex], count * sizeof(SkOperand)); michael@0: } michael@0: if (type != SkType_MemberProperty) { michael@0: info->getValue(target, fActive->fSaveRestore[activeIndex], count); michael@0: if (useLast) michael@0: info->setValue(target, last.begin(), count); michael@0: } else { michael@0: SkScriptValue scriptValue; michael@0: SkDEBUGCODE(bool success = ) target->getProperty(info->propertyIndex(), &scriptValue); michael@0: SkASSERT(success == true); michael@0: SkASSERT(scriptValue.fType == SkType_Float); michael@0: fActive->fSaveRestore[activeIndex][0] = scriptValue.fOperand; michael@0: if (useLast) { michael@0: SkScriptValue scriptValue; michael@0: scriptValue.fType = type; michael@0: scriptValue.fOperand = last[0]; michael@0: target->setProperty(info->propertyIndex(), scriptValue); michael@0: } michael@0: } michael@0: // !!! end of unneeded michael@0: } michael@0: michael@0: bool SkApply::setProperty(int index, SkScriptValue& scriptValue) { michael@0: switch (index) { michael@0: case SK_PROPERTY(animator): { michael@0: SkAnimateBase* animate = (SkAnimateBase*) scriptValue.fOperand.fDisplayable; michael@0: SkASSERT(animate->isAnimate()); michael@0: *fAnimators.append() = animate; michael@0: return true; michael@0: } michael@0: case SK_PROPERTY(steps): michael@0: steps = scriptValue.fOperand.fS32; michael@0: if (fActive) michael@0: fActive->setSteps(steps); michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: void SkApply::setSteps(int _steps) { michael@0: steps = _steps; michael@0: } michael@0: michael@0: #ifdef SK_DEBUG michael@0: void SkApply::validate() { michael@0: if (fActive) michael@0: fActive->validate(); michael@0: } michael@0: #endif