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
--- 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