Bug 1334036 - Part 8: Add AddLayerChangesForAnimation in ServoRestyleManager. draft
authorBoris Chiou <boris.chiou@gmail.com>
Tue, 02 May 2017 14:03:16 +0800
changeset 581941 31462ec4c7f2b94bb7168f6d13b3c9f1786db0fa
parent 581940 343345a6a709c08c1a726e7f4c9ec866e976b106
child 581942 7492d38b17b2f3e7bcb55a6adb27ef4fb6ab8f88
push id59916
push userbmo:boris.chiou@gmail.com
push dateSat, 20 May 2017 06:48:29 +0000
bugs1334036
milestone55.0a1
Bug 1334036 - Part 8: Add AddLayerChangesForAnimation in ServoRestyleManager. Some changes to animations don't affect the computed style and yet still require the layer to be updated. Therefore, we also need to call AddLayerChangesForAnimation in ServoRestyleManager. In this patch, we factor out this function from GeckoRestyleManager, so we can reuse it. MozReview-Commit-ID: LL7D1oGS65l
layout/base/GeckoRestyleManager.cpp
layout/base/GeckoRestyleManager.h
layout/base/RestyleManager.cpp
layout/base/RestyleManager.h
layout/base/ServoRestyleManager.cpp
--- a/layout/base/GeckoRestyleManager.cpp
+++ b/layout/base/GeckoRestyleManager.cpp
@@ -14,17 +14,16 @@
 #include "mozilla/EffectSet.h"
 #include "mozilla/EventStates.h"
 #include "mozilla/ViewportFrame.h"
 #include "mozilla/css/StyleRule.h" // For nsCSSSelector
 #include "nsLayoutUtils.h"
 #include "AnimationCommon.h" // For GetLayerAnimationInfo
 #include "FrameLayerBuilder.h"
 #include "GeckoProfiler.h"
-#include "LayerAnimationInfo.h" // For LayerAnimationInfo::sRecords
 #include "nsAutoPtr.h"
 #include "nsStyleChangeList.h"
 #include "nsRuleProcessorData.h"
 #include "nsStyleSet.h"
 #include "nsStyleUtil.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsSVGEffects.h"
 #include "nsCSSPseudoElements.h"
@@ -45,17 +44,16 @@
 #include "nsContentUtils.h"
 #include "nsIFrameInlines.h"
 #include "ActiveLayerTracker.h"
 #include "nsDisplayList.h"
 #include "RestyleTrackerInlines.h"
 #include "nsSMILAnimationController.h"
 #include "nsCSSRuleProcessor.h"
 #include "ChildIterator.h"
