Bug 1049975 - Part 5: Move timing related code into AnimationEffectReadOnly.
Move the mTiming, mAnimation, and the implementaion of timing into
AnimationEffectReadOnly.
MozReview-Commit-ID: EZhlbphVvCo
--- a/dom/animation/AnimationEffectReadOnly.cpp
+++ b/dom/animation/AnimationEffectReadOnly.cpp
@@ -1,24 +1,355 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/AnimationEffectReadOnly.h"
#include "mozilla/dom/AnimationEffectReadOnlyBinding.h"
+#include "mozilla/AnimationUtils.h"
+#include "mozilla/FloatingPoint.h"
namespace mozilla {
namespace dom {
-NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(AnimationEffectReadOnly, mDocument)
+NS_IMPL_CYCLE_COLLECTION_CLASS(AnimationEffectReadOnly)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AnimationEffectReadOnly)
+ if (tmp->mTiming) {
+ tmp->mTiming->Unlink();
+ }
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument, mTiming, mAnimation)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AnimationEffectReadOnly)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument, mTiming, mAnimation)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(AnimationEffectReadOnly)
NS_IMPL_CYCLE_COLLECTING_ADDREF(AnimationEffectReadOnly)
NS_IMPL_CYCLE_COLLECTING_RELEASE(AnimationEffectReadOnly)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AnimationEffectReadOnly)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
+AnimationEffectReadOnly::AnimationEffectReadOnly(
+ nsIDocument* aDocument, AnimationEffectTimingReadOnly* aTiming)
+ : mDocument(aDocument)
+ , mTiming(aTiming)
+{
+ MOZ_ASSERT(aTiming);
+}
+
+// https://w3c.github.io/web-animations/#in-play
+bool
+AnimationEffectReadOnly::IsInPlay() const
+{
+ if (!mAnimation || mAnimation->PlayState() == AnimationPlayState::Finished) {
+ return false;
+ }
+
+ return GetComputedTiming().mPhase == ComputedTiming::AnimationPhase::Active;
+}
+
+// https://w3c.github.io/web-animations/#current
+bool
+AnimationEffectReadOnly::IsCurrent() const
+{
+ if (!mAnimation || mAnimation->PlayState() == AnimationPlayState::Finished) {
+ return false;
+ }
+
+ ComputedTiming computedTiming = GetComputedTiming();
+ return computedTiming.mPhase == ComputedTiming::AnimationPhase::Before ||
+ computedTiming.mPhase == ComputedTiming::AnimationPhase::Active;
+}
+
+// https://w3c.github.io/web-animations/#in-effect
+bool
+AnimationEffectReadOnly::IsInEffect() const
+{
+ ComputedTiming computedTiming = GetComputedTiming();
+ return !computedTiming.mProgress.IsNull();
+}
+
+already_AddRefed<AnimationEffectTimingReadOnly>
+AnimationEffectReadOnly::Timing()
+{
+ RefPtr<AnimationEffectTimingReadOnly> temp(mTiming);
+ return temp.forget();
+}
+
+void
+AnimationEffectReadOnly::SetSpecifiedTiming(const TimingParams& aTiming)
+{
+ if (mTiming->AsTimingParams() == aTiming) {
+ return;
+ }
+ mTiming->SetTimingParams(aTiming);
+ if (mAnimation) {
+ mAnimation->NotifyEffectTimingUpdated();
+ }
+ // NotifyEffectTimingUpdated will eventually cause
+ // NotifyAnimationTimingUpdated to be called on this object which will
+ // update our registration with the target element.
+}
+
+ComputedTiming
+AnimationEffectReadOnly::GetComputedTimingAt(
+ const Nullable<TimeDuration>& aLocalTime,
+ const TimingParams& aTiming,
+ double aPlaybackRate)
+{
+ const StickyTimeDuration zeroDuration;
+
+ // Always return the same object to benefit from return-value optimization.
+ ComputedTiming result;
+
+ if (aTiming.mDuration) {
+ MOZ_ASSERT(aTiming.mDuration.ref() >= zeroDuration,
+ "Iteration duration should be positive");
+ result.mDuration = aTiming.mDuration.ref();
+ }
+
+ MOZ_ASSERT(aTiming.mIterations >= 0.0 && !IsNaN(aTiming.mIterations),
+ "mIterations should be nonnegative & finite, as ensured by "
+ "ValidateIterations or CSSParser");
+ result.mIterations = aTiming.mIterations;
+
+ MOZ_ASSERT(aTiming.mIterationStart >= 0.0,
+ "mIterationStart should be nonnegative, as ensured by "
+ "ValidateIterationStart");
+ result.mIterationStart = aTiming.mIterationStart;
+
+ result.mActiveDuration = aTiming.ActiveDuration();
+ result.mEndTime = aTiming.EndTime();
+ result.mFill = aTiming.mFill == dom::FillMode::Auto ?
+ dom::FillMode::None :
+ aTiming.mFill;
+
+ // The default constructor for ComputedTiming sets all other members to
+ // values consistent with an animation that has not been sampled.
+ if (aLocalTime.IsNull()) {
+ return result;
+ }
+ const TimeDuration& localTime = aLocalTime.Value();
+
+ // Calculate the time within the active interval.
+ // https://w3c.github.io/web-animations/#active-time
+ StickyTimeDuration activeTime;
+
+ StickyTimeDuration beforeActiveBoundary =
+ std::min(StickyTimeDuration(aTiming.mDelay), result.mEndTime);
+ StickyTimeDuration activeAfterBoundary =
+ std::min(StickyTimeDuration(aTiming.mDelay + result.mActiveDuration),
+ result.mEndTime);
+
+ if (localTime > activeAfterBoundary ||
+ (aPlaybackRate >= 0 && localTime == activeAfterBoundary)) {
+ result.mPhase = ComputedTiming::AnimationPhase::After;
+ if (!result.FillsForwards()) {
+ // The animation isn't active or filling at this time.
+ return result;
+ }
+ activeTime = std::max(std::min(result.mActiveDuration,
+ result.mActiveDuration + aTiming.mEndDelay),
+ zeroDuration);
+ } else if (localTime < beforeActiveBoundary ||
+ (aPlaybackRate < 0 && localTime == beforeActiveBoundary)) {
+ result.mPhase = ComputedTiming::AnimationPhase::Before;
+ if (!result.FillsBackwards()) {
+ // The animation isn't active or filling at this time.
+ return result;
+ }
+ // activeTime is zero
+ } else {
+ MOZ_ASSERT(result.mActiveDuration != zeroDuration,
+ "How can we be in the middle of a zero-duration interval?");
+ result.mPhase = ComputedTiming::AnimationPhase::Active;
+ activeTime = localTime - aTiming.mDelay;
+ }
+
+ // Convert active time to a multiple of iterations.
+ // https://w3c.github.io/web-animations/#overall-progress
+ double overallProgress;
+ if (result.mDuration == zeroDuration) {
+ overallProgress = result.mPhase == ComputedTiming::AnimationPhase::Before
+ ? 0.0
+ : result.mIterations;
+ } else {
+ overallProgress = activeTime / result.mDuration;
+ }
+
+ // Factor in iteration start offset.
+ if (IsFinite(overallProgress)) {
+ overallProgress += result.mIterationStart;
+ }
+
+ // Determine the 0-based index of the current iteration.
+ // https://w3c.github.io/web-animations/#current-iteration
+ result.mCurrentIteration =
+ IsInfinite(result.mIterations) &&
+ result.mPhase == ComputedTiming::AnimationPhase::After
+ ? UINT64_MAX // In GetComputedTimingDictionary(),
+ // we will convert this into Infinity
+ : static_cast<uint64_t>(overallProgress);
+
+ // Convert the overall progress to a fraction of a single iteration--the
+ // simply iteration progress.
+ // https://w3c.github.io/web-animations/#simple-iteration-progress
+ double progress = IsFinite(overallProgress)
+ ? fmod(overallProgress, 1.0)
+ : fmod(result.mIterationStart, 1.0);
+
+ // When we finish exactly at the end of an iteration we need to report
+ // the end of the final iteration and not the start of the next iteration.
+ // We *don't* want to do this when we have a zero-iteration animation or
+ // when the animation has been effectively made into a zero-duration animation
+ // using a negative end-delay, however.
+ if (result.mPhase == ComputedTiming::AnimationPhase::After &&
+ progress == 0.0 &&
+ result.mIterations != 0.0 &&
+ (activeTime != zeroDuration || result.mDuration == zeroDuration)) {
+ // The only way we can be in the after phase with a progress of zero and
+ // a current iteration of zero, is if we have a zero iteration count or
+ // were clipped using a negative end delay--both of which we should have
+ // detected above.
+ MOZ_ASSERT(result.mCurrentIteration != 0,
+ "Should not have zero current iteration");
+ progress = 1.0;
+ if (result.mCurrentIteration != UINT64_MAX) {
+ result.mCurrentIteration--;
+ }
+ }
+
+ // Factor in the direction.
+ bool thisIterationReverse = false;
+ switch (aTiming.mDirection) {
+ case PlaybackDirection::Normal:
+ thisIterationReverse = false;
+ break;
+ case PlaybackDirection::Reverse:
+ thisIterationReverse = true;
+ break;
+ case PlaybackDirection::Alternate:
+ thisIterationReverse = (result.mCurrentIteration & 1) == 1;
+ break;
+ case PlaybackDirection::Alternate_reverse:
+ thisIterationReverse = (result.mCurrentIteration & 1) == 0;
+ break;
+ default:
+ MOZ_ASSERT(true, "Unknown PlaybackDirection type");
+ }
+ if (thisIterationReverse) {
+ progress = 1.0 - progress;
+ }
+
+ // Calculate the 'before flag' which we use when applying step timing
+ // functions.
+ if ((result.mPhase == ComputedTiming::AnimationPhase::After &&
+ thisIterationReverse) ||
+ (result.mPhase == ComputedTiming::AnimationPhase::Before &&
+ !thisIterationReverse)) {
+ result.mBeforeFlag = ComputedTimingFunction::BeforeFlag::Set;
+ }
+
+ // Apply the easing.
+ if (aTiming.mFunction) {
+ progress = aTiming.mFunction->GetValue(progress, result.mBeforeFlag);
+ }
+
+ MOZ_ASSERT(IsFinite(progress), "Progress value should be finite");
+ result.mProgress.SetValue(progress);
+ return result;
+}
+
+ComputedTiming
+AnimationEffectReadOnly::GetComputedTiming(const TimingParams* aTiming) const
+{
+ double playbackRate = mAnimation ? mAnimation->PlaybackRate() : 1;
+ return GetComputedTimingAt(GetLocalTime(),
+ aTiming ? *aTiming : SpecifiedTiming(),
+ playbackRate);
+}
+
+// Helper functions for generating a ComputedTimingProperties dictionary
+static void
+GetComputedTimingDictionary(const ComputedTiming& aComputedTiming,
+ const Nullable<TimeDuration>& aLocalTime,
+ const TimingParams& aTiming,
+ ComputedTimingProperties& aRetVal)
+{
+ // AnimationEffectTimingProperties
+ aRetVal.mDelay = aTiming.mDelay.ToMilliseconds();
+ aRetVal.mEndDelay = aTiming.mEndDelay.ToMilliseconds();
+ aRetVal.mFill = aComputedTiming.mFill;
+ aRetVal.mIterations = aComputedTiming.mIterations;
+ aRetVal.mIterationStart = aComputedTiming.mIterationStart;
+ aRetVal.mDuration.SetAsUnrestrictedDouble() =
+ aComputedTiming.mDuration.ToMilliseconds();
+ aRetVal.mDirection = aTiming.mDirection;
+
+ // ComputedTimingProperties
+ aRetVal.mActiveDuration = aComputedTiming.mActiveDuration.ToMilliseconds();
+ aRetVal.mEndTime = aComputedTiming.mEndTime.ToMilliseconds();
+ aRetVal.mLocalTime = AnimationUtils::TimeDurationToDouble(aLocalTime);
+ aRetVal.mProgress = aComputedTiming.mProgress;
+
+ if (!aRetVal.mProgress.IsNull()) {
+ // Convert the returned currentIteration into Infinity if we set
+ // (uint64_t) aComputedTiming.mCurrentIteration to UINT64_MAX
+ double iteration = aComputedTiming.mCurrentIteration == UINT64_MAX
+ ? PositiveInfinity<double>()
+ : static_cast<double>(aComputedTiming.mCurrentIteration);
+ aRetVal.mCurrentIteration.SetValue(iteration);
+ }
+}
+
+void
+AnimationEffectReadOnly::GetComputedTimingAsDict(
+ ComputedTimingProperties& aRetVal) const
+{
+ double playbackRate = mAnimation ? mAnimation->PlaybackRate() : 1;
+ const Nullable<TimeDuration> currentTime = GetLocalTime();
+ GetComputedTimingDictionary(GetComputedTimingAt(currentTime,
+ SpecifiedTiming(),
+ playbackRate),
+ currentTime,
+ SpecifiedTiming(),
+ aRetVal);
+}
+
+void
+AnimationEffectReadOnly::SetAnimation(Animation* aAnimation)
+{
+ mAnimation = aAnimation;
+ NotifyAnimationTimingUpdated();
+}
+
+AnimationEffectReadOnly::~AnimationEffectReadOnly()
+{
+ // mTiming is cycle collected, so we have to do null check first even though
+ // mTiming shouldn't be null during the lifetime of KeyframeEffect.
+ if (mTiming) {
+ mTiming->Unlink();
+ }
+}
+
+Nullable<TimeDuration>
+AnimationEffectReadOnly::GetLocalTime() const
+{
+ // Since the *animation* start time is currently always zero, the local
+ // time is equal to the parent time.
+ Nullable<TimeDuration> result;
+ if (mAnimation) {
+ result = mAnimation->GetCurrentTime();
+ }
+ return result;
+}
+
} // namespace dom
} // namespace mozilla
--- a/dom/animation/AnimationEffectReadOnly.h
+++ b/dom/animation/AnimationEffectReadOnly.h
@@ -2,17 +2,24 @@
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_AnimationEffectReadOnly_h
#define mozilla_dom_AnimationEffectReadOnly_h
+#include "mozilla/ComputedTiming.h"
+#include "mozilla/dom/AnimationEffectTimingReadOnly.h"
#include "mozilla/dom/BindingDeclarations.h"
+#include "mozilla/dom/Nullable.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/StickyTimeDuration.h"
+#include "mozilla/TimeStamp.h"
+#include "mozilla/TimingParams.h"
#include "nsCycleCollectionParticipant.h"
#include "nsWrapperCache.h"
namespace mozilla {
struct ElementPropertyTransition;
namespace dom {
@@ -24,52 +31,70 @@ struct ComputedTimingProperties;
class AnimationEffectReadOnly : public nsISupports,
public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AnimationEffectReadOnly)
- explicit AnimationEffectReadOnly(nsIDocument* aDocument)
- : mDocument(aDocument)
- {
- }
+ AnimationEffectReadOnly(nsIDocument* aDocument,
+ AnimationEffectTimingReadOnly* aTiming);
virtual KeyframeEffectReadOnly* AsKeyframeEffect() { return nullptr; }
virtual ElementPropertyTransition* AsTransition() { return nullptr; }
virtual const ElementPropertyTransition* AsTransition() const
{
return nullptr;
}
nsISupports* GetParentObject() const { return mDocument; }
- virtual bool IsInPlay() const = 0;
- virtual bool IsCurrent() const = 0;
- virtual bool IsInEffect() const = 0;
+ bool IsInPlay() const;
+ bool IsCurrent() const;
+ bool IsInEffect() const;
- virtual already_AddRefed<AnimationEffectTimingReadOnly> Timing() const = 0;
- virtual const TimingParams& SpecifiedTiming() const = 0;
- virtual void SetSpecifiedTiming(const TimingParams& aTiming) = 0;
+ already_AddRefed<AnimationEffectTimingReadOnly> Timing();
+ const TimingParams& SpecifiedTiming() const
+ {
+ return mTiming->AsTimingParams();
+ }
+ void SetSpecifiedTiming(const TimingParams& aTiming);
virtual void NotifyAnimationTimingUpdated() = 0;
+ // This function takes as input the timing parameters of an animation and
+ // returns the computed timing at the specified local time.
+ //
+ // The local time may be null in which case only static parameters such as the
+ // active duration are calculated. All other members of the returned object
+ // are given a null/initial value.
+ //
+ // This function returns a null mProgress member of the return value
+ // if the animation should not be run
+ // (because it is not currently active and is not filling at this time).
+ static ComputedTiming
+ GetComputedTimingAt(const Nullable<TimeDuration>& aLocalTime,
+ const TimingParams& aTiming,
+ double aPlaybackRate);
// Shortcut that gets the computed timing using the current local time as
// calculated from the timeline time.
- virtual ComputedTiming GetComputedTiming(
- const TimingParams* aTiming = nullptr) const = 0;
- virtual void GetComputedTimingAsDict(
- ComputedTimingProperties& aRetVal) const = 0;
+ ComputedTiming GetComputedTiming(const TimingParams* aTiming = nullptr) const;
+ void GetComputedTimingAsDict(ComputedTimingProperties& aRetVal) const;
- virtual void SetAnimation(Animation* aAnimation) = 0;
+ void SetAnimation(Animation* aAnimation);
+ Animation* GetAnimation() const { return mAnimation; };
protected:
- virtual ~AnimationEffectReadOnly() = default;
+ virtual ~AnimationEffectReadOnly();
+
+ Nullable<TimeDuration> GetLocalTime() const;
protected:
RefPtr<nsIDocument> mDocument;
+ RefPtr<AnimationEffectTimingReadOnly> mTiming;
+ RefPtr<Animation> mAnimation;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_AnimationEffectReadOnly_h
--- a/dom/animation/KeyframeEffect.cpp
+++ b/dom/animation/KeyframeEffect.cpp
@@ -19,65 +19,21 @@
#include "nsCSSPropertyIDSet.h"
#include "nsCSSProps.h" // For nsCSSProps::PropHasFlags
#include "nsCSSPseudoElements.h" // For CSSPseudoElementType
#include "nsDOMMutationObserver.h" // For nsAutoAnimationMutationBatch
#include "nsIPresShell.h" // For nsIPresShell
#include "nsIScriptError.h"
namespace mozilla {
-
-// Helper functions for generating a ComputedTimingProperties dictionary
-static void
-GetComputedTimingDictionary(const ComputedTiming& aComputedTiming,
- const Nullable<TimeDuration>& aLocalTime,
- const TimingParams& aTiming,
- dom::ComputedTimingProperties& aRetVal)
-{
- // AnimationEffectTimingProperties
- aRetVal.mDelay = aTiming.mDelay.ToMilliseconds();
- aRetVal.mEndDelay = aTiming.mEndDelay.ToMilliseconds();
- aRetVal.mFill = aComputedTiming.mFill;
- aRetVal.mIterations = aComputedTiming.mIterations;
- aRetVal.mIterationStart = aComputedTiming.mIterationStart;
- aRetVal.mDuration.SetAsUnrestrictedDouble() =
- aComputedTiming.mDuration.ToMilliseconds();
- aRetVal.mDirection = aTiming.mDirection;
-
- // ComputedTimingProperties
- aRetVal.mActiveDuration = aComputedTiming.mActiveDuration.ToMilliseconds();
- aRetVal.mEndTime = aComputedTiming.mEndTime.ToMilliseconds();
- aRetVal.mLocalTime = AnimationUtils::TimeDurationToDouble(aLocalTime);
- aRetVal.mProgress = aComputedTiming.mProgress;
-
- if (!aRetVal.mProgress.IsNull()) {
- // Convert the returned currentIteration into Infinity if we set
- // (uint64_t) aComputedTiming.mCurrentIteration to UINT64_MAX
- double iteration = aComputedTiming.mCurrentIteration == UINT64_MAX
- ? PositiveInfinity<double>()
- : static_cast<double>(aComputedTiming.mCurrentIteration);
- aRetVal.mCurrentIteration.SetValue(iteration);
- }
-}
-
namespace dom {
-NS_IMPL_CYCLE_COLLECTION_CLASS(KeyframeEffectReadOnly)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(KeyframeEffectReadOnly,
- AnimationEffectReadOnly)
- if (tmp->mTiming) {
- tmp->mTiming->Unlink();
- }
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mTarget, mAnimation, mTiming)
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(KeyframeEffectReadOnly,
- AnimationEffectReadOnly)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTarget, mAnimation, mTiming)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+NS_IMPL_CYCLE_COLLECTION_INHERITED(KeyframeEffectReadOnly,
+ AnimationEffectReadOnly,
+ mTarget)
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(KeyframeEffectReadOnly,
AnimationEffectReadOnly)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(KeyframeEffectReadOnly)
NS_INTERFACE_MAP_END_INHERITING(AnimationEffectReadOnly)
@@ -96,24 +52,22 @@ KeyframeEffectReadOnly::KeyframeEffectRe
{
}
KeyframeEffectReadOnly::KeyframeEffectReadOnly(
nsIDocument* aDocument,
const Maybe<OwningAnimationTarget>& aTarget,
AnimationEffectTimingReadOnly* aTiming,
const KeyframeEffectParams& aOptions)
- : AnimationEffectReadOnly(aDocument)
+ : AnimationEffectReadOnly(aDocument, aTiming)
, mTarget(aTarget)
- , mTiming(aTiming)
, mEffectOptions(aOptions)
, mInEffectOnLastAnimationTimingUpdate(false)
, mCumulativeChangeHint(nsChangeHint(0))
{
- MOZ_ASSERT(aTiming);
}
JSObject*
KeyframeEffectReadOnly::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto)
{
return KeyframeEffectReadOnlyBinding::Wrap(aCx, this, aGivenProto);
}
@@ -125,38 +79,16 @@ KeyframeEffectReadOnly::IterationComposi
}
CompositeOperation
KeyframeEffectReadOnly::Composite() const
{
return CompositeOperation::Replace;
}
-already_AddRefed<AnimationEffectTimingReadOnly>
-KeyframeEffectReadOnly::Timing() const
-{
- RefPtr<AnimationEffectTimingReadOnly> temp(mTiming);
- return temp.forget();
-}
-
-void
-KeyframeEffectReadOnly::SetSpecifiedTiming(const TimingParams& aTiming)
-{
- if (mTiming->AsTimingParams() == aTiming) {
- return;
- }
- mTiming->SetTimingParams(aTiming);
- if (mAnimation) {
- mAnimation->NotifyEffectTimingUpdated();
- }
- // NotifyEffectTimingUpdated will eventually cause
- // NotifyAnimationTimingUpdated to be called on this object which will
- // update our registration with the target element.
-}
-
void
KeyframeEffectReadOnly::NotifyAnimationTimingUpdated()
{
UpdateTargetRegistration();
// If the effect is not relevant it will be removed from the target
// element's effect set. However, effects not in the effect set
// will not be included in the set of candidate effects for running on
@@ -200,259 +132,16 @@ KeyframeEffectReadOnly::NotifyAnimationT
// called and we will never have a chance to update mProgressOnLastCompose.
// We clear mProgressOnLastCompose here to ensure that if we later become
// "in effect" we will request a restyle (above).
if (!inEffect) {
mProgressOnLastCompose.SetNull();
}
}
-Nullable<TimeDuration>
-KeyframeEffectReadOnly::GetLocalTime() const
-{
- // Since the *animation* start time is currently always zero, the local
- // time is equal to the parent time.
- Nullable<TimeDuration> result;
- if (mAnimation) {
- result = mAnimation->GetCurrentTime();
- }
- return result;
-}
-
-void
-KeyframeEffectReadOnly::GetComputedTimingAsDict(
- ComputedTimingProperties& aRetVal) const
-{
- double playbackRate = mAnimation ? mAnimation->PlaybackRate() : 1;
- const Nullable<TimeDuration> currentTime = GetLocalTime();
- GetComputedTimingDictionary(GetComputedTimingAt(currentTime,
- SpecifiedTiming(),
- playbackRate),
- currentTime,
- SpecifiedTiming(),
- aRetVal);
-}
-
-ComputedTiming
-KeyframeEffectReadOnly::GetComputedTimingAt(
- const Nullable<TimeDuration>& aLocalTime,
- const TimingParams& aTiming,
- double aPlaybackRate)
-{
- const StickyTimeDuration zeroDuration;
-
- // Always return the same object to benefit from return-value optimization.
- ComputedTiming result;
-
- if (aTiming.mDuration) {
- MOZ_ASSERT(aTiming.mDuration.ref() >= zeroDuration,
- "Iteration duration should be positive");
- result.mDuration = aTiming.mDuration.ref();
- }
-
- MOZ_ASSERT(aTiming.mIterations >= 0.0 && !IsNaN(aTiming.mIterations),
- "mIterations should be nonnegative & finite, as ensured by "
- "ValidateIterations or CSSParser");
- result.mIterations = aTiming.mIterations;
-
- MOZ_ASSERT(aTiming.mIterationStart >= 0.0,
- "mIterationStart should be nonnegative, as ensured by "
- "ValidateIterationStart");
- result.mIterationStart = aTiming.mIterationStart;
-
- result.mActiveDuration = aTiming.ActiveDuration();
- result.mEndTime = aTiming.EndTime();
- result.mFill = aTiming.mFill == dom::FillMode::Auto ?
- dom::FillMode::None :
- aTiming.mFill;
-
- // The default constructor for ComputedTiming sets all other members to
- // values consistent with an animation that has not been sampled.
- if (aLocalTime.IsNull()) {
- return result;
- }
- const TimeDuration& localTime = aLocalTime.Value();
-
- // Calculate the time within the active interval.
- // https://w3c.github.io/web-animations/#active-time
- StickyTimeDuration activeTime;
-
- StickyTimeDuration beforeActiveBoundary =
- std::min(StickyTimeDuration(aTiming.mDelay), result.mEndTime);
- StickyTimeDuration activeAfterBoundary =
- std::min(StickyTimeDuration(aTiming.mDelay + result.mActiveDuration),
- result.mEndTime);
-
- if (localTime > activeAfterBoundary ||
- (aPlaybackRate >= 0 && localTime == activeAfterBoundary)) {
- result.mPhase = ComputedTiming::AnimationPhase::After;
- if (!result.FillsForwards()) {
- // The animation isn't active or filling at this time.
- return result;
- }
- activeTime = std::max(std::min(result.mActiveDuration,
- result.mActiveDuration + aTiming.mEndDelay),
- zeroDuration);
- } else if (localTime < beforeActiveBoundary ||
- (aPlaybackRate < 0 && localTime == beforeActiveBoundary)) {
- result.mPhase = ComputedTiming::AnimationPhase::Before;
- if (!result.FillsBackwards()) {
- // The animation isn't active or filling at this time.
- return result;
- }
- // activeTime is zero
- } else {
- MOZ_ASSERT(result.mActiveDuration != zeroDuration,
- "How can we be in the middle of a zero-duration interval?");
- result.mPhase = ComputedTiming::AnimationPhase::Active;
- activeTime = localTime - aTiming.mDelay;
- }
-
- // Convert active time to a multiple of iterations.
- // https://w3c.github.io/web-animations/#overall-progress
- double overallProgress;
- if (result.mDuration == zeroDuration) {
- overallProgress = result.mPhase == ComputedTiming::AnimationPhase::Before
- ? 0.0
- : result.mIterations;
- } else {
- overallProgress = activeTime / result.mDuration;
- }
-
- // Factor in iteration start offset.
- if (IsFinite(overallProgress)) {
- overallProgress += result.mIterationStart;
- }
-
- // Determine the 0-based index of the current iteration.
- // https://w3c.github.io/web-animations/#current-iteration
- result.mCurrentIteration =
- IsInfinite(result.mIterations) &&
- result.mPhase == ComputedTiming::AnimationPhase::After
- ? UINT64_MAX // In GetComputedTimingDictionary(),
- // we will convert this into Infinity
- : static_cast<uint64_t>(overallProgress);
-
- // Convert the overall progress to a fraction of a single iteration--the
- // simply iteration progress.
- // https://w3c.github.io/web-animations/#simple-iteration-progress
- double progress = IsFinite(overallProgress)
- ? fmod(overallProgress, 1.0)
- : fmod(result.mIterationStart, 1.0);
-
- // When we finish exactly at the end of an iteration we need to report
- // the end of the final iteration and not the start of the next iteration.
- // We *don't* want to do this when we have a zero-iteration animation or
- // when the animation has been effectively made into a zero-duration animation
- // using a negative end-delay, however.
- if (result.mPhase == ComputedTiming::AnimationPhase::After &&
- progress == 0.0 &&
- result.mIterations != 0.0 &&
- (activeTime != zeroDuration || result.mDuration == zeroDuration)) {
- // The only way we can be in the after phase with a progress of zero and
- // a current iteration of zero, is if we have a zero iteration count or
- // were clipped using a negative end delay--both of which we should have
- // detected above.
- MOZ_ASSERT(result.mCurrentIteration != 0,
- "Should not have zero current iteration");
- progress = 1.0;
- if (result.mCurrentIteration != UINT64_MAX) {
- result.mCurrentIteration--;
- }
- }
-
- // Factor in the direction.
- bool thisIterationReverse = false;
- switch (aTiming.mDirection) {
- case PlaybackDirection::Normal:
- thisIterationReverse = false;
- break;
- case PlaybackDirection::Reverse:
- thisIterationReverse = true;
- break;
- case PlaybackDirection::Alternate:
- thisIterationReverse = (result.mCurrentIteration & 1) == 1;
- break;
- case PlaybackDirection::Alternate_reverse:
- thisIterationReverse = (result.mCurrentIteration & 1) == 0;
- break;
- default:
- MOZ_ASSERT(true, "Unknown PlaybackDirection type");
- }
- if (thisIterationReverse) {
- progress = 1.0 - progress;
- }
-
- // Calculate the 'before flag' which we use when applying step timing
- // functions.
- if ((result.mPhase == ComputedTiming::AnimationPhase::After &&
- thisIterationReverse) ||
- (result.mPhase == ComputedTiming::AnimationPhase::Before &&
- !thisIterationReverse)) {
- result.mBeforeFlag = ComputedTimingFunction::BeforeFlag::Set;
- }
-
- // Apply the easing.
- if (aTiming.mFunction) {
- progress = aTiming.mFunction->GetValue(progress, result.mBeforeFlag);
- }
-
- MOZ_ASSERT(IsFinite(progress), "Progress value should be finite");
- result.mProgress.SetValue(progress);
- return result;
-}
-
-ComputedTiming
-KeyframeEffectReadOnly::GetComputedTiming(const TimingParams* aTiming) const
-{
- double playbackRate = mAnimation ? mAnimation->PlaybackRate() : 1;
- return GetComputedTimingAt(GetLocalTime(),
- aTiming ? *aTiming : SpecifiedTiming(),
- playbackRate);
-}
-
-// https://w3c.github.io/web-animations/#in-play
-bool
-KeyframeEffectReadOnly::IsInPlay() const
-{
- if (!mAnimation || mAnimation->PlayState() == AnimationPlayState::Finished) {
- return false;
- }
-
- return GetComputedTiming().mPhase == ComputedTiming::AnimationPhase::Active;
-}
-
-// https://w3c.github.io/web-animations/#current
-bool
-KeyframeEffectReadOnly::IsCurrent() const
-{
- if (!mAnimation || mAnimation->PlayState() == AnimationPlayState::Finished) {
- return false;
- }
-
- ComputedTiming computedTiming = GetComputedTiming();
- return computedTiming.mPhase == ComputedTiming::AnimationPhase::Before ||
- computedTiming.mPhase == ComputedTiming::AnimationPhase::Active;
-}
-
-// https://w3c.github.io/web-animations/#in-effect
-bool
-KeyframeEffectReadOnly::IsInEffect() const
-{
- ComputedTiming computedTiming = GetComputedTiming();
- return !computedTiming.mProgress.IsNull();
-}
-
-void
-KeyframeEffectReadOnly::SetAnimation(Animation* aAnimation)
-{
- mAnimation = aAnimation;
- NotifyAnimationTimingUpdated();
-}
-
static bool
KeyframesEqualIgnoringComputedOffsets(const nsTArray<Keyframe>& aLhs,
const nsTArray<Keyframe>& aRhs)
{
if (aLhs.Length() != aRhs.Length()) {
return false;
}
@@ -767,20 +456,16 @@ KeyframeEffectReadOnly::SetIsRunningOnCo
void
KeyframeEffectReadOnly::ResetIsRunningOnCompositor()
{
for (AnimationProperty& property : mProperties) {
property.mIsRunningOnCompositor = false;
}
}
-KeyframeEffectReadOnly::~KeyframeEffectReadOnly()
-{
-}
-
static const KeyframeEffectOptions&
KeyframeEffectOptionsFromUnion(
const UnrestrictedDoubleOrKeyframeEffectOptions& aOptions)
{
MOZ_ASSERT(aOptions.IsKeyframeEffectOptions());
return aOptions.GetAsKeyframeEffectOptions();
}
@@ -1678,19 +1363,10 @@ KeyframeEffect::SetTarget(const Nullable
nsNodeUtils::AnimationAdded(mAnimation);
}
} else if (mEffectOptions.mSpacingMode == SpacingMode::paced) {
// New target is null, so fall back to distribute spacing.
KeyframeUtils::ApplyDistributeSpacing(mKeyframes);
}
}
-KeyframeEffect::~KeyframeEffect()
-{
- // mTiming is cycle collected, so we have to do null check first even though
- // mTiming shouldn't be null during the lifetime of KeyframeEffect.
- if (mTiming) {
- mTiming->Unlink();
- }
-}
-
} // namespace dom
} // namespace mozilla
--- a/dom/animation/KeyframeEffect.h
+++ b/dom/animation/KeyframeEffect.h
@@ -11,30 +11,23 @@
#include "nsCSSPropertyID.h"
#include "nsCSSValue.h"
#include "nsCycleCollectionParticipant.h"
#include "nsTArray.h"
#include "nsWrapperCache.h"
#include "mozilla/AnimationPerformanceWarning.h"
#include "mozilla/AnimationTarget.h"
#include "mozilla/Attributes.h"
-#include "mozilla/ComputedTiming.h"
#include "mozilla/ComputedTimingFunction.h"
#include "mozilla/EffectCompositor.h"
#include "mozilla/KeyframeEffectParams.h"
#include "mozilla/LayerAnimationInfo.h" // LayerAnimations::kRecords
-#include "mozilla/Maybe.h"
-#include "mozilla/StickyTimeDuration.h"
#include "mozilla/StyleAnimationValue.h"
-#include "mozilla/TimeStamp.h"
-#include "mozilla/TimingParams.h"
#include "mozilla/dom/AnimationEffectReadOnly.h"
-#include "mozilla/dom/AnimationEffectTimingReadOnly.h"
#include "mozilla/dom/Element.h"
-#include "mozilla/dom/Nullable.h"
struct JSContext;
class nsCSSPropertyIDSet;
class nsIContent;
class nsIDocument;
class nsIFrame;
class nsIPresShell;
class nsPresContext;
@@ -232,55 +225,18 @@ public:
IterationCompositeOperation IterationComposite() const;
CompositeOperation Composite() const;
void GetSpacing(nsString& aRetVal) const
{
mEffectOptions.GetSpacingAsString(aRetVal);
}
- already_AddRefed<AnimationEffectTimingReadOnly> Timing() const override;
-
- const TimingParams& SpecifiedTiming() const override
- {
- return mTiming->AsTimingParams();
- }
- void SetSpecifiedTiming(const TimingParams& aTiming) override;
void NotifyAnimationTimingUpdated() override;
- Nullable<TimeDuration> GetLocalTime() const;
-
- // This function takes as input the timing parameters of an animation and
- // returns the computed timing at the specified local time.
- //
- // The local time may be null in which case only static parameters such as the
- // active duration are calculated. All other members of the returned object
- // are given a null/initial value.
- //
- // This function returns a null mProgress member of the return value
- // if the animation should not be run
- // (because it is not currently active and is not filling at this time).
- static ComputedTiming
- GetComputedTimingAt(const Nullable<TimeDuration>& aLocalTime,
- const TimingParams& aTiming,
- double aPlaybackRate);
-
- ComputedTiming
- GetComputedTiming(const TimingParams* aTiming = nullptr) const override;
-
- void
- GetComputedTimingAsDict(ComputedTimingProperties& aRetVal) const override;
-
- bool IsInPlay() const override;
- bool IsCurrent() const override;
- bool IsInEffect() const override;
-
- void SetAnimation(Animation* aAnimation) override;
- Animation* GetAnimation() const { return mAnimation; }
-
void SetKeyframes(JSContext* aContext, JS::Handle<JSObject*> aKeyframes,
ErrorResult& aRv);
void SetKeyframes(nsTArray<Keyframe>&& aKeyframes,
nsStyleContext* aStyleContext);
const AnimationProperty*
GetAnimationOfProperty(nsCSSPropertyID aProperty) const;
bool HasAnimationOfProperty(nsCSSPropertyID aProperty) const
{
@@ -346,17 +302,17 @@ public:
bool CanIgnoreIfNotVisible() const;
protected:
KeyframeEffectReadOnly(nsIDocument* aDocument,
const Maybe<OwningAnimationTarget>& aTarget,
AnimationEffectTimingReadOnly* aTiming,
const KeyframeEffectParams& aOptions);
- virtual ~KeyframeEffectReadOnly();
+ ~KeyframeEffectReadOnly() override = default;
template<class KeyframeEffectType, class OptionsType>
static already_AddRefed<KeyframeEffectType>
ConstructKeyframeEffect(const GlobalObject& aGlobal,
const Nullable<ElementOrCSSPseudoElement>& aTarget,
JS::Handle<JSObject*> aKeyframes,
const OptionsType& aOptions,
ErrorResult& aRv);
@@ -389,19 +345,17 @@ protected:
// We need to be careful to *not* call this when we are updating the style
// context. That's because calling GetStyleContextForElement when we are in
// the process of building a style context may trigger various forms of
// infinite recursion.
already_AddRefed<nsStyleContext>
GetTargetStyleContext();
Maybe<OwningAnimationTarget> mTarget;
- RefPtr<Animation> mAnimation;
- RefPtr<AnimationEffectTimingReadOnly> mTiming;
KeyframeEffectParams mEffectOptions;
// The specified keyframes.
nsTArray<Keyframe> mKeyframes;
// A set of per-property value arrays, derived from |mKeyframes|.
nsTArray<AnimationProperty> mProperties;
@@ -464,17 +418,14 @@ public:
void NotifySpecifiedTimingUpdated();
// This method calls GetTargetStyleContext which is not safe to use when
// we are in the middle of updating style. If we need to use this when
// updating style, we should pass the nsStyleContext into this method and use
// that to update the properties rather than calling
// GetStyleContextForElement.
void SetTarget(const Nullable<ElementOrCSSPseudoElement>& aTarget);
-
-protected:
- ~KeyframeEffect() override;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_KeyframeEffect_h
--- a/gfx/layers/composite/AsyncCompositionManager.cpp
+++ b/gfx/layers/composite/AsyncCompositionManager.cpp
@@ -646,17 +646,17 @@ SampleAnimations(Layer* aLayer, TimeStam
// example, while they are waiting to be removed) we currently just
// assume that we should fill.
timing.mFill = dom::FillMode::Both;
timing.mFunction =
AnimationUtils::TimingFunctionToComputedTimingFunction(
animation.easingFunction());
ComputedTiming computedTiming =
- dom::KeyframeEffectReadOnly::GetComputedTimingAt(
+ dom::AnimationEffectReadOnly::GetComputedTimingAt(
Nullable<TimeDuration>(elapsedDuration), timing,
animation.playbackRate());
MOZ_ASSERT(!computedTiming.mProgress.IsNull(),
"iteration progress should not be null");
uint32_t segmentIndex = 0;
size_t segmentSize = animation.segments().Length();