Bug 1261754 - Part 11: Move opacity from nsStyleDisplay to nsStyleEffects. r=dholbert
authorCameron McCormack <cam@mcc.id.au>
Tue, 12 Apr 2016 15:52:43 +1000
changeset 330640 62a953a61527cc01d5f6bd2c1175a823b117e097
parent 330639 5d69c89223a5f157d80d747f0ddcd66a75ce0866
child 330641 ada58caa17b4f4c5788b89ff28787ff5a774089f
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1261754
milestone48.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 1261754 - Part 11: Move opacity from nsStyleDisplay to nsStyleEffects. r=dholbert
accessible/base/nsAccessiblePivot.cpp
accessible/generic/Accessible.cpp
layout/base/nsDisplayList.cpp
layout/base/nsLayoutUtils.cpp
layout/generic/nsFrame.cpp
layout/style/nsCSSPropList.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsRuleNode.cpp
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/svg/nsSVGContainerFrame.cpp
layout/svg/nsSVGImageFrame.cpp
layout/svg/nsSVGIntegrationUtils.cpp
layout/svg/nsSVGPathGeometryFrame.cpp
layout/svg/nsSVGSwitchFrame.cpp
layout/svg/nsSVGUtils.cpp
layout/xul/tree/nsTreeBodyFrame.cpp
--- a/accessible/base/nsAccessiblePivot.cpp
+++ b/accessible/base/nsAccessiblePivot.cpp
@@ -896,17 +896,17 @@ RuleCache::ApplyFilter(Accessible* aAcce
         *aResult |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
         return NS_OK;
       }
     }
 
     if ((nsIAccessibleTraversalRule::PREFILTER_TRANSPARENT & mPreFilter) &&
         !(state & states::OPAQUE1)) {
       nsIFrame* frame = aAccessible->GetFrame();
-      if (frame->StyleDisplay()->mOpacity == 0.0f) {
+      if (frame->StyleEffects()->mOpacity == 0.0f) {
         *aResult |= nsIAccessibleTraversalRule::FILTER_IGNORE_SUBTREE;
         return NS_OK;
       }
     }
   }
 
   if (mAcceptRolesLength > 0) {
     uint32_t accessibleRole = aAccessible->Role();
--- a/accessible/generic/Accessible.cpp
+++ b/accessible/generic/Accessible.cpp
@@ -1200,18 +1200,17 @@ Accessible::State()
     state |= states::EXPANDABLE;
 
   // For some reasons DOM node may have not a frame. We tract such accessibles
   // as invisible.
   nsIFrame *frame = GetFrame();
   if (!frame)
     return state;
 
-  const nsStyleDisplay* display = frame->StyleDisplay();
-  if (display && display->mOpacity == 1.0f &&
+  if (frame->StyleEffects()->mOpacity == 1.0f &&
       !(state & states::INVISIBLE)) {
     state |= states::OPAQUE1;
   }
 
   return state;
 }
 
 void
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -1519,17 +1519,17 @@ TreatAsOpaque(nsDisplayItem* aItem, nsDi
     // effectively ignored, as it should be.
     // We treat leaf chrome items as opaque to ensure that they cover
     // content plugins, for security reasons.
     // Non-leaf chrome items don't render contents of their own so shouldn't
     // be treated as opaque (and their bounds is just the union of their
     // children, which might be a large area their contents don't really cover).
     nsIFrame* f = aItem->Frame();
     if (f->PresContext()->IsChrome() && !aItem->GetChildren() &&
-        f->StyleDisplay()->mOpacity != 0.0) {
+        f->StyleEffects()->mOpacity != 0.0) {
       opaque = aItem->GetBounds(aBuilder, &snap);
     }
   }
   if (opaque.IsEmpty()) {
     return opaque;
   }
   nsRegion opaqueClipped;
   for (auto iter = opaque.RectIter(); !iter.Done(); iter.Next()) {
@@ -4165,17 +4165,17 @@ nsresult nsDisplayWrapper::WrapListsInPl
   return WrapEachDisplayItem(aBuilder, aLists.Outlines(), this);
 }
 
 nsDisplayOpacity::nsDisplayOpacity(nsDisplayListBuilder* aBuilder,
                                    nsIFrame* aFrame, nsDisplayList* aList,
                                    const DisplayItemScrollClip* aScrollClip,
                                    bool aForEventsOnly)
     : nsDisplayWrapList(aBuilder, aFrame, aList, aScrollClip)
-    , mOpacity(aFrame->StyleDisplay()->mOpacity)
+    , mOpacity(aFrame->StyleEffects()->mOpacity)
     , mForEventsOnly(aForEventsOnly)
     , mParticipatesInPreserve3D(false)
 {
   MOZ_COUNT_CTOR(nsDisplayOpacity);
 }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
 nsDisplayOpacity::~nsDisplayOpacity() {
@@ -6563,17 +6563,17 @@ nsDisplaySVGEffects::BuildLayer(nsDispla
       NS_ASSERTION(false, "why?");
       return nullptr;
     }
     if (!static_cast<const nsSVGElement*>(content)->HasValidDimensions()) {
       return nullptr; // The SVG spec says not to draw filters for this
     }
   }
 
-  float opacity = mFrame->StyleDisplay()->mOpacity;
+  float opacity = mFrame->StyleEffects()->mOpacity;
   if (opacity == 0.0f)
     return nullptr;
 
   nsIFrame* firstFrame =
     nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
   nsSVGEffects::EffectProperties effectProperties =
     nsSVGEffects::GetEffectProperties(firstFrame);
 
@@ -6673,19 +6673,19 @@ nsDisplaySVGEffects::PrintEffects(nsACSt
   nsIFrame* firstFrame =
     nsLayoutUtils::FirstContinuationOrIBSplitSibling(mFrame);
   nsSVGEffects::EffectProperties effectProperties =
     nsSVGEffects::GetEffectProperties(firstFrame);
   bool isOK = true;
   nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
   bool first = true;
   aTo += " effects=(";
-  if (mFrame->StyleDisplay()->mOpacity != 1.0f) {
+  if (mFrame->StyleEffects()->mOpacity != 1.0f) {
     first = false;
-    aTo += nsPrintfCString("opacity(%f)", mFrame->StyleDisplay()->mOpacity);
+    aTo += nsPrintfCString("opacity(%f)", mFrame->StyleEffects()->mOpacity);
   }
   if (clipPathFrame) {
     if (!first) {
       aTo += ", ";
     }
     aTo += nsPrintfCString("clip(%s)", clipPathFrame->IsTrivial() ? "trivial" : "non-trivial");
     first = false;
   }
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -6864,17 +6864,17 @@ nsLayoutUtils::HasNonZeroCornerOnSide(co
       return true;
   }
   return false;
 }
 
 /* static */ nsTransparencyMode
 nsLayoutUtils::GetFrameTransparency(nsIFrame* aBackgroundFrame,
                                     nsIFrame* aCSSRootFrame) {
-  if (aCSSRootFrame->StyleDisplay()->mOpacity < 1.0f)
+  if (aCSSRootFrame->StyleEffects()->mOpacity < 1.0f)
     return eTransparencyTransparent;
 
   if (HasNonZeroCorner(aCSSRootFrame->StyleBorder()->mBorderRadius))
     return eTransparencyTransparent;
 
   if (aCSSRootFrame->StyleDisplay()->mAppearance == NS_THEME_WIN_GLASS)
     return eTransparencyGlass;
 
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1148,19 +1148,18 @@ nsIFrame::IsTransformed() const
             IsFrameOfType(eSupportsCSSTransforms) &&
             mContent->GetPrimaryFrame() == this)));
 }
 
 bool
 nsIFrame::HasOpacityInternal(float aThreshold) const
 {
   MOZ_ASSERT(0.0 <= aThreshold && aThreshold <= 1.0, "Invalid argument");
-  const nsStyleDisplay* displayStyle = StyleDisplay();
-  return StyleDisplay()->mOpacity < aThreshold ||
-         (displayStyle->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) ||
+  return StyleEffects()->mOpacity < aThreshold ||
+         (StyleDisplay()->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) ||
          (mContent &&
            EffectCompositor::HasAnimationsForCompositor(
              this, eCSSProperty_opacity) &&
            mContent->GetPrimaryFrame() == this);
 }
 
 bool
 nsIFrame::IsSVGTransformed(gfx::Matrix *aOwnTransforms,
@@ -2143,26 +2142,27 @@ nsIFrame::BuildDisplayListForStackingCon
     return;
 
   // Replaced elements have their visibility handled here, because
   // they're visually atomic
   if (IsFrameOfType(eReplaced) && !IsVisibleForPainting(aBuilder))
     return;
 
   const nsStyleDisplay* disp = StyleDisplay();
+  const nsStyleEffects* effects = StyleEffects();
   // We can stop right away if this is a zero-opacity stacking context and
   // we're painting, and we're not animating opacity. Don't do this
   // if we're going to compute plugin geometry, since opacity-0 plugins
   // need to have display items built for them.
   bool needEventRegions =
     aBuilder->IsBuildingLayerEventRegions() &&
     StyleUserInterface()->GetEffectivePointerEvents(this) !=
       NS_STYLE_POINTER_EVENTS_NONE;
   bool opacityItemForEventsOnly = false;
-  if (disp->mOpacity == 0.0 && aBuilder->IsForPainting() &&
+  if (effects->mOpacity == 0.0 && aBuilder->IsForPainting() &&
       !aBuilder->WillComputePluginGeometry() &&
       !(disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_OPACITY) &&
       !nsLayoutUtils::HasCurrentAnimationOfProperty(this,
                                                     eCSSProperty_opacity)) {
     if (needEventRegions) {
       opacityItemForEventsOnly = true;
     } else {
       return;
@@ -2230,17 +2230,16 @@ nsIFrame::BuildDisplayListForStackingCon
   nsRect dirtyRectOutsideSVGEffects = dirtyRect;
   nsDisplayList hoistedScrollInfoItemsStorage;
   if (usingSVGEffects) {
     dirtyRect =
       nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(this, dirtyRect);
     aBuilder->EnterSVGEffectsContents(&hoistedScrollInfoItemsStorage);
   }
 
-  const nsStyleEffects* effects = StyleEffects();
   bool useOpacity = HasVisualOpacity() && !nsSVGUtils::CanOptimizeOpacity(this) && !usingSVGEffects;
   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));
   bool useFixedPosition = nsLayoutUtils::IsFixedPosFrameInDisplayPort(this);
@@ -9299,21 +9298,23 @@ nsIFrame::DestroyContentArray(ContentArr
     content->UnbindFromTree();
     NS_RELEASE(content);
   }
   delete aArray;
 }
 
 bool
 nsIFrame::IsPseudoStackingContextFromStyle() {
-  const nsStyleDisplay* disp = StyleDisplay();
   // If you change this, also change the computation of pseudoStackingContext
   // in BuildDisplayListForChild()
-  return disp->mOpacity != 1.0f ||
-         disp->IsAbsPosContainingBlock(this) ||
+  if (StyleEffects()->mOpacity != 1.0f) {
+    return true;
+  }
+  const nsStyleDisplay* disp = StyleDisplay();
+  return disp->IsAbsPosContainingBlock(this) ||
          disp->IsFloating(this) ||
          (disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT);
 }
 
 Element*
 nsIFrame::GetPseudoElement(CSSPseudoElementType aType)
 {
   nsIFrame* frame = nullptr;
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -2726,28 +2726,28 @@ CSS_PROP_LOGICAL(
         CSS_PROPERTY_LOGICAL,
     "layout.css.vertical-text.enabled",
     VARIANT_AHLP | VARIANT_CALC,
     nullptr,
     Offset,
     Position,
     CSS_PROP_NO_OFFSET,
     eStyleAnimType_None)
-CSS_PROP_DISPLAY(
+CSS_PROP_EFFECTS(
     opacity,
     opacity,
     Opacity,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
         CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR |
         CSS_PROPERTY_CREATES_STACKING_CONTEXT,
     "",
     VARIANT_HN,
     nullptr,
-    offsetof(nsStyleDisplay, mOpacity),
+    offsetof(nsStyleEffects, mOpacity),
     eStyleAnimType_float)
 CSS_PROP_DISPLAY(
     -moz-orient,
     orient,
     CSS_PROP_DOMPROP_PREFIXED(Orient),
     CSS_PROPERTY_PARSE_VALUE,
     "",
     VARIANT_HK,
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -988,17 +988,17 @@ nsComputedDOMStyle::DoGetColorAdjust()
                                    nsCSSProps::kColorAdjustKTable));
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetOpacity()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-  val->SetNumber(StyleDisplay()->mOpacity);
+  val->SetNumber(StyleEffects()->mOpacity);
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetColumnCount()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -5625,21 +5625,16 @@ nsRuleNode::ComputeDisplayData(void* aSt
       // until we're out of animations to populate
       if (d.list) {
         d.list = d.list->mNext ? d.list->mNext :
           aRuleData->ValueFor(info.property)->GetListValue();
       }
     }
   }
 
-  // opacity: factor, inherit, initial
-  SetFactor(*aRuleData->ValueForOpacity(), display->mOpacity, conditions,
-            parentDisplay->mOpacity, 1.0f,
-            SETFCT_OPACITY | SETFCT_UNSET_INITIAL);
-
   // display: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForDisplay(), display->mDisplay, conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentDisplay->mDisplay,
               NS_STYLE_DISPLAY_INLINE, 0, 0, 0, 0);
 
   // contain: none, enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForContain(), display->mContain, conditions,
