Bug 1413397 - Avoid empty border's fallback. r=kats
authorEthan Lin <ethlin@mozilla.com>
Wed, 01 Nov 2017 17:30:04 +0800
changeset 443228 a16aef250227226e3abe41cf0e835fdbb57ded13
parent 443227 2c77266e1b40c7a67901de4c3ccca2554422da4a
child 443229 9ee2bbdb739021cf352e4cac630d0bdd596b6c33
push id1618
push userCallek@gmail.com
push dateThu, 11 Jan 2018 17:45:48 +0000
treeherdermozilla-release@882ca853e05a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats
bugs1413397
milestone58.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 1413397 - Avoid empty border's fallback. r=kats MozReview-Commit-ID: 1KXYjcObJdi
layout/forms/nsButtonFrameRenderer.cpp
layout/forms/nsButtonFrameRenderer.h
layout/generic/nsColumnSetFrame.cpp
layout/mathml/nsMathMLmtableFrame.cpp
layout/painting/nsCSSRendering.cpp
layout/painting/nsCSSRendering.h
layout/painting/nsDisplayList.cpp
layout/painting/nsDisplayList.h
--- a/layout/forms/nsButtonFrameRenderer.cpp
+++ b/layout/forms/nsButtonFrameRenderer.cpp
@@ -325,18 +325,18 @@ nsDisplayButtonBorder::GetLayerState(nsD
     mBorderIsEmpty = false;
     Maybe<nsCSSBorderRenderer> br =
     nsCSSRendering::CreateBorderRenderer(mFrame->PresContext(),
                                          nullptr,
                                          mFrame,
                                          nsRect(),
                                          nsRect(offset, mFrame->GetSize()),
                                          mFrame->StyleContext(),
-                                         mFrame->GetSkipSides(),
-                                         &mBorderIsEmpty);
+                                         &mBorderIsEmpty,
+                                         mFrame->GetSkipSides());
     if (!br) {
       if (mBorderIsEmpty) {
         return LAYER_ACTIVE;
       }
       return LAYER_NONE;
     }
 
     if (!br->CanCreateWebRenderCommands()) {
@@ -515,18 +515,23 @@ nsDisplayButtonForeground::GetLayerState
 {
   Maybe<nsCSSBorderRenderer> br;
 
   if (ShouldUseAdvancedLayer(aManager, gfxPrefs::LayersAllowButtonForegroundLayers)) {
     nsPresContext *presContext = mFrame->PresContext();
     const nsStyleDisplay *disp = mFrame->StyleDisplay();
     if (!mFrame->IsThemed(disp) ||
         !presContext->GetTheme()->ThemeDrawsFocusForWidget(disp->mAppearance)) {
+      bool borderIsEmpty = false;
       nsRect r = nsRect(ToReferenceFrame(), mFrame->GetSize());
-      br = mBFR->CreateInnerFocusBorderRenderer(aBuilder, presContext, nullptr, mVisibleRect, r);
+      br = mBFR->CreateInnerFocusBorderRenderer(aBuilder, presContext, nullptr,
+                                                mVisibleRect, r, &borderIsEmpty);
+      if (borderIsEmpty) {
+        return LAYER_ACTIVE;
+      }
     }
   }
 
   if (!br || !br->CanCreateWebRenderCommands()) {
     return LAYER_NONE;
   }
 
   mBorderRenderer = br;
@@ -549,16 +554,21 @@ nsDisplayButtonForeground::CreateWebRend
                                                    mozilla::layers::WebRenderLayerManager* aManager,
                                                    nsDisplayListBuilder* aDisplayListBuilder)
 {
   ContainerLayerParameters parameter;
   if (GetLayerState(aDisplayListBuilder, aManager, parameter) != LAYER_ACTIVE) {
     return false;
   }
 
+  // empty border, nothing to do
+  if (!mBorderRenderer) {
+    return true;
+  }
+
   mBorderRenderer->CreateWebRenderCommands(this, aBuilder, aResources, aSc);
   return true;
 }
 
 nsresult
 nsButtonFrameRenderer::DisplayButton(nsDisplayListBuilder* aBuilder,
                                      nsDisplayList* aBackground,
                                      nsDisplayList* aForeground)
@@ -629,29 +639,31 @@ nsButtonFrameRenderer::PaintInnerFocusBo
 }
 
 Maybe<nsCSSBorderRenderer>
 nsButtonFrameRenderer::CreateInnerFocusBorderRenderer(
   nsDisplayListBuilder* aBuilder,
   nsPresContext* aPresContext,
   gfxContext* aRenderingContext,
   const nsRect& aDirtyRect,
-  const nsRect& aRect)
+  const nsRect& aRect,
+  bool* aBorderIsEmpty)
 {
   if (mInnerFocusStyle) {
     nsRect rect;
     GetButtonInnerFocusRect(aRect, rect);
 
     gfx::DrawTarget* dt = aRenderingContext ? aRenderingContext->GetDrawTarget() : nullptr;
     return nsCSSRendering::CreateBorderRenderer(aPresContext,
                                                 dt,
                                                 mFrame,
                                                 aDirtyRect,
                                                 rect,
-                                                mInnerFocusStyle);
+                                                mInnerFocusStyle,
+                                                aBorderIsEmpty);
   }
 
   return Nothing();
 }
 
 DrawResult
 nsButtonFrameRenderer::PaintBorder(
   nsDisplayListBuilder* aBuilder,
--- a/layout/forms/nsButtonFrameRenderer.h
+++ b/layout/forms/nsButtonFrameRenderer.h
@@ -44,17 +44,18 @@ public:
                                    gfxContext& aRenderingContext,
                                    const nsRect& aDirtyRect,
                                    const nsRect& aRect);
 
   mozilla::Maybe<nsCSSBorderRenderer> CreateInnerFocusBorderRenderer(nsDisplayListBuilder* aBuilder,
                                                                      nsPresContext* aPresContext,
                                                                      gfxContext* aRenderingContext,
                                                                      const nsRect& aDirtyRect,
-                                                                     const nsRect& aRect);
+                                                                     const nsRect& aRect,
+                                                                     bool* aBorderIsEmpty);
 
   DrawResult PaintBorder(nsDisplayListBuilder* aBuilder,
                          nsPresContext* aPresContext,
                          gfxContext& aRenderingContext,
                          const nsRect& aDirtyRect,
                          const nsRect& aRect);
 
   void SetFrame(nsFrame* aFrame, nsPresContext* aPresContext);
--- a/layout/generic/nsColumnSetFrame.cpp
+++ b/layout/generic/nsColumnSetFrame.cpp
@@ -279,22 +279,26 @@ nsColumnSetFrame::CreateBorderRenderers(
   ForEachColumn([&]
                 (const nsRect& aLineRect)
                 {
                   // Assert that we're not drawing a border-image here; if we were, we
                   // couldn't ignore the DrawResult that PaintBorderWithStyleBorder returns.
                   MOZ_ASSERT(border.mBorderImageSource.GetType() == eStyleImageType_Null);
 
                   gfx::DrawTarget* dt = aCtx ? aCtx->GetDrawTarget() : nullptr;
+                  bool borderIsEmpty = false;
                   Maybe<nsCSSBorderRenderer> br =
                     nsCSSRendering::CreateBorderRendererWithStyleBorder(presContext, dt,
                                                                         this, aDirtyRect,
                                                                         aLineRect, border,
-                                                                        StyleContext(), skipSides);
+                                                                        StyleContext(),
+                                                                        &borderIsEmpty,
+                                                                        skipSides);
                   if (br.isSome()) {
+                    MOZ_ASSERT(!borderIsEmpty);
                     aBorderRenderers.AppendElement(br.value());
                   }
                 }, aPt);
 }
 
 static nscoord
 GetAvailableContentISize(const ReflowInput& aReflowInput)
 {
--- a/layout/mathml/nsMathMLmtableFrame.cpp
+++ b/layout/mathml/nsMathMLmtableFrame.cpp
@@ -326,16 +326,25 @@ public:
                                                  bounds,
                                                  styleBorder,
                                                  mFrame->StyleContext(),
                                                  flags,
                                                  mFrame->GetSkipSides());
 
     nsDisplayItemGenericImageGeometry::UpdateDrawResult(this, result);
   }
+
+  bool CreateWebRenderCommands(mozilla::wr::DisplayListBuilder& aBuilder,
+                               mozilla::wr::IpcResourceUpdateQueue& aResources,
+                               const StackingContextHelper& aSc,
+                               mozilla::layers::WebRenderLayerManager* aManager,
+                               nsDisplayListBuilder* aDisplayListBuilder) override
+  {
+    return false;
+  }
 };
 
 #ifdef DEBUG
 #define DEBUG_VERIFY_THAT_FRAME_IS(_frame, _expected)                              \
   MOZ_ASSERT(mozilla::StyleDisplay::_expected == _frame->StyleDisplay()->mDisplay, \
              "internal error");
 #else
 #define DEBUG_VERIFY_THAT_FRAME_IS(_frame, _expected)
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -662,65 +662,70 @@ nsCSSRendering::PaintBorder(nsPresContex
 
 Maybe<nsCSSBorderRenderer>
 nsCSSRendering::CreateBorderRenderer(nsPresContext* aPresContext,
                                      DrawTarget* aDrawTarget,
                                      nsIFrame* aForFrame,
                                      const nsRect& aDirtyRect,
                                      const nsRect& aBorderArea,
                                      nsStyleContext* aStyleContext,
-                                     Sides aSkipSides,
-                                     bool* aOutBorderIsEmpty)
+                                     bool* aOutBorderIsEmpty,
+                                     Sides aSkipSides)
 {
   nsStyleContext *styleIfVisited = aStyleContext->GetStyleIfVisited();
   const nsStyleBorder *styleBorder = aStyleContext->StyleBorder();
   // Don't check RelevantLinkVisited here, since we want to take the
   // same amount of time whether or not it's true.
   if (!styleIfVisited) {
     return CreateBorderRendererWithStyleBorder(aPresContext, aDrawTarget,
                                                aForFrame, aDirtyRect,
                                                aBorderArea, *styleBorder,
-                                               aStyleContext, aSkipSides,
-                                               aOutBorderIsEmpty);
+                                               aStyleContext, aOutBorderIsEmpty,
+                                               aSkipSides);
   }
 
   nsStyleBorder newStyleBorder(*styleBorder);
 
   NS_FOR_CSS_SIDES(side) {
     nscolor color = aStyleContext->
       GetVisitedDependentColor(nsStyleBorder::BorderColorFieldFor(side));
     newStyleBorder.mBorderColor[side] = StyleComplexColor::FromColor(color);
   }
   return CreateBorderRendererWithStyleBorder(aPresContext, aDrawTarget,
                                              aForFrame, aDirtyRect, aBorderArea,
                                              newStyleBorder, aStyleContext,
-                                             aSkipSides, aOutBorderIsEmpty);
+                                             aOutBorderIsEmpty, aSkipSides);
 }
 
 
 bool
 nsCSSRendering::CreateWebRenderCommandsForBorder(nsDisplayItem* aItem,
                                                  nsIFrame* aForFrame,
                                                  const nsRect& aBorderArea,
                                                  mozilla::wr::DisplayListBuilder& aBuilder,
                                                  mozilla::wr::IpcResourceUpdateQueue& aResources,
                                                  const mozilla::layers::StackingContextHelper& aSc,
                                                  mozilla::layers::WebRenderLayerManager* aManager,
                                                  nsDisplayListBuilder* aDisplayListBuilder)
 {
   // First try to draw a normal border
   {
+    bool borderIsEmpty = false;
     Maybe<nsCSSBorderRenderer> br =
       nsCSSRendering::CreateBorderRenderer(aForFrame->PresContext(),
                                            nullptr,
                                            aForFrame,
                                            nsRect(),
                                            aBorderArea,
                                            aForFrame->StyleContext(),
+                                           &borderIsEmpty,
                                            aForFrame->GetSkipSides());
+    if (borderIsEmpty) {
+      return true;
+    }
 
     if (br) {
       if (!br->CanCreateWebRenderCommands()) {
         return false;
       }
       br->CreateWebRenderCommands(aItem, aBuilder, aResources, aSc);
       return true;
     }
@@ -979,18 +984,18 @@ nsCSSRendering::PaintBorderWithStyleBord
 Maybe<nsCSSBorderRenderer>
 nsCSSRendering::CreateBorderRendererWithStyleBorder(nsPresContext* aPresContext,
                                                     DrawTarget* aDrawTarget,
                                                     nsIFrame* aForFrame,
                                                     const nsRect& aDirtyRect,
                                                     const nsRect& aBorderArea,
                                                     const nsStyleBorder& aStyleBorder,
                                                     nsStyleContext* aStyleContext,
-                                                    Sides aSkipSides,
-                                                    bool* aOutBorderIsEmpty)
+                                                    bool* aOutBorderIsEmpty,
+                                                    Sides aSkipSides)
 {
   const nsStyleDisplay* displayData = aStyleContext->StyleDisplay();
   if (displayData->mAppearance) {
     nsITheme *theme = aPresContext->GetTheme();
     if (theme &&
         theme->ThemeSupportsWidget(aPresContext, aForFrame,
                                    displayData->mAppearance)) {
       return Nothing();
--- a/layout/painting/nsCSSRendering.h
+++ b/layout/painting/nsCSSRendering.h
@@ -188,29 +188,29 @@ struct nsCSSRendering {
 
   static mozilla::Maybe<nsCSSBorderRenderer>
   CreateBorderRenderer(nsPresContext* aPresContext,
                        DrawTarget* aDrawTarget,
                        nsIFrame* aForFrame,
                        const nsRect& aDirtyRect,
                        const nsRect& aBorderArea,
                        nsStyleContext* aStyleContext,
-                       Sides aSkipSides = Sides(),
-                       bool* aOutBorderIsEmpty = nullptr);
+                       bool* aOutBorderIsEmpty,
+                       Sides aSkipSides = Sides());
 
   static mozilla::Maybe<nsCSSBorderRenderer>
   CreateBorderRendererWithStyleBorder(nsPresContext* aPresContext,
                                       DrawTarget* aDrawTarget,
                                       nsIFrame* aForFrame,
                                       const nsRect& aDirtyRect,
                                       const nsRect& aBorderArea,
                                       const nsStyleBorder& aBorderStyle,
                                       nsStyleContext* aStyleContext,
-                                      Sides aSkipSides = Sides(),
-                                      bool* aOutBorderIsEmpty = nullptr);
+                                      bool* aOutBorderIsEmpty,
+                                      Sides aSkipSides = Sides());
 
   static mozilla::Maybe<nsCSSBorderRenderer>
   CreateBorderRendererForOutline(nsPresContext* aPresContext,
                                  gfxContext* aRenderingContext,
                                  nsIFrame* aForFrame,
                                  const nsRect& aDirtyRect,
                                  const nsRect& aBorderArea,
                                  nsStyleContext* aStyleContext);
--- a/layout/painting/nsDisplayList.cpp
+++ b/layout/painting/nsDisplayList.cpp
@@ -5110,16 +5110,17 @@ nsDisplayCaret::BuildLayer(nsDisplayList
                            LayerManager* aManager,
                            const ContainerLayerParameters& aContainerParameters)
 {
   return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
 }
 
 nsDisplayBorder::nsDisplayBorder(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
   : nsDisplayItem(aBuilder, aFrame)
+  , mBorderIsEmpty(false)
 {
   MOZ_COUNT_CTOR(nsDisplayBorder);
 
   mBounds = CalculateBounds(*mFrame->StyleBorder()).GetBounds();
 }
 
 bool
 nsDisplayBorder::IsInvisibleInRect(const nsRect& aRect) const
@@ -5174,37 +5175,34 @@ LayerState
 nsDisplayBorder::GetLayerState(nsDisplayListBuilder* aBuilder,
                                LayerManager* aManager,
                                const ContainerLayerParameters& aParameters)
 {
   if (!ShouldUseAdvancedLayer(aManager, gfxPrefs::LayersAllowBorderLayers)) {
     return LAYER_NONE;
   }
 
+  mBorderIsEmpty = false;
   nsPoint offset = ToReferenceFrame();
   Maybe<nsCSSBorderRenderer> br =
     nsCSSRendering::CreateBorderRenderer(mFrame->PresContext(),
                                          nullptr,
                                          mFrame,
                                          nsRect(),
                                          nsRect(offset, mFrame->GetSize()),
                                          mFrame->StyleContext(),
+                                         &mBorderIsEmpty,
                                          mFrame->GetSkipSides());
 
-  const nsStyleBorder *styleBorder = mFrame->StyleContext()->StyleBorder();
-  const nsStyleImage* image = &styleBorder->mBorderImageSource;
   mBorderRenderer = Nothing();
   mBorderImageRenderer = Nothing();
-  if ((!image ||
-       image->GetType() != eStyleImageType_Image ||
-       image->GetType() != eStyleImageType_Gradient) && !br) {
-    return LAYER_NONE;
-  }
-
   if (!br) {
+    if (mBorderIsEmpty) {
+      return LAYER_ACTIVE;
+    }
     return LAYER_NONE;
   }
 
   bool hasCompositeColors;
   if (!br->AllBordersSolid(&hasCompositeColors) || hasCompositeColors) {
     return LAYER_NONE;
   }
 
@@ -5238,16 +5236,20 @@ nsDisplayBorder::GetLayerState(nsDisplay
   return LAYER_ACTIVE;
 }
 
 already_AddRefed<Layer>
 nsDisplayBorder::BuildLayer(nsDisplayListBuilder* aBuilder,
                             LayerManager* aManager,
                             const ContainerLayerParameters& aContainerParameters)
 {
+  if (mBorderIsEmpty) {
+    return nullptr;
+  }
+
   if (ShouldUseAdvancedLayer(aManager, gfxPrefs::LayersAllowBorderLayers)) {
     return BuildDisplayItemLayer(aBuilder, aManager, aContainerParameters);
   } else {
     RefPtr<BorderLayer> layer = static_cast<BorderLayer*>
       (aManager->GetLayerBuilder()->GetLeafLayerFor(aBuilder, this));
     if (!layer) {
       layer = aManager->CreateBorderLayer();
       if (!layer)
--- a/layout/painting/nsDisplayList.h
+++ b/layout/painting/nsDisplayList.h
@@ -3432,16 +3432,17 @@ protected:
   mozilla::Array<mozilla::LayerSize, 4> mCorners;
   mozilla::Array<uint8_t, 4> mBorderStyles;
   mozilla::LayerRect mRect;
 
   mozilla::Maybe<nsCSSBorderRenderer> mBorderRenderer;
   mozilla::Maybe<nsCSSBorderImageRenderer> mBorderImageRenderer;
 
   nsRect mBounds;
+  bool mBorderIsEmpty;
 };
 
 /**
  * A simple display item that just renders a solid color across the
  * specified bounds. For canvas frames (in the CSS sense) we split off the
  * drawing of the background color into this class (from nsDisplayBackground
  * via nsDisplayCanvasBackground). This is done so that we can always draw a
  * background color to avoid ugly flashes of white when we can't draw a full