Refactor some parts of nsTransitionManager into common base class to be shared with AnimationManager. (Bug 435442, patch 7) r=bzbarsky
authorL. David Baron <dbaron@dbaron.org>
Mon, 11 Apr 2011 23:18:43 -0700
changeset 67981 548241dd0c12732ff0c5c3b3a3b9ba650411e484
parent 67980 23d79d8f5eda84afe7caf167bd48ac8e030245fe
child 67982 f4d2a9cb8e06bbf0936399684a67f693b70ff111
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky
bugs435442
milestone2.2a1pre
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
Refactor some parts of nsTransitionManager into common base class to be shared with AnimationManager. (Bug 435442, patch 7) r=bzbarsky
layout/style/AnimationCommon.cpp
layout/style/AnimationCommon.h
layout/style/Makefile.in
layout/style/nsTransitionManager.cpp
layout/style/nsTransitionManager.h
new file mode 100644
--- /dev/null
+++ b/layout/style/AnimationCommon.cpp
@@ -0,0 +1,231 @@
+/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is AnimationCommon, common animation code for transitions
+ * and animations.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   L. David Baron <dbaron@dbaron.org>, Mozilla Corporation (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "AnimationCommon.h"
+#include "nsRuleData.h"
+#include "nsCSSValue.h"
+#include "nsStyleContext.h"
+
+namespace mozilla {
+namespace css {
+
+CommonAnimationManager::CommonAnimationManager(nsPresContext *aPresContext)
+  : mPresContext(aPresContext)
+{
+  PR_INIT_CLIST(&mElementData);
+}
+
+CommonAnimationManager::~CommonAnimationManager()
+{
+  NS_ABORT_IF_FALSE(!mPresContext, "Disconnect should have been called");
+}
+
+void
+CommonAnimationManager::Disconnect()
+{
+  // Content nodes might outlive the transition or animation manager.
+  RemoveAllElementData();
+
+  mPresContext = nsnull;
+}
+
+void
+CommonAnimationManager::AddElementData(CommonElementAnimationData* aData)
+{
+  if (PR_CLIST_IS_EMPTY(&mElementData)) {
+    // We need to observe the refresh driver.
+    nsRefreshDriver *rd = mPresContext->RefreshDriver();
+    rd->AddRefreshObserver(this, Flush_Style);
+  }
+
+  PR_INSERT_BEFORE(aData, &mElementData);
+}
+
+void
+CommonAnimationManager::ElementDataRemoved()
+{
+  // If we have no transitions or animations left, remove ourselves from
+  // the refresh driver.
+  if (PR_CLIST_IS_EMPTY(&mElementData)) {
+    mPresContext->RefreshDriver()->RemoveRefreshObserver(this, Flush_Style);
+  }
+}
+
+void
+CommonAnimationManager::RemoveAllElementData()
+{
+  while (!PR_CLIST_IS_EMPTY(&mElementData)) {
+    CommonElementAnimationData *head =
+      static_cast<CommonElementAnimationData*>(PR_LIST_HEAD(&mElementData));
+    head->Destroy();
+  }
+}
+
+/*
+ * nsISupports implementation
+ */
+
+NS_IMPL_ISUPPORTS1(CommonAnimationManager, nsIStyleRuleProcessor)
+
+nsRestyleHint
+CommonAnimationManager::HasStateDependentStyle(StateRuleProcessorData* aData)
+{
+  return nsRestyleHint(0);
+}
+
+PRBool
+CommonAnimationManager::HasDocumentStateDependentStyle(StateRuleProcessorData* aData)
+{
+  return PR_FALSE;
+}
+
+nsRestyleHint
+CommonAnimationManager::HasAttributeDependentStyle(AttributeRuleProcessorData* aData)
+{
+  return nsRestyleHint(0);
+}
+
+/* virtual */ PRBool
+CommonAnimationManager::MediumFeaturesChanged(nsPresContext* aPresContext)
+{
+  return PR_FALSE;
+}
+
+/* static */ PRBool
+CommonAnimationManager::ExtractComputedValueForTransition(
+                          nsCSSProperty aProperty,
+                          nsStyleContext* aStyleContext,
+                          nsStyleAnimation::Value& aComputedValue)
+{
+  PRBool result =
+    nsStyleAnimation::ExtractComputedValue(aProperty, aStyleContext,
+                                           aComputedValue);
+  if (aProperty == eCSSProperty_visibility) {
+    NS_ABORT_IF_FALSE(aComputedValue.GetUnit() ==
+                        nsStyleAnimation::eUnit_Enumerated,
+                      "unexpected unit");
+    aComputedValue.SetIntValue(aComputedValue.GetIntValue(),
+                               nsStyleAnimation::eUnit_Visibility);
+  }
+  return result;
+}
+
+NS_IMPL_ISUPPORTS1(AnimValuesStyleRule, nsIStyleRule)
+
+/* virtual */ void
+AnimValuesStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
+{
+  nsStyleContext *contextParent = aRuleData->mStyleContext->GetParent();
+  if (contextParent && contextParent->HasPseudoElementData()) {
+    // Don't apply transitions or animations to things inside of
+    // pseudo-elements.
+    // FIXME (Bug 522599): Add tests for this.
+    return;
+  }
+
+  for (PRUint32 i = 0, i_end = mPropertyValuePairs.Length(); i < i_end; ++i) {
+    PropertyValuePair &cv = mPropertyValuePairs[i];
+    if (aRuleData->mSIDs & nsCachedStyleData::GetBitForSID(
+                             nsCSSProps::kSIDTable[cv.mProperty]))
+    {
+      nsCSSValue *prop = aRuleData->ValueFor(cv.mProperty);
+      if (prop->GetUnit() == eCSSUnit_Null) {
+#ifdef DEBUG
+        PRBool ok =
+#endif
+          nsStyleAnimation::UncomputeValue(cv.mProperty,
+                                           aRuleData->mPresContext,
+                                           cv.mValue, *prop);
+        NS_ABORT_IF_FALSE(ok, "could not store computed value");
+      }
+    }
+  }
+}
+
+#ifdef DEBUG
+/* virtual */ void
+AnimValuesStyleRule::List(FILE* out, PRInt32 aIndent) const
+{
+  // WRITE ME?
+}
+#endif
+
+void
+ComputedTimingFunction::Init(const nsTimingFunction &aFunction)
+{
+  mType = aFunction.mType;
+  if (mType == nsTimingFunction::Function) {
+    mTimingFunction.Init(aFunction.mFunc.mX1, aFunction.mFunc.mY1,
+                         aFunction.mFunc.mX2, aFunction.mFunc.mY2);
+  } else {
+    mSteps = aFunction.mSteps;
+  }
+}
+
+static inline double
+StepEnd(PRUint32 aSteps, double aPortion)
+{
+  NS_ABORT_IF_FALSE(0.0 <= aPortion && aPortion <= 1.0, "out of range");
+  PRUint32 step = PRUint32(aPortion * aSteps); // floor
+  return double(step) / double(aSteps);
+}
+
+double
+ComputedTimingFunction::GetValue(double aPortion) const
+{
+  switch (mType) {
+    case nsTimingFunction::Function:
+      return mTimingFunction.GetSplineValue(aPortion);
+    case nsTimingFunction::StepStart:
+      // There are diagrams in the spec that seem to suggest this check
+      // and the bounds point should not be symmetric with StepEnd, but
+      // should actually step up at rather than immediately after the
+      // fraction points.  However, we rely on rounding negative values
+      // up to zero, so we can't do that.  And it's not clear the spec
+      // really meant it.
+      return 1.0 - StepEnd(mSteps, 1.0 - aPortion);
+    default:
+      NS_ABORT_IF_FALSE(PR_FALSE, "bad type");
+      // fall through
+    case nsTimingFunction::StepEnd:
+      return StepEnd(mSteps, aPortion);
+  }
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/layout/style/AnimationCommon.h
@@ -0,0 +1,183 @@
+/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is AnimationCommon, common animation code for transitions
+ * and animations.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   L. David Baron <dbaron@dbaron.org>, Mozilla Corporation (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_css_AnimationCommon_h
+#define mozilla_css_AnimationCommon_h
+
+#include "nsIStyleRuleProcessor.h"
+#include "nsIStyleRule.h"
+#include "nsRefreshDriver.h"
+#include "prclist.h"
+#include "nsStyleAnimation.h"
+#include "nsCSSProperty.h"
+#include "mozilla/dom/Element.h"
+#include "nsSMILKeySpline.h"
+#include "nsStyleStruct.h"
+
+class nsPresContext;
+
+namespace mozilla {
+namespace css {
+
+struct CommonElementAnimationData;
+
+class CommonAnimationManager : public nsIStyleRuleProcessor,
+                               public nsARefreshObserver {
+public:
+  CommonAnimationManager(nsPresContext *aPresContext);
+  virtual ~CommonAnimationManager();
+
+  // nsISupports
+  NS_DECL_ISUPPORTS
+
+  // nsIStyleRuleProcessor (parts)
+  virtual nsRestyleHint HasStateDependentStyle(StateRuleProcessorData* aData);
+  virtual PRBool HasDocumentStateDependentStyle(StateRuleProcessorData* aData);
+  virtual nsRestyleHint
+    HasAttributeDependentStyle(AttributeRuleProcessorData* aData);
+  virtual PRBool MediumFeaturesChanged(nsPresContext* aPresContext);
+
+  /**
+   * Notify the manager that the pres context is going away.
+   */
+  void Disconnect();
+
+  static PRBool ExtractComputedValueForTransition(
+                  nsCSSProperty aProperty,
+                  nsStyleContext* aStyleContext,
+                  nsStyleAnimation::Value& aComputedValue);
+protected:
+  friend struct CommonElementAnimationData; // for ElementDataRemoved
+
+  void AddElementData(CommonElementAnimationData* aData);
+  void ElementDataRemoved();
+  void RemoveAllElementData();
+
+  PRCList mElementData;
+  nsPresContext *mPresContext; // weak (non-null from ctor to Disconnect)
+};
+
+/**
+ * A style rule that maps property-nsStyleAnimation::Value pairs.
+ */
+class AnimValuesStyleRule : public nsIStyleRule
+{
+public:
+  // nsISupports implementation
+  NS_DECL_ISUPPORTS
+
+  // nsIStyleRule implementation
+  virtual void MapRuleInfoInto(nsRuleData* aRuleData);
+#ifdef DEBUG
+  virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
+#endif
+
+  void AddValue(nsCSSProperty aProperty, nsStyleAnimation::Value &aStartValue)
+  {
+    PropertyValuePair v = { aProperty, aStartValue };
+    mPropertyValuePairs.AppendElement(v);
+  }
+
+  // Caller must fill in returned value, when non-null.
+  nsStyleAnimation::Value* AddEmptyValue(nsCSSProperty aProperty)
+  {
+    PropertyValuePair *p = mPropertyValuePairs.AppendElement();
+    if (!p) {
+      return nsnull;
+    }
+    p->mProperty = aProperty;
+    return &p->mValue;
+  }
+
+  struct PropertyValuePair {
+    nsCSSProperty mProperty;
+    nsStyleAnimation::Value mValue;
+  };
+
+private:
+  nsTArray<PropertyValuePair> mPropertyValuePairs;
+};
+
+class ComputedTimingFunction {
+public:
+  typedef nsTimingFunction::Type Type;
+  void Init(const nsTimingFunction &aFunction);
+  double GetValue(double aPortion) const;
+private:
+  Type mType;
+  nsSMILKeySpline mTimingFunction;
+  PRUint32 mSteps;
+};
+
+struct CommonElementAnimationData : public PRCList
+{
+  CommonElementAnimationData(dom::Element *aElement, nsIAtom *aElementProperty,
+                             CommonAnimationManager *aManager)
+    : mElement(aElement)
+    , mElementProperty(aElementProperty)
+    , mManager(aManager)
+  {
+    MOZ_COUNT_CTOR(CommonElementAnimationData);
+    PR_INIT_CLIST(this);
+  }
+  ~CommonElementAnimationData()
+  {
+    MOZ_COUNT_DTOR(CommonElementAnimationData);
+    PR_REMOVE_LINK(this);
+    mManager->ElementDataRemoved();
+  }
+
+  void Destroy()
+  {
+    // This will call our destructor.
+    mElement->DeleteProperty(mElementProperty);
+  }
+
+  dom::Element *mElement;
+
+  // the atom we use in mElement's prop table (must be a static atom,
+  // i.e., in an atom list)
+  nsIAtom *mElementProperty;
+
+  CommonAnimationManager *mManager;
+};
+
+}
+}
+
+#endif /* !defined(mozilla_css_AnimationCommon_h) */
--- a/layout/style/Makefile.in
+++ b/layout/style/Makefile.in
@@ -101,16 +101,17 @@ EXPORTS_mozilla/css = \
 		GroupRule.h \
 		ImportRule.h \
 		Loader.h \
 		NameSpaceRule.h \
 		StyleRule.h \
 		$(NULL)
 
 CPPSRCS		= \
+		AnimationCommon.cpp \
 		nsCSSAnonBoxes.cpp \
 		nsCSSDataBlock.cpp \
 		Declaration.cpp \
 		nsCSSKeywords.cpp \
 		Loader.cpp \
 		nsCSSParser.cpp \
 		nsCSSProps.cpp \
 		nsCSSPseudoClasses.cpp \
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -43,95 +43,42 @@
 #include "nsStyleContext.h"
 #include "nsCSSProps.h"
 #include "mozilla/TimeStamp.h"
 #include "nsRefreshDriver.h"
 #include "nsRuleProcessorData.h"
 #include "nsIStyleRule.h"
 #include "nsRuleWalker.h"
 #include "nsRuleData.h"
-#include "nsSMILKeySpline.h"
 #include "gfxColor.h"
 #include "nsCSSPropertySet.h"
 #include "nsStyleAnimation.h"
 #include "nsEventDispatcher.h"
 #include "nsGUIEvent.h"
 #include "mozilla/dom/Element.h"
 
 using mozilla::TimeStamp;
 using mozilla::TimeDuration;
 
 namespace dom = mozilla::dom;
+namespace css = mozilla::css;
 
 /*****************************************************************************
  * Per-Element data                                                          *
  *****************************************************************************/
 
-class ComputedTimingFunction {
-public:
-  typedef nsTimingFunction::Type Type;
-  void Init(const nsTimingFunction &aFunction);
-  double GetValue(double aPortion) const;
-private:
-  Type mType;
-  nsSMILKeySpline mTimingFunction;
-  PRUint32 mSteps;
-};
-
-void
-ComputedTimingFunction::Init(const nsTimingFunction &aFunction)
-{
-  mType = aFunction.mType;
-  if (mType == nsTimingFunction::Function) {
-    mTimingFunction.Init(aFunction.mFunc.mX1, aFunction.mFunc.mY1,
-                         aFunction.mFunc.mX2, aFunction.mFunc.mY2);
-  } else {
-    mSteps = aFunction.mSteps;
-  }
-}
-
-static inline double
-StepEnd(PRUint32 aSteps, double aPortion)
-{
-  NS_ABORT_IF_FALSE(0.0 <= aPortion && aPortion <= 1.0, "out of range");
-  PRUint32 step = PRUint32(aPortion * aSteps); // floor
-  return double(step) / double(aSteps);
-}
-
-double
-ComputedTimingFunction::GetValue(double aPortion) const
-{
-  switch (mType) {
-    case nsTimingFunction::Function:
-      return mTimingFunction.GetSplineValue(aPortion);
-    case nsTimingFunction::StepStart:
-      // There are diagrams in the spec that seem to suggest this check
-      // and the bounds point should not be symmetric with StepEnd, but
-      // should actually step up at rather than immediately after the
-      // fraction points.  However, we rely on rounding negative values
-      // up to zero, so we can't do that.  And it's not clear the spec
-      // really meant it.
-      return 1.0 - StepEnd(mSteps, 1.0 - aPortion);
-    default:
-      NS_ABORT_IF_FALSE(PR_FALSE, "bad type");
-      // fall through
-    case nsTimingFunction::StepEnd:
-      return StepEnd(mSteps, aPortion);
-  }
-}
-
 struct ElementPropertyTransition
 {
   nsCSSProperty mProperty;
   nsStyleAnimation::Value mStartValue, mEndValue;
   TimeStamp mStartTime; // actual start plus transition delay
 
   // data from the relevant nsTransition
   TimeDuration mDuration;
-  ComputedTimingFunction mTimingFunction;
+  css::ComputedTimingFunction mTimingFunction;
 
   // This is the start value to be used for a check for whether a
   // transition is being reversed.  Normally the same as mStartValue,
   // except when this transition started as the reversal of another
   // in-progress transition.  Needed so we can handle two reverses in a
   // row.
   nsStyleAnimation::Value mStartForReversingTest;
   // Likewise, the portion (in value space) of the "full" reversed
@@ -185,119 +132,57 @@ ElementPropertyTransition::ValuePortionF
       timePortion = 0.0; // use start value during transition-delay
     if (timePortion > 1.0)
       timePortion = 1.0; // we might be behind on flushing
   }
 
   return mTimingFunction.GetValue(timePortion);
 }
 
-/**
- * A style rule that maps property-nsStyleAnimation::Value pairs.
- */
-class AnimValuesStyleRule : public nsIStyleRule
-{
-public:
-  // nsISupports implementation
-  NS_DECL_ISUPPORTS
-
-  // nsIStyleRule implementation
-  virtual void MapRuleInfoInto(nsRuleData* aRuleData);
-#ifdef DEBUG
-  virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
-#endif
-
-  void AddValue(nsCSSProperty aProperty, nsStyleAnimation::Value &aStartValue)
-  {
-    PropertyValuePair v = { aProperty, aStartValue };
-    mPropertyValuePairs.AppendElement(v);
-  }
-
-  // Caller must fill in returned value, when non-null.
-  nsStyleAnimation::Value* AddEmptyValue(nsCSSProperty aProperty)
-  {
-    PropertyValuePair *p = mPropertyValuePairs.AppendElement();
-    if (!p) {
-      return nsnull;
-    }
-    p->mProperty = aProperty;
-    return &p->mValue;
-  }
-
-  struct PropertyValuePair {
-    nsCSSProperty mProperty;
-    nsStyleAnimation::Value mValue;
-  };
-
-private:
-  nsTArray<PropertyValuePair> mPropertyValuePairs;
-};
-
-struct ElementTransitions : public PRCList
+struct ElementTransitions : public mozilla::css::CommonElementAnimationData
 {
   ElementTransitions(dom::Element *aElement, nsIAtom *aElementProperty,
                      nsTransitionManager *aTransitionManager)
-    : mElement(aElement)
-    , mElementProperty(aElementProperty)
-    , mTransitionManager(aTransitionManager)
-  {
-    PR_INIT_CLIST(this);
-  }
-  ~ElementTransitions()
+    : CommonElementAnimationData(aElement, aElementProperty,
+                                 aTransitionManager)
   {
-    PR_REMOVE_LINK(this);
-    mTransitionManager->TransitionsRemoved();
-  }
-
-  void Destroy()
-  {
-    // This will call our destructor.
-    mElement->DeleteProperty(mElementProperty);
   }
 
   void EnsureStyleRuleFor(TimeStamp aRefreshTime);
 
 
   // Either zero or one for each CSS property:
   nsTArray<ElementPropertyTransition> mPropertyTransitions;
 
   // This style rule overrides style data with the currently
   // transitioning value for an element that is executing a transition.
   // It only matches when styling with animation.  When we style without
   // animation, we need to not use it so that we can detect any new
   // changes; if necessary we restyle immediately afterwards with
   // animation.
-  nsRefPtr<AnimValuesStyleRule> mStyleRule;
+  nsRefPtr<css::AnimValuesStyleRule> mStyleRule;
   // The refresh time associated with mStyleRule.
   TimeStamp mStyleRuleRefreshTime;
-
-  dom::Element *mElement;
-
-  // the atom we use in mElement's prop table (must be a static atom,
-  // i.e., in an atom list)
-  nsIAtom *mElementProperty;
-
-  nsTransitionManager *mTransitionManager;
 };
 
 static void
 ElementTransitionsPropertyDtor(void           *aObject,
                                nsIAtom        *aPropertyName,
                                void           *aPropertyValue,
                                void           *aData)
 {
   ElementTransitions *et = static_cast<ElementTransitions*>(aPropertyValue);
   delete et;
 }
 
 void
 ElementTransitions::EnsureStyleRuleFor(TimeStamp aRefreshTime)
 {
   if (!mStyleRule || mStyleRuleRefreshTime != aRefreshTime) {
-    mStyleRule = new AnimValuesStyleRule();
+    mStyleRule = new css::AnimValuesStyleRule();
     mStyleRuleRefreshTime = aRefreshTime;
 
     for (PRUint32 i = 0, i_end = mPropertyTransitions.Length(); i < i_end; ++i)
     {
       ElementPropertyTransition &pt = mPropertyTransitions[i];
       if (pt.IsRemovedSentinel()) {
         continue;
       }
@@ -314,107 +199,20 @@ ElementTransitions::EnsureStyleRuleFor(T
         nsStyleAnimation::Interpolate(pt.mProperty,
                                       pt.mStartValue, pt.mEndValue,
                                       valuePortion, *val);
       NS_ABORT_IF_FALSE(ok, "could not interpolate values");
     }
   }
 }
 
-NS_IMPL_ISUPPORTS1(AnimValuesStyleRule, nsIStyleRule)
-
-/* virtual */ void
-AnimValuesStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
-{
-  nsStyleContext *contextParent = aRuleData->mStyleContext->GetParent();
-  if (contextParent && contextParent->HasPseudoElementData()) {
-    // Don't apply transitions to things inside of pseudo-elements.
-    // FIXME (Bug 522599): Add tests for this.
-    return;
-  }
-
-  for (PRUint32 i = 0, i_end = mPropertyValuePairs.Length(); i < i_end; ++i) {
-    PropertyValuePair &cv = mPropertyValuePairs[i];
-    if (aRuleData->mSIDs & nsCachedStyleData::GetBitForSID(
-                             nsCSSProps::kSIDTable[cv.mProperty]))
-    {
-      nsCSSValue *prop = aRuleData->ValueFor(cv.mProperty);
-      if (prop->GetUnit() == eCSSUnit_Null) {
-#ifdef DEBUG
-        PRBool ok =
-#endif
-          nsStyleAnimation::UncomputeValue(cv.mProperty,
-                                           aRuleData->mPresContext,
-                                           cv.mValue, *prop);
-        NS_ABORT_IF_FALSE(ok, "could not store computed value");
-      }
-    }
-  }
-}
-
-#ifdef DEBUG
-/* virtual */ void
-AnimValuesStyleRule::List(FILE* out, PRInt32 aIndent) const
-{
-  // WRITE ME?
-}
-#endif
-
 /*****************************************************************************
  * nsTransitionManager                                                       *
  *****************************************************************************/
 
-nsTransitionManager::nsTransitionManager(nsPresContext *aPresContext)
-  : mPresContext(aPresContext)
-{
-  PR_INIT_CLIST(&mElementTransitions);
-}
-
-nsTransitionManager::~nsTransitionManager()
-{
-  NS_ABORT_IF_FALSE(!mPresContext, "Disconnect should have been called");
-}
-
-void
-nsTransitionManager::Disconnect()
-{
-  // Content nodes might outlive the transition manager.
-  RemoveAllTransitions();
-
-  mPresContext = nsnull;
-}
-
-void
-nsTransitionManager::RemoveAllTransitions()
-{
-  while (!PR_CLIST_IS_EMPTY(&mElementTransitions)) {
-    ElementTransitions *head = static_cast<ElementTransitions*>(
-                                 PR_LIST_HEAD(&mElementTransitions));
-    head->Destroy();
-  }
-}
-
-static PRBool
-TransExtractComputedValue(nsCSSProperty aProperty,
-                          nsStyleContext* aStyleContext,
-                          nsStyleAnimation::Value& aComputedValue)
-{
-  PRBool result =
-    nsStyleAnimation::ExtractComputedValue(aProperty, aStyleContext,
-                                           aComputedValue);
-  if (aProperty == eCSSProperty_visibility) {
-    NS_ABORT_IF_FALSE(aComputedValue.GetUnit() ==
-                        nsStyleAnimation::eUnit_Enumerated,
-                      "unexpected unit");
-    aComputedValue.SetIntValue(aComputedValue.GetIntValue(),
-                               nsStyleAnimation::eUnit_Visibility);
-  }
-  return result;
-}
-
 already_AddRefed<nsIStyleRule>
 nsTransitionManager::StyleContextChanged(dom::Element *aElement,
                                          nsStyleContext *aOldStyleContext,
                                          nsStyleContext *aNewStyleContext)
 {
   NS_PRECONDITION(aOldStyleContext->GetPseudo() ==
                       aNewStyleContext->GetPseudo(),
                   "pseudo type mismatch");
@@ -555,18 +353,18 @@ nsTransitionManager::StyleContextChanged
     do {
       --i;
       ElementPropertyTransition &pt = pts[i];
           // properties no longer in 'transition-property'
       if ((checkProperties &&
            !allTransitionProperties.HasProperty(pt.mProperty)) ||
           // properties whose computed values changed but delay and
           // duration are both zero
-          !TransExtractComputedValue(pt.mProperty, aNewStyleContext,
-                                     currentValue) ||
+          !ExtractComputedValueForTransition(pt.mProperty, aNewStyleContext,
+                                             currentValue) ||
           currentValue != pt.mEndValue) {
         // stop the transition
         pts.RemoveElementAt(i);
       }
     } while (i != 0);
 
     if (pts.IsEmpty()) {
       et->Destroy();
@@ -591,17 +389,17 @@ nsTransitionManager::StyleContextChanged
   // restyle that caused this transition using a "covering" rule that
   // covers up any changes on which we started transitions, so that
   // descendants don't start their own transitions.  (In the case of
   // negative transition delay, this covering rule produces different
   // results than applying the transition rule immediately would).
   // Our caller is responsible for restyling again using this covering
   // rule.
 
-  nsRefPtr<AnimValuesStyleRule> coverRule = new AnimValuesStyleRule;
+  nsRefPtr<css::AnimValuesStyleRule> coverRule = new css::AnimValuesStyleRule;
   if (!coverRule) {
     NS_WARNING("out of memory");
     return nsnull;
   }
   
   nsTArray<ElementPropertyTransition> &pts = et->mPropertyTransitions;
   for (PRUint32 i = 0, i_end = pts.Length(); i < i_end; ++i) {
     ElementPropertyTransition &pt = pts[i];
@@ -637,18 +435,20 @@ nsTransitionManager::ConsiderStartingTra
 
   if (nsCSSProps::kAnimTypeTable[aProperty] == eStyleAnimType_None) {
     return;
   }
 
   ElementPropertyTransition pt;
   nsStyleAnimation::Value dummyValue;
   PRBool haveValues =
-    TransExtractComputedValue(aProperty, aOldStyleContext, pt.mStartValue) &&
-    TransExtractComputedValue(aProperty, aNewStyleContext, pt.mEndValue);
+    ExtractComputedValueForTransition(aProperty, aOldStyleContext,
+                                      pt.mStartValue) &&
+    ExtractComputedValueForTransition(aProperty, aNewStyleContext,
+                                      pt.mEndValue);
   PRBool shouldAnimate =
     haveValues &&
     pt.mStartValue != pt.mEndValue &&
     // Check that we can interpolate between these values
     // (If this is ever a performance problem, we could add a
     // CanInterpolate method, but it seems fine for now.)
     nsStyleAnimation::Interpolate(aProperty, pt.mStartValue, pt.mEndValue,
                                   0.5, dummyValue);
@@ -797,17 +597,17 @@ nsTransitionManager::ConsiderStartingTra
   aWhichStarted->AddProperty(aProperty);
 }
 
 ElementTransitions*
 nsTransitionManager::GetElementTransitions(dom::Element *aElement,
                                            nsCSSPseudoElements::Type aPseudoType,
                                            PRBool aCreateIfNeeded)
 {
-  if (!aCreateIfNeeded && PR_CLIST_IS_EMPTY(&mElementTransitions)) {
+  if (!aCreateIfNeeded && PR_CLIST_IS_EMPTY(&mElementData)) {
     // Early return for the most common case.
     return nsnull;
   }
 
   nsIAtom *propName;
   if (aPseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) {
     propName = nsGkAtoms::transitionsProperty;
   } else if (aPseudoType == nsCSSPseudoElements::ePseudo_before) {
@@ -832,40 +632,22 @@ nsTransitionManager::GetElementTransitio
     nsresult rv = aElement->SetProperty(propName, et,
                                         ElementTransitionsPropertyDtor, nsnull);
     if (NS_FAILED(rv)) {
       NS_WARNING("SetProperty failed");
       delete et;
       return nsnull;
     }
 
-    AddElementTransitions(et);
+    AddElementData(et);
   }
 
   return et;
 }
 
-void
-nsTransitionManager::AddElementTransitions(ElementTransitions* aElementTransitions)
-{
-  if (PR_CLIST_IS_EMPTY(&mElementTransitions)) {
-    // We need to observe the refresh driver.
-    nsRefreshDriver *rd = mPresContext->RefreshDriver();
-    rd->AddRefreshObserver(this, Flush_Style);
-  }
-
-  PR_INSERT_BEFORE(aElementTransitions, &mElementTransitions);
-}
-
-/*
- * nsISupports implementation
- */
-
-NS_IMPL_ISUPPORTS1(nsTransitionManager, nsIStyleRuleProcessor)
-
 /*
  * nsIStyleRuleProcessor implementation
  */
 
 void
 nsTransitionManager::WalkTransitionRule(RuleProcessorData* aData,
                                         nsCSSPseudoElements::Type aPseudoType)
 {
@@ -927,40 +709,16 @@ nsTransitionManager::RulesMatching(AnonB
 
 #ifdef MOZ_XUL
 /* virtual */ void
 nsTransitionManager::RulesMatching(XULTreeRuleProcessorData* aData)
 {
 }
 #endif
 
-nsRestyleHint
-nsTransitionManager::HasStateDependentStyle(StateRuleProcessorData* aData)
-{
-  return nsRestyleHint(0);
-}
-
-PRBool
-nsTransitionManager::HasDocumentStateDependentStyle(StateRuleProcessorData* aData)
-{
-  return PR_FALSE;
-}
-
-nsRestyleHint
-nsTransitionManager::HasAttributeDependentStyle(AttributeRuleProcessorData* aData)
-{
-  return nsRestyleHint(0);
-}
-
-/* virtual */ PRBool
-nsTransitionManager::MediumFeaturesChanged(nsPresContext* aPresContext)
-{
-  return PR_FALSE;
-}
-
 struct TransitionEventInfo {
   nsCOMPtr<nsIContent> mElement;
   nsTransitionEvent mEvent;
 
   TransitionEventInfo(nsIContent *aElement, nsCSSProperty aProperty,
                       TimeDuration aDuration)
     : mElement(aElement),
       mEvent(PR_TRUE, NS_TRANSITION_END,
@@ -985,27 +743,27 @@ nsTransitionManager::WillRefresh(mozilla
   NS_ABORT_IF_FALSE(mPresContext,
                     "refresh driver should not notify additional observers "
                     "after pres context has been destroyed");
   if (!mPresContext->GetPresShell()) {
     // Someone might be keeping mPresContext alive past the point
     // where it has been torn down; don't bother doing anything in
     // this case.  But do get rid of all our transitions so we stop
     // triggering refreshes.
-    RemoveAllTransitions();
+    RemoveAllElementData();
     return;
   }
 
   nsTArray<TransitionEventInfo> events;
 
   // Trim transitions that have completed, and post restyle events for
   // frames that are still transitioning.
   {
-    PRCList *next = PR_LIST_HEAD(&mElementTransitions);
-    while (next != &mElementTransitions) {
+    PRCList *next = PR_LIST_HEAD(&mElementData);
+    while (next != &mElementData) {
       ElementTransitions *et = static_cast<ElementTransitions*>(next);
       next = PR_NEXT_LINK(next);
 
       NS_ABORT_IF_FALSE(et->mElement->GetCurrentDoc() ==
                           mPresContext->Document(),
                         "nsGenericElement::UnbindFromTree should have "
                         "destroyed the element transitions object");
 
@@ -1059,29 +817,19 @@ nsTransitionManager::WillRefresh(mozilla
         et->Destroy();
         // |et| is now a dangling pointer!
         et = nsnull;
       }
     }
   }
 
   // We might have removed transitions above.
-  TransitionsRemoved();
+  ElementDataRemoved();
 
   for (PRUint32 i = 0, i_end = events.Length(); i < i_end; ++i) {
     TransitionEventInfo &info = events[i];
     nsEventDispatcher::Dispatch(info.mElement, mPresContext, &info.mEvent);
 
     if (!mPresContext) {
       break;
     }
   }
 }
-
-void
-nsTransitionManager::TransitionsRemoved()
-{
-  // If we have no transitions left, remove ourselves from the refresh
-  // driver.
-  if (PR_CLIST_IS_EMPTY(&mElementTransitions)) {
-    mPresContext->RefreshDriver()->RemoveRefreshObserver(this, Flush_Style);
-  }
-}
--- a/layout/style/nsTransitionManager.h
+++ b/layout/style/nsTransitionManager.h
@@ -35,38 +35,32 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 /* Code to start and animate CSS transitions. */
 
 #ifndef nsTransitionManager_h_
 #define nsTransitionManager_h_
 
-#include "prclist.h"
-#include "nsCSSProperty.h"
-#include "nsIStyleRuleProcessor.h"
-#include "nsRefreshDriver.h"
+#include "AnimationCommon.h"
 #include "nsCSSPseudoElements.h"
 
 class nsStyleContext;
 class nsPresContext;
 class nsCSSPropertySet;
 struct nsTransition;
 struct ElementTransitions;
 
-class nsTransitionManager : public nsIStyleRuleProcessor,
-                            public nsARefreshObserver {
+class nsTransitionManager : public mozilla::css::CommonAnimationManager
+{
 public:
-  nsTransitionManager(nsPresContext *aPresContext);
-  ~nsTransitionManager();
-
-  /**
-   * Notify the transition manager that the pres context is going away.
-   */
-  void Disconnect();
+  nsTransitionManager(nsPresContext *aPresContext)
+    : mozilla::css::CommonAnimationManager(aPresContext)
+  {
+  }
 
   /**
    * StyleContextChanged 
    *
    * To be called from nsFrameManager::ReResolveStyleContext when the
    * style of an element has changed, to initiate transitions from
    * that style change.  For style contexts with :before and :after
    * pseudos, aElement is expected to be the generated before/after
@@ -79,53 +73,36 @@ public:
    * element *again* with the original sequence of rules plus the
    * returned cover rule as the most specific rule.
    */
   already_AddRefed<nsIStyleRule>
     StyleContextChanged(mozilla::dom::Element *aElement,
                         nsStyleContext *aOldStyleContext,
                         nsStyleContext *aNewStyleContext);
 
-  // nsISupports
-  NS_DECL_ISUPPORTS
-
-  // nsIStyleRuleProcessor
+  // nsIStyleRuleProcessor (parts)
   virtual void RulesMatching(ElementRuleProcessorData* aData);
   virtual void RulesMatching(PseudoElementRuleProcessorData* aData);
   virtual void RulesMatching(AnonBoxRuleProcessorData* aData);
 #ifdef MOZ_XUL
   virtual void RulesMatching(XULTreeRuleProcessorData* aData);
 #endif
-  virtual nsRestyleHint HasStateDependentStyle(StateRuleProcessorData* aData);
-  virtual PRBool HasDocumentStateDependentStyle(StateRuleProcessorData* aData);
-  virtual nsRestyleHint
-    HasAttributeDependentStyle(AttributeRuleProcessorData* aData);
-  virtual PRBool MediumFeaturesChanged(nsPresContext* aPresContext);
 
   // nsARefreshObserver
   virtual void WillRefresh(mozilla::TimeStamp aTime);
 
 private:
-  friend struct ElementTransitions; // for TransitionsRemoved
-
   void ConsiderStartingTransition(nsCSSProperty aProperty,
                                   const nsTransition& aTransition,
                                   mozilla::dom::Element *aElement,
                                   ElementTransitions *&aElementTransitions,
                                   nsStyleContext *aOldStyleContext,
                                   nsStyleContext *aNewStyleContext,
                                   PRBool *aStartedAny,
                                   nsCSSPropertySet *aWhichStarted);
   ElementTransitions* GetElementTransitions(mozilla::dom::Element *aElement,
                                             nsCSSPseudoElements::Type aPseudoType,
                                             PRBool aCreateIfNeeded);
-  void AddElementTransitions(ElementTransitions* aElementTransitions);
-  void TransitionsRemoved();
   void WalkTransitionRule(RuleProcessorData* aData,
                           nsCSSPseudoElements::Type aPseudoType);
-
-  void RemoveAllTransitions();
-
-  PRCList mElementTransitions;
-  nsPresContext *mPresContext; // weak (non-null from ctor to Disconnect)
 };
 
 #endif /* !defined(nsTransitionManager_h_) */