nsIStyleRule* CommonAnimationManager::GetAnimationRule(mozilla::dom::Element* aElement, nsCSSPseudoElements::Type aPseudoType) { MOZ_ASSERT( aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement || aPseudoType == nsCSSPseudoElements::ePseudo_before || aPseudoType == nsCSSPseudoElements::ePseudo_after, "forbidden pseudo type"); if (!mPresContext->IsDynamic()) { // For print or print preview, ignore animations. return nullptr; } AnimationCollection* collection = GetAnimationCollection(aElement, aPseudoType, false /* aCreateIfNeeded */); if (!collection) { return nullptr; } RestyleManager* restyleManager = mPresContext->RestyleManager(); if (restyleManager->SkipAnimationRules()) { return nullptr; } collection->EnsureStyleRuleFor( mPresContext->RefreshDriver()->MostRecentRefresh()); return collection->mStyleRule; }
void Animation::Tick() { // Since we are not guaranteed to get only one call per refresh driver tick, // it's possible that mPendingReadyTime is set to a time in the future. // In that case, we should wait until the next refresh driver tick before // resuming. if (mPendingState != PendingState::NotPending && !mPendingReadyTime.IsNull() && mTimeline && !mTimeline->GetCurrentTime().IsNull() && mPendingReadyTime.Value() <= mTimeline->GetCurrentTime().Value()) { FinishPendingAt(mPendingReadyTime.Value()); mPendingReadyTime.SetNull(); } if (IsPossiblyOrphanedPendingAnimation()) { MOZ_ASSERT(mTimeline && !mTimeline->GetCurrentTime().IsNull(), "Orphaned pending animtaions should have an active timeline"); FinishPendingAt(mTimeline->GetCurrentTime().Value()); } UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async); // FIXME: Detect the no-change case and don't request a restyle at all // FIXME: Detect changes to IsPlaying() state and request RestyleType::Layer // so that layers get updated immediately AnimationCollection* collection = GetCollection(); if (collection) { collection->RequestRestyle(CanThrottle() ? AnimationCollection::RestyleType::Throttled : AnimationCollection::RestyleType::Standard); } }
void Animation::PostUpdate() { AnimationCollection* collection = GetCollection(); if (collection) { collection->RequestRestyle(AnimationCollection::RestyleType::Layer); } }
void Animation::PostUpdate() { AnimationCollection* collection = GetCollection(); if (collection) { collection->NotifyAnimationUpdated(); } }
void CommonAnimationManager::RemoveAllElementCollections() { while (!PR_CLIST_IS_EMPTY(&mElementCollections)) { AnimationCollection* head = static_cast<AnimationCollection*>(PR_LIST_HEAD(&mElementCollections)); head->Destroy(); } }
void CommonAnimationManager::ClearIsRunningOnCompositor(const nsIFrame* aFrame, nsCSSProperty aProperty) { AnimationCollection* collection = GetAnimationCollection(aFrame); if (collection) { collection->ClearIsRunningOnCompositor(aProperty); } }
void CommonAnimationManager::NotifyCollectionUpdated(AnimationCollection& aCollection) { MaybeStartObservingRefreshDriver(); mPresContext->ClearLastStyleUpdateForAllAnimations(); mPresContext->RestyleManager()->IncrementAnimationGeneration(); aCollection.UpdateAnimationGeneration(mPresContext); aCollection.PostRestyleForAnimation(mPresContext); }
AnimationCollection* CommonAnimationManager::GetAnimationsForCompositor(const nsIFrame* aFrame, nsCSSProperty aProperty) { AnimationCollection* collection = GetAnimationCollection(aFrame); if (!collection || !collection->HasCurrentAnimationOfProperty(aProperty) || !collection->CanPerformOnCompositorThread( AnimationCollection::CanAnimate_AllowPartial)) { return nullptr; } // This animation can be done on the compositor. return collection; }
void nsAnimationManager::StopAnimationsForElement( mozilla::dom::Element* aElement, nsCSSPseudoElements::Type aPseudoType) { MOZ_ASSERT(aElement); AnimationCollection* collection = GetAnimations(aElement, aPseudoType, false); if (!collection) { return; } nsAutoAnimationMutationBatch mb(aElement->OwnerDoc()); collection->Destroy(); }
Actor::Actor(const Point& position, const AnimationCollection& animations, const String& currentAnimation): animations_(animations), currAnimation_(currentAnimation), rect_(position, animations.animation(currentAnimation).size()), updater_(std::bind(&Actor::updatedFrameFromCurrentAnimation, this, std::placeholders::_1, std::placeholders::_2)) { ASSERT(!currAnimation_.empty(), "current animation name is empty"); }
void CommonAnimationManager::AddStyleUpdatesTo(RestyleTracker& aTracker) { TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh(); for (AnimationCollection* collection = mElementCollections.getFirst(); collection; collection = collection->getNext()) { collection->EnsureStyleRuleFor(now); dom::Element* elementToRestyle = collection->GetElementToRestyle(); if (elementToRestyle) { nsRestyleHint rshint = collection->IsForTransitions() ? eRestyle_CSSTransitions : eRestyle_CSSAnimations; aTracker.AddPendingRestyle(elementToRestyle, rshint, nsChangeHint(0)); } } }
void CommonAnimationManager::FlushAnimations() { TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh(); for (AnimationCollection* collection = mElementCollections.getFirst(); collection; collection = collection->getNext()) { if (collection->mStyleRuleRefreshTime == now) { continue; } MOZ_ASSERT(collection->mElement->GetComposedDoc() == mPresContext->Document(), "Should not have a transition/animation collection for an " "element that is not part of the document tree"); collection->RequestRestyle(AnimationCollection::RestyleType::Standard); } }
AnimationCollection* CommonAnimationManager::GetAnimationsForCompositor(nsIContent* aContent, nsIAtom* aElementProperty, nsCSSProperty aProperty) { if (!aContent->MayHaveAnimations()) return nullptr; AnimationCollection* collection = static_cast<AnimationCollection*>(aContent->GetProperty(aElementProperty)); if (!collection || !collection->HasAnimationOfProperty(aProperty) || !collection->CanPerformOnCompositorThread( AnimationCollection::CanAnimate_AllowPartial)) { return nullptr; } // This animation can be done on the compositor. return collection; }
void CommonAnimationManager::AddStyleUpdatesTo(RestyleTracker& aTracker) { TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh(); PRCList* next = PR_LIST_HEAD(&mElementCollections); while (next != &mElementCollections) { AnimationCollection* collection = static_cast<AnimationCollection*>(next); next = PR_NEXT_LINK(next); collection->EnsureStyleRuleFor(now); dom::Element* elementToRestyle = collection->GetElementToRestyle(); if (elementToRestyle) { nsRestyleHint rshint = collection->IsForTransitions() ? eRestyle_CSSTransitions : eRestyle_CSSAnimations; aTracker.AddPendingRestyle(elementToRestyle, rshint, nsChangeHint(0)); } } }
void CommonAnimationManager::FlushAnimations(FlushFlags aFlags) { TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh(); for (AnimationCollection* collection = mElementCollections.getFirst(); collection; collection = collection->getNext()) { if (collection->mStyleRuleRefreshTime == now) { continue; } if (aFlags == Cannot_Throttle) { collection->RequestRestyle(AnimationCollection::RestyleType::Standard); } nsAutoAnimationMutationBatch mb(collection->mElement); collection->Tick(); } MaybeStartOrStopObservingRefreshDriver(); }
void CommonAnimationManager::FlushAnimations(FlushFlags aFlags) { TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh(); for (PRCList *l = PR_LIST_HEAD(&mElementCollections); l != &mElementCollections; l = PR_NEXT_LINK(l)) { AnimationCollection* collection = static_cast<AnimationCollection*>(l); if (collection->mStyleRuleRefreshTime == now) { continue; } if (aFlags == Cannot_Throttle) { collection->RequestRestyle(AnimationCollection::RestyleType::Standard); } nsAutoAnimationMutationBatch mb(collection->mElement); collection->Tick(); } MaybeStartOrStopObservingRefreshDriver(); }
void nsAnimationManager::FlushAnimations(FlushFlags aFlags) { TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh(); bool didThrottle = false; for (PRCList *l = PR_LIST_HEAD(&mElementCollections); l != &mElementCollections; l = PR_NEXT_LINK(l)) { AnimationCollection* collection = static_cast<AnimationCollection*>(l); nsAutoAnimationMutationBatch mb(collection->mElement); collection->Tick(); bool canThrottleTick = aFlags == Can_Throttle && collection->CanPerformOnCompositorThread( AnimationCollection::CanAnimateFlags(0)) && collection->CanThrottleAnimation(now); nsRefPtr<css::AnimValuesStyleRule> oldStyleRule = collection->mStyleRule; UpdateStyleAndEvents(collection, now, canThrottleTick ? EnsureStyleRule_IsThrottled : EnsureStyleRule_IsNotThrottled); if (oldStyleRule != collection->mStyleRule) { collection->PostRestyleForAnimation(mPresContext); } else { didThrottle = true; } } if (didThrottle) { mPresContext->Document()->SetNeedStyleFlush(); } MaybeStartOrStopObservingRefreshDriver(); DispatchEvents(); // may destroy us }
void Animation::Tick() { // Finish pending if we have a pending ready time, but only if we also // have an active timeline. if (mPendingState != PendingState::NotPending && !mPendingReadyTime.IsNull() && mTimeline && !mTimeline->GetCurrentTime().IsNull()) { // Even though mPendingReadyTime is initialized using TimeStamp::Now() // during the *previous* tick of the refresh driver, it can still be // ahead of the *current* timeline time when we are using the // vsync timer so we need to clamp it to the timeline time. mPendingReadyTime.SetValue(std::min(mTimeline->GetCurrentTime().Value(), mPendingReadyTime.Value())); FinishPendingAt(mPendingReadyTime.Value()); mPendingReadyTime.SetNull(); } if (IsPossiblyOrphanedPendingAnimation()) { MOZ_ASSERT(mTimeline && !mTimeline->GetCurrentTime().IsNull(), "Orphaned pending animtaions should have an active timeline"); FinishPendingAt(mTimeline->GetCurrentTime().Value()); } UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async); // FIXME: Detect the no-change case and don't request a restyle at all // FIXME: Detect changes to IsPlaying() state and request RestyleType::Layer // so that layers get updated immediately AnimationCollection* collection = GetCollection(); if (collection) { collection->RequestRestyle(CanThrottle() ? AnimationCollection::RestyleType::Throttled : AnimationCollection::RestyleType::Standard); } }
nsIStyleRule* nsAnimationManager::CheckAnimationRule(nsStyleContext* aStyleContext, mozilla::dom::Element* aElement) { if (!mPresContext->IsDynamic()) { // For print or print preview, ignore animations. return nullptr; } // Everything that causes our animation data to change triggers a // style change, which in turn triggers a non-animation restyle. // Likewise, when we initially construct frames, we're not in a // style change, but also not in an animation restyle. const nsStyleDisplay* disp = aStyleContext->StyleDisplay(); AnimationCollection* collection = GetAnimations(aElement, aStyleContext->GetPseudoType(), false); if (!collection && disp->mAnimationNameCount == 1 && disp->mAnimations[0].GetName().IsEmpty()) { return nullptr; } nsAutoAnimationMutationBatch mb(aElement); // build the animations list dom::DocumentTimeline* timeline = aElement->OwnerDoc()->Timeline(); AnimationPtrArray newAnimations; if (!aStyleContext->IsInDisplayNoneSubtree()) { BuildAnimations(aStyleContext, aElement, timeline, newAnimations); } if (newAnimations.IsEmpty()) { if (collection) { // There might be transitions that run now that animations don't // override them. mPresContext->TransitionManager()-> UpdateCascadeResultsWithAnimationsToBeDestroyed(collection); collection->Destroy(); } return nullptr; } if (collection) { collection->mStyleRule = nullptr; collection->mStyleRuleRefreshTime = TimeStamp(); collection->UpdateAnimationGeneration(mPresContext); // Copy over the start times and (if still paused) pause starts // for each animation (matching on name only) that was also in the // old list of animations. // This means that we honor dynamic changes, which isn't what the // spec says to do, but WebKit seems to honor at least some of // them. See // http://lists.w3.org/Archives/Public/www-style/2011Apr/0079.html // In order to honor what the spec said, we'd copy more data over // (or potentially optimize BuildAnimations to avoid rebuilding it // in the first place). if (!collection->mAnimations.IsEmpty()) { for (size_t newIdx = newAnimations.Length(); newIdx-- != 0;) { Animation* newAnim = newAnimations[newIdx]; // Find the matching animation with this name in the old list // of animations. We iterate through both lists in a backwards // direction which means that if there are more animations in // the new list of animations with a given name than in the old // list, it will be the animations towards the of the beginning of // the list that do not match and are treated as new animations. nsRefPtr<CSSAnimation> oldAnim; size_t oldIdx = collection->mAnimations.Length(); while (oldIdx-- != 0) { CSSAnimation* a = collection->mAnimations[oldIdx]->AsCSSAnimation(); MOZ_ASSERT(a, "All animations in the CSS Animation collection should" " be CSSAnimation objects"); if (a->Name() == newAnim->Name()) { oldAnim = a; break; } } if (!oldAnim) { continue; } bool animationChanged = false; // Update the old from the new so we can keep the original object // identity (and any expando properties attached to it). if (oldAnim->GetEffect() && newAnim->GetEffect()) { KeyframeEffectReadOnly* oldEffect = oldAnim->GetEffect(); KeyframeEffectReadOnly* newEffect = newAnim->GetEffect(); animationChanged = oldEffect->Timing() != newEffect->Timing() || oldEffect->Properties() != newEffect->Properties(); oldEffect->Timing() = newEffect->Timing(); oldEffect->Properties() = newEffect->Properties(); } // Reset compositor state so animation will be re-synchronized. oldAnim->ClearIsRunningOnCompositor(); // Handle changes in play state. If the animation is idle, however, // changes to animation-play-state should *not* restart it. if (oldAnim->PlayState() != AnimationPlayState::Idle) { // CSSAnimation takes care of override behavior so that, // for example, if the author has called pause(), that will // override the animation-play-state. // (We should check newAnim->IsStylePaused() but that requires // downcasting to CSSAnimation and we happen to know that // newAnim will only ever be paused by calling PauseFromStyle // making IsPausedOrPausing synonymous in this case.) if (!oldAnim->IsStylePaused() && newAnim->IsPausedOrPausing()) { oldAnim->PauseFromStyle(); animationChanged = true; } else if (oldAnim->IsStylePaused() && !newAnim->IsPausedOrPausing()) { oldAnim->PlayFromStyle(); animationChanged = true; } } if (animationChanged) { nsNodeUtils::AnimationChanged(oldAnim); } // Replace new animation with the (updated) old one and remove the // old one from the array so we don't try to match it any more. // // Although we're doing this while iterating this is safe because // we're not changing the length of newAnimations and we've finished // iterating over the list of old iterations. newAnim->CancelFromStyle(); newAnim = nullptr; newAnimations.ReplaceElementAt(newIdx, oldAnim); collection->mAnimations.RemoveElementAt(oldIdx); // We've touched the old animation's timing properties, so this // could update the old animation's relevance. oldAnim->UpdateRelevance(); } } } else { collection = GetAnimations(aElement, aStyleContext->GetPseudoType(), true); } collection->mAnimations.SwapElements(newAnimations); collection->mNeedsRefreshes = true; collection->Tick(); // Cancel removed animations for (size_t newAnimIdx = newAnimations.Length(); newAnimIdx-- != 0; ) { newAnimations[newAnimIdx]->CancelFromStyle(); } UpdateCascadeResults(aStyleContext, collection); TimeStamp refreshTime = mPresContext->RefreshDriver()->MostRecentRefresh(); UpdateStyleAndEvents(collection, refreshTime, EnsureStyleRule_IsNotThrottled); // We don't actually dispatch the mPendingEvents now. We'll either // dispatch them the next time we get a refresh driver notification // or the next time somebody calls // nsPresShell::FlushPendingNotifications. if (!mPendingEvents.IsEmpty()) { mPresContext->Document()->SetNeedStyleFlush(); } return GetAnimationRule(aElement, aStyleContext->GetPseudoType()); }
Texture Actor::updatedFrameFromCurrentAnimation(AnimationCollection& animations, std::chrono::milliseconds elapsed) { auto& currAnim = animations.animation(currAnimation_); currAnim.update(elapsed); return currAnim.currentFrame(); }
nsIStyleRule* nsAnimationManager::CheckAnimationRule(nsStyleContext* aStyleContext, mozilla::dom::Element* aElement) { // Ignore animations for print or print preview, and for elements // that are not attached to the document tree. if (!mPresContext->IsDynamic() || !aElement->IsInComposedDoc()) { return nullptr; } // Everything that causes our animation data to change triggers a // style change, which in turn triggers a non-animation restyle. // Likewise, when we initially construct frames, we're not in a // style change, but also not in an animation restyle. const nsStyleDisplay* disp = aStyleContext->StyleDisplay(); AnimationCollection* collection = GetAnimationCollection(aElement, aStyleContext->GetPseudoType(), false /* aCreateIfNeeded */); if (!collection && disp->mAnimationNameCount == 1 && disp->mAnimations[0].GetName().IsEmpty()) { return nullptr; } nsAutoAnimationMutationBatch mb(aElement->OwnerDoc()); // build the animations list dom::DocumentTimeline* timeline = aElement->OwnerDoc()->Timeline(); AnimationPtrArray newAnimations; if (!aStyleContext->IsInDisplayNoneSubtree()) { BuildAnimations(aStyleContext, aElement, timeline, newAnimations); } if (newAnimations.IsEmpty()) { if (collection) { collection->Destroy(); } return nullptr; } if (collection) { collection->mStyleRuleRefreshTime = TimeStamp(); EffectSet* effectSet = EffectSet::GetEffectSet(aElement, aStyleContext->GetPseudoType()); if (effectSet) { effectSet->UpdateAnimationGeneration(mPresContext); } // Copy over the start times and (if still paused) pause starts // for each animation (matching on name only) that was also in the // old list of animations. // This means that we honor dynamic changes, which isn't what the // spec says to do, but WebKit seems to honor at least some of // them. See // http://lists.w3.org/Archives/Public/www-style/2011Apr/0079.html // In order to honor what the spec said, we'd copy more data over // (or potentially optimize BuildAnimations to avoid rebuilding it // in the first place). if (!collection->mAnimations.IsEmpty()) { for (size_t newIdx = newAnimations.Length(); newIdx-- != 0;) { Animation* newAnim = newAnimations[newIdx]; // Find the matching animation with this name in the old list // of animations. We iterate through both lists in a backwards // direction which means that if there are more animations in // the new list of animations with a given name than in the old // list, it will be the animations towards the of the beginning of // the list that do not match and are treated as new animations. RefPtr<CSSAnimation> oldAnim; size_t oldIdx = collection->mAnimations.Length(); while (oldIdx-- != 0) { CSSAnimation* a = collection->mAnimations[oldIdx]->AsCSSAnimation(); MOZ_ASSERT(a, "All animations in the CSS Animation collection should" " be CSSAnimation objects"); if (a->AnimationName() == newAnim->AsCSSAnimation()->AnimationName()) { oldAnim = a; break; } } if (!oldAnim) { // FIXME: Bug 1134163 - We shouldn't queue animationstart events // until the animation is actually ready to run. However, we // currently have some tests that assume that these events are // dispatched within the same tick as the animation is added // so we need to queue up any animationstart events from newly-created // animations. newAnim->AsCSSAnimation()->QueueEvents(); continue; } bool animationChanged = false; // Update the old from the new so we can keep the original object // identity (and any expando properties attached to it). if (oldAnim->GetEffect() && newAnim->GetEffect()) { KeyframeEffectReadOnly* oldEffect = oldAnim->GetEffect(); KeyframeEffectReadOnly* newEffect = newAnim->GetEffect(); animationChanged = oldEffect->Timing() != newEffect->Timing() || oldEffect->Properties() != newEffect->Properties(); oldEffect->SetTiming(newEffect->Timing()); // To preserve the mIsRunningOnCompositor value on each property, // we copy it from the old effect to the new effect since, in the // following step, we will completely clobber the properties on the // old effect with the values on the new effect. CopyIsRunningOnCompositor(*oldEffect, *newEffect); oldEffect->Properties() = newEffect->Properties(); } // Handle changes in play state. If the animation is idle, however, // changes to animation-play-state should *not* restart it. if (oldAnim->PlayState() != AnimationPlayState::Idle) { // CSSAnimation takes care of override behavior so that, // for example, if the author has called pause(), that will // override the animation-play-state. // (We should check newAnim->IsStylePaused() but that requires // downcasting to CSSAnimation and we happen to know that // newAnim will only ever be paused by calling PauseFromStyle // making IsPausedOrPausing synonymous in this case.) if (!oldAnim->IsStylePaused() && newAnim->IsPausedOrPausing()) { oldAnim->PauseFromStyle(); animationChanged = true; } else if (oldAnim->IsStylePaused() && !newAnim->IsPausedOrPausing()) { oldAnim->PlayFromStyle(); animationChanged = true; } } oldAnim->CopyAnimationIndex(*newAnim->AsCSSAnimation()); // Updating the effect timing above might already have caused the // animation to become irrelevant so only add a changed record if // the animation is still relevant. if (animationChanged && oldAnim->IsRelevant()) { nsNodeUtils::AnimationChanged(oldAnim); } // Replace new animation with the (updated) old one and remove the // old one from the array so we don't try to match it any more. // // Although we're doing this while iterating this is safe because // we're not changing the length of newAnimations and we've finished // iterating over the list of old iterations. newAnim->CancelFromStyle(); newAnim = nullptr; newAnimations.ReplaceElementAt(newIdx, oldAnim); collection->mAnimations.RemoveElementAt(oldIdx); } } } else { collection = GetAnimationCollection(aElement, aStyleContext->GetPseudoType(), true /* aCreateIfNeeded */); for (Animation* animation : newAnimations) { // FIXME: Bug 1134163 - As above, we have shouldn't actually need to // queue events here. (But we do for now since some tests expect // animationstart events to be dispatched immediately.) animation->AsCSSAnimation()->QueueEvents(); } } collection->mAnimations.SwapElements(newAnimations); collection->mStyleChanging = true; // Cancel removed animations for (size_t newAnimIdx = newAnimations.Length(); newAnimIdx-- != 0; ) { newAnimations[newAnimIdx]->CancelFromStyle(); } EffectCompositor::UpdateCascadeResults(aElement, aStyleContext->GetPseudoType(), aStyleContext); TimeStamp refreshTime = mPresContext->RefreshDriver()->MostRecentRefresh(); collection->EnsureStyleRuleFor(refreshTime); // We don't actually dispatch the pending events now. We'll either // dispatch them the next time we get a refresh driver notification // or the next time somebody calls // nsPresShell::FlushPendingNotifications. if (mEventDispatcher.HasQueuedEvents()) { mPresContext->Document()->SetNeedStyleFlush(); } return GetAnimationRule(aElement, aStyleContext->GetPseudoType()); }
/* static */ void EffectCompositor::UpdateCascadeResults(EffectSet& aEffectSet, Element* aElement, nsCSSPseudoElements::Type aPseudoType, nsStyleContext* aStyleContext) { MOZ_ASSERT(EffectSet::GetEffectSet(aElement, aPseudoType) == &aEffectSet, "Effect set should correspond to the specified (pseudo-)element"); if (aEffectSet.IsEmpty()) { aEffectSet.MarkCascadeUpdated(); return; } // Get a list of effects sorted by composite order. nsTArray<KeyframeEffectReadOnly*> sortedEffectList; for (KeyframeEffectReadOnly* effect : aEffectSet) { sortedEffectList.AppendElement(effect); } sortedEffectList.Sort(EffectCompositeOrderComparator()); // Get properties that override the *animations* level of the cascade. // // We only do this for properties that we can animate on the compositor // since we will apply other properties on the main thread where the usual // cascade applies. nsCSSPropertySet overriddenProperties; if (aStyleContext) { GetOverriddenProperties(aStyleContext, aEffectSet, overriddenProperties); } bool changed = false; nsCSSPropertySet animatedProperties; // Iterate from highest to lowest composite order. for (KeyframeEffectReadOnly* effect : Reversed(sortedEffectList)) { MOZ_ASSERT(effect->GetAnimation(), "Effects on a target element should have an Animation"); bool inEffect = effect->IsInEffect(); for (AnimationProperty& prop : effect->Properties()) { bool winsInCascade = !animatedProperties.HasProperty(prop.mProperty) && inEffect; // If this property wins in the cascade, add it to the set of animated // properties. We need to do this even if the property is overridden // (in which case we set winsInCascade to false below) since we don't // want to fire transitions on these properties. if (winsInCascade) { animatedProperties.AddProperty(prop.mProperty); } // For effects that will be applied to the animations level of the // cascade, we need to check that the property isn't being set by // something with higher priority in the cascade. // // We only do this, however, for properties that can be animated on // the compositor. For properties animated on the main thread the usual // cascade ensures these animations will be correctly overridden. if (winsInCascade && effect->GetAnimation()->CascadeLevel() == CascadeLevel::Animations && overriddenProperties.HasProperty(prop.mProperty)) { winsInCascade = false; } if (winsInCascade != prop.mWinsInCascade) { changed = true; } prop.mWinsInCascade = winsInCascade; } } aEffectSet.MarkCascadeUpdated(); // If there is any change in the cascade result, update animations on // layers with the winning animations. nsPresContext* presContext = GetPresContext(aElement); if (changed && presContext) { // We currently unconditionally update both animations and transitions // even if we could, for example, get away with only updating animations. // This is a temporary measure until we unify all animation style updating // under EffectCompositor. AnimationCollection* animations = presContext->AnimationManager()->GetAnimationCollection(aElement, aPseudoType, false); /* don't create */ if (animations) { animations->RequestRestyle(AnimationCollection::RestyleType::Layer); } AnimationCollection* transitions = presContext->TransitionManager()->GetAnimationCollection(aElement, aPseudoType, false); /* don't create */ if (transitions) { transitions->RequestRestyle(AnimationCollection::RestyleType::Layer); } } }
int main(int argc, char *argv[]) { g_SDLwindow = NULL; g_SDLwindow = SDL_CreateWindow("Tertian", 100, 100, WINDOW_WIDTH, WINDOW_HEIGHT, 0); sdlApp.Initialize(g_SDLwindow); XMLFileReader file_reader = XMLFileReader("Data/Animations/test.xml"); //file_reader.OpenFile("Data/Animations/test.xml"); for(int i = 0; i < 10; i++) cout << file_reader.GetToken("frame", i) << endl; //set up the animation collection AnimationCollection ac = AnimationCollection(); ac.InsertAnimation("librarian_attack"); ac.InsertAnimation("librarian_idle"); CubeGrid level = CubeGrid(2,3,2); // Access array elements int block_size = 32; Timer timer; float delta_time; string frame_name; int x = WINDOW_WIDTH/2 + 100; int y = WINDOW_HEIGHT/2; while(sdlApp.IsRunning()) { delta_time = timer.GetDt(); //move the animation frame around if(Keyboard::GetKey("Up")) y--; if(Keyboard::GetKey("Down")) y++; if(Keyboard::GetKey("Left")) x--; if(Keyboard::GetKey("right")) x++; if(Keyboard::GetKey("s")) ac.StopActiveAnimation(); if(Keyboard::GetKey("a")) ac.PauseActiveAnimation(); if(Keyboard::GetKey("p")) ac.PlayActiveAnimation(); //select the active animation if(Keyboard::GetKey("1")) ac.SetActiveAnimation("librarian_idle"); if(Keyboard::GetKey("2")) ac.SetActiveAnimation("librarian_attack"); //get the current animation frame name frame_name = ac.UpdateActiveAnimation(delta_time); //blit the animation frame Graphics::BlitImage(frame_name, x, y); Graphics::Print("[S]top animation.", 0, 12); Graphics::Print("P[a]use animation.", 0, 24); Graphics::Print("[P]lay animation.", 0, 36); Graphics::Print("Select animation [1]/[2] ", 0, 48); Graphics::DrawLevelBlock(WINDOW_WIDTH/2, WINDOW_HEIGHT/2); Graphics::DrawLevelBlock(WINDOW_WIDTH/2 + 128, WINDOW_HEIGHT/2); Graphics::DrawLevelBlock(WINDOW_WIDTH/2 - 128, WINDOW_HEIGHT/2); Graphics::DrawLevelBlock(WINDOW_WIDTH/2 - 64, WINDOW_HEIGHT/2 - 32); Graphics::DrawLevelBlock(WINDOW_WIDTH/2 + 64, WINDOW_HEIGHT/2 - 32); Graphics::DrawLevelBlock(WINDOW_WIDTH/2 + 64, WINDOW_HEIGHT/2 - 53); Graphics::DrawLevelBlock(WINDOW_WIDTH/2, WINDOW_HEIGHT/2 - 64); Graphics::SetDrawColor(); for(int i = 0; i < level.GetSizeX(); i++) for(int j = 0; j < level.GetSizeY(); j++) for(int k = 0; k < level.GetSizeZ(); k++){ int value = level.GetCell(i,j,k); Graphics::Print(value, block_size * i , block_size * j + 120 * k); } sdlApp.Update(timer.GetDt()); #if _DEBUG //printf("time :%f\n", timer.GetDt()); #endif } SDL_DestroyWindow(g_SDLwindow); return 0; }