Bug 1040543 part 11 - Make ElementPropertyTransition inherit from Animation instead of AnimationPlayer; r=bz
authorBrian Birtles <birtles@gmail.com>
Sun, 10 Aug 2014 17:06:52 +1000
changeset 198793 4234319389c31359a13512e6348457a7aed8dbb7
parent 198792 851652501f189f119c679de6a11ad00b7b105f4c
child 198794 a246e66e8e5346a9cd14bd5b3b09e194169b845e
push id27286
push usernigelbabu@gmail.com
push dateMon, 11 Aug 2014 06:26:45 +0000
treeherdermozilla-central@8c4a1b3a2a8b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1040543
milestone34.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1040543 part 11 - Make ElementPropertyTransition inherit from Animation instead of AnimationPlayer; r=bz This patch changes the inheritance of ElementPropertyTransition so that it is a subclass of Animation not AnimationPlayer. The only thing special about ElementPropertyTransition is it stores some extra state for reversing transitions and an extra ValuePortionFor convenience method. This reversing behavior is implemented by the transition manager by creating a new AnimationPlayer (i.e. it is *not* a property of the AnimationPlayer). As a result this extra state can be pushed down to Animation which simplifies the code significantly. In future if we implement KeyframeEffect as a separate object we may be able to push transition-specific state down to KeyframeEffect instead.
dom/animation/Animation.h
dom/animation/AnimationPlayer.h
layout/style/nsTransitionManager.cpp
layout/style/nsTransitionManager.h
--- a/dom/animation/Animation.h
+++ b/dom/animation/Animation.h
@@ -111,19 +111,21 @@ struct AnimationPropertySegment
 };
 
 struct AnimationProperty
 {
   nsCSSProperty mProperty;
   InfallibleTArray<AnimationPropertySegment> mSegments;
 };
 
