Backed out changesets ce0ef3278d5f, d9d1983edb5c, and 7e0609e54c24 (bug 914847) for bustage. a=backout
authorRyan VanderMeulen <ryanvm@gmail.com>
Sun, 19 Jan 2014 23:04:26 -0500
changeset 175883 2f9b15aa2f8b6a4b8e4fd8e8667e4d4a4e36fdfa
parent 175882 ce0ef3278d5fbd71b7dfb18c179eb3d133611b6f
child 175884 0d61b4fd72f551fd479877cc1e433afb86e014ca
push id445
push userffxbld
push dateMon, 10 Mar 2014 22:05:19 +0000
treeherdermozilla-release@dc38b741b04e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbackout
bugs914847
milestone28.0a2
backs outce0ef3278d5fbd71b7dfb18c179eb3d133611b6f
d9d1983edb5c790457a6d2f2d7cdb1bb810430f4
7e0609e54c24ecf418dcfe776bf76166124a1873
Backed out changesets ce0ef3278d5f, d9d1983edb5c, and 7e0609e54c24 (bug 914847) for bustage. a=backout
browser/metro/base/tests/mochitest/head.js
layout/base/nsPresContext.cpp
layout/base/nsPresContext.h
layout/base/nsPresShell.cpp
layout/style/AnimationCommon.cpp
layout/style/AnimationCommon.h
layout/style/nsAnimationManager.cpp
layout/style/nsAnimationManager.h
layout/style/nsTransitionManager.cpp
layout/style/nsTransitionManager.h
--- a/browser/metro/base/tests/mochitest/head.js
+++ b/browser/metro/base/tests/mochitest/head.js
@@ -894,18 +894,16 @@ TouchDragAndHold.prototype = {
     this._utils = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                          .getInterface(Ci.nsIDOMWindowUtils);
     this._endPoint = { xPos: aEndX, yPos: aEndY };
     this._currentPoint = { xPos: aStartX, yPos: aStartY };
     this._step = { steps: 0, x: (aEndX - aStartX) / this._numSteps, y: (aEndY - aStartY) / this._numSteps };
     if (this._debug) {
       info("[0] touchstart " + aStartX + " x " + aStartY);
     }
-    // flush layout, bug 914847
-    this._utils.elementFromPoint(aStartX, aStartY, false, true);
     if (this._native) {
       this._utils.sendNativeTouchPoint(this._pointerId, this._dui.TOUCH_CONTACT,
                                        aStartX, aStartY, 1, 90);
     } else {
       EventUtils.synthesizeTouchAtPoint(aStartX, aStartY, { type: "touchstart" }, aWindow);
     }
     let self = this;
     setTimeout(function () { self.callback(); }, this._timeoutStep);
@@ -923,17 +921,17 @@ TouchDragAndHold.prototype = {
                    x: (aEndX - this._endPoint.xPos) / this._numSteps,
                    y: (aEndY - this._endPoint.yPos) / this._numSteps };
     this._endPoint = { xPos: aEndX, yPos: aEndY };
     let self = this;
     setTimeout(function () { self.callback(); }, this._timeoutStep);
     return this._defer.promise;
   },
 
