Bug 785648 - Improve OMTA logging r=cjones
authorDavid Zbarsky <dzbarsky@gmail.com>
Sat, 25 Aug 2012 21:27:28 -0400
changeset 105501 9961642b6f0acdb455732b2b33d50a88c21cc87d
parent 105500 b543ecb718e3dd5e51b43942a137f75d86c1c2ed
child 105502 90c92e55affdf1698371956adf6e24fa182d91b9
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
reviewerscjones
bugs785648
milestone17.0a1
Bug 785648 - Improve OMTA logging r=cjones
layout/base/nsDisplayList.cpp
layout/base/nsDisplayList.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
@@ -42,16 +42,17 @@
 #include "nsTransitionManager.h"
 #include "nsIViewManager.h"
 #include "ImageLayers.h"
 #include "ImageContainer.h"
 
 #include "mozilla/StandardInteger.h"
 
 using namespace mozilla;
+using namespace mozilla::css;
 using namespace mozilla::layers;
 typedef FrameMetrics::ViewID ViewID;
 
 static void AddTransformFunctions(nsCSSValueList* aList,
                                   nsStyleContext* aContext,
                                   nsPresContext* aPresContext,
                                   nsRect& aBounds,
                                   float aAppUnitsPerPixel,
@@ -341,26 +342,16 @@ AddAnimationsAndTransitionsToLayer(Layer
 
   if (!ea && !et) {
     return;
   }
 
   // If the frame is not prerendered, bail out.  Layout will still perform the
   // animation.
   if (!aItem->CanUseAsyncAnimations(aBuilder)) {
-    if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
-      printf_stderr("Performance warning: Async animation disabled because the frame for element '%s'",
-                    nsAtomCString(aContent->Tag()).get());
-      nsIAtom* id = aContent->GetID();
-      if (id) {
-        printf_stderr(" with id '%s'",
-                      nsAtomCString(aContent->GetID()).get());
-      }
-      printf_stderr(" is not prerendered\n");
-    }
     return;
   }
 
   mozilla::TimeStamp currentTime =
     frame->PresContext()->RefreshDriver()->MostRecentRefresh();
   AnimationData data;
   if (aProperty == eCSSProperty_transform) {
     nsRect bounds = nsDisplayTransform::GetFrameBoundsForTransform(frame);
@@ -3335,33 +3326,79 @@ nsDisplayTransform::GetResultingTransfor
       return nsLayoutUtils::ChangeMatrixBasis(newOrigin + toMozOrigin, result) * parent;
   }
 
   return nsLayoutUtils::ChangeMatrixBasis
     (newOrigin + toMozOrigin, result);
 }
 
 bool
