Bug 1361668 - Fix the bound of nsDisplayColumnRules. r=mattwoodrow
authorEthan Lin <ethlin@mozilla.com>
Wed, 10 May 2017 13:55:15 +0800
changeset 359295 f9fc89f8b6ff99102523607476d032626edb2ccd
parent 359294 a3916eccfa832ce5273a5775b408e5ee33bb7d9f
child 359296 c509185bf7e5f29f4685b4f3d8d4467581b49cfa
push id31852
push userkwierso@gmail.com
push dateFri, 19 May 2017 21:47:27 +0000
treeherdermozilla-central@979f11deabd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmattwoodrow
bugs1361668
milestone55.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 1361668 - Fix the bound of nsDisplayColumnRules. r=mattwoodrow
layout/generic/nsColumnSetFrame.cpp
layout/generic/nsColumnSetFrame.h
--- a/layout/generic/nsColumnSetFrame.cpp
+++ b/layout/generic/nsColumnSetFrame.cpp
@@ -29,17 +29,17 @@ public:
 
   /**
    * Returns the frame's visual overflow rect instead of the frame's bounds.
    */
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder,
                            bool* aSnap) override
   {
     *aSnap = false;
-    return Frame()->GetVisualOverflowRect() + ToReferenceFrame();
+    return static_cast<nsColumnSetFrame*>(mFrame)->CalculateBounds(ToReferenceFrame());
   }
 
   virtual LayerState GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters) override;
   virtual already_AddRefed<Layer> BuildLayer(nsDisplayListBuilder* aBuilder,
                                              LayerManager* aManager,
                                              const ContainerLayerParameters& aContainerParameters) override;
@@ -61,18 +61,16 @@ nsDisplayColumnRule::Paint(nsDisplayList
                            nsRenderingContext* aCtx)
 {
   static_cast<nsColumnSetFrame*>(mFrame)->
     CreateBorderRenderers(mBorderRenderers, aCtx, mVisibleRect, ToReferenceFrame());
 
   for (auto iter = mBorderRenderers.begin(); iter != mBorderRenderers.end(); iter++) {
     iter->DrawBorders();
   }
-
-
 }
 LayerState
 nsDisplayColumnRule::GetLayerState(nsDisplayListBuilder* aBuilder,
                                    LayerManager* aManager,
                                    const ContainerLayerParameters& aParameters)
 {
   if (!gfxPrefs::LayersAllowColumnRuleLayers()) {
     return LAYER_NONE;
@@ -132,35 +130,95 @@ NS_IMPL_FRAMEARENA_HELPERS(nsColumnSetFr
 
 nsColumnSetFrame::nsColumnSetFrame(nsStyleContext* aContext)
   : nsContainerFrame(aContext, LayoutFrameType::ColumnSet)
   , mLastBalanceBSize(NS_INTRINSICSIZE)
 {
 }
 
 void
-nsColumnSetFrame::CreateBorderRenderers(nsTArray<nsCSSBorderRenderer>& aBorderRenderers,
-                                        nsRenderingContext* aCtx,
-                                        const nsRect& aDirtyRect,
-                                        const nsPoint& aPt)
+nsColumnSetFrame::ForEachColumn(const std::function<void(const nsRect& lineRect)>& aSetLineRect,
+                                const nsPoint& aPt)
 {
   nsIFrame* child = mFrames.FirstChild();
   if (!child)
     return;  // no columns
 
   nsIFrame* nextSibling = child->GetNextSibling();
   if (!nextSibling)
     return;  // 1 column only - this means no gap to draw on
 
+  const nsStyleColumn* colStyle = StyleColumn();
+  nscoord ruleWidth = colStyle->GetComputedColumnRuleWidth();
+  if (!ruleWidth)
+    return;
+
   WritingMode wm = GetWritingMode();
   bool isVertical = wm.IsVertical();
   bool isRTL = !wm.IsBidiLTR();
-  const nsStyleColumn* colStyle = StyleColumn();
+
+  // Get our content rect as an absolute coordinate, not relative to
+  // our parent (which is what the X and Y normally is)
+  nsRect contentRect = GetContentRect() - GetRect().TopLeft() + aPt;
+  nsSize ruleSize = isVertical ? nsSize(contentRect.width, ruleWidth)
+                               : nsSize(ruleWidth, contentRect.height);
+
+  while (nextSibling) {
+    // The frame tree goes RTL in RTL.
+    // The |prevFrame| and |nextFrame| frames here are the visually preceding
+    // (left/above) and following (right/below) frames, not in logical writing-
+    // mode direction.
+    nsIFrame* prevFrame = isRTL ? nextSibling : child;
+    nsIFrame* nextFrame = isRTL ? child : nextSibling;
 
+    // Each child frame's position coordinates is actually relative to this
+    // nsColumnSetFrame.
+    // linePt will be at the top-left edge to paint the line.
+    nsPoint linePt;
+    if (isVertical) {
+      nscoord edgeOfPrev = prevFrame->GetRect().YMost() + aPt.y;
+      nscoord edgeOfNext = nextFrame->GetRect().Y() + aPt.y;
+      linePt = nsPoint(contentRect.x,
+                       (edgeOfPrev + edgeOfNext - ruleSize.height) / 2);
+    } else {
+      nscoord edgeOfPrev = prevFrame->GetRect().XMost() + aPt.x;
+      nscoord edgeOfNext = nextFrame->GetRect().X() + aPt.x;
+      linePt = nsPoint((edgeOfPrev + edgeOfNext - ruleSize.width) / 2,
+                       contentRect.y);
+    }
+
+    aSetLineRect(nsRect(linePt, ruleSize));
+
+    child = nextSibling;
+    nextSibling = nextSibling->GetNextSibling();
+  }
+}
+
+nsRect
+nsColumnSetFrame::CalculateBounds(const nsPoint& aOffset)
+{
+  nsRect combined;
+  ForEachColumn([&combined](const nsRect& aLineRect)
+                {
+                  combined = combined.Union(aLineRect);
+                }, aOffset);
+  return combined;
+}
+
+void
+nsColumnSetFrame::CreateBorderRenderers(nsTArray<nsCSSBorderRenderer>& aBorderRenderers,
+                                        nsRenderingContext* aCtx,
+                                        const nsRect& aDirtyRect,
+                                        const nsPoint& aPt)
+{
+  WritingMode wm = GetWritingMode();
+  bool isVertical = wm.IsVertical();
+  const nsStyleColumn* colStyle = StyleColumn();
   uint8_t ruleStyle;
+
   // Per spec, inset => ridge and outset => groove
   if (colStyle->mColumnRuleStyle == NS_STYLE_BORDER_STYLE_INSET)
     ruleStyle = NS_STYLE_BORDER_STYLE_RIDGE;
   else if (colStyle->mColumnRuleStyle == NS_STYLE_BORDER_STYLE_OUTSET)
     ruleStyle = NS_STYLE_BORDER_STYLE_GROOVE;
   else
     ruleStyle = colStyle->mColumnRuleStyle;
 
@@ -189,64 +247,33 @@ nsColumnSetFrame::CreateBorderRenderers(
   } else {
     border.SetBorderWidth(eSideLeft, ruleWidth);
     border.SetBorderStyle(eSideLeft, ruleStyle);
     border.mBorderLeftColor = StyleComplexColor::FromColor(ruleColor);
     skipSides |= mozilla::eSideBitsTopBottom;
     skipSides |= mozilla::eSideBitsRight;
   }
 
-  // Get our content rect as an absolute coordinate, not relative to
-  // our parent (which is what the X and Y normally is)
-  nsRect contentRect = GetContentRect() - GetRect().TopLeft() + aPt;
-  nsSize ruleSize = isVertical ? nsSize(contentRect.width, ruleWidth)
-                               : nsSize(ruleWidth, contentRect.height);
-
-  while (nextSibling) {
-    // The frame tree goes RTL in RTL.
-    // The |prevFrame| and |nextFrame| frames here are the visually preceding
-    // (left/above) and following (right/below) frames, not in logical writing-
-    // mode direction.
-    nsIFrame* prevFrame = isRTL ? nextSibling : child;
-    nsIFrame* nextFrame = isRTL ? child : nextSibling;
+  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);
 
-    // Each child frame's position coordinates is actually relative to this
-    // nsColumnSetFrame.
-    // linePt will be at the top-left edge to paint the line.
-    nsPoint linePt;
-    if (isVertical) {
-      nscoord edgeOfPrev = prevFrame->GetRect().YMost() + aPt.y;
-      nscoord edgeOfNext = nextFrame->GetRect().Y() + aPt.y;
-      linePt = nsPoint(contentRect.x,
-                       (edgeOfPrev + edgeOfNext - ruleSize.height) / 2);
-    } else {
-      nscoord edgeOfPrev = prevFrame->GetRect().XMost() + aPt.x;
-      nscoord edgeOfNext = nextFrame->GetRect().X() + aPt.x;
-      linePt = nsPoint((edgeOfPrev + edgeOfNext - ruleSize.width) / 2,
-                       contentRect.y);
-    }
-
-    nsRect lineRect(linePt, ruleSize);
-
-    // 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;
-    Maybe<nsCSSBorderRenderer> br =
-      nsCSSRendering::CreateBorderRendererWithStyleBorder(presContext, dt,
-                                                          this, aDirtyRect,
-                                                          lineRect, border,
-                                                          StyleContext(), skipSides);
-    if (br.isSome()) {
-      aBorderRenderers.AppendElement(br.value());
-    }
-    child = nextSibling;
-    nextSibling = nextSibling->GetNextSibling();
-  }
+                  gfx::DrawTarget* dt = aCtx ? aCtx->GetDrawTarget() : nullptr;
+                  Maybe<nsCSSBorderRenderer> br =
+                    nsCSSRendering::CreateBorderRendererWithStyleBorder(presContext, dt,
+                                                                        this, aDirtyRect,
+                                                                        aLineRect, border,
+                                                                        StyleContext(), skipSides);
+                  if (br.isSome()) {
+                    aBorderRenderers.AppendElement(br.value());
+                  }
+                }, aPt);
 }
 
 static nscoord
 GetAvailableContentISize(const ReflowInput& aReflowInput)
 {
   if (aReflowInput.AvailableISize() == NS_INTRINSICSIZE) {
     return NS_INTRINSICSIZE;
   }
@@ -546,17 +573,16 @@ nsColumnSetFrame::ReflowChildren(ReflowO
                                  const ReflowConfig&      aConfig,
                                  bool                     aUnboundedLastColumn,
                                  nsCollapsingMargin*      aCarriedOutBEndMargin,
                                  ColumnBalanceData&       aColData)
 {
   aColData.Reset();
   bool allFit = true;
   WritingMode wm = GetWritingMode();
-  bool isVertical = wm.IsVertical();
   bool isRTL = !wm.IsBidiLTR();
   bool shrinkingBSizeOnly = !NS_SUBTREE_DIRTY(this) &&
     mLastBalanceBSize > aConfig.mColMaxBSize;
 
 #ifdef DEBUG_roc
   printf("*** Doing column reflow pass: mLastBalanceBSize=%d, mColMaxBSize=%d, RTL=%d\n"
          "    mBalanceColCount=%d, mColISize=%d, mColGap=%d\n",
          mLastBalanceBSize, aConfig.mColMaxBSize, isRTL, aConfig.mBalanceColCount,
@@ -596,17 +622,17 @@ nsColumnSetFrame::ReflowChildren(ReflowO
 
   // For RTL, since the columns might not fill the frame exactly, we
   // need to account for the slop. Otherwise we'll waste time moving the
   // columns by some tiny amount
 
   // XXX when all of layout is converted to logical coordinates, we
   //     probably won't need to do this hack any more. For now, we
   //     confine it to the legacy horizontal-rl case
-  if (!isVertical && isRTL) {
+  if (!wm.IsVertical() && isRTL) {
     nscoord availISize = aReflowInput.AvailableISize();
     if (aReflowInput.ComputedISize() != NS_INTRINSICSIZE) {
       availISize = aReflowInput.ComputedISize();
     }
     if (availISize != NS_INTRINSICSIZE) {
       childOrigin.I(wm) = containerSize.width - borderPadding.Left(wm) -
                           availISize;
 #ifdef DEBUG_roc
--- a/layout/generic/nsColumnSetFrame.h
+++ b/layout/generic/nsColumnSetFrame.h
@@ -85,16 +85,17 @@ public:
                                      nsChangeHint aHintForThisFrame) override;
 
 #ifdef DEBUG_FRAME_DUMP
   virtual nsresult GetFrameName(nsAString& aResult) const override {
     return MakeFrameName(NS_LITERAL_STRING("ColumnSet"), aResult);
   }
 #endif
 
+  nsRect CalculateBounds(const nsPoint& aOffset);
   void CreateBorderRenderers(nsTArray<nsCSSBorderRenderer>& aBorderRenderers,
                              nsRenderingContext* aCtx,
                              const nsRect& aDirtyRect,
                              const nsPoint& aPt);
 
 protected:
   nscoord        mLastBalanceBSize;
   nsReflowStatus mLastFrameStatus;
@@ -225,11 +226,14 @@ protected:
    */
   bool ReflowChildren(ReflowOutput& aDesiredSize,
                         const ReflowInput& aReflowInput,
                         nsReflowStatus& aStatus,
                         const ReflowConfig& aConfig,
                         bool aLastColumnUnbounded,
                         nsCollapsingMargin* aCarriedOutBEndMargin,
                         ColumnBalanceData& aColData);
+
+  void ForEachColumn(const std::function<void(const nsRect& lineRect)>& aSetLineRect,
+                     const nsPoint& aPt);
 };
 
 #endif // nsColumnSetFrame_h___