Bug 1466954 - Create an nsDisplayOpacity item if we might have animations for it, so that we avoid changing the display list without an invalidation. r?hiro draft
authorMatt Woodrow <mwoodrow@mozilla.com>
Wed, 06 Jun 2018 09:42:43 +1200
changeset 804391 0e205f1269a8f14c1319ddc37af885e9266b03fc
parent 802711 9900cebb1f9000bd05731ba67736b7c51f7eb812
child 805121 198c4983fbeb29b64bf71a4994f997307f8a40d9
push id112367
push usermwoodrow@mozilla.com
push dateTue, 05 Jun 2018 21:43:05 +0000
reviewershiro
bugs1466954
milestone62.0a1
Bug 1466954 - Create an nsDisplayOpacity item if we might have animations for it, so that we avoid changing the display list without an invalidation. r?hiro MozReview-Commit-ID: 7HkLNEpeHND
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/generic/nsFrame.cpp
layout/generic/nsIFrame.h
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -236,18 +236,19 @@ nsLayoutUtils::HasCurrentTransitions(con
     {
       // Since |aEffect| is current, it must have an associated Animation
       // so we don't need to null-check the result of GetAnimation().
       return aEffect.IsCurrent() && aEffect.GetAnimation()->AsCSSTransition();
     }
   );
 }
 