+nsDisplayOpacity::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder)
+{
+  if (GetUnderlyingFrame()->AreLayersMarkedActive(nsChangeHint_UpdateOpacityLayer)) {
+    return true;
+  }
+
+  if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
+    nsCString message;
+    message.AppendLiteral("Performance warning: Async animation disabled because frame was not marked active for opacity animation");
+    CommonElementAnimationData::LogAsyncAnimationFailure(message);
+  }
+  return false;
+}
+
+bool
+nsDisplayTransform::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder)
+{
+  return ShouldPrerenderTransformedContent(aBuilder,
+                                           GetUnderlyingFrame(),
+                                           nsLayoutUtils::IsAnimationLoggingEnabled());
+}
+
+/* static */ bool
 nsDisplayTransform::ShouldPrerenderTransformedContent(nsDisplayListBuilder* aBuilder,
-                                                      nsIFrame* aFrame)
+                                                      nsIFrame* aFrame,
+                                                      bool aLogAnimations)
 {
-  if (aFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer)) {
-    nsSize refSize = aBuilder->ReferenceFrame()->GetSize();
-    // Only prerender if the transformed frame's size is <= the
-    // reference frame size (~viewport), allowing a 1/8th fuzz factor
-    // for shadows, borders, etc.
-    refSize += nsSize(refSize.width / 8, refSize.height / 8);
-    if (aFrame->GetVisualOverflowRectRelativeToSelf().Size() <= refSize) {
-      // Bug 717521 - pre-render max 4096 x 4096 device pixels.
-      nscoord max = aFrame->PresContext()->DevPixelsToAppUnits(4096);
-      nsRect visual = aFrame->GetVisualOverflowRect();
-      if (visual.width <= max && visual.height <= max) {
-        return true;
-      }
+  if (!aFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer)) {
+    if (aLogAnimations) {
+      nsCString message;
+      message.AppendLiteral("Performance warning: Async animation disabled because frame was not marked active for transform animation");
+      CommonElementAnimationData::LogAsyncAnimationFailure(message);
     }
+    return false;
+  }
+
+  nsSize refSize = aBuilder->ReferenceFrame()->GetSize();
+  // Only prerender if the transformed frame's size is <= the
+  // reference frame size (~viewport), allowing a 1/8th fuzz factor
+  // for shadows, borders, etc.
+  refSize += nsSize(refSize.width / 8, refSize.height / 8);
+  nsSize frameSize = aFrame->GetVisualOverflowRectRelativeToSelf().Size();
+  if (frameSize <= refSize) {
+    // Bug 717521 - pre-render max 4096 x 4096 device pixels.
+    nscoord max = aFrame->PresContext()->DevPixelsToAppUnits(4096);
+    nsRect visual = aFrame->GetVisualOverflowRect();
+    if (visual.width <= max && visual.height <= max) {
+      return true;
+    }
+  }
+
+  if (aLogAnimations) {
+    nsCString message;
+    message.AppendLiteral("Performance warning: Async animation disabled because frame size (");
+    message.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(frameSize.width));
+    message.AppendLiteral(", ");
+    message.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(frameSize.height));
+    message.AppendLiteral(") is bigger than the viewport (");
+    message.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(refSize.width));
+    message.AppendLiteral(", ");
+    message.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(refSize.height));
+    message.AppendLiteral(")");
+    CommonElementAnimationData::LogAsyncAnimationFailure(message);
   }
   return false;
 }
 
 /* If the matrix is singular, or a hidden backface is shown, the frame won't be visible or hit. */
 static bool IsFrameVisible(nsIFrame* aFrame, const gfx3DMatrix& aMatrix)
 {
   if (aMatrix.IsSingular()) {
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -1902,19 +1902,17 @@ public:
                                    LayerManager* aManager,
                                    const ContainerParameters& aParameters);
   virtual bool ComputeVisibility(nsDisplayListBuilder* aBuilder,
                                    nsRegion* aVisibleRegion,
                                    const nsRect& aAllowVisibleRegionExpansion);  
   virtual bool TryMerge(nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem);
   NS_DISPLAY_DECL_NAME("Opacity", TYPE_OPACITY)
 
-  bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) {
-    return GetUnderlyingFrame()->AreLayersMarkedActive(nsChangeHint_UpdateOpacityLayer);
-  }
+  bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder);
 };
 
 /**
  * A display item that has no purpose but to ensure its contents get
  * their own layer.
  */
 class nsDisplayOwnLayer : public nsDisplayWrapList {
 public:
@@ -2415,21 +2413,19 @@ public:
                                                  gfxPoint3D* aToPerspectiveOrigin = nullptr,
                                                  nscoord* aChildPerspective = nullptr,
                                                  nsIFrame** aOutAncestor = nullptr);
   /**
    * Return true when we should try to prerender the entire contents of the
    * transformed frame even when it's not completely visible (yet).
    */
   static bool ShouldPrerenderTransformedContent(nsDisplayListBuilder* aBuilder,
-                                                nsIFrame* aFrame);
-  bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder) {
-    return nsDisplayTransform::ShouldPrerenderTransformedContent(aBuilder,
-                                                                 GetUnderlyingFrame());
-  }
+                                                nsIFrame* aFrame,
+                                                bool aLogAnimations = false);
+  bool CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder);
 
 private:
   nsDisplayWrapList mStoredList;
   gfx3DMatrix mTransform;
   float mCachedAppUnitsPerPixel;
   uint32_t mIndex;
 };
 