-  end: function end() {
+  end: function start() {
     if (this._debug) {
       info("[" + this._step.steps + "] touchend " + this._endPoint.xPos + " x " + this._endPoint.yPos);
       SelectionHelperUI.debugClearDebugPoints();
     }
     if (this._native) {
       this._utils.sendNativeTouchPoint(this._pointerId, this._dui.TOUCH_REMOVE,
                                        this._endPoint.xPos, this._endPoint.yPos,
                                        1, 90);
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -983,18 +983,17 @@ nsPresContext::Init(nsDeviceContext* aDe
 
     if (!mRefreshDriver) {
       mRefreshDriver = new nsRefreshDriver(this);
     }
   }
 
   // Initialise refresh tick counters for OMTA
   mLastStyleUpdateForAllAnimations =
-    mLastUpdateThrottledAnimationStyle =
-    mLastUpdateThrottledTransitionStyle = mRefreshDriver->MostRecentRefresh();
+    mLastUpdateThrottledStyle = mRefreshDriver->MostRecentRefresh();
 
   mLangService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID);
 
   // Register callbacks so we're notified when the preferences change
   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
                                 "font.",
                                 this);
   Preferences::RegisterCallback(nsPresContext::PrefChangedCallback,
--- a/layout/base/nsPresContext.h
+++ b/layout/base/nsPresContext.h
@@ -652,20 +652,18 @@ public:
   void   SetBackgroundColorDraw(bool aCanDraw)
   {
     mDrawColorBackground = aCanDraw;
   }
   
   /**
    * Getter and setter for OMTA time counters
    */
-  bool ThrottledTransitionStyleIsUpToDate() const;
-  void TickLastUpdateThrottledTransitionStyle();
-  bool ThrottledAnimationStyleIsUpToDate() const;
-  void TickLastUpdateThrottledAnimationStyle();
+  bool ThrottledStyleIsUpToDate() const;
+  void TickLastUpdateThrottledStyle();
   bool StyleUpdateForAllAnimationsIsUpToDate();
   void TickLastStyleUpdateForAllAnimations();
 
 #ifdef IBMBIDI
   /**
    *  Check if bidi enabled (set depending on the presence of RTL
    *  characters or when default directionality is RTL).
    *  If enabled, we should apply the Unicode Bidi Algorithm
@@ -1230,20 +1228,18 @@ protected:
   LangGroupFontPrefs    mLangGroupFontPrefs;
 
   nscoord               mBorderWidthTable[3];
 
   uint32_t              mInterruptChecksToSkip;
 
   mozilla::TimeStamp    mReflowStartTime;
 
-  // last time animations styles were flushed to their primary frames
-  mozilla::TimeStamp    mLastUpdateThrottledAnimationStyle;
-  // last time transition styles were flushed to their primary frames
-  mozilla::TimeStamp    mLastUpdateThrottledTransitionStyle;
+  // last time animations/transition styles were flushed to their primary frames
+  mozilla::TimeStamp    mLastUpdateThrottledStyle;
   // last time we did a full style flush
   mozilla::TimeStamp    mLastStyleUpdateForAllAnimations;
 
   unsigned              mHasPendingInterrupt : 1;
   unsigned              mInterruptsEnabled : 1;
   unsigned              mUseDocumentFonts : 1;
   unsigned              mUseDocumentColors : 1;
   unsigned              mUnderlineLinks : 1;
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -6186,31 +6186,16 @@ nsIFrame* GetNearestFrameContainingPresS
   nsIFrame* frame = nullptr;
   if (view) {
     frame = view->GetFrame();
   }
 
   return frame;
 }
 
-static bool
-FlushThrottledStyles(nsIDocument *aDocument, void *aData)
-{
-  nsIPresShell* shell = aDocument->GetShell();
-  if (shell && shell->IsVisible()) {
-    nsPresContext* presContext = shell->GetPresContext();
-    if (presContext) {
-      presContext->TransitionManager()->UpdateAllThrottledStyles();
-      presContext->AnimationManager()->UpdateAllThrottledStyles();
-    }
-  }
-
-  return true;
-}
-
 nsresult
 PresShell::HandleEvent(nsIFrame* aFrame,
                        WidgetGUIEvent* aEvent,
                        bool aDontRetargetEvents,
                        nsEventStatus* aEventStatus)
 {
   NS_ASSERTION(aFrame, "null frame");
 
@@ -6297,31 +6282,24 @@ PresShell::HandleEvent(nsIFrame* aFrame,
         delete event;
       }
     }
     return NS_OK;
   }
 
   nsIFrame* frame = aFrame;
 
+  if (aEvent->eventStructType == NS_TOUCH_EVENT) {
+    nsIDocument::UnlockPointer();
+    FlushPendingNotifications(Flush_Layout);
+    frame = GetNearestFrameContainingPresShell(this);
+  }
+
   bool dispatchUsingCoordinates = aEvent->IsUsingCoordinates();
   if (dispatchUsingCoordinates) {
-    if (nsLayoutUtils::AreAsyncAnimationsEnabled() && mDocument) {
-      if (aEvent->eventStructType == NS_TOUCH_EVENT) {
-        nsIDocument::UnlockPointer();
-      }
-
-      {  // scope for scriptBlocker.
-        nsAutoScriptBlocker scriptBlocker;
-        GetRootPresShell()->GetDocument()->
-          EnumerateSubDocuments(FlushThrottledStyles, nullptr);
-      }
-      frame = GetNearestFrameContainingPresShell(this);
-    }
-
     NS_WARN_IF_FALSE(frame, "Nothing to handle this event!");
     if (!frame)
       return NS_OK;
 
     nsPresContext* framePresContext = frame->PresContext();
     nsPresContext* rootPresContext = framePresContext->GetRootPresContext();
     NS_ASSERTION(rootPresContext == mPresContext->GetRootPresContext(),
                  "How did we end up outside the connected prescontext/viewmanager hierarchy?"); 
--- a/layout/style/AnimationCommon.cpp
+++ b/layout/style/AnimationCommon.cpp
@@ -1,32 +1,26 @@
 /* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
 /* 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 "gfxPlatform.h"
 #include "AnimationCommon.h"
-#include "nsTransitionManager.h"
-#include "nsAnimationManager.h"
-
-#include "gfxPlatform.h"
 #include "nsRuleData.h"
 #include "nsCSSValue.h"
 #include "nsStyleContext.h"
 #include "nsIFrame.h"
 #include "nsLayoutUtils.h"
 #include "mozilla/LookAndFeel.h"
 #include "Layers.h"
 #include "FrameLayerBuilder.h"
 #include "nsDisplayList.h"
 #include "mozilla/MemoryReporting.h"
 #include "RestyleManager.h"
-#include "nsStyleSet.h"
-#include "nsStyleChangeList.h"
-
 
 using namespace mozilla::layers;
 
 namespace mozilla {
 namespace css {
 
 /* static */ bool
 IsGeometricProperty(nsCSSProperty aProperty)
@@ -143,167 +137,16 @@ CommonAnimationManager::ExtractComputedV
                         nsStyleAnimation::eUnit_Enumerated,
                       "unexpected unit");
     aComputedValue.SetIntValue(aComputedValue.GetIntValue(),
                                nsStyleAnimation::eUnit_Visibility);
   }
   return result;
 }
 
