Bug 1049975 - Part 4: Merge two Animation::SetEffect()s.
This is a pre-patch for part 5, which is trying to make our code closer to the
spec. Some methods in KeyframeEffectReadOnly belong to AnimationEffectReadOnly,
so first, use AsKeyframeEffect() to access those keyframe-related methods, and
then add virtual methods for timing-related methods to AnimationEffectReadOnly.
MozReview-Commit-ID: 1srA1f8JYeN
--- a/dom/animation/Animation.cpp
+++ b/dom/animation/Animation.cpp
@@ -119,17 +119,17 @@ Animation::SetId(const nsAString& aId)
if (mId == aId) {
return;
}
mId = aId;
nsNodeUtils::AnimationChanged(this);
}
void
-Animation::SetEffect(KeyframeEffectReadOnly* aEffect)
+Animation::SetEffect(AnimationEffectReadOnly* aEffect)
{
RefPtr<Animation> kungFuDeathGrip(this);
if (mEffect == aEffect) {
return;
}
if (mEffect) {
mEffect->SetAnimation(nullptr);
@@ -512,25 +512,30 @@ Animation::Tick()
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");
+ "Orphaned pending animations should have an active timeline");
FinishPendingAt(mTimeline->GetCurrentTime().Value());
}
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
+ if (!mEffect) {
+ return;
+ }
+
// Update layers if we are newly finished.
- if (mEffect &&
- !mEffect->Properties().IsEmpty() &&
+ KeyframeEffectReadOnly* keyframeEffect = mEffect->AsKeyframeEffect();
+ if (keyframeEffect &&
+ !keyframeEffect->Properties().IsEmpty() &&
!mFinishedAtLastComposeStyle &&
PlayState() == AnimationPlayState::Finished) {
PostUpdate();
}
}
void
Animation::TriggerOnNextTick(const Nullable<TimeDuration>& aReadyTime)
@@ -821,17 +826,20 @@ Animation::ComposeStyle(RefPtr<AnimValue
timeToUse = mTimeline->ToTimelineTime(TimeStamp::Now());
}
if (!timeToUse.IsNull()) {
mHoldTime.SetValue((timeToUse.Value() - mStartTime.Value())
.MultDouble(mPlaybackRate));
}
}
- mEffect->ComposeStyle(aStyleRule, aSetProperties);
+ KeyframeEffectReadOnly* keyframeEffect = mEffect->AsKeyframeEffect();
+ if (keyframeEffect) {
+ keyframeEffect->ComposeStyle(aStyleRule, aSetProperties);
+ }
}
MOZ_ASSERT(playState == PlayState(),
"Play state should not change during the course of compositing");
mFinishedAtLastComposeStyle = (playState == AnimationPlayState::Finished);
}
void
@@ -1110,30 +1118,35 @@ Animation::FlushStyle() const
if (doc) {
doc->FlushPendingNotifications(Flush_Style);
}
}
void
Animation::PostUpdate()
{
- nsPresContext* presContext = GetPresContext();
- if (!presContext) {
- return;
- }
-
if (!mEffect) {
return;
}
- Maybe<NonOwningAnimationTarget> target = mEffect->GetTarget();
+ KeyframeEffectReadOnly* keyframeEffect = mEffect->AsKeyframeEffect();
+ if (!keyframeEffect) {
+ return;
+ }
+
+ Maybe<NonOwningAnimationTarget> target = keyframeEffect->GetTarget();
if (!target) {
return;
}
+ nsPresContext* presContext = keyframeEffect->GetPresContext();
+ if (!presContext) {
+ return;
+ }
+
presContext->EffectCompositor()
->RequestRestyle(target->mElement,
target->mPseudoType,
EffectCompositor::RestyleType::Layer,
CascadeLevel());
}
void
@@ -1221,31 +1234,21 @@ Animation::EffectEnd() const
}
return mEffect->SpecifiedTiming().EndTime();
}
nsIDocument*
Animation::GetRenderedDocument() const
{
- if (!mEffect) {
+ if (!mEffect || !mEffect->AsKeyframeEffect()) {
return nullptr;
}
- return mEffect->GetRenderedDocument();
-}
-
-nsPresContext*
-Animation::GetPresContext() const
-{
- if (!mEffect) {
- return nullptr;
- }
-
- return mEffect->GetPresContext();
+ return mEffect->AsKeyframeEffect()->GetRenderedDocument();
}
void
Animation::DoFinishNotification(SyncNotifyFlag aSyncNotifyFlag)
{
CycleCollectedJSRuntime* runtime = CycleCollectedJSRuntime::Get();
if (aSyncNotifyFlag == SyncNotifyFlag::Sync) {
@@ -1307,13 +1310,15 @@ Animation::DispatchPlaybackEvent(const n
RefPtr<AsyncEventDispatcher> asyncDispatcher =
new AsyncEventDispatcher(this, event);
asyncDispatcher->PostDOMEvent();
}
bool
Animation::IsRunningOnCompositor() const
{
- return mEffect && mEffect->IsRunningOnCompositor();
+ return mEffect &&
+ mEffect->AsKeyframeEffect() &&
+ mEffect->AsKeyframeEffect()->IsRunningOnCompositor();
}
} // namespace dom
} // namespace mozilla
--- a/dom/animation/Animation.h
+++ b/dom/animation/Animation.h
@@ -92,22 +92,18 @@ public:
// Animation interface methods
static already_AddRefed<Animation>
Constructor(const GlobalObject& aGlobal,
KeyframeEffectReadOnly* aEffect,
const Optional<AnimationTimeline*>& aTimeline,
ErrorResult& aRv);
void GetId(nsAString& aResult) const { aResult = mId; }
void SetId(const nsAString& aId);
- KeyframeEffectReadOnly* GetEffect() const { return mEffect; }
- void SetEffect(AnimationEffectReadOnly* aEffect)
- {
- // TODO: Merged with SetEffect(KeyframeEffectReadOnly*) in the next patch.
- }
- virtual void SetEffect(KeyframeEffectReadOnly* aEffect);
+ AnimationEffectReadOnly* GetEffect() const { return mEffect; }
+ virtual void SetEffect(AnimationEffectReadOnly* aEffect);
AnimationTimeline* GetTimeline() const { return mTimeline; }
void SetTimeline(AnimationTimeline* aTimeline);
Nullable<TimeDuration> GetStartTime() const { return mStartTime; }
void SetStartTime(const Nullable<TimeDuration>& aNewStartTime);
Nullable<TimeDuration> GetCurrentTime() const;
void SetCurrentTime(const TimeDuration& aNewCurrentTime);
double PlaybackRate() const { return mPlaybackRate; }
void SetPlaybackRate(double aPlaybackRate);
@@ -373,20 +369,19 @@ protected:
* aborting the mReady promise as necessary.
*/
void CancelPendingTasks();
bool IsPossiblyOrphanedPendingAnimation() const;
StickyTimeDuration EffectEnd() const;
nsIDocument* GetRenderedDocument() const;
- nsPresContext* GetPresContext() const;
RefPtr<AnimationTimeline> mTimeline;
- RefPtr<KeyframeEffectReadOnly> mEffect;
+ RefPtr<AnimationEffectReadOnly> mEffect;
// The beginning of the delay period.
Nullable<TimeDuration> mStartTime; // Timeline timescale
Nullable<TimeDuration> mHoldTime; // Animation timescale
Nullable<TimeDuration> mPendingReadyTime; // Timeline timescale
Nullable<TimeDuration> mPreviousCurrentTime; // Animation timescale
double mPlaybackRate;
// A Promise that is replaced on each call to Play()
--- a/dom/animation/AnimationEffectReadOnly.h
+++ b/dom/animation/AnimationEffectReadOnly.h
@@ -7,38 +7,65 @@
#ifndef mozilla_dom_AnimationEffectReadOnly_h
#define mozilla_dom_AnimationEffectReadOnly_h
#include "mozilla/dom/BindingDeclarations.h"
#include "nsCycleCollectionParticipant.h"
#include "nsWrapperCache.h"
namespace mozilla {
+
+struct ElementPropertyTransition;
+
namespace dom {
+class Animation;
class AnimationEffectTimingReadOnly;
+class KeyframeEffectReadOnly;
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)
{
}
+ 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;
+
virtual already_AddRefed<AnimationEffectTimingReadOnly> Timing() const = 0;
+ virtual const TimingParams& SpecifiedTiming() const = 0;
+ virtual void SetSpecifiedTiming(const TimingParams& aTiming) = 0;
+ virtual void NotifyAnimationTimingUpdated() = 0;
- virtual void GetComputedTimingAsDict(ComputedTimingProperties& aRetVal) const = 0;
+ // 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;
+
+ virtual void SetAnimation(Animation* aAnimation) = 0;
protected:
virtual ~AnimationEffectReadOnly() = default;
protected:
RefPtr<nsIDocument> mDocument;
};
--- a/dom/animation/KeyframeEffect.h
+++ b/dom/animation/KeyframeEffect.h
@@ -200,21 +200,17 @@ public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(KeyframeEffectReadOnly,
AnimationEffectReadOnly)
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
- virtual ElementPropertyTransition* AsTransition() { return nullptr; }
- virtual const ElementPropertyTransition* AsTransition() const
- {
- return nullptr;
- }
+ KeyframeEffectReadOnly* AsKeyframeEffect() override { return this; }
// KeyframeEffectReadOnly interface
static already_AddRefed<KeyframeEffectReadOnly>
Constructor(const GlobalObject& aGlobal,
const Nullable<ElementOrCSSPseudoElement>& aTarget,
JS::Handle<JSObject*> aKeyframes,
const UnrestrictedDoubleOrKeyframeEffectOptions& aOptions,
ErrorResult& aRv);
@@ -238,22 +234,22 @@ public:
CompositeOperation Composite() const;
void GetSpacing(nsString& aRetVal) const
{
mEffectOptions.GetSpacingAsString(aRetVal);
}
already_AddRefed<AnimationEffectTimingReadOnly> Timing() const override;
- const TimingParams& SpecifiedTiming() const
+ const TimingParams& SpecifiedTiming() const override
{
return mTiming->AsTimingParams();
}
- void SetSpecifiedTiming(const TimingParams& aTiming);
- void NotifyAnimationTimingUpdated();
+ 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
@@ -262,44 +258,45 @@ public:
// 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 for that gets the computed timing using the current local time as
- // calculated from the timeline time.
ComputedTiming
- GetComputedTiming(const TimingParams* aTiming = nullptr) const;
+ GetComputedTiming(const TimingParams* aTiming = nullptr) const override;
void
GetComputedTimingAsDict(ComputedTimingProperties& aRetVal) const override;
- bool IsInPlay() const;
- bool IsCurrent() const;
- bool IsInEffect() const;
+ bool IsInPlay() const override;
+ bool IsCurrent() const override;
+ bool IsInEffect() const override;
- void SetAnimation(Animation* aAnimation);
+ 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 {
+ bool HasAnimationOfProperty(nsCSSPropertyID aProperty) const
+ {
return GetAnimationOfProperty(aProperty) != nullptr;
}
- const InfallibleTArray<AnimationProperty>& Properties() const {
+ const InfallibleTArray<AnimationProperty>& Properties() const
+ {
return mProperties;
}
- InfallibleTArray<AnimationProperty>& Properties() {
+ InfallibleTArray<AnimationProperty>& Properties()
+ {
return mProperties;
}
// Update |mProperties| by recalculating from |mKeyframes| using
// |aStyleContext| to resolve specified values.
void UpdateProperties(nsStyleContext* aStyleContext);
// Updates |aStyleRule| with the animation values produced by this
--- a/dom/base/nsDOMMutationObserver.cpp
+++ b/dom/base/nsDOMMutationObserver.cpp
@@ -385,22 +385,28 @@ void nsMutationReceiver::NodeWillBeDestr
NS_ASSERTION(!mParent, "Shouldn't have mParent here!");
Disconnect(true);
}
void
nsAnimationReceiver::RecordAnimationMutation(Animation* aAnimation,
AnimationMutation aMutationType)
{
- mozilla::dom::KeyframeEffectReadOnly* effect = aAnimation->GetEffect();
+ mozilla::dom::AnimationEffectReadOnly* effect = aAnimation->GetEffect();
if (!effect) {
return;
}
- Maybe<NonOwningAnimationTarget> animationTarget = effect->GetTarget();
+ mozilla::dom::KeyframeEffectReadOnly* keyframeEffect =
+ effect->AsKeyframeEffect();
+ if (!keyframeEffect) {
+ return;
+ }
+
+ Maybe<NonOwningAnimationTarget> animationTarget = keyframeEffect->GetTarget();
if (!animationTarget) {
return;
}
Element* elem = animationTarget->mElement;
if (!Animations() || !(Subtree() || elem == Target()) ||
elem->ChromeOnlyAccess()) {
return;
--- a/dom/base/nsNodeUtils.cpp
+++ b/dom/base/nsNodeUtils.cpp
@@ -226,18 +226,21 @@ nsNodeUtils::ContentRemoved(nsINode* aCo
IMPL_MUTATION_NOTIFICATION(ContentRemoved, aContainer,
(document, container, aChild, aIndexInContainer,
aPreviousSibling));
}
Maybe<NonOwningAnimationTarget>
nsNodeUtils::GetTargetForAnimation(const Animation* aAnimation)
{
- KeyframeEffectReadOnly* effect = aAnimation->GetEffect();
- return effect ? effect->GetTarget() : Nothing();
+ AnimationEffectReadOnly* effect = aAnimation->GetEffect();
+ if (!effect || !effect->AsKeyframeEffect()) {
+ return Nothing();
+ }
+ return effect->AsKeyframeEffect()->GetTarget();
}
void
nsNodeUtils::AnimationMutated(Animation* aAnimation,
AnimationMutationType aMutatedType)
{
Maybe<NonOwningAnimationTarget> target = GetTargetForAnimation(aAnimation);
if (!target) {
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -469,20 +469,23 @@ AddAnimationsForProperty(nsIFrame* aFram
"inconsistent property flags");
// Add from first to last (since last overrides)
for (size_t animIdx = 0; animIdx < aAnimations.Length(); animIdx++) {
dom::Animation* anim = aAnimations[animIdx];
if (!anim->IsPlaying()) {
continue;
}
- dom::KeyframeEffectReadOnly* effect = anim->GetEffect();
- MOZ_ASSERT(effect, "A playing animation should have an effect");
+
+ dom::KeyframeEffectReadOnly* keyframeEffect =
+ anim->GetEffect() ? anim->GetEffect()->AsKeyframeEffect() : nullptr;
+ MOZ_ASSERT(keyframeEffect,
+ "A playing animation should have a keyframe effect");
const AnimationProperty* property =
- effect->GetAnimationOfProperty(aProperty);
+ keyframeEffect->GetAnimationOfProperty(aProperty);
if (!property) {
continue;
}
// Note that if mWinsInCascade on property was false,
// GetAnimationOfProperty returns null instead.
// This is what we want, since if we have an animation or transition
// that isn't actually winning in the CSS cascade, we don't want to
@@ -506,17 +509,17 @@ AddAnimationsForProperty(nsIFrame* aFram
// driver is advanced it will trigger any pending animations.
if (anim->PlayState() == AnimationPlayState::Pending &&
(!anim->GetTimeline() ||
!anim->GetTimeline()->TracksWallclockTime())) {
continue;
}
AddAnimationForProperty(aFrame, *property, anim, aLayer, aData, aPending);
- effect->SetIsRunningOnCompositor(aProperty, true);
+ keyframeEffect->SetIsRunningOnCompositor(aProperty, true);
}
}
static bool
GenerateAndPushTextMask(nsIFrame* aFrame, nsRenderingContext* aContext,
const nsRect& aFillRect, nsDisplayListBuilder* aBuilder)
{
if (aBuilder->IsForGenerateGlyphMask() ||
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -543,17 +543,19 @@ GetMinAndMaxScaleForAnimationProperty(co
{
for (dom::Animation* anim : aAnimations) {
// This method is only expected to be passed animations that are running on
// the compositor and we only pass playing animations to the compositor,
// which are, by definition, "relevant" animations (animations that are
// not yet finished or which are filling forwards).
MOZ_ASSERT(anim->IsRelevant());
- dom::KeyframeEffectReadOnly* effect = anim->GetEffect();
+ dom::KeyframeEffectReadOnly* effect =
+ anim->GetEffect() ? anim->GetEffect()->AsKeyframeEffect() : nullptr;
+ MOZ_ASSERT(effect, "A playing animation should have a keyframe effect");
for (size_t propIdx = effect->Properties().Length(); propIdx-- != 0; ) {
AnimationProperty& prop = effect->Properties()[propIdx];
if (prop.mProperty == eCSSProperty_transform) {
for (uint32_t segIdx = prop.mSegments.Length(); segIdx-- != 0; ) {
AnimationPropertySegment& segment = prop.mSegments[segIdx];
gfxSize from = segment.mFromValue.GetScaleValue(aFrame);
aMaxScale.width = std::max<float>(aMaxScale.width, from.width);
aMaxScale.height = std::max<float>(aMaxScale.height, from.height);
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -331,21 +331,24 @@ UpdateOldAnimationPropertiesWithNew(
bool aNewIsStylePaused,
nsStyleContext* aStyleContext)
{
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 (aOld.GetEffect()) {
- KeyframeEffectReadOnly* oldEffect = aOld.GetEffect();
- animationChanged =
- oldEffect->SpecifiedTiming() != aNewTiming;
+ AnimationEffectReadOnly* oldEffect = aOld.GetEffect();
+ animationChanged = oldEffect->SpecifiedTiming() != aNewTiming;
oldEffect->SetSpecifiedTiming(aNewTiming);
- oldEffect->SetKeyframes(Move(aNewKeyframes), aStyleContext);
+
+ KeyframeEffectReadOnly* oldKeyframeEffect = oldEffect->AsKeyframeEffect();
+ if (oldKeyframeEffect) {
+ oldKeyframeEffect->SetKeyframes(Move(aNewKeyframes), aStyleContext);
+ }
}
// Handle changes in play state. If the animation is idle, however,
// changes to animation-play-state should *not* restart it.
if (aOld.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.
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -263,17 +263,17 @@ CSSTransition::GetCurrentTimeAt(const Do
result.SetValue((timelineTime.Value() - aStartTime)
.MultDouble(aPlaybackRate));
}
return result;
}
void
-CSSTransition::SetEffect(KeyframeEffectReadOnly* aEffect)
+CSSTransition::SetEffect(AnimationEffectReadOnly* aEffect)
{
Animation::SetEffect(aEffect);
// Initialize transition property.
ElementPropertyTransition* pt = aEffect ? aEffect->AsTransition() : nullptr;
if (eCSSProperty_UNKNOWN == mTransitionProperty && pt) {
mTransitionProperty = pt->TransitionProperty();
mTransitionToValue = pt->ToValue();
--- a/layout/style/nsTransitionManager.h
+++ b/layout/style/nsTransitionManager.h
@@ -206,17 +206,17 @@ public:
// because the animation on the compositor may be running ahead while
// main-thread is busy.
static Nullable<TimeDuration> GetCurrentTimeAt(
const DocumentTimeline& aTimeline,
const TimeStamp& aBaseTime,
const TimeDuration& aStartTime,
double aPlaybackRate);
- void SetEffect(KeyframeEffectReadOnly* aEffect) override;
+ void SetEffect(AnimationEffectReadOnly* aEffect) override;
protected:
virtual ~CSSTransition()
{
MOZ_ASSERT(!mOwningElement.IsSet(), "Owning element should be cleared "
"before a CSS transition is destroyed");
}