Bug 1413397 - Avoid empty border's fallback. r=kats draft
authorEthan Lin <ethlin@mozilla.com>
Wed, 01 Nov 2017 17:30:04 +0800
changeset 692424 6c14c8fa180552a91eee19829dc348503fe9e2b8
parent 691806 0a50066b2de805de843762b9787b2b3d2d5bf93f
child 692476 cca3500d8ade3b7a555487796979296135516be1
child 692552 6f1095fd320134f5b96ed07e1e46f260f1a255d6
push id87499
push userbmo:ethlin@mozilla.com
push dateFri, 03 Nov 2017 03:46:22 +0000
reviewerskats
bugs1413397
milestone58.0a1
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
@@ -5101,16 +5101,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
@@ -5165,37 +5166,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;
   }
 
@@ -5229,16 +5227,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
@@ -3427,16 +3427,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