-static bool
-MayHaveAnimationOfProperty(EffectSet* effects, nsCSSPropertyID aProperty)
+bool
+nsLayoutUtils::MayHaveAnimationOfProperty(EffectSet* effects,
+                                          nsCSSPropertyID aProperty)
 {
   MOZ_ASSERT(effects);
 
   if (aProperty == eCSSProperty_transform &&
       !effects->MayHaveTransformAnimation()) {
     return false;
   }
   if (aProperty == eCSSProperty_opacity &&
@@ -272,17 +273,17 @@ nsLayoutUtils::MayHaveAnimationOfPropert
       return false;
   }
 }
 
 bool
 nsLayoutUtils::HasAnimationOfProperty(EffectSet* aEffectSet,
                                       nsCSSPropertyID aProperty)
 {
-  if (!aEffectSet || !::MayHaveAnimationOfProperty(aEffectSet, aProperty)) {
+  if (!aEffectSet || !MayHaveAnimationOfProperty(aEffectSet, aProperty)) {
     return false;
   }
 
   return HasMatchingAnimations(aEffectSet,
     [&aProperty](KeyframeEffect& aEffect)
     {
       return (aEffect.IsInEffect() || aEffect.IsCurrent()) &&
              aEffect.HasAnimationOfProperty(aProperty);
@@ -308,17 +309,17 @@ nsLayoutUtils::HasAnimationOfProperty(co
 
 }
 
 bool
 nsLayoutUtils::HasEffectiveAnimation(const nsIFrame* aFrame,
                                      nsCSSPropertyID aProperty)
 {
   EffectSet* effects = EffectSet::GetEffectSet(aFrame);
-  if (!effects || !::MayHaveAnimationOfProperty(effects, aProperty)) {
+  if (!effects || !MayHaveAnimationOfProperty(effects, aProperty)) {
     return false;
   }
 
 
   return HasMatchingAnimations(effects,
     [&aProperty](KeyframeEffect& aEffect)
     {
       return (aEffect.IsInEffect() || aEffect.IsCurrent()) &&
@@ -327,17 +328,17 @@ nsLayoutUtils::HasEffectiveAnimation(con
   );
 }
 
 bool
 nsLayoutUtils::MayHaveEffectiveAnimation(const nsIFrame* aFrame,
                                          nsCSSPropertyID aProperty)
 {
   EffectSet* effects = EffectSet::GetEffectSet(aFrame);
-  if (!effects || !::MayHaveAnimationOfProperty(effects, aProperty)) {
+  if (!effects || !MayHaveAnimationOfProperty(effects, aProperty)) {
     return false;
   }
   return true;
 }
 
 static float
 GetSuitableScale(float aMaxScale, float aMinScale,
                  nscoord aVisibleDimension, nscoord aDisplayDimension)
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -2336,16 +2336,18 @@ public:
                                          nsCSSPropertyID aProperty);
 
   /**
    * Returns true if |aEffectSet| has an animation of |aProperty| regardless of
    * whether the property is overridden by !important rule.
    */
   static bool HasAnimationOfProperty(mozilla::EffectSet* aEffectSet,
                                      nsCSSPropertyID aProperty);
+  static bool MayHaveAnimationOfProperty(mozilla::EffectSet* aEffectSet,
+                                         nsCSSPropertyID aProperty);
 
   /**
    * Returns true if |aFrame| has an animation of |aProperty| which is
    * not overridden by !important rules.
    */
   static bool HasEffectiveAnimation(const nsIFrame* aFrame,
                                     nsCSSPropertyID aProperty);
   static bool MayHaveEffectiveAnimation(const nsIFrame* aFrame,
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1554,17 +1554,18 @@ bool
 nsIFrame::ChildrenHavePerspective(const nsStyleDisplay* aStyleDisplay) const
 {
   MOZ_ASSERT(aStyleDisplay == StyleDisplay());
   return aStyleDisplay->HasPerspective(this);
 }
 
 bool
 nsIFrame::HasOpacityInternal(float aThreshold,
-                             EffectSet* aEffectSet) const
+                             EffectSet* aEffectSet,
+                             bool aMaybe) const
 {
   MOZ_ASSERT(0.0 <= aThreshold && aThreshold <= 1.0, "Invalid argument");
   if (StyleEffects()->mOpacity < aThreshold ||
       (StyleDisplay()->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY)) {
     return true;
   }
 
   if (!mMayHaveOpacityAnimation) {
@@ -1572,20 +1573,27 @@ nsIFrame::HasOpacityInternal(float aThre
   }
 
   EffectSet* effects =
     aEffectSet ? aEffectSet : EffectSet::GetEffectSet(this);
   if (!effects) {
     return false;
   }
 
-  return ((IsPrimaryFrame() ||
-           nsLayoutUtils::FirstContinuationOrIBSplitSibling(this)->
-             IsPrimaryFrame()) &&
-          nsLayoutUtils::HasAnimationOfProperty(effects, eCSSProperty_opacity));
+  if (!IsPrimaryFrame() &&
+      !nsLayoutUtils::FirstContinuationOrIBSplitSibling(this)->
+        IsPrimaryFrame()) {
+    return false;
+  }
+
+  if (aMaybe) {
+    return nsLayoutUtils::MayHaveAnimationOfProperty(effects, eCSSProperty_opacity);
+  } else {
+    return nsLayoutUtils::HasAnimationOfProperty(effects, eCSSProperty_opacity);
+  }
 }
 
 bool
 nsIFrame::IsSVGTransformed(gfx::Matrix *aOwnTransforms,
                            gfx::Matrix *aFromParentTransforms) const
 {
   return false;
 }
@@ -2966,17 +2974,17 @@ nsIFrame::BuildDisplayListForStackingCon
   // We build an opacity item if it's not going to be drawn by SVG content, or
   // SVG effects. SVG effects won't handle the opacity if we want an active
   // layer (for async animations), see
   // nsSVGIntegrationsUtils::PaintMaskAndClipPath or
   // nsSVGIntegrationsUtils::PaintFilter.
   // Use MayNeedActiveLayer to decide, since we don't want to condition the wrapping
   // display item on values that might change silently between paints (opacity activity
   // can depend on the will-change budget).
-  bool useOpacity = HasVisualOpacity(effectSet) &&
+  bool useOpacity = MayHaveVisualOpacity(effectSet) &&
                     !nsSVGUtils::CanOptimizeOpacity(this) &&
                     (!usingSVGEffects || nsDisplayOpacity::MayNeedActiveLayer(this));
   bool useBlendMode = effects->mMixBlendMode != NS_STYLE_BLEND_NORMAL;
   bool useStickyPosition = disp->mPosition == NS_STYLE_POSITION_STICKY &&
     IsScrollFrameActive(aBuilder,
                         nsLayoutUtils::GetNearestScrollableFrame(GetParent(),
                         nsLayoutUtils::SCROLLABLE_SAME_DOC |
                         nsLayoutUtils::SCROLLABLE_INCLUDE_HIDDEN));
--- a/layout/generic/nsIFrame.h
+++ b/layout/generic/nsIFrame.h
@@ -1788,16 +1788,21 @@ public:
   bool HasVisualOpacity(mozilla::EffectSet* aEffectSet = nullptr) const
   {
     // Treat an opacity value of 0.99 and above as opaque.  This is an
     // optimization aimed at Web content which use opacity:0.99 as a hint for
     // creating a stacking context only.
     return HasOpacityInternal(0.99f, aEffectSet);
   }
 
+  bool MayHaveVisualOpacity(mozilla::EffectSet* aEffectSet = nullptr) const
+  {
+    return HasOpacityInternal(0.99f, aEffectSet, /* aMaybe = */ true);
+  }
+
    /**
    * Return true if this frame might be using a transform getter.
    */
   virtual bool HasTransformGetter() const { return false; }
 
   /**
    * Returns true if this frame is an SVG frame that has SVG transforms applied
    * to it, or if its parent frame is an SVG frame that has children-only
@@ -4485,17 +4490,18 @@ private:
   // Helper-functions for SortFrameList():
   template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
   static nsIFrame* SortedMerge(nsIFrame *aLeft, nsIFrame *aRight);
 
   template<bool IsLessThanOrEqual(nsIFrame*, nsIFrame*)>
   static nsIFrame* MergeSort(nsIFrame *aSource);
 
   bool HasOpacityInternal(float aThreshold,
-                          mozilla::EffectSet* aEffectSet = nullptr) const;
+                          mozilla::EffectSet* aEffectSet = nullptr,
+                          bool aMaybe = false) const;
 
   // Maps mClass to LayoutFrameType.
   static const mozilla::LayoutFrameType sLayoutFrameTypes[
 #define FRAME_ID(...) 1 +
 #define ABSTRACT_FRAME_ID(...)
 #include "nsFrameIdList.h"
 #undef FRAME_ID
 #undef ABSTRACT_FRAME_ID