Bug 929362 - When refusing compositor animation during BuildLayer, set a property on the frame that disables all async animations on it forever. r=roc a=koi
authorMarkus Stange <mstange>
Fri, 25 Oct 2013 08:31:00 +0100
changeset 160847 7d0eadd8576d2abf01ffe036c8158040354664ce
parent 160846 f5422c59a1ec2602c795b612896090f2f7da5aa1
child 160848 844d1594df32513bb01f4c3eade0b96cc39b5a52
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, koi
bugs929362
milestone26.0a2
Bug 929362 - When refusing compositor animation during BuildLayer, set a property on the frame that disables all async animations on it forever. r=roc a=koi
layout/base/nsDisplayList.cpp
layout/generic/nsIFrame.h
layout/style/AnimationCommon.cpp
layout/style/AnimationCommon.h
layout/style/nsAnimationManager.cpp
layout/style/nsTransitionManager.cpp
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -372,19 +372,27 @@ AddAnimationsAndTransitionsToLayer(Layer
 
   ElementAnimations* ea =
     nsAnimationManager::GetAnimationsForCompositor(content, aProperty);
 
   if (!ea && !et) {
     return;
   }
 
-  // If the frame is not prerendered, bail out.  Layout will still perform the
-  // animation.
+  // If the frame is not prerendered, bail out.
   if (!aItem->CanUseAsyncAnimations(aBuilder)) {
+    // AnimationManager or TransitionManager need to know that we refused to
+    // run this animation asynchronously so that they will not throttle the
+    // main thread animation.
+    frame->Properties().Set(nsIFrame::RefusedAsyncAnimation(),
+                            reinterpret_cast<void*>(intptr_t(true)));
+
+    // We need to schedule another refresh driver run so that AnimationManager
+    // or TransitionManager get a chance to unthrottle the animation.
+    frame->SchedulePaint();
     return;
   }
 
   mozilla::TimeStamp currentTime =
     frame->PresContext()->RefreshDriver()->MostRecentRefresh();
   AnimationData data;
   if (aProperty == eCSSProperty_transform) {
     nsRect bounds = nsDisplayTransform::GetFrameBoundsForTransform(frame);
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -959,16 +959,18 @@ public:
   NS_DECLARE_FRAME_PROPERTY(ScrollLayerCount, nullptr)
 
   NS_DECLARE_FRAME_PROPERTY(LineBaselineOffset, nullptr)
 
   NS_DECLARE_FRAME_PROPERTY(CachedBackgroundImage, DestroySurface)
 
   NS_DECLARE_FRAME_PROPERTY(InvalidationRect, DestroyRect)
 
+  NS_DECLARE_FRAME_PROPERTY(RefusedAsyncAnimation, nullptr)
+
   /**
    * Return the distance between the border edge of the frame and the
    * margin edge of the frame.  Like GetRect(), returns the dimensions
    * as of the most recent reflow.
    *
    * This doesn't include any margin collapsing that may have occurred.
    *
    * It also treats 'auto' margins as zero, and treats any margins that
--- a/layout/style/AnimationCommon.cpp
+++ b/layout/style/AnimationCommon.cpp
@@ -283,16 +283,23 @@ CommonElementAnimationData::CanAnimatePr
     LogAsyncAnimationFailure(message);
   }
   bool propertyAllowed = (aProperty == eCSSProperty_transform) ||
                          (aProperty == eCSSProperty_opacity) ||
                          (aFlags & CanAnimate_AllowPartial);
   return enabled && propertyAllowed;
 }
 
+/* static */ bool
+CommonElementAnimationData::IsCompositorAnimationDisabledForFrame(nsIFrame* aFrame)
+{
+  void* prop = aFrame->Properties().Get(nsIFrame::RefusedAsyncAnimation());
+  return bool(reinterpret_cast<intptr_t>(prop));
+}
+
 /* static */ void
 CommonElementAnimationData::LogAsyncAnimationFailure(nsCString& aMessage,
                                                      const nsIContent* aContent)
 {
   if (aContent) {
     aMessage.AppendLiteral(" [");
     aMessage.Append(nsAtomCString(aContent->Tag()));
 
--- a/layout/style/AnimationCommon.h
+++ b/layout/style/AnimationCommon.h
@@ -14,16 +14,17 @@
 #include "nsCSSProperty.h"
 #include "mozilla/MemoryReporting.h"
 #include "mozilla/dom/Element.h"
 #include "nsSMILKeySpline.h"
 #include "nsStyleStruct.h"
 #include "mozilla/Attributes.h"
 
 class nsPresContext;
+class nsIFrame;
 
 
 namespace mozilla {
 namespace css {
 
 bool IsGeometricProperty(nsCSSProperty aProperty);
 
 struct CommonElementAnimationData;
@@ -170,16 +171,18 @@ struct CommonElementAnimationData : publ
     CanAnimate_AllowPartial = 2
   };
 
   static bool
   CanAnimatePropertyOnCompositor(const dom::Element *aElement,
                                  nsCSSProperty aProperty,
                                  CanAnimateFlags aFlags);
 
+  static bool IsCompositorAnimationDisabledForFrame(nsIFrame* aFrame);
+
   // True if this animation can be performed on the compositor thread.
   // Do not pass CanAnimate_AllowPartial to make sure that all properties of this
   // animation are supported by the compositor.
   virtual bool CanPerformOnCompositorThread(CanAnimateFlags aFlags) const = 0;
   virtual bool HasAnimationOfProperty(nsCSSProperty aProperty) const = 0;
 
   static void LogAsyncAnimationFailure(nsCString& aMessage,
                                        const nsIContent* aContent = nullptr);
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -395,17 +395,18 @@ ElementAnimations::CanPerformOnComposito
       continue;
     }
 
     for (uint32_t propIdx = 0, propEnd = anim.mProperties.Length();
          propIdx != propEnd; ++propIdx) {
       const AnimationProperty& prop = anim.mProperties[propIdx];
       if (!CanAnimatePropertyOnCompositor(mElement,
                                           prop.mProperty,
-                                          aFlags)) {
+                                          aFlags) ||
+          IsCompositorAnimationDisabledForFrame(frame)) {
         return false;
       }
       if (prop.mProperty == eCSSProperty_opacity) {
         hasOpacity = true;
       } else if (prop.mProperty == eCSSProperty_transform) {
         hasTransform = true;
       }
     }
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -173,17 +173,18 @@ ElementTransitions::CanPerformOnComposit
     if (pt.IsRemovedSentinel()) {
       continue;
     }
     
     existsProperty = true;
 
     if (!css::CommonElementAnimationData::CanAnimatePropertyOnCompositor(mElement,
                                                                          pt.mProperty,
-                                                                         aFlags)) {
+                                                                         aFlags) ||
+        !css::CommonElementAnimationData::IsCompositorAnimationDisabledForFrame(frame)) {
       return false;
     }
     if (pt.mProperty == eCSSProperty_opacity) {
       hasOpacity = true;
     } else if (pt.mProperty == eCSSProperty_transform) {
       hasTransform = true;
     }
   }