Bug 911889. Part 6: A scripted change to element.style.opacity or element.style.transform in a setTimeout or requestAnimationFrame callback should trigger our "style property is animated" heuristic. r=dbaron
authorRobert O'Callahan <robert@ocallahan.org>
Wed, 04 Sep 2013 23:47:23 +1200
changeset 153239 ed7763980b353f5c3f126684c0339cbe2e8acd60
parent 153238 a871905cadb7cef04565d837ed39bc3a560c0b8e
child 153240 82578c63ceb5d59ecd690bc1364d512181006f66
push id25578
push userphilringnalda@gmail.com
push dateSun, 03 Nov 2013 21:05:48 +0000
treeherdermozilla-central@fc3414dda755 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs911889
milestone28.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 911889. Part 6: A scripted change to element.style.opacity or element.style.transform in a setTimeout or requestAnimationFrame callback should trigger our "style property is animated" heuristic. r=dbaron
layout/base/ActiveLayerTracker.cpp
layout/base/ActiveLayerTracker.h
layout/style/nsDOMCSSAttrDeclaration.cpp
layout/style/nsDOMCSSAttrDeclaration.h
--- a/layout/base/ActiveLayerTracker.cpp
+++ b/layout/base/ActiveLayerTracker.cpp
@@ -2,16 +2,19 @@
  * 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 "ActiveLayerTracker.h"
 
 #include "nsExpirationTracker.h"
 #include "nsIFrame.h"
 #include "nsIContent.h"