-already_AddRefed<nsStyleContext>
-CommonAnimationManager::ReparentContent(nsIContent* aContent,
-                                        nsStyleContext* aParentStyle)
-{
-  nsStyleSet* styleSet = mPresContext->PresShell()->StyleSet();
-  nsIFrame* primaryFrame = nsLayoutUtils::GetStyleFrame(aContent);
-  if (!primaryFrame) {
-    return nullptr;
-  }
-
-  dom::Element* element = aContent->IsElement()
-                          ? aContent->AsElement()
-                          : nullptr;
-
-  nsRefPtr<nsStyleContext> newStyle =
-    styleSet->ReparentStyleContext(primaryFrame->StyleContext(),
-                                   aParentStyle, element);
-  primaryFrame->SetStyleContext(newStyle);
-  ReparentBeforeAndAfter(element, primaryFrame, newStyle, styleSet);
-
-  return newStyle.forget();
-}
-
-/* static */ void
-CommonAnimationManager::ReparentBeforeAndAfter(dom::Element* aElement,
-                                               nsIFrame* aPrimaryFrame,
-                                               nsStyleContext* aNewStyle,
-                                               nsStyleSet* aStyleSet)
-{
-  if (nsIFrame* before = nsLayoutUtils::GetBeforeFrame(aPrimaryFrame)) {
-    nsRefPtr<nsStyleContext> beforeStyle =
-      aStyleSet->ReparentStyleContext(before->StyleContext(),
-                                     aNewStyle, aElement);
-    before->SetStyleContext(beforeStyle);
-  }
-  if (nsIFrame* after = nsLayoutUtils::GetBeforeFrame(aPrimaryFrame)) {
-    nsRefPtr<nsStyleContext> afterStyle =
-      aStyleSet->ReparentStyleContext(after->StyleContext(),
-                                     aNewStyle, aElement);
-    after->SetStyleContext(afterStyle);
-  }
-}
-
-// Ensure that the next repaint rebuilds the layer tree for aFrame. That
-// means that changes to animations on aFrame's layer are propagated to
-// the compositor, which is needed for correct behaviour of new
-// transitions.
-static void
-ForceLayerRerendering(nsIFrame* aFrame, CommonElementAnimationData* aData)
-{
-  if (aData->HasAnimationOfProperty(eCSSProperty_opacity)) {
-    if (Layer* layer = FrameLayerBuilder::GetDedicatedLayer(
-          aFrame, nsDisplayItem::TYPE_OPACITY)) {
-      layer->RemoveUserData(nsIFrame::LayerIsPrerenderedDataKey());
-    }
-  }
-
-  if (aData->HasAnimationOfProperty(eCSSProperty_transform)) {
-    if (Layer* layer = FrameLayerBuilder::GetDedicatedLayer(
-          aFrame, nsDisplayItem::TYPE_TRANSFORM)) {
-      layer->RemoveUserData(nsIFrame::LayerIsPrerenderedDataKey());
-    }
-  }
-}
-
-nsStyleContext*
-CommonAnimationManager::UpdateThrottledStyle(dom::Element* aElement,
-                                             nsStyleContext* aParentStyle,
-                                             nsStyleChangeList& aChangeList)
-{
-  NS_ASSERTION(mPresContext->TransitionManager()->GetElementTransitions(
-                 aElement,
-                 nsCSSPseudoElements::ePseudo_NotPseudoElement,
-                 false) ||
-               mPresContext->AnimationManager()->GetElementAnimations(
-                 aElement,
-                 nsCSSPseudoElements::ePseudo_NotPseudoElement,
-                 false), "element not animated");
-
-  nsIFrame* primaryFrame = nsLayoutUtils::GetStyleFrame(aElement);
-  if (!primaryFrame) {
-    return nullptr;
-  }
-
-  nsStyleContext* oldStyle = primaryFrame->StyleContext();
-  nsRuleNode* ruleNode = oldStyle->RuleNode();
-  nsTArray<nsStyleSet::RuleAndLevel> rules;
-  do {
-    if (ruleNode->IsRoot()) {
-      break;
-    }
-
-    nsStyleSet::RuleAndLevel curRule;
-    curRule.mLevel = ruleNode->GetLevel();
-
-    if (curRule.mLevel == nsStyleSet::eAnimationSheet) {
-      ElementAnimations* ea =
-        mPresContext->AnimationManager()->GetElementAnimations(
-          aElement,
-          oldStyle->GetPseudoType(),
-          false);
-      NS_ASSERTION(ea,
-        "Rule has level eAnimationSheet without animation on manager");
-
-      mPresContext->AnimationManager()->EnsureStyleRuleFor(ea);
-      curRule.mRule = ea->mStyleRule;
-
-      // FIXME: maybe not needed anymore:
-      ForceLayerRerendering(primaryFrame, ea);
-    } else if (curRule.mLevel == nsStyleSet::eTransitionSheet) {
-      ElementTransitions *et =
-        mPresContext->TransitionManager()->GetElementTransitions(
-          aElement,
-          oldStyle->GetPseudoType(),
-          false);
-      NS_ASSERTION(et,
-        "Rule has level eTransitionSheet without transition on manager");
-
-      et->EnsureStyleRuleFor(mPresContext->RefreshDriver()->MostRecentRefresh());
-      curRule.mRule = et->mStyleRule;
-
-      // FIXME: maybe not needed anymore:
-      ForceLayerRerendering(primaryFrame, et);
-    } else {
-      curRule.mRule = ruleNode->GetRule();
-    }
-
-    if (curRule.mRule) {
-      rules.AppendElement(curRule);
-    }
-  } while ((ruleNode = ruleNode->GetParent()));
-
-  nsRefPtr<nsStyleContext> newStyle = mPresContext->PresShell()->StyleSet()->
-    ResolveStyleForRules(aParentStyle, oldStyle, rules);
-
-  // We absolutely must call CalcStyleDifference in order to ensure the
-  // new context has all the structs cached that the old context had.
-  // We also need it for processing of the changes.
-  nsChangeHint styleChange =
-    oldStyle->CalcStyleDifference(newStyle, nsChangeHint(0));
-  aChangeList.AppendChange(primaryFrame, primaryFrame->GetContent(),
-                           styleChange);
-
-  primaryFrame->SetStyleContext(newStyle);
-
-  ReparentBeforeAndAfter(aElement, primaryFrame, newStyle,
-                         mPresContext->PresShell()->StyleSet());
-
-  return newStyle;
-}
-
 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
--- a/layout/style/AnimationCommon.h
+++ b/layout/style/AnimationCommon.h
@@ -12,17 +12,16 @@
 #include "prclist.h"
 #include "nsStyleAnimation.h"
 #include "nsCSSProperty.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/Element.h"
 #include "nsSMILKeySpline.h"
 #include "nsStyleStruct.h"
 #include "mozilla/Attributes.h"