+struct ElementPropertyTransition;
+
 namespace dom {
 
-class Animation MOZ_FINAL : public nsWrapperCache
+class Animation : public nsWrapperCache
 {
 public:
   Animation(nsIDocument* aDocument, const AnimationTiming &aTiming)
     : mDocument(aDocument)
     , mTiming(aTiming)
     , mIsFinishedTransition(false)
     , mLastNotification(LAST_NOTIFICATION_NONE)
   {
@@ -131,16 +133,24 @@ public:
   }
 
   NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(Animation)
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(Animation)
 
   nsIDocument* GetParentObject() const { return mDocument; }
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
+  // FIXME: If we succeed in moving transition-specific code to a type of
+  // AnimationEffect (as per the Web Animations API) we should remove these
+  // virtual methods.
+  virtual ElementPropertyTransition* AsTransition() { return nullptr; }
+  virtual const ElementPropertyTransition* AsTransition() const {
+    return nullptr;
+  }
+
   void SetParentTime(Nullable<TimeDuration> aParentTime);
 
   const AnimationTiming& Timing() const {
     return mTiming;
   }
   AnimationTiming& Timing() {
     return mTiming;
   }
@@ -187,20 +197,18 @@ public:
   // cycle (for reasons see explanation in
   // layout/style/nsTransitionManager.cpp).
   // In the meantime, however, they should be ignored.
   bool IsFinishedTransition() const {
     return mIsFinishedTransition;
   }
 
   void SetIsFinishedTransition() {
-    // FIXME: Restore assertion of AsTransition once we make transitions
-    // a subclass of Animations
-    // MOZ_ASSERT(AsTransition(),
-    //           "Calling SetIsFinishedTransition but it's not a transition");
+    MOZ_ASSERT(AsTransition(),
+               "Calling SetIsFinishedTransition but it's not a transition");
     mIsFinishedTransition = true;
   }
 
   bool IsCurrent() const {
     if (IsFinishedTransition()) {
       return false;
     }
 
--- a/dom/animation/AnimationPlayer.h
+++ b/dom/animation/AnimationPlayer.h
@@ -18,22 +18,19 @@
 // X11 has a #define for CurrentTime.
 #ifdef CurrentTime
 #undef CurrentTime
 #endif
 
 struct JSContext;
 
 namespace mozilla {
-
-struct ElementPropertyTransition;
-
 namespace dom {
 
-class AnimationPlayer : public nsWrapperCache
+class AnimationPlayer MOZ_FINAL : public nsWrapperCache
 {
 protected:
   virtual ~AnimationPlayer() { }
 
 public:
   explicit AnimationPlayer(AnimationTimeline* aTimeline)
     : mIsRunningOnCompositor(false)
     , mTimeline(aTimeline)
@@ -51,24 +48,16 @@ public:
   Animation* GetSource() const { return mSource; }
   AnimationTimeline* Timeline() const { return mTimeline; }
   double StartTime() const;
   double CurrentTime() const;
 
   void SetSource(Animation* aSource);
   void Tick();
 
-  // FIXME: If we succeed in moving transition-specific code to a type of
-  // AnimationEffect (as per the Web Animations API) we should remove these
-  // virtual methods.
-  virtual ElementPropertyTransition* AsTransition() { return nullptr; }
-  virtual const ElementPropertyTransition* AsTransition() const {
-    return nullptr;
-  }
-
   bool IsPaused() const {
     return mPlayState == NS_STYLE_ANIMATION_PLAY_STATE_PAUSED;
   }
 
   bool IsRunning() const;
   bool IsCurrent() const;
 
   // Return the duration since the start time of the player, taking into
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -36,45 +36,43 @@ using mozilla::dom::Animation;
 
 using namespace mozilla;
 using namespace mozilla::layers;
 using namespace mozilla::css;
 
 double
 ElementPropertyTransition::CurrentValuePortion() const
 {
-  MOZ_ASSERT(GetSource(), "Transitions should have source content");
   // It would be easy enough to handle finished transitions by using a time
   // fraction of 1 but currently we should not be called for finished
   // transitions.
-  MOZ_ASSERT(!GetSource()->IsFinishedTransition(),
+  MOZ_ASSERT(!IsFinishedTransition(),
              "Getting the value portion of a finished transition");
-  MOZ_ASSERT(!GetCurrentTimeDuration().IsNull(),
+  MOZ_ASSERT(!GetLocalTime().IsNull(),
              "Getting the value portion of an animation that's not being "
              "sampled");
 
   // Transitions use a fill mode of 'backwards' so GetComputedTiming will
   // never return a null time fraction due to being *before* the animation
   // interval. However, it might be possible that we're behind on flushing
   // causing us to get called *after* the animation interval. So, just in
   // case, we override the fill mode to 'both' to ensure the time fraction
   // is never null.
-  AnimationTiming timingToUse = GetSource()->Timing();
+  AnimationTiming timingToUse = mTiming;
   timingToUse.mFillMode = NS_STYLE_ANIMATION_FILL_MODE_BOTH;
-  ComputedTiming computedTiming = GetSource()->GetComputedTiming(&timingToUse);
+  ComputedTiming computedTiming = GetComputedTiming(&timingToUse);
 
   MOZ_ASSERT(computedTiming.mTimeFraction != ComputedTiming::kNullTimeFraction,
              "Got a null time fraction for a fill mode of 'both'");
-  MOZ_ASSERT(GetSource() && GetSource()->Properties().Length() == 1,
+  MOZ_ASSERT(mProperties.Length() == 1,
              "Should have one animation property for a transition");
-  MOZ_ASSERT(GetSource() &&
-             GetSource()->Properties()[0].mSegments.Length() == 1,
+  MOZ_ASSERT(mProperties[0].mSegments.Length() == 1,
              "Animation property should have one segment for a transition");
-  return GetSource()->Properties()[0].mSegments[0].mTimingFunction
-                      .GetValue(computedTiming.mTimeFraction);
+  return mProperties[0].mSegments[0].mTimingFunction
+         .GetValue(computedTiming.mTimeFraction);
 }
 
 /*****************************************************************************
  * nsTransitionManager                                                       *
  *****************************************************************************/
 
 void
 nsTransitionManager::ElementCollectionRemoved()
@@ -360,18 +358,16 @@ nsTransitionManager::ConsiderStartingTra
     return;
   }
 
   if (nsCSSProps::kAnimTypeTable[aProperty] == eStyleAnimType_None) {
     return;
   }
 
   dom::AnimationTimeline* timeline = aElement->OwnerDoc()->Timeline();
-  nsRefPtr<ElementPropertyTransition> pt =
-    new ElementPropertyTransition(timeline);
 
   StyleAnimationValue startValue, endValue, dummyValue;
   bool haveValues =
     ExtractComputedValueForTransition(aProperty, aOldStyleContext,
                                       startValue) &&
     ExtractComputedValueForTransition(aProperty, aNewStyleContext,
                                       endValue);
 
@@ -393,53 +389,51 @@ nsTransitionManager::ConsiderStartingTra
     AnimationPlayerPtrArray& players = aElementTransitions->mPlayers;
     for (size_t i = 0, i_end = players.Length(); i < i_end; ++i) {
       MOZ_ASSERT(players[i]->GetSource() &&
                  players[i]->GetSource()->Properties().Length() == 1,
                  "Should have one animation property for a transition");
       if (players[i]->GetSource()->Properties()[0].mProperty == aProperty) {
         haveCurrentTransition = true;
         currentIndex = i;
-        oldPT =
-          aElementTransitions->mPlayers[currentIndex]->AsTransition();
+        oldPT = players[currentIndex]->GetSource()->AsTransition();
         break;
       }
     }
   }
 
   // If we got a style change that changed the value to the endpoint
   // of the currently running transition, we don't want to interrupt
   // its timing function.
   // This needs to be before the !shouldAnimate && haveCurrentTransition
   // case below because we might be close enough to the end of the
   // transition that the current value rounds to the final value.  In
   // this case, we'll end up with shouldAnimate as false (because
   // there's no value change), but we need to return early here rather
   // than cancel the running transition because shouldAnimate is false!
-  MOZ_ASSERT(!oldPT ||
-             (oldPT->GetSource() &&
-              oldPT->GetSource()->Properties()[0].mSegments.Length() == 1),
+  MOZ_ASSERT(!oldPT || oldPT->Properties()[0].mSegments.Length() == 1,
              "Should have one animation property segment for a transition");
   if (haveCurrentTransition && haveValues &&
-      oldPT->GetSource()->Properties()[0].mSegments[0].mToValue == endValue) {
+      oldPT->Properties()[0].mSegments[0].mToValue == endValue) {
     // WalkTransitionRule already called RestyleForAnimation.
     return;
   }
 
   nsPresContext *presContext = aNewStyleContext->PresContext();
 
   if (!shouldAnimate) {
     if (haveCurrentTransition) {
       // We're in the middle of a transition, and just got a non-transition
       // style change to something that we can't animate.  This might happen
       // because we got a non-transition style change changing to the current
       // in-progress value (which is particularly easy to cause when we're
       // currently in the 'transition-delay').  It also might happen because we
       // just got a style change to a value that can't be interpolated.
       AnimationPlayerPtrArray& players = aElementTransitions->mPlayers;
+      oldPT = nullptr; // Clear pointer so it doesn't dangle
       players.RemoveElementAt(currentIndex);
       aElementTransitions->UpdateAnimationGeneration(mPresContext);
 
       if (players.IsEmpty()) {
         aElementTransitions->Destroy();
         // |aElementTransitions| is now a dangling pointer!
         aElementTransitions = nullptr;
       }
@@ -450,23 +444,24 @@ nsTransitionManager::ConsiderStartingTra
 
   const nsTimingFunction &tf = aTransition.GetTimingFunction();
   float delay = aTransition.GetDelay();
   float duration = aTransition.GetDuration();
   if (duration < 0.0) {
     // The spec says a negative duration is treated as zero.
     duration = 0.0;
   }
-  pt->mStartForReversingTest = startValue;
-  pt->mReversePortion = 1.0;
+
+  StyleAnimationValue startForReversingTest = startValue;
+  double reversePortion = 1.0;
 
   // If the new transition reverses an existing one, we'll need to
   // handle the timing differently.
   if (haveCurrentTransition &&
-      !oldPT->GetSource()->IsFinishedTransition() &&
+      !oldPT->IsFinishedTransition() &&
       oldPT->mStartForReversingTest == endValue) {
     // Compute the appropriate negative transition-delay such that right
     // now we'd end up at the current position.
     double valuePortion =
       oldPT->CurrentValuePortion() * oldPT->mReversePortion +
       (1.0 - oldPT->mReversePortion);
     // A timing function with negative y1 (or y2!) might make
     // valuePortion negative.  In this case, we still want to apply our
@@ -488,45 +483,47 @@ nsTransitionManager::ConsiderStartingTra
     // function, so reduce them along with the duration, but don't
     // reduce positive delays.
     if (delay < 0.0f) {
       delay *= valuePortion;
     }
 
     duration *= valuePortion;
 
-    pt->mStartForReversingTest =
-      oldPT->GetSource()->Properties()[0].mSegments[0].mToValue;
-    pt->mReversePortion = valuePortion;
+    startForReversingTest = oldPT->Properties()[0].mSegments[0].mToValue;
+    reversePortion = valuePortion;
   }
 
   AnimationTiming timing;
   timing.mIterationDuration = TimeDuration::FromMilliseconds(duration);
   timing.mDelay = TimeDuration::FromMilliseconds(delay);
   timing.mIterationCount = 1;
   timing.mDirection = NS_STYLE_ANIMATION_DIRECTION_NORMAL;
   timing.mFillMode = NS_STYLE_ANIMATION_FILL_MODE_BACKWARDS;
 
-  nsRefPtr<dom::Animation> anim =
-    new dom::Animation(aElement->OwnerDoc(), timing);
+  nsRefPtr<ElementPropertyTransition> pt =
+    new ElementPropertyTransition(aElement->OwnerDoc(), timing);
+  pt->mStartForReversingTest = startForReversingTest;
+  pt->mReversePortion = reversePortion;
 
-  AnimationProperty& prop = *anim->Properties().AppendElement();
+  AnimationProperty& prop = *pt->Properties().AppendElement();
   prop.mProperty = aProperty;
 
   AnimationPropertySegment& segment = *prop.mSegments.AppendElement();
   segment.mFromValue = startValue;
   segment.mToValue = endValue;
   segment.mFromKey = 0;
   segment.mToKey = 1;
   segment.mTimingFunction.Init(tf);
 
-  pt->mStartTime = timeline->GetCurrentTimeStamp();
-  pt->mPlayState = NS_STYLE_ANIMATION_PLAY_STATE_RUNNING;
-  pt->mPauseStart = TimeStamp();
-  pt->SetSource(anim);
+  nsRefPtr<dom::AnimationPlayer> player = new dom::AnimationPlayer(timeline);
+  player->mStartTime = timeline->GetCurrentTimeStamp();
+  player->mPlayState = NS_STYLE_ANIMATION_PLAY_STATE_RUNNING;
+  player->mPauseStart = TimeStamp();
+  player->SetSource(pt);
 
   if (!aElementTransitions) {
     aElementTransitions =
       GetElementTransitions(aElement, aNewStyleContext->GetPseudoType(),
                             true);
     if (!aElementTransitions) {
       NS_WARNING("allocating CommonAnimationManager failed");
       return;
@@ -542,19 +539,19 @@ nsTransitionManager::ConsiderStartingTra
     NS_ABORT_IF_FALSE(i == currentIndex ||
                       (players[i]->GetSource() &&
                        players[i]->GetSource()->Properties()[0].mProperty
                        != aProperty),
                       "duplicate transitions for property");
   }
 #endif
   if (haveCurrentTransition) {
-    players[currentIndex] = pt;
+    players[currentIndex] = player;
   } else {
-    if (!players.AppendElement(pt)) {
+    if (!players.AppendElement(player)) {
       NS_WARNING("out of memory");
       return;
     }
   }
   aElementTransitions->UpdateAnimationGeneration(mPresContext);
   aElementTransitions->PostRestyleForAnimation(presContext);
 
   *aStartedAny = true;
--- a/layout/style/nsTransitionManager.h
+++ b/layout/style/nsTransitionManager.h
@@ -5,17 +5,17 @@
 
 /* Code to start and animate CSS transitions. */
 
 #ifndef nsTransitionManager_h_
 #define nsTransitionManager_h_
 
 #include "mozilla/Attributes.h"
 #include "mozilla/MemoryReporting.h"
-#include "mozilla/dom/AnimationPlayer.h"
+#include "mozilla/dom/Animation.h"
 #include "AnimationCommon.h"
 #include "nsCSSPseudoElements.h"
 
 class nsStyleContext;
 class nsPresContext;
 class nsCSSPropertySet;
 struct ElementDependentRuleProcessorData;
 
@@ -24,20 +24,21 @@ struct StyleTransition;
 }
 
 /*****************************************************************************
  * Per-Element data                                                          *
  *****************************************************************************/
 
 namespace mozilla {
 
-struct ElementPropertyTransition : public dom::AnimationPlayer
+struct ElementPropertyTransition : public dom::Animation
 {
-  explicit ElementPropertyTransition(dom::AnimationTimeline* aTimeline)
-    : dom::AnimationPlayer(aTimeline) { }
+  ElementPropertyTransition(nsIDocument* aDocument,
+                            const AnimationTiming &aTiming)
+    : dom::Animation(aDocument, aTiming) { }
 
   virtual ElementPropertyTransition* AsTransition() { return this; }
   virtual const ElementPropertyTransition* AsTransition() const { return this; }
 
   // This is the start value to be used for a check for whether a
   // transition is being reversed.  Normally the same as
   // mProperties[0].mSegments[0].mFromValue, except when this transition
   // started as the reversal of another in-progress transition.