+#include "nsRefreshDriver.h"
+#include "nsPIDOMWindow.h"
+#include "nsIDocument.h"
 
 namespace mozilla {
 
 /**
  * This tracks the state of a frame that may need active layers due to
  * ongoing content changes or style changes that indicate animation.
  *
  * When no changes of *any* kind are detected after 75-100ms we remove this
@@ -127,16 +130,38 @@ ActiveLayerTracker::NotifyRestyle(nsIFra
 ActiveLayerTracker::NotifyAnimated(nsIFrame* aFrame, nsCSSProperty aProperty)
 {
   LayerActivity* layerActivity = GetLayerActivityForUpdate(aFrame);
   uint8_t& mutationCount = layerActivity->RestyleCountForProperty(aProperty);
   // We know this is animated, so just hack the mutation count.
   mutationCount = 0xFF;
 }
 
+static bool
+IsPresContextInScriptAnimationCallback(nsPresContext* aPresContext)
+{
+  if (aPresContext->RefreshDriver()->IsInRefresh()) {
+    return true;
+  }
+  // Treat timeouts/setintervals as scripted animation callbacks for our
+  // purposes.
+  nsPIDOMWindow* win = aPresContext->Document()->GetInnerWindow();
+  return win && win->IsRunningTimeout();
+}
+
+/* static */ void
+ActiveLayerTracker::NotifyInlineStyleRuleModified(nsIFrame* aFrame,
+                                                  nsCSSProperty aProperty)
+{
+  if (!IsPresContextInScriptAnimationCallback(aFrame->PresContext())) {
+    return;
+  }
+  NotifyAnimated(aFrame, aProperty);
+}
+
 /* static */ bool
 ActiveLayerTracker::IsStyleAnimated(nsIFrame* aFrame, nsCSSProperty aProperty)
 {
   LayerActivity* layerActivity = GetLayerActivity(aFrame);
   if (layerActivity) {
     // XXX should we really treat a single change to transform as animation?
     uint8_t minStyleChangesToBeConsideredAnimation =
         aProperty == eCSSProperty_opacity ? 2 : 1;
--- a/layout/base/ActiveLayerTracker.h
+++ b/layout/base/ActiveLayerTracker.h
@@ -14,16 +14,18 @@ namespace mozilla {
 /**
  * This class receives various notifications about style changes and content
  * changes that affect layerization decisions, and implements the heuristics
  * that drive those decisions. It manages per-frame state to support those
  * heuristics.
  */
 class ActiveLayerTracker {
 public:
+  static void Shutdown();
+
   /*
    * We track eCSSProperty_transform and eCSSProperty_opacity style changes
    * and use that information to guess whether style changes are animated.
    */
 
   /**
    * Notify aFrame's style property as having changed due to a restyle,
    * and therefore possibly wanting an active layer to render that style.
@@ -32,29 +34,39 @@ public:
    */
   static void NotifyRestyle(nsIFrame* aFrame, nsCSSProperty aProperty);
   /**
    * Mark aFrame as being known to have an animation of aProperty.
    * Any such marking will time out after a short period.
    */
   static void NotifyAnimated(nsIFrame* aFrame, nsCSSProperty aProperty);
   /**
+   * Notify that a property in the inline style rule of aFrame's element
+   * has been modified.
+   * This notification is incomplete --- not all modifications to inline
+   * style will trigger this.
+   */
+  static void NotifyInlineStyleRuleModified(nsIFrame* aFrame, nsCSSProperty aProperty);
+  /**
    * Return true if aFrame's aProperty style should be considered as being animated
    * for constructing active layers.
    */
   static bool IsStyleAnimated(nsIFrame* aFrame, nsCSSProperty aProperty);
 
+  /*
+   * We track modifications to the content of certain frames (i.e. canvas frames)
+   * and use that to make layering decisions.
+   */
+
   /**
    * Mark aFrame's content as being active. This marking will time out after
-   * a short period. This is useful for frames such as canvas frames.
+   * a short period.
    */
   static void NotifyContentChange(nsIFrame* aFrame);
   /**
    * Return true if this frame's content is still marked as active.
    */
   static bool IsContentActive(nsIFrame* aFrame);
-
-  static void Shutdown();
 };
 
 }
 
 #endif /* ACTIVELAYERTRACKER_H_ */
--- a/layout/style/nsDOMCSSAttrDeclaration.cpp
+++ b/layout/style/nsDOMCSSAttrDeclaration.cpp
@@ -10,19 +10,20 @@
 #include "mozilla/css/Declaration.h"
 #include "mozilla/css/StyleRule.h"
 #include "mozilla/dom/Element.h"
 #include "nsIDocument.h"
 #include "nsIDOMMutationEvent.h"
 #include "nsIURI.h"
 #include "nsNodeUtils.h"
 #include "nsWrapperCacheInlines.h"
+#include "nsIFrame.h"
+#include "ActiveLayerTracker.h"
 
-namespace css = mozilla::css;
-namespace dom = mozilla::dom;
+using namespace mozilla;
 
 nsDOMCSSAttributeDeclaration::nsDOMCSSAttributeDeclaration(dom::Element* aElement,
                                                            bool aIsSMILOverride)
   : mElement(aElement)
   , mIsSMILOverride(aIsSMILOverride)
 {
   MOZ_COUNT_CTOR(nsDOMCSSAttributeDeclaration);
 
@@ -164,8 +165,24 @@ nsDOMCSSAttributeDeclaration::GetParentR
   return NS_OK;
 }
 
 /* virtual */ nsINode*
 nsDOMCSSAttributeDeclaration::GetParentObject()
 {
   return mElement;
 }
+
+NS_IMETHODIMP
+nsDOMCSSAttributeDeclaration::SetPropertyValue(const nsCSSProperty aPropID,
+                                               const nsAString& aValue)
+{
+  // Scripted modifications to style.opacity or style.transform
+  // could immediately force us into the animated state if heuristics suggest
+  // this is scripted animation.
+  if (aPropID == eCSSProperty_opacity || aPropID == eCSSProperty_transform) {
+    nsIFrame* frame = mElement->GetPrimaryFrame();
+    if (frame) {
+      ActiveLayerTracker::NotifyInlineStyleRuleModified(frame, aPropID);
+    }
+  }
+  return nsDOMCSSDeclaration::SetPropertyValue(aPropID, aValue);
+}
--- a/layout/style/nsDOMCSSAttrDeclaration.h
+++ b/layout/style/nsDOMCSSAttrDeclaration.h
@@ -33,16 +33,19 @@ public:
   // If GetCSSDeclaration returns non-null, then the decl it returns
   // is owned by our current style rule.
   virtual mozilla::css::Declaration* GetCSSDeclaration(bool aAllocate);
   virtual void GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv) MOZ_OVERRIDE;
   NS_IMETHOD GetParentRule(nsIDOMCSSRule **aParent) MOZ_OVERRIDE;
 
   virtual nsINode* GetParentObject() MOZ_OVERRIDE;
 
+  NS_IMETHOD SetPropertyValue(const nsCSSProperty aPropID,
+                              const nsAString& aValue);
+
 protected:
   virtual nsresult SetCSSDeclaration(mozilla::css::Declaration* aDecl) MOZ_OVERRIDE;
   virtual nsIDocument* DocToUpdate() MOZ_OVERRIDE;
 
   nsRefPtr<Element> mElement;
 
   /* If true, this indicates that this nsDOMCSSAttributeDeclaration
    * should interact with mContent's SMIL override style rule (rather