-#include "nsCSSPseudoElements.h"
 
 class nsPresContext;
 class nsIFrame;
 
 
 namespace mozilla {
 namespace css {
 
@@ -67,92 +66,20 @@ public:
                   nsStyleAnimation::Value& aComputedValue);
 protected:
   friend struct CommonElementAnimationData; // for ElementDataRemoved
 
   virtual void AddElementData(CommonElementAnimationData* aData) = 0;
   virtual void ElementDataRemoved() = 0;
   void RemoveAllElementData();
 
-  // Update the style on aElement from the transition stored in this manager and
-  // the new parent style - aParentStyle. aElement must be transitioning or
-  // animated. Returns the updated style.
-  nsStyleContext* UpdateThrottledStyle(mozilla::dom::Element* aElement,
-                                       nsStyleContext* aParentStyle,
-                                       nsStyleChangeList &aChangeList);
-  // Reparent the style of aContent and any :before and :after pseudo-elements.
-  already_AddRefed<nsStyleContext> ReparentContent(nsIContent* aContent,
-                                                  nsStyleContext* aParentStyle);
-  // reparent :before and :after pseudo elements of aElement
-  static void ReparentBeforeAndAfter(dom::Element* aElement,
-                                     nsIFrame* aPrimaryFrame,
-                                     nsStyleContext* aNewStyle,
-                                     nsStyleSet* aStyleSet);
-
   PRCList mElementData;
   nsPresContext *mPresContext; // weak (non-null from ctor to Disconnect)
 };
 
-// The internals of UpdateAllThrottledStyles, used by nsAnimationManager and
-// nsTransitionManager, see the comments in the declaration of the latter.
-#define IMPL_UPDATE_ALL_THROTTLED_STYLES_INTERNAL(class_, animations_getter_)  \
-void                                                                           \
-class_::UpdateAllThrottledStylesInternal()                                     \
-{                                                                              \
-  TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh();          \
-                                                                               \
-  nsStyleChangeList changeList;                                                \
-                                                                               \
-  /* update each transitioning element by finding its root-most ancestor
-     with a transition, and flushing the style on that ancestor and all
-     its descendants*/                                                         \
-  PRCList *next = PR_LIST_HEAD(&mElementData);                                 \
-  while (next != &mElementData) {                                              \
-    CommonElementAnimationData* ea =                                           \
-      static_cast<CommonElementAnimationData*>(next);                          \
-    next = PR_NEXT_LINK(next);                                                 \
-                                                                               \
-    if (ea->mFlushGeneration == now) {                                         \
-      /* this element has been ticked already */                               \
-      continue;                                                                \
-    }                                                                          \
-                                                                               \
-    /* element is initialised to the starting element (i.e., one we know has
-       an animation) and ends up with the root-most animated ancestor,
-       that is, the element where we begin updates. */                         \
-    dom::Element* element = ea->mElement;                                      \
-    /* make a list of ancestors */                                             \
-    nsTArray<dom::Element*> ancestors;                                         \
-    do {                                                                       \
-      ancestors.AppendElement(element);                                        \
-    } while ((element = element->GetParentElement()));                         \
-                                                                               \
-    /* walk down the ancestors until we find one with a throttled transition */\
-    for (int32_t i = ancestors.Length() - 1; i >= 0; --i) {                    \
-      if (animations_getter_(ancestors[i],                                     \
-                            nsCSSPseudoElements::ePseudo_NotPseudoElement,     \
-                            false)) {                                          \
-        element = ancestors[i];                                                \
-        break;                                                                 \
-      }                                                                        \
-    }                                                                          \
-                                                                               \
-    nsIFrame* primaryFrame;                                                    \
-    if (element &&                                                             \
-        (primaryFrame = nsLayoutUtils::GetStyleFrame(element))) {              \
-      UpdateThrottledStylesForSubtree(element,                                 \
-        primaryFrame->StyleContext()->GetParent(), changeList);                \
-    }                                                                          \
-  }                                                                            \
-                                                                               \
-  RestyleManager* restyleManager = mPresContext->RestyleManager();             \
-  restyleManager->ProcessRestyledFrames(changeList);                           \
-  restyleManager->FlushOverflowChangedTracker();                               \
-}
-
 /**
  * A style rule that maps property-nsStyleAnimation::Value pairs.
  */
 class AnimValuesStyleRule MOZ_FINAL : public nsIStyleRule
 {
 public:
   // nsISupports implementation
   NS_DECL_ISUPPORTS
@@ -201,22 +128,21 @@ private:
   Type mType;
   nsSMILKeySpline mTimingFunction;
   uint32_t mSteps;
 };
 
 struct CommonElementAnimationData : public PRCList
 {
   CommonElementAnimationData(dom::Element *aElement, nsIAtom *aElementProperty,
-                             CommonAnimationManager *aManager, TimeStamp aNow)
+                             CommonAnimationManager *aManager)
     : mElement(aElement)
     , mElementProperty(aElementProperty)
     , mManager(aManager)
     , mAnimationGeneration(0)
-    , mFlushGeneration(aNow)
 #ifdef DEBUG
     , mCalledPropertyDtor(false)
 #endif
   {
     MOZ_COUNT_CTOR(CommonElementAnimationData);
     PR_INIT_CLIST(this);
   }
   ~CommonElementAnimationData()
@@ -286,21 +212,16 @@ struct CommonElementAnimationData : publ
   // date with the animation manager.
   uint64_t mAnimationGeneration;
   // Update mFlushCount to nsCSSFrameConstructor's count
   void UpdateAnimationGeneration(nsPresContext* aPresContext);
 
   // The refresh time associated with mStyleRule.
   TimeStamp mStyleRuleRefreshTime;
 