@@ -10020,16 +10015,21 @@ nsRuleNode::ComputeEffectsData(void* aSt
     }
     break;
   }
 
   default:
     MOZ_ASSERT(false, "unrecognized clip unit");
   }
 
+  // opacity: factor, inherit, initial
+  SetFactor(*aRuleData->ValueForOpacity(), effects->mOpacity, conditions,
+            parentEffects->mOpacity, 1.0f,
+            SETFCT_OPACITY | SETFCT_UNSET_INITIAL);
+
   // mix-blend-mode: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForMixBlendMode(), effects->mMixBlendMode,
               conditions,
               SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
               parentEffects->mMixBlendMode, NS_STYLE_BLEND_NORMAL,
               0, 0, 0, 0);
 
   COMPUTE_END_RESET(Effects, effects)
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -2866,17 +2866,16 @@ nsStyleDisplay::nsStyleDisplay(StyleStru
   mBreakType = NS_STYLE_CLEAR_NONE;
   mBreakInside = NS_STYLE_PAGE_BREAK_AUTO;
   mBreakBefore = false;
   mBreakAfter = false;
   mOverflowX = NS_STYLE_OVERFLOW_VISIBLE;
   mOverflowY = NS_STYLE_OVERFLOW_VISIBLE;
   mOverflowClipBox = NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX;
   mResize = NS_STYLE_RESIZE_NONE;
-  mOpacity = 1.0f;
   mSpecifiedTransform = nullptr;
   mTransformOrigin[0].SetPercentValue(0.5f); // Transform is centered on origin
   mTransformOrigin[1].SetPercentValue(0.5f);
   mTransformOrigin[2].SetCoordValue(0);
   mPerspectiveOrigin[0].SetPercentValue(0.5f);
   mPerspectiveOrigin[1].SetPercentValue(0.5f);
   mChildPerspective.SetNoneValue();
   mVerticalAlign.SetIntValue(NS_STYLE_VERTICAL_ALIGN_BASELINE, eStyleUnit_Enumerated);
@@ -2915,17 +2914,16 @@ nsStyleDisplay::nsStyleDisplay(StyleStru
   mAnimationDirectionCount = 1;
   mAnimationFillModeCount = 1;
   mAnimationPlayStateCount = 1;
   mAnimationIterationCountCount = 1;
 }
 
 nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource)
   : mBinding(aSource.mBinding)
-  , mOpacity(aSource.mOpacity)
   , mDisplay(aSource.mDisplay)
   , mOriginalDisplay(aSource.mOriginalDisplay)
   , mContain(aSource.mContain)
   , mAppearance(aSource.mAppearance)
   , mPosition(aSource.mPosition)
   , mFloats(aSource.mFloats)
   , mOriginalFloats(aSource.mOriginalFloats)
   , mBreakType(aSource.mBreakType)
@@ -3047,31 +3045,16 @@ nsChangeHint nsStyleDisplay::CalcDiffere
       || mBreakBefore != aOther.mBreakBefore
       || mBreakAfter != aOther.mBreakAfter
       || mAppearance != aOther.mAppearance
       || mOrient != aOther.mOrient
       || mOverflowClipBox != aOther.mOverflowClipBox)
     NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_AllReflowHints,
                                        nsChangeHint_RepaintFrame));
 
-  if (mOpacity != aOther.mOpacity) {
-    // If we're going from the optimized >=0.99 opacity value to 1.0 or back, then
-    // repaint the frame because DLBI will not catch the invalidation.  Otherwise,
-    // just update the opacity layer.
-    if ((mOpacity >= 0.99f && mOpacity < 1.0f && aOther.mOpacity == 1.0f) ||
-        (aOther.mOpacity >= 0.99f && aOther.mOpacity < 1.0f && mOpacity == 1.0f)) {
-      NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
-    } else {
-      NS_UpdateHint(hint, nsChangeHint_UpdateOpacityLayer);
-      if ((mOpacity == 1.0f) != (aOther.mOpacity == 1.0f)) {
-        NS_UpdateHint(hint, nsChangeHint_UpdateUsesOpacity);
-      }
-    }
-  }
-
   if (mIsolation != aOther.mIsolation) {
     NS_UpdateHint(hint, nsChangeHint_RepaintFrame);
   }
 
   /* If we've added or removed the transform property, we need to reconstruct the frame to add
    * or remove the view object, and also to handle abs-pos and fixed-pos containers.
    */
   if (HasTransformStyle() != aOther.HasTransformStyle()) {
@@ -3980,25 +3963,27 @@ nsStyleVariables::CalcDifference(const n
 
 //-----------------------
 // nsStyleEffects
 //
 
 nsStyleEffects::nsStyleEffects(StyleStructContext aContext)
   : mBoxShadow(nullptr)
   , mClip(0, 0, 0, 0)
+  , mOpacity(1.0f)
   , mClipFlags(NS_STYLE_CLIP_AUTO)
   , mMixBlendMode(NS_STYLE_BLEND_NORMAL)
 {
   MOZ_COUNT_CTOR(nsStyleEffects);
 }
 
 nsStyleEffects::nsStyleEffects(const nsStyleEffects& aSource)
   : mBoxShadow(aSource.mBoxShadow)
   , mClip(aSource.mClip)
+  , mOpacity(aSource.mOpacity)
   , mClipFlags(aSource.mClipFlags)
   , mMixBlendMode(aSource.mMixBlendMode)
 {
   MOZ_COUNT_CTOR(nsStyleEffects);
 }
 
 nsStyleEffects::~nsStyleEffects()
 {
@@ -4027,16 +4012,31 @@ nsStyleEffects::CalcDifference(const nsS
 
   if (!mClip.IsEqualInterior(aOther.mClip)) {
     // If the clip has changed, we just need to update overflow areas. DLBI
     // will handle the invalidation.
     hint |= nsChangeHint_UpdateOverflow |
             nsChangeHint_SchedulePaint;
   }
 
+  if (mOpacity != aOther.mOpacity) {
+    // If we're going from the optimized >=0.99 opacity value to 1.0 or back, then
+    // repaint the frame because DLBI will not catch the invalidation.  Otherwise,
+    // just update the opacity layer.
+    if ((mOpacity >= 0.99f && mOpacity < 1.0f && aOther.mOpacity == 1.0f) ||
+        (aOther.mOpacity >= 0.99f && aOther.mOpacity < 1.0f && mOpacity == 1.0f)) {
+      hint |= nsChangeHint_RepaintFrame;
+    } else {
+      hint |= nsChangeHint_UpdateOpacityLayer;
+      if ((mOpacity == 1.0f) != (aOther.mOpacity == 1.0f)) {
+        hint |= nsChangeHint_UpdateUsesOpacity;
+      }
+    }
+  }
+
   if (mMixBlendMode != aOther.mMixBlendMode) {
     hint |= nsChangeHint_RepaintFrame;
   }
 
   if (!hint &&
       !mClip.IsEqualEdges(aOther.mClip)) {
     hint |= nsChangeHint_NeutralChange;
   }
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -2438,18 +2438,16 @@ struct nsStyleDisplay
     aContext->PresShell()->
       FreeByObjectID(mozilla::eArenaObjectID_nsStyleDisplay, this);
   }
 
   nsChangeHint CalcDifference(const nsStyleDisplay& aOther) const;
   static nsChangeHint MaxDifference() {
     // All the parts of FRAMECHANGE are present in CalcDifference.
     return nsChangeHint(NS_STYLE_HINT_FRAMECHANGE |
-                        nsChangeHint_UpdateOpacityLayer |
-                        nsChangeHint_UpdateUsesOpacity |
                         nsChangeHint_UpdateTransformLayer |
                         nsChangeHint_UpdateOverflow |
                         nsChangeHint_UpdatePostTransformOverflow |
                         nsChangeHint_UpdateContainingBlock |
                         nsChangeHint_NeutralChange);
   }
   static nsChangeHint DifferenceAlwaysHandledForDescendants() {
     // CalcDifference can return all of the reflow hints that are
@@ -2461,17 +2459,16 @@ struct nsStyleDisplay
   // XXXdholbert, XXXkgilbert nsStyleImageLayers::Position should probably be
   // moved to a different scope, since we're now using it in multiple style
   // structs.
   typedef nsStyleImageLayers::Position Position;
 
   // We guarantee that if mBinding is non-null, so are mBinding->GetURI() and
   // mBinding->mOriginPrincipal.
   RefPtr<mozilla::css::URLValue> mBinding;    // [reset]
-  float   mOpacity;             // [reset]
   uint8_t mDisplay;             // [reset] see nsStyleConsts.h NS_STYLE_DISPLAY_*
   uint8_t mOriginalDisplay;     // [reset] saved mDisplay for position:absolute/fixed
                                 //         and float:left/right; otherwise equal
                                 //         to mDisplay
   uint8_t mContain;             // [reset] see nsStyleConsts.h NS_STYLE_CONTAIN_*
   uint8_t mAppearance;          // [reset]
   uint8_t mPosition;            // [reset] see nsStyleConsts.h
   uint8_t mFloats;              // [reset] see nsStyleConsts.h NS_STYLE_FLOAT_*
@@ -3579,25 +3576,28 @@ struct nsStyleEffects
   }
 
   nsChangeHint CalcDifference(const nsStyleEffects& aOther) const;
   static nsChangeHint MaxDifference() {
     return nsChangeHint_AllReflowHints |
            nsChangeHint_UpdateOverflow |
            nsChangeHint_SchedulePaint |
            nsChangeHint_RepaintFrame |
+           nsChangeHint_UpdateOpacityLayer |
+           nsChangeHint_UpdateUsesOpacity |
            nsChangeHint_NeutralChange;
   }
   static nsChangeHint DifferenceAlwaysHandledForDescendants() {
     // CalcDifference never returns the reflow hints that are sometimes
     // handled for descendants as hints not handled for descendants.
     return nsChangeHint_NeedReflow |
            nsChangeHint_ReflowChangesSizeOrPosition |
            nsChangeHint_ClearAncestorIntrinsics;
   }
 
   RefPtr<nsCSSShadowArray> mBoxShadow; // [reset] nullptr for 'none'
-  nsRect mClip;                        // [reset] offsets from UL border edge
+  nsRect  mClip;                       // [reset] offsets from UL border edge
+  float   mOpacity;                    // [reset]
   uint8_t mClipFlags;                  // [reset] see nsStyleConsts.h
   uint8_t mMixBlendMode;               // [reset] see nsStyleConsts.h
 };
 
 #endif /* nsStyleStruct_h___ */
--- a/layout/svg/nsSVGContainerFrame.cpp
+++ b/layout/svg/nsSVGContainerFrame.cpp
@@ -254,18 +254,17 @@ nsSVGDisplayContainerFrame::PaintSVG(gfx
                                      const nsIntRect *aDirtyRect)
 {
   NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
                (mState & NS_FRAME_IS_NONDISPLAY) ||
                PresContext()->IsGlyph(),
                "If display lists are enabled, only painting of non-display "
                "SVG should take this code path");
 
-  const nsStyleDisplay *display = StyleDisplay();
-  if (display->mOpacity == 0.0) {
+  if (StyleEffects()->mOpacity == 0.0) {
     return NS_OK;
   }
 
   gfxMatrix matrix = aTransform;
   if (GetContent()->IsSVGElement()) { // must check before cast
     matrix = static_cast<const nsSVGElement*>(GetContent())->
                PrependLocalTransformsTo(matrix, eChildToUserSpace);
     if (matrix.IsSingular()) {
--- a/layout/svg/nsSVGImageFrame.cpp
+++ b/layout/svg/nsSVGImageFrame.cpp
@@ -361,17 +361,17 @@ nsSVGImageFrame::PaintSVG(gfxContext& aC
       return NS_ERROR_FAILURE;
     }
 
     // fill-opacity doesn't affect <image>, so if we're allowed to
     // optimize group opacity, the opacity used for compositing the
     // image into the current canvas is just the group opacity.
     float opacity = 1.0f;
     if (nsSVGUtils::CanOptimizeOpacity(this)) {
-      opacity = StyleDisplay()->mOpacity;
+      opacity = StyleEffects()->mOpacity;
     }
 
     if (opacity != 1.0f || StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
       aContext.PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, opacity);
     }
 
     nscoord appUnitsPerDevPx = PresContext()->AppUnitsPerDevPixel();
     nsRect dirtyRect; // only used if aDirtyRect is non-null
--- a/layout/svg/nsSVGIntegrationUtils.cpp
+++ b/layout/svg/nsSVGIntegrationUtils.cpp
@@ -446,17 +446,17 @@ nsSVGIntegrationUtils::PaintFramesWithEf
       NS_ASSERTION(false, "why?");
       return;
     }
     if (!static_cast<const nsSVGElement*>(content)->HasValidDimensions()) {
       return; // The SVG spec says not to draw _anything_
     }
   }
 
-  float opacity = aFrame->StyleDisplay()->mOpacity;
+  float opacity = aFrame->StyleEffects()->mOpacity;
   if (opacity == 0.0f) {
     return;
   }
   if (opacity != 1.0f &&
       hasSVGLayout && nsSVGUtils::CanOptimizeOpacity(aFrame)) {
     opacity = 1.0f;
   }
 
--- a/layout/svg/nsSVGPathGeometryFrame.cpp
+++ b/layout/svg/nsSVGPathGeometryFrame.cpp
@@ -148,19 +148,19 @@ nsSVGPathGeometryFrame::AttributeChanged
 }
 
 /* virtual */ void
 nsSVGPathGeometryFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
 {
   nsSVGPathGeometryFrameBase::DidSetStyleContext(aOldStyleContext);
 
   if (aOldStyleContext) {
-    auto oldStyleDisplay = aOldStyleContext->PeekStyleDisplay();
-    if (oldStyleDisplay &&
-        StyleDisplay()->mOpacity != oldStyleDisplay->mOpacity &&
+    auto oldStyleEffects = aOldStyleContext->PeekStyleEffects();
+    if (oldStyleEffects &&
+        StyleEffects()->mOpacity != oldStyleEffects->mOpacity &&
         nsSVGUtils::CanOptimizeOpacity(this)) {
       // nsIFrame::BuildDisplayListForStackingContext() is not going to create an
       // nsDisplayOpacity display list item, so DLBI won't invalidate for us.
       InvalidateFrame();
     }
 
     nsSVGPathGeometryElement* element =
       static_cast<nsSVGPathGeometryElement*>(mContent);
--- a/layout/svg/nsSVGSwitchFrame.cpp
+++ b/layout/svg/nsSVGSwitchFrame.cpp
@@ -109,17 +109,17 @@ nsSVGSwitchFrame::PaintSVG(gfxContext& a
                            const gfxMatrix& aTransform,
                            const nsIntRect* aDirtyRect)
 {
   NS_ASSERTION(!NS_SVGDisplayListPaintingEnabled() ||
                (mState & NS_FRAME_IS_NONDISPLAY),
                "If display lists are enabled, only painting of non-display "
                "SVG should take this code path");
 
-  if (StyleDisplay()->mOpacity == 0.0)
+  if (StyleEffects()->mOpacity == 0.0)
     return NS_OK;
 
   nsIFrame *kid = GetActiveChildFrame();
   if (kid) {
     gfxMatrix tm = aTransform;
     if (kid->GetContent()->IsSVGElement()) {
       tm = static_cast<nsSVGElement*>(kid->GetContent())->
              PrependLocalTransformsTo(tm, eUserSpaceToParent);
--- a/layout/svg/nsSVGUtils.cpp
+++ b/layout/svg/nsSVGUtils.cpp
@@ -496,17 +496,17 @@ nsSVGUtils::PaintFrameWithEffects(nsIFra
                aFrame->PresContext()->IsGlyph(),
                "If display lists are enabled, only painting of non-display "
                "SVG should take this code path");
 
   nsISVGChildFrame *svgChildFrame = do_QueryFrame(aFrame);
   if (!svgChildFrame)
     return;
 
-  float opacity = aFrame->StyleDisplay()->mOpacity;
+  float opacity = aFrame->StyleEffects()->mOpacity;
   if (opacity == 0.0f)
     return;
 
   const nsIContent* content = aFrame->GetContent();
   if (content->IsSVGElement() &&
       !static_cast<const nsSVGElement*>(content)->HasValidDimensions()) {
     return;
   }
@@ -1291,17 +1291,17 @@ nsSVGUtils::GetFallbackOrPaintColor(nsSt
     }
   }
   return color;
 }
 
 static float
 MaybeOptimizeOpacity(nsIFrame *aFrame, float aFillOrStrokeOpacity)
 {
-  float opacity = aFrame->StyleDisplay()->mOpacity;
+  float opacity = aFrame->StyleEffects()->mOpacity;
   if (opacity < 1 && nsSVGUtils::CanOptimizeOpacity(aFrame)) {
     return aFillOrStrokeOpacity * opacity;
   }
   return aFillOrStrokeOpacity;
 }
 
 /* static */ void
 nsSVGUtils::MakeFillPatternFor(nsIFrame* aFrame,
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -3512,17 +3512,17 @@ nsTreeBodyFrame::PaintImage(int32_t     
   NS_PRECONDITION(aColumn && aColumn->GetFrame(), "invalid column passed");
 
   bool isRTL = StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
   nscoord rightEdge = aCurrX + aRemainingWidth;
   // Resolve style for the image.
   nsStyleContext* imageContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreeimage);
 
   // Obtain opacity value for the image.
-  float opacity = imageContext->StyleDisplay()->mOpacity;
+  float opacity = imageContext->StyleEffects()->mOpacity;
 
   // Obtain the margins for the image and then deflate our rect by that
   // amount.  The image is assumed to be contained within the deflated rect.
   nsRect imageRect(aImageRect);
   nsMargin imageMargin;
   imageContext->StyleMargin()->GetMargin(imageMargin);
   imageRect.Deflate(imageMargin);
 
@@ -3710,17 +3710,17 @@ nsTreeBodyFrame::PaintText(int32_t      
   int32_t appUnitsPerDevPixel = PresContext()->AppUnitsPerDevPixel();
   DrawTarget* drawTarget = aRenderingContext.GetDrawTarget();
 
   // Resolve style for the text.  It contains all the info we need to lay ourselves
   // out and to paint.
   nsStyleContext* textContext = GetPseudoStyleContext(nsCSSAnonBoxes::moztreecelltext);
 
   // Obtain opacity value for the image.
-  float opacity = textContext->StyleDisplay()->mOpacity;
+  float opacity = textContext->StyleEffects()->mOpacity;
 
   // Obtain the margins for the text and then deflate our rect by that 
   // amount.  The text is assumed to be contained within the deflated rect.
   nsRect textRect(aTextRect);
   nsMargin textMargin;
   textContext->StyleMargin()->GetMargin(textMargin);
   textRect.Deflate(textMargin);