--- a/layout/style/AnimationCommon.cpp
+++ b/layout/style/AnimationCommon.cpp
@@ -1,13 +1,14 @@
 /* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
 /* 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 "CompositorParent.h"
 #include "AnimationCommon.h"
 #include "nsRuleData.h"
 #include "nsCSSValue.h"
 #include "nsStyleContext.h"
 #include "nsIFrame.h"
 #include "nsAnimationManager.h"
 #include "nsLayoutUtils.h"
 
@@ -233,55 +234,93 @@ ComputedTimingFunction::GetValue(double 
 }
 
 bool
 CommonElementAnimationData::CanAnimatePropertyOnCompositor(const dom::Element *aElement,
                                                            nsCSSProperty aProperty,
                                                            bool aHasGeometricProperties)
 {
   bool shouldLog = nsLayoutUtils::IsAnimationLoggingEnabled();
+  if (shouldLog && !layers::CompositorParent::CompositorLoop()) {
+    nsCString message;
+    message.AppendLiteral("Performance warning: Compositor disabled");
+    LogAsyncAnimationFailure(message);
+    return false;
+  }
+
   nsIFrame* frame = aElement->GetPrimaryFrame();
   if (IsGeometricProperty(aProperty)) {
     if (shouldLog) {
-      printf_stderr("Performance warning: Async animation of geometric property '%s' is disabled\n", aProperty);
+      nsCString message;
+      message.AppendLiteral("Performance warning: Async animation of geometric property '");
+      message.Append(aProperty);
+      message.AppendLiteral(" is disabled");
+      LogAsyncAnimationFailure(message, aElement);
     }
     return false;
   }
   if (aProperty == eCSSProperty_opacity) {
     bool enabled = nsLayoutUtils::AreOpacityAnimationsEnabled();
     if (!enabled && shouldLog) {
-      printf_stderr("Performance warning: Async animation of 'opacity' is disabled\n");
+      nsCString message;
+      message.AppendLiteral("Performance warning: Async animation of 'opacity' is disabled");
+      LogAsyncAnimationFailure(message);
     }
     return enabled;
   }
   if (aProperty == eCSSProperty_transform) {
     if (frame->Preserves3D() &&
         frame->Preserves3DChildren()) {
       if (shouldLog) {
-        printf_stderr("Gecko bug: Async animation of 'preserve-3d' transforms is not supported.  See bug 779598\n");
+        nsCString message;
+        message.AppendLiteral("Gecko bug: Async animation of 'preserve-3d' transforms is not supported.  See bug 779598");
+        LogAsyncAnimationFailure(message, aElement);
       }
       return false;
     }
     if (frame->IsSVGTransformed()) {
       if (shouldLog) {
-        printf_stderr("Gecko bug: Async 'transform' animations of frames with SVG transforms is not supported.  See bug 779599\n");
+        nsCString message;
+        message.AppendLiteral("Gecko bug: Async 'transform' animations of frames with SVG transforms is not supported.  See bug 779599");
+        LogAsyncAnimationFailure(message, aElement);
       }
       return false;
     }
     if (aHasGeometricProperties) {
       if (shouldLog) {
-        printf_stderr("Performance warning: Async animation of 'transform' not possible due to presence of geometric properties\n");
+        nsCString message;
+        message.AppendLiteral("Performance warning: Async animation of 'transform' not possible due to presence of geometric properties");
+        LogAsyncAnimationFailure(message, aElement);
       }
       return false;
     }
     bool enabled = nsLayoutUtils::AreTransformAnimationsEnabled();
     if (!enabled && shouldLog) {
-      printf_stderr("Performance warning: Async animation of 'transform' is disabled\n");
+      nsCString message;
+      message.AppendLiteral("Performance warning: Async animation of 'transform' is disabled");
+      LogAsyncAnimationFailure(message);
     }
     return enabled;
   }
   return true;
 }
 
+/* static */ void
+CommonElementAnimationData::LogAsyncAnimationFailure(nsCString& aMessage,
+                                                     const nsIContent* aContent)
+{
+  if (aContent) {
+    aMessage.AppendLiteral(" [");
+    aMessage.Append(nsAtomCString(aContent->Tag()));
 
+    nsIAtom* id = aContent->GetID();
+    if (id) {
+      aMessage.AppendLiteral(" with id '");
+      aMessage.Append(nsAtomCString(aContent->GetID()));
+      aMessage.AppendLiteral("'");
+    }
+    aMessage.AppendLiteral("]");
+  }
+  printf_stderr(aMessage.get());
+}
 
 }
 }
--- a/layout/style/AnimationCommon.h
+++ b/layout/style/AnimationCommon.h
@@ -151,16 +151,19 @@ struct CommonElementAnimationData : publ
     mElement->DeleteProperty(mElementProperty);
   }
 
   static bool
   CanAnimatePropertyOnCompositor(const dom::Element *aElement,
                                  nsCSSProperty aProperty,
                                  bool aHasGeometricProperties);
 
+  static void LogAsyncAnimationFailure(nsCString& aMessage,
+                                       const nsIContent* aContent = nullptr);
+
   dom::Element *mElement;
 
   // the atom we use in mElement's prop table (must be a static atom,
   // i.e., in an atom list)
   nsIAtom *mElementProperty;
 
   CommonAnimationManager *mManager;
 
--- a/layout/style/nsAnimationManager.cpp
+++ b/layout/style/nsAnimationManager.cpp
@@ -294,26 +294,30 @@ ElementAnimations::HasAnimationOfPropert
     }
   }
   return false;
 }
 
 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;
-  }
   nsIFrame* frame = mElement->GetPrimaryFrame();
   if (!frame) {
     return false;
   }
+
+  if (mElementProperty != nsGkAtoms::animationsProperty) {
+    if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
+      nsCString message;
+      message.AppendLiteral("Gecko bug: Async animation of pseudoelements not supported.  See bug 771367");
+      LogAsyncAnimationFailure(message, mElement);
+    }
+    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) &&
--- a/layout/style/nsTransitionManager.cpp
+++ b/layout/style/nsTransitionManager.cpp
@@ -122,26 +122,30 @@ ElementTransitions::HasTransitionOfPrope
     }
   }
   return false;
 }
 
 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;
-  }
   nsIFrame* frame = mElement->GetPrimaryFrame();
   if (!frame) {
     return false;
   }
+
+  if (mElementProperty != nsGkAtoms::transitionsProperty) {
+    if (nsLayoutUtils::IsAnimationLoggingEnabled()) {
+      nsCString message;
+      message.AppendLiteral("Gecko bug: Async transition of pseudoelements not supported.  See bug 771367");
+      LogAsyncAnimationFailure(message, mElement);
+    }
+    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;