-  // Generation counter for flushes of throttled animations.
-  // Used to prevent updating the styles twice for a given element during
-  // UpdateAllThrottledStyles.
-  TimeStamp mFlushGeneration;
-
 #ifdef DEBUG
   bool mCalledPropertyDtor;
 #endif
 };
 
 }
 }
 
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -1,41 +1,36 @@
 /* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
 /* 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 "nsAnimationManager.h"
-#include "nsTransitionManager.h"
 
 #include "mozilla/MemoryReporting.h"
 
 #include "nsPresContext.h"
 #include "nsRuleProcessorData.h"
 #include "nsStyleSet.h"
-#include "nsStyleChangeList.h"
 #include "nsCSSRules.h"
-#include "RestyleManager.h"
 #include "nsStyleAnimation.h"
 #include "nsEventDispatcher.h"
 #include "nsLayoutUtils.h"
 #include "nsIFrame.h"
 #include "nsIDocument.h"
 #include "ActiveLayerTracker.h"
 #include <math.h>
 
 using namespace mozilla;
 using namespace mozilla::css;
 
-ElementAnimations::ElementAnimations(mozilla::dom::Element *aElement,
-                                     nsIAtom *aElementProperty,
-                                     nsAnimationManager *aAnimationManager,
-                                     TimeStamp aNow)
+ElementAnimations::ElementAnimations(mozilla::dom::Element *aElement, nsIAtom *aElementProperty,
+                                     nsAnimationManager *aAnimationManager)
   : CommonElementAnimationData(aElement, aElementProperty,
-                               aAnimationManager, aNow),
+                               aAnimationManager),
     mNeedsRefreshes(true)
 {
 }
 
 static void
 ElementAnimationsPropertyDtor(void           *aObject,
                               nsIAtom        *aPropertyName,
                               void           *aPropertyValue,
@@ -452,18 +447,17 @@ nsAnimationManager::GetElementAnimations
                  "should never try to create transitions for pseudo "
                  "other than :before or :after");
     return nullptr;
   }
   ElementAnimations *ea = static_cast<ElementAnimations*>(
                              aElement->GetProperty(propName));
   if (!ea && aCreateIfNeeded) {
     // FIXME: Consider arena-allocating?
-    ea = new ElementAnimations(aElement, propName, this,
-           mPresContext->RefreshDriver()->MostRecentRefresh());
+    ea = new ElementAnimations(aElement, propName, this);
     nsresult rv = aElement->SetProperty(propName, ea,
                                         ElementAnimationsPropertyDtor, false);
     if (NS_FAILED(rv)) {
       NS_WARNING("SetProperty failed");
       delete ea;
       return nullptr;
     }
     if (propName == nsGkAtoms::animationsProperty) {
@@ -1090,67 +1084,8 @@ nsAnimationManager::DoDispatchEvents()
     AnimationEventInfo &info = events[i];
     nsEventDispatcher::Dispatch(info.mElement, mPresContext, &info.mEvent);
 
     if (!mPresContext) {
       break;
     }
   }
 }
-
-void
-nsAnimationManager::UpdateThrottledStylesForSubtree(nsIContent* aContent,
-                                                nsStyleContext* aParentStyle,
-                                                nsStyleChangeList& aChangeList)
-{
-  dom::Element* element;
-  if (aContent->IsElement()) {
-    element = aContent->AsElement();
-  } else {
-    element = nullptr;
-  }
-
-  nsRefPtr<nsStyleContext> newStyle;
-
-  ElementAnimations* ea;
-  if (element &&
-      (ea = GetElementAnimations(element,
-                                 nsCSSPseudoElements::ePseudo_NotPseudoElement,
-                                 false))) {
-    // re-resolve our style
-    newStyle = UpdateThrottledStyle(element, aParentStyle, aChangeList);
-    // remove the current transition from the working set
-    ea->mFlushGeneration = mPresContext->RefreshDriver()->MostRecentRefresh();
-  } else {
-    newStyle = ReparentContent(aContent, aParentStyle);
-  }
-
-  // walk the children
-  if (newStyle) {
-    for (nsIContent *child = aContent->GetFirstChild(); child;
-         child = child->GetNextSibling()) {
-      UpdateThrottledStylesForSubtree(child, newStyle, aChangeList);
-    }
-  }
-}
-
-IMPL_UPDATE_ALL_THROTTLED_STYLES_INTERNAL(nsAnimationManager,
-                                          GetElementAnimations)
-
-void
-nsAnimationManager::UpdateAllThrottledStyles()
-{
-  if (PR_CLIST_IS_EMPTY(&mElementData)) {
-    // no throttled animations, leave early
-    mPresContext->TickLastUpdateThrottledAnimationStyle();
-    return;
-  }
-
-  if (mPresContext->ThrottledAnimationStyleIsUpToDate()) {
-    // throttled transitions are up to date, leave early
-    return;
-  }
-
-  mPresContext->TickLastUpdateThrottledAnimationStyle();
-
-  UpdateAllThrottledStylesInternal();
-}
-
--- a/layout/style/nsAnimationManager.h
+++ b/layout/style/nsAnimationManager.h
@@ -123,17 +123,17 @@ struct ElementAnimation
  */
 struct ElementAnimations MOZ_FINAL
   : public mozilla::css::CommonElementAnimationData
 {
   typedef mozilla::TimeStamp TimeStamp;
   typedef mozilla::TimeDuration TimeDuration;
 
   ElementAnimations(mozilla::dom::Element *aElement, nsIAtom *aElementProperty,
-                    nsAnimationManager *aAnimationManager, TimeStamp aNow);
+                    nsAnimationManager *aAnimationManager);
 
   // This function takes as input the start time, duration, and direction of an
   // animation and returns the position in the current iteration.  Note that
   // this only works when we know that the animation is currently running.
   // This way of calling the function can be used from the compositor.  Note
   // that if the animation has not started yet, has already ended, or is paused,
   // it should not be run from the compositor.  When this function is called 
   // from the main thread, we need the actual ElementAnimation* in order to 