-#include "Layers.h"
 
 #ifdef ACCESSIBILITY
 #include "nsAccessibilityService.h"
 #endif
 
 namespace mozilla {
 
 using namespace layers;
@@ -1222,64 +1220,16 @@ ElementRestyler::ElementRestyler(nsPresC
 #endif
 {
   MOZ_ASSERT(!(mHintsHandledByAncestors & nsChangeHint_ReconstructFrame),
              "why restyle descendants if we are reconstructing the frame for "
              "an ancestor?");
 }
 
 void
-ElementRestyler::AddLayerChangesForAnimation()
-{
-  uint64_t frameGeneration =
-    GeckoRestyleManager::GetAnimationGenerationForFrame(mFrame);
-
-  nsChangeHint hint = nsChangeHint(0);
-  for (const LayerAnimationInfo::Record& layerInfo :
-         LayerAnimationInfo::sRecords) {
-    Layer* layer =
-      FrameLayerBuilder::GetDedicatedLayer(mFrame, layerInfo.mLayerType);
-    if (layer && frameGeneration != layer->GetAnimationGeneration()) {
-      // If we have a transform layer but don't have any transform style, we
-      // probably just removed the transform but haven't destroyed the layer
-      // yet. In this case we will add the appropriate change hint
-      // (nsChangeHint_UpdateContainingBlock) when we compare style contexts
-      // so we can skip adding any change hint here. (If we *were* to add
-      // nsChangeHint_UpdateTransformLayer, ApplyRenderingChangeToTree would
-      // complain that we're updating a transform layer without a transform).
-      if (layerInfo.mLayerType == nsDisplayItem::TYPE_TRANSFORM &&
-          !mFrame->StyleDisplay()->HasTransformStyle()) {
-        continue;
-      }
-      hint |= layerInfo.mChangeHint;
-    }
-
-    // We consider it's the first paint for the frame if we have an animation
-    // for the property but have no layer.
-    // Note that in case of animations which has properties preventing running
-    // on the compositor, e.g., width or height, corresponding layer is not
-    // created at all, but even in such cases, we normally set valid change
-    // hint for such animations in each tick, i.e. restyles in each tick. As
-    // a result, we usually do restyles for such animations in every tick on
-    // the main-thread.  The only animations which will be affected by this
-    // explicit change hint are animations that have opacity/transform but did
-    // not have those properies just before. e.g,  setting transform by
-    // setKeyframes or changing target element from other target which prevents
-    // running on the compositor, etc.
-    if (!layer &&
-        nsLayoutUtils::HasEffectiveAnimation(mFrame, layerInfo.mProperty)) {
-      hint |= layerInfo.mChangeHint;
-    }
-  }
-  if (hint) {
-    mChangeList->AppendChange(mFrame, mContent, hint);
-  }
-}
-
-void
 ElementRestyler::CaptureChange(nsStyleContext* aOldContext,
                                nsStyleContext* aNewContext,
                                nsChangeHint aChangeToAssume,
                                uint32_t* aEqualStructs,
                                uint32_t* aSamePointerStructs)
 {
   static_assert(nsStyleStructID_Length <= 32,
                 "aEqualStructs is not big enough");
@@ -1874,25 +1824,25 @@ ElementRestyler::Restyle(nsRestyleHint a
 
     f = GeckoRestyleManager::GetNextContinuationWithSameStyle(
             f, oldContext, &haveMoreContinuations);
   }
 
   // Some changes to animations don't affect the computed style and yet still
   // require the layer to be updated. For example, pausing an animation via
   // the Web Animations API won't affect an element's style but still
-  // requires us to pull the animation off the layer.
+  // requires to update the animation on the layer.
   //
   // Although we only expect this code path to be called when computed style
   // is not changing, we can sometimes reach this at the end of a transition
   // when the animated style is being removed. Since
   // AddLayerChangesForAnimation checks if mFrame has a transform style or not,
   // we need to call it *after* calling RestyleSelf to ensure the animated
   // transform has been removed first.
-  AddLayerChangesForAnimation();
+  RestyleManager::AddLayerChangesForAnimation(mFrame, mContent, *mChangeList);
 
   if (haveMoreContinuations && hintToRestore) {
     // If we have more continuations with different style (e.g., because
     // we're inside a ::first-letter or ::first-line), put the restyle
     // hint back.
     mRestyleTracker.AddPendingRestyleToTable(mContent->AsElement(),
                                              hintToRestore, nsChangeHint(0));
   }
--- a/layout/base/GeckoRestyleManager.h
+++ b/layout/base/GeckoRestyleManager.h
@@ -579,18 +579,16 @@ private:
    * This is used to check whether it is appropriate to call
    * ReparentStyleContext.
    */
   bool CanReparentStyleContext(nsRestyleHint aRestyleHint);
 
   /**
    * Helpers for Restyle().
    */
-  void AddLayerChangesForAnimation();
-
   bool MoveStyleContextsForContentChildren(nsIFrame* aParent,
                                            nsStyleContext* aOldContext,
                                            nsTArray<nsStyleContext*>& aContextsToMove);
   bool MoveStyleContextsForChildren(nsStyleContext* aOldContext);
 
   /**
    * Helpers for RestyleSelf().
    */
--- a/layout/base/RestyleManager.cpp
+++ b/layout/base/RestyleManager.cpp
@@ -1,20 +1,24 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/RestyleManager.h"
 #include "mozilla/RestyleManagerInlines.h"
+
+#include "Layers.h"
+#include "LayerAnimationInfo.h" // For LayerAnimationInfo::sRecords
 #include "mozilla/StyleSetHandleInlines.h"
 #include "nsIFrame.h"
 #include "nsIPresShellInlines.h"
 
+
 namespace mozilla {
 
 RestyleManager::RestyleManager(StyleBackendType aType,
                                nsPresContext* aPresContext)
   : mPresContext(aPresContext)
   , mRestyleGeneration(1)
   , mHoverGeneration(0)
   , mType(aType)
@@ -1766,16 +1770,72 @@ RestyleManager::IncrementAnimationGenera
   // ProcessPendingRestyles so we should ignore any subsequent (redundant)
   // calls that occur while we are still processing restyles.
   if ((IsGecko() && !AsGecko()->IsProcessingRestyles()) ||
       (IsServo() && !mInStyleRefresh)) {
     ++mAnimationGeneration;
   }
 }
 
+/* static */ void
+RestyleManager::AddLayerChangesForAnimation(nsIFrame* aFrame,
+                                            nsIContent* aContent,
+                                            nsStyleChangeList&
+                                              aChangeListToProcess)
+{
+  if (!aFrame || !aContent) {
+    return;
+  }
+
+  uint64_t frameGeneration =
+    RestyleManager::GetAnimationGenerationForFrame(aFrame);
+
+  nsChangeHint hint = nsChangeHint(0);
+  for (const LayerAnimationInfo::Record& layerInfo :
+         LayerAnimationInfo::sRecords) {
+    layers::Layer* layer =
+      FrameLayerBuilder::GetDedicatedLayer(aFrame, layerInfo.mLayerType);
+    if (layer && frameGeneration != layer->GetAnimationGeneration()) {
+      // If we have a transform layer but don't have any transform style, we
+      // probably just removed the transform but haven't destroyed the layer
+      // yet. In this case we will add the appropriate change hint
+      // (nsChangeHint_UpdateContainingBlock) when we compare style contexts
+      // so we can skip adding any change hint here. (If we *were* to add
+      // nsChangeHint_UpdateTransformLayer, ApplyRenderingChangeToTree would
+      // complain that we're updating a transform layer without a transform).
+      if (layerInfo.mLayerType == nsDisplayItem::TYPE_TRANSFORM &&
+          !aFrame->StyleDisplay()->HasTransformStyle()) {
+        continue;
+      }
+      hint |= layerInfo.mChangeHint;
+    }
+
+    // We consider it's the first paint for the frame if we have an animation
+    // for the property but have no layer.
+    // Note that in case of animations which has properties preventing running
+    // on the compositor, e.g., width or height, corresponding layer is not
+    // created at all, but even in such cases, we normally set valid change
+    // hint for such animations in each tick, i.e. restyles in each tick. As
+    // a result, we usually do restyles for such animations in every tick on
+    // the main-thread.  The only animations which will be affected by this
+    // explicit change hint are animations that have opacity/transform but did
+    // not have those properies just before. e.g, setting transform by
+    // setKeyframes or changing target element from other target which prevents
+    // running on the compositor, etc.
+    if (!layer &&
+        nsLayoutUtils::HasEffectiveAnimation(aFrame, layerInfo.mProperty)) {
+      hint |= layerInfo.mChangeHint;
+    }
+  }
+
+  if (hint) {
+    aChangeListToProcess.AppendChange(aFrame, aContent, hint);
+  }
+}
+
 RestyleManager::AnimationsWithDestroyedFrame::AnimationsWithDestroyedFrame(
                                                 RestyleManager* aRestyleManager)
   : mRestyleManager(aRestyleManager)
   , mRestorePointer(mRestyleManager->mAnimationsWithDestroyedFrame)
 {
   MOZ_ASSERT(!mRestyleManager->mAnimationsWithDestroyedFrame,
              "shouldn't construct recursively");
   mRestyleManager->mAnimationsWithDestroyedFrame = this;
--- a/layout/base/RestyleManager.h
+++ b/layout/base/RestyleManager.h
@@ -189,16 +189,21 @@ public:
   // Update the animation generation count to mark that animation state
   // has changed.
   //
   // This is normally performed automatically by ProcessPendingRestyles
   // but it is also called when we have out-of-band changes to animations
   // such as changes made through the Web Animations API.
   void IncrementAnimationGeneration();
 
+  static void AddLayerChangesForAnimation(nsIFrame* aFrame,
+                                          nsIContent* aContent,
+                                          nsStyleChangeList&
+                                            aChangeListToProcess);
+
 protected:
   RestyleManager(StyleBackendType aType, nsPresContext* aPresContext);
 
   virtual ~RestyleManager()
   {
     MOZ_ASSERT(!mAnimationsWithDestroyedFrame,
                "leaving dangling pointers from AnimationsWithDestroyedFrame");
   }
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -310,16 +310,27 @@ ServoRestyleManager::ProcessPostTraversa
     if (MOZ_UNLIKELY(displayContentsNode)) {
       MOZ_ASSERT(!styleFrame);
       displayContentsNode->mStyle = newContext;
     }
 
     if (styleFrame) {
       styleFrame->UpdateStyleOfOwnedAnonBoxes(*aStyleSet, aChangeList, changeHint);
     }
+
+    // Some changes to animations don't affect the computed style and yet still
+    // require the layer to be updated. For example, pausing an animation via
+    // the Web Animations API won't affect an element's style but still
+    // requires to update the animation on the layer.
+    //
+    // We can sometimes reach this when the animated style is being removed.
+    // Since AddLayerChangesForAnimation checks if |styleFrame| has a transform
+    // style or not, we need to call it *after* setting |newContext| to
+    // |styleFrame| to ensure the animated transform has been removed first.
+    AddLayerChangesForAnimation(styleFrame, aElement, aChangeList);
   }
 
   const bool descendantsNeedFrames =
     aElement->HasFlag(NODE_DESCENDANTS_NEED_FRAMES);
   const bool traverseElementChildren =
     aElement->HasDirtyDescendantsForServo() || descendantsNeedFrames;
   const bool traverseTextChildren = recreateContext || descendantsNeedFrames;
   if (traverseElementChildren || traverseTextChildren) {