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 105468 39da15b8b6aaad0f65535ef66e806a4b52564c9a
parent 105467 1a6fa8dd582bcefa1ebbf529c3ec9ce57c392188
child 105469 7112cff6bdbf958f12f9c49ea0911c02c866cd73
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
reviewersroc
bugs780692
milestone17.0a1
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                                                       *
  *****************************************************************************/