Bug 780692 Part 0: Make sure frames that have async animations are marked as having active layers r=roc
authorDavid Zbarsky <dzbarsky@gmail.com>
Sat, 25 Aug 2012 10:52:30 -0400
changeset 103402 39da15b8b6aaad0f65535ef66e806a4b52564c9a
parent 103401 1a6fa8dd582bcefa1ebbf529c3ec9ce57c392188
child 103403 7112cff6bdbf958f12f9c49ea0911c02c866cd73
push id13976
push userdzbarsky@gmail.com
push dateSat, 25 Aug 2012 14:52:33 +0000
treeherdermozilla-inbound@39da15b8b6aa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs780692
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 780692 Part 0: Make sure frames that have async animations are marked as having active layers r=roc
layout/style/nsAnimationManager.cpp
layout/style/nsTransitionManager.cpp
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -300,49 +300,67 @@ bool
 ElementAnimations::CanPerformOnCompositorThread() const
 {
   if (mElementProperty != nsGkAtoms::animationsProperty) {
     if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
       printf_stderr("Gecko bug: Async animation of pseudoelements not supported.  See bug 771367\n");
     }
     return false;
   }
-  bool hasGeometricProperty = false;
   nsIFrame* frame = mElement->GetPrimaryFrame();
+  if (!frame) {
+    return false;
+  }
   TimeStamp now = frame->PresContext()->RefreshDriver()->MostRecentRefresh();
 
+  bool hasGeometricProperty = false;
   for (uint32_t animIdx = mAnimations.Length(); animIdx-- != 0; ) {
     const ElementAnimation& anim = mAnimations[animIdx];
     for (uint32_t propIdx = 0, propEnd = anim.mProperties.Length();
          propIdx != propEnd; ++propIdx) {
       if (IsGeometricProperty(anim.mProperties[propIdx].mProperty) &&
           anim.IsRunningAt(now)) {
         hasGeometricProperty = true;
         break;
       }
     }
   }
 
+  bool hasOpacity = false;
+  bool hasTransform = false;
   for (uint32_t animIdx = mAnimations.Length(); animIdx-- != 0; ) {
     const ElementAnimation& anim = mAnimations[animIdx];
     if (anim.mIterationDuration.ToMilliseconds() <= 0.0) {
       // No animation data
       continue;
     }
 
     for (uint32_t propIdx = 0, propEnd = anim.mProperties.Length();
          propIdx != propEnd; ++propIdx) {
       const AnimationProperty& prop = anim.mProperties[propIdx];
       if (!CanAnimatePropertyOnCompositor(mElement,
                                           prop.mProperty,
                                           hasGeometricProperty)) {
         return false;
       }
+      if (prop.mProperty == eCSSProperty_opacity) {
+        hasOpacity = true;
+      } else if (prop.mProperty == eCSSProperty_transform) {
+        hasTransform = true;
+      }
     }
   }
+  // This animation can be done on the compositor.  Mark the frame as active, in
+  // case we are able to throttle this animation.
+  if (hasOpacity) {
+    frame->MarkLayersActive(nsChangeHint_UpdateOpacityLayer);
+  }
+  if (hasTransform) {
+    frame->MarkLayersActive(nsChangeHint_UpdateTransformLayer);
+  }
   return true;
 }
 
 ElementAnimations*
 nsAnimationManager::GetElementAnimations(dom::Element *aElement,
                                          nsCSSPseudoElements::Type aPseudoType,
                                          bool aCreateIfNeeded)
 {
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -128,38 +128,56 @@ bool
 ElementTransitions::CanPerformOnCompositorThread() const
 {
   if (mElementProperty != nsGkAtoms::transitionsProperty) {
     if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
       printf_stderr("Gecko bug: Async transition of pseudoelements not supported.  See bug 771367\n");
     }
     return false;
   }
-  bool hasGeometricProperty = false;
   nsIFrame* frame = mElement->GetPrimaryFrame();
+  if (!frame) {
+    return false;
+  }
   TimeStamp now = frame->PresContext()->RefreshDriver()->MostRecentRefresh();
 
+  bool hasGeometricProperty = false;
   for (uint32_t i = 0, i_end = mPropertyTransitions.Length(); i < i_end; ++i) {
     const ElementPropertyTransition& pt = mPropertyTransitions[i];
     if (css::IsGeometricProperty(pt.mProperty) && pt.IsRunningAt(now)) {
       hasGeometricProperty = true;
       break;
     }
   }
 
+  bool hasOpacity = false;
+  bool hasTransform = false;
   for (uint32_t i = 0, i_end = mPropertyTransitions.Length(); i < i_end; ++i) {
     const ElementPropertyTransition& pt = mPropertyTransitions[i];
     if (pt.IsRemovedSentinel()) {
       continue;
     }
     if (!css::CommonElementAnimationData::CanAnimatePropertyOnCompositor(mElement,
                                                                          pt.mProperty,
                                                                          hasGeometricProperty)) {
       return false;
     }
+    if (pt.mProperty == eCSSProperty_opacity) {
+      hasOpacity = true;
+    } else if (pt.mProperty == eCSSProperty_transform) {
+      hasTransform = true;
+    }
+  }
+  // This transition can be done on the compositor.  Mark the frame as active, in
+  // case we are able to throttle this transition.
+  if (hasOpacity) {
+    frame->MarkLayersActive(nsChangeHint_UpdateOpacityLayer);
+  }
+  if (hasTransform) {
+    frame->MarkLayersActive(nsChangeHint_UpdateTransformLayer);
   }
   return true;
 }
 
 /*****************************************************************************
  * nsTransitionManager                                                       *
  *****************************************************************************/