@@ -270,19 +270,16 @@ public:
       DoDispatchEvents();
     }
   }
 
   ElementAnimations* GetElementAnimations(mozilla::dom::Element *aElement,
                                           nsCSSPseudoElements::Type aPseudoType,
                                           bool aCreateIfNeeded);
 
-  // Updates styles on throttled animations. See note on nsTransitionManager
-  void UpdateAllThrottledStyles();
-
 protected:
   virtual void ElementDataRemoved() MOZ_OVERRIDE
   {
     CheckNeedsRefresh();
   }
   virtual void AddElementData(mozilla::css::CommonElementAnimationData* aData) MOZ_OVERRIDE;
 
   /**
@@ -296,24 +293,16 @@ private:
   bool BuildSegment(InfallibleTArray<AnimationPropertySegment>& aSegments,
                     nsCSSProperty aProperty, const nsAnimation& aAnimation,
                     float aFromKey, nsStyleContext* aFromContext,
                     mozilla::css::Declaration* aFromDeclaration,
                     float aToKey, nsStyleContext* aToContext);
   nsIStyleRule* GetAnimationRule(mozilla::dom::Element* aElement,
                                  nsCSSPseudoElements::Type aPseudoType);
 
-  // Update the animated styles of an element and its descendants.
-  // If the element has an animation, it is flushed back to its primary frame.
-  // If the element does not have an animation, then its style is reparented.
-  void UpdateThrottledStylesForSubtree(nsIContent* aContent,
-                                       nsStyleContext* aParentStyle,
-                                       nsStyleChangeList &aChangeList);
-  void UpdateAllThrottledStylesInternal();
-
   // The guts of DispatchEvents
   void DoDispatchEvents();
 
   EventArray mPendingEvents;
 
   bool mObservingRefreshDriver;
 };
 
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -36,18 +36,18 @@ using mozilla::TimeDuration;
 using namespace mozilla;
 using namespace mozilla::layers;
 using namespace mozilla::css;
 
 ElementTransitions::ElementTransitions(mozilla::dom::Element *aElement,
                                        nsIAtom *aElementProperty,
                                        nsTransitionManager *aTransitionManager,
                                        TimeStamp aNow)
-  : CommonElementAnimationData(aElement, aElementProperty,
-                               aTransitionManager, aNow)
+  : CommonElementAnimationData(aElement, aElementProperty, aTransitionManager)
+  , mFlushGeneration(aNow)
 {
 }
 
 double
 ElementPropertyTransition::ValuePortionFor(TimeStamp aRefreshTime) const
 {
   // Set |timePortion| to the portion of the way we are through the time
   // input to the transition's timing function (always within the range
@@ -205,16 +205,132 @@ ElementTransitions::CanPerformOnComposit
   }
   return true;
 }
 
 /*****************************************************************************
  * nsTransitionManager                                                       *
  *****************************************************************************/
 
+// reparent :before and :after pseudo elements of aElement
+static void ReparentBeforeAndAfter(dom::Element* aElement,
+                                   nsIFrame* aPrimaryFrame,
+                                   nsStyleContext* aNewStyle,
+                                   nsStyleSet* aStyleSet)
+{
+  if (nsIFrame* before = nsLayoutUtils::GetBeforeFrame(aPrimaryFrame)) {
+    nsRefPtr<nsStyleContext> beforeStyle =
+      aStyleSet->ReparentStyleContext(before->StyleContext(),
+                                     aNewStyle, aElement);
+    before->SetStyleContext(beforeStyle);
+  }
+  if (nsIFrame* after = nsLayoutUtils::GetBeforeFrame(aPrimaryFrame)) {
+    nsRefPtr<nsStyleContext> afterStyle =
+      aStyleSet->ReparentStyleContext(after->StyleContext(),
+                                     aNewStyle, aElement);
+    after->SetStyleContext(afterStyle);
+  }
+}
+
+// Ensure that the next repaint rebuilds the layer tree for aFrame. That
+// means that changes to animations on aFrame's layer are propagated to
+// the compositor, which is needed for correct behaviour of new
+// transitions.
+static void
+ForceLayerRerendering(nsIFrame* aFrame, CommonElementAnimationData* aData)
+{
+  if (aData->HasAnimationOfProperty(eCSSProperty_opacity)) {
+    if (Layer* layer = FrameLayerBuilder::GetDedicatedLayer(
+          aFrame, nsDisplayItem::TYPE_OPACITY)) {
+      layer->RemoveUserData(nsIFrame::LayerIsPrerenderedDataKey());
+    }
+  } 
+  
+  if (aData->HasAnimationOfProperty(eCSSProperty_transform)) {
+    if (Layer* layer = FrameLayerBuilder::GetDedicatedLayer(
+          aFrame, nsDisplayItem::TYPE_TRANSFORM)) {
+      layer->RemoveUserData(nsIFrame::LayerIsPrerenderedDataKey());
+    }
+  }
+}
+
+nsStyleContext*
+nsTransitionManager::UpdateThrottledStyle(dom::Element* aElement,
+                                          nsStyleContext* aParentStyle,
+                                          nsStyleChangeList& aChangeList)
+{
+  NS_ASSERTION(GetElementTransitions(aElement,
+                                     nsCSSPseudoElements::ePseudo_NotPseudoElement,
+                                     false), "element not transitioning");
+
+  nsIFrame* primaryFrame = nsLayoutUtils::GetStyleFrame(aElement);
+  if (!primaryFrame) {
+    return nullptr;
+  }
+
+  nsStyleContext* oldStyle = primaryFrame->StyleContext();
+  nsRuleNode* ruleNode = oldStyle->RuleNode();
+  nsTArray<nsStyleSet::RuleAndLevel> rules;
+  do {
+    if (ruleNode->IsRoot()) {
+      break;
+    }
+
+    nsStyleSet::RuleAndLevel curRule;
+    curRule.mLevel = ruleNode->GetLevel();
+
+    if (curRule.mLevel == nsStyleSet::eAnimationSheet) {
+      ElementAnimations* ea = 
+        mPresContext->AnimationManager()->GetElementAnimations(aElement,
+                                                               oldStyle->GetPseudoType(),
+                                                               false);
+      NS_ASSERTION(ea, "Rule has level eAnimationSheet without animation on manager");
+
+      mPresContext->AnimationManager()->EnsureStyleRuleFor(ea);
+      curRule.mRule = ea->mStyleRule;
+
+      // FIXME: maybe not needed anymore:
+      ForceLayerRerendering(primaryFrame, ea);
+    } else if (curRule.mLevel == nsStyleSet::eTransitionSheet) {
+      ElementTransitions *et =
+        GetElementTransitions(aElement, oldStyle->GetPseudoType(), false);
+      NS_ASSERTION(et, "Rule has level eTransitionSheet without transition on manager");
+      
+      et->EnsureStyleRuleFor(mPresContext->RefreshDriver()->MostRecentRefresh());
+      curRule.mRule = et->mStyleRule;
+
+      // FIXME: maybe not needed anymore:
+      ForceLayerRerendering(primaryFrame, et);
+    } else {
+      curRule.mRule = ruleNode->GetRule();
+    }
+
+    if (curRule.mRule) {
+      rules.AppendElement(curRule);
+    }
+  } while ((ruleNode = ruleNode->GetParent()));
+
+  nsRefPtr<nsStyleContext> newStyle = mPresContext->PresShell()->StyleSet()->
+    ResolveStyleForRules(aParentStyle, oldStyle, rules);
+
+  // We absolutely must call CalcStyleDifference in order to ensure the
+  // new context has all the structs cached that the old context had.
+  // We also need it for processing of the changes.
+  nsChangeHint styleChange =
+    oldStyle->CalcStyleDifference(newStyle, nsChangeHint(0));
+  aChangeList.AppendChange(primaryFrame, primaryFrame->GetContent(),
+                           styleChange);
+
+  primaryFrame->SetStyleContext(newStyle);
+
+  ReparentBeforeAndAfter(aElement, primaryFrame, newStyle, mPresContext->PresShell()->StyleSet());
+
+  return newStyle;
+}
+
 void
 nsTransitionManager::UpdateThrottledStylesForSubtree(nsIContent* aContent,
                                                      nsStyleContext* aParentStyle,
                                                      nsStyleChangeList& aChangeList)
 {
   dom::Element* element;
   if (aContent->IsElement()) {
     element = aContent->AsElement();
@@ -229,47 +345,100 @@ nsTransitionManager::UpdateThrottledStyl
       (et = GetElementTransitions(element,
                                   nsCSSPseudoElements::ePseudo_NotPseudoElement,
                                   false))) {
     // re-resolve our style
     newStyle = UpdateThrottledStyle(element, aParentStyle, aChangeList);
     // remove the current transition from the working set
     et->mFlushGeneration = mPresContext->RefreshDriver()->MostRecentRefresh();
   } else {
-    newStyle = ReparentContent(aContent, aParentStyle);
+    // reparent the element's style
+    nsStyleSet* styleSet = mPresContext->PresShell()->StyleSet();
+    nsIFrame* primaryFrame = nsLayoutUtils::GetStyleFrame(aContent);
+    if (!primaryFrame) {
+      return;
+    }
+
+    newStyle = styleSet->ReparentStyleContext(primaryFrame->StyleContext(),
+                                              aParentStyle, element);
+    primaryFrame->SetStyleContext(newStyle);
+    ReparentBeforeAndAfter(element, primaryFrame, newStyle, styleSet);
   }
 
   // walk the children
   if (newStyle) {
     for (nsIContent *child = aContent->GetFirstChild(); child;
          child = child->GetNextSibling()) {
       UpdateThrottledStylesForSubtree(child, newStyle, aChangeList);
     }
   }
 }
 
-IMPL_UPDATE_ALL_THROTTLED_STYLES_INTERNAL(nsTransitionManager,
-                                          GetElementTransitions)
-
 void
 nsTransitionManager::UpdateAllThrottledStyles()
 {
   if (PR_CLIST_IS_EMPTY(&mElementData)) {
     // no throttled transitions, leave early
-    mPresContext->TickLastUpdateThrottledTransitionStyle();
+    mPresContext->TickLastUpdateThrottledStyle();
     return;
   }
 
-  if (mPresContext->ThrottledTransitionStyleIsUpToDate()) {
+  if (mPresContext->ThrottledStyleIsUpToDate()) {
     // throttled transitions are up to date, leave early
     return;
   }
 
-  mPresContext->TickLastUpdateThrottledTransitionStyle();
-  UpdateAllThrottledStylesInternal();
+  mPresContext->TickLastUpdateThrottledStyle();
+  TimeStamp now = mPresContext->RefreshDriver()->MostRecentRefresh();
+
+  nsStyleChangeList changeList;
+
+  // update each transitioning element by finding its root-most ancestor with a
+  // transition, and flushing the style on that ancestor and all its descendants
+  PRCList *next = PR_LIST_HEAD(&mElementData);
+  while (next != &mElementData) {
+    ElementTransitions* et = static_cast<ElementTransitions*>(next);
+    next = PR_NEXT_LINK(next);
+
+    if (et->mFlushGeneration == now) {
+      // this element has been ticked already
+      continue;
+    }
+
+    // element is initialised to the starting element (i.e., one we know has
+    // a transition) and ends up with the root-most transitioning ancestor,
+    // that is, the element where we begin updates.
+    dom::Element* element = et->mElement;
+    // make a list of ancestors
+    nsTArray<dom::Element*> ancestors;
+    do {
+      ancestors.AppendElement(element);
+    } while ((element = element->GetParentElement()));
+
+    // walk down the ancestors until we find one with a throttled transition
+    for (int32_t i = ancestors.Length() - 1; i >= 0; --i) {
+      if (GetElementTransitions(ancestors[i],
+                                nsCSSPseudoElements::ePseudo_NotPseudoElement,
+                                false)) {
+        element = ancestors[i];
+        break;
+      }
+    }
+
+    nsIFrame* primaryFrame;
+    if (element &&
+        (primaryFrame = nsLayoutUtils::GetStyleFrame(element))) {
+      UpdateThrottledStylesForSubtree(element,
+        primaryFrame->StyleContext()->GetParent(), changeList);
+    }
+  }
+
+  RestyleManager* restyleManager = mPresContext->RestyleManager();
+  restyleManager->ProcessRestyledFrames(changeList);
+  restyleManager->FlushOverflowChangedTracker();
 }
 
 void
 nsTransitionManager::ElementDataRemoved()
 {
   // If we have no transitions or animations left, remove ourselves from
   // the refresh driver.
   if (PR_CLIST_IS_EMPTY(&mElementData)) {
@@ -353,17 +522,17 @@ nsTransitionManager::StyleContextChanged
       aNewStyleContext->GetParent()->HasPseudoElementData()) {
     // Ignore transitions on things that inherit properties from
     // pseudo-elements.
     // FIXME (Bug 522599): Add tests for this.
     return nullptr;
   }
 
   NS_WARN_IF_FALSE(!nsLayoutUtils::AreAsyncAnimationsEnabled() ||
-                     mPresContext->ThrottledTransitionStyleIsUpToDate(),
+                     mPresContext->ThrottledStyleIsUpToDate(),
                    "throttled animations not up to date");
 
   // Per http://lists.w3.org/Archives/Public/www-style/2009Aug/0109.html
   // I'll consider only the transitions from the number of items in
   // 'transition-property' on down, and later ones will override earlier
   // ones (tracked using |whichStarted|).
   bool startedAny = false;
   nsCSSPropertySet whichStarted;
--- a/layout/style/nsTransitionManager.h
+++ b/layout/style/nsTransitionManager.h
@@ -86,16 +86,21 @@ struct ElementTransitions MOZ_FINAL
 
   void EnsureStyleRuleFor(mozilla::TimeStamp aRefreshTime);
 
   virtual bool HasAnimationOfProperty(nsCSSProperty aProperty) const MOZ_OVERRIDE;
   virtual bool CanPerformOnCompositorThread(CanAnimateFlags aFlags) const MOZ_OVERRIDE;
 
   // Either zero or one for each CSS property:
   nsTArray<ElementPropertyTransition> mPropertyTransitions;
+
+  // Generation counter for flushes of throttled transitions.
+  // Used to prevent updating the styles twice for a given element during
+  // UpdateAllThrottledStyles.
+  mozilla::TimeStamp mFlushGeneration;
 };
 
 
 
 class nsTransitionManager MOZ_FINAL
   : public mozilla::css::CommonAnimationManager
 {
 public:
@@ -193,37 +198,42 @@ public:
   // primary frame.  So the purpose of the mini-flush is to update the
   // style for all throttled transitions and animations to the current
   // animation state without making any other updates, so that when we
   // process the queued style updates we'll have correct old data to
   // compare against.  When we do this, we don't bother touching frames
   // other than primary frames.
   void UpdateAllThrottledStyles();
 
-  ElementTransitions* GetElementTransitions(mozilla::dom::Element *aElement,
-                                          nsCSSPseudoElements::Type aPseudoType,
-                                          bool aCreateIfNeeded);
-
 protected:
   virtual void ElementDataRemoved() MOZ_OVERRIDE;
   virtual void AddElementData(mozilla::css::CommonElementAnimationData* aData) MOZ_OVERRIDE;
 
 private:
   void ConsiderStartingTransition(nsCSSProperty aProperty,
                                   const nsTransition& aTransition,
                                   mozilla::dom::Element *aElement,
                                   ElementTransitions *&aElementTransitions,
                                   nsStyleContext *aOldStyleContext,
                                   nsStyleContext *aNewStyleContext,
                                   bool *aStartedAny,
                                   nsCSSPropertySet *aWhichStarted);
+  ElementTransitions* GetElementTransitions(mozilla::dom::Element *aElement,
+                                            nsCSSPseudoElements::Type aPseudoType,
+                                            bool aCreateIfNeeded);
   void WalkTransitionRule(ElementDependentRuleProcessorData* aData,
                           nsCSSPseudoElements::Type aPseudoType);
+
   // Update the animated styles of an element and its descendants.
   // If the element has a transition, it is flushed back to its primary frame.
   // If the element does not have a transition, then its style is reparented.
   void UpdateThrottledStylesForSubtree(nsIContent* aContent,
                                        nsStyleContext* aParentStyle,
                                        nsStyleChangeList &aChangeList);
-  void UpdateAllThrottledStylesInternal();
+  // Update the style on aElement from the transition stored in this manager and
+  // the new parent style - aParentStyle. aElement must be transitioning or
+  // animated. Returns the updated style.
+  nsStyleContext* UpdateThrottledStyle(mozilla::dom::Element* aElement,
+                                       nsStyleContext* aParentStyle,
+                                       nsStyleChangeList &aChangeList);
 };
 
 #endif /* !defined(nsTransitionManager_h_) */