Bug 1025669 - part 1, Implement layout of block margins for box-decoration-break:clone. r=roc a=lmandel
authorMats Palmgren <mats@mozilla.com>
Tue, 24 Jun 2014 17:52:19 +0000
changeset 208956 0e2480168a62d17c071d47eab10c20b9e56feccc
parent 208955 dd81079207fd72014e35b3da17069b161f82cedc
child 208957 98deeb8e384349d9b7b4dd4e13b18be8413d6ecf
push id494
push userraliiev@mozilla.com
push dateMon, 25 Aug 2014 18:42:16 +0000
treeherdermozilla-release@a3cc3e46b571 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc, lmandel
bugs1025669
milestone32.0a2
Bug 1025669 - part 1, Implement layout of block margins for box-decoration-break:clone. r=roc a=lmandel
layout/generic/nsBlockFrame.cpp
layout/generic/nsBlockFrame.h
layout/generic/nsBlockReflowState.cpp
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -2852,24 +2852,27 @@ nsBlockFrame::IsEmpty()
       return false;
   }
 
   return true;
 }
 
 bool
 nsBlockFrame::ShouldApplyTopMargin(nsBlockReflowState& aState,
-                                   nsLineBox* aLine)
+                                   nsLineBox* aLine,
+                                   nsIFrame* aChildFrame)
 {
   if (aState.GetFlag(BRS_APPLYTOPMARGIN)) {
     // Apply short-circuit check to avoid searching the line list
     return true;
   }
 
-  if (!aState.IsAdjacentWithTop()) {
+  if (!aState.IsAdjacentWithTop() ||
+      aChildFrame->StyleBorder()->mBoxDecorationBreak ==
+        NS_STYLE_BOX_DECORATION_BREAK_CLONE) {
     // If we aren't at the top Y coordinate then something of non-zero
     // height must have been placed. Therefore the childs top-margin
     // applies.
     aState.SetFlag(BRS_APPLYTOPMARGIN, true);
     return true;
   }
 
   // Determine if this line is "essentially" the first line
@@ -2921,21 +2924,22 @@ nsBlockFrame::ReflowBlockFrame(nsBlockRe
     aState.mFloatBreakType = NS_STYLE_CLEAR_NONE;
   }
 
   // Clear past floats before the block if the clear style is not none
   aLine->SetBreakTypeBefore(breakType);
 
   // See if we should apply the top margin. If the block frame being
   // reflowed is a continuation (non-null prev-in-flow) then we don't
-  // apply its top margin because it's not significant. Otherwise, dig
-  // deeper.
-  bool applyTopMargin =
-    !frame->GetPrevInFlow() && ShouldApplyTopMargin(aState, aLine);
-
+  // apply its top margin because it's not significant unless it has
+  // 'box-decoration-break:clone'.  Otherwise, dig deeper.
+  bool applyTopMargin = (frame->StyleBorder()->mBoxDecorationBreak ==
+                           NS_STYLE_BOX_DECORATION_BREAK_CLONE ||
+                         !frame->GetPrevInFlow()) &&
+                        ShouldApplyTopMargin(aState, aLine, frame);
   if (applyTopMargin) {
     // The HasClearance setting is only valid if ShouldApplyTopMargin
     // returned false (in which case the top-margin-root set our
     // clearance flag). Otherwise clear it now. We'll set it later on
     // ourselves if necessary.
     aLine->ClearHasClearance();
   }
   bool treatWithClearance = aLine->HasClearance();
@@ -3386,17 +3390,17 @@ nsBlockFrame::ReflowInlineFrames(nsBlock
                                  bool* aKeepReflowGoing)
 {
   *aKeepReflowGoing = true;
 
   aLine->SetLineIsImpactedByFloat(false);
 
   // Setup initial coordinate system for reflowing the inline frames
   // into. Apply a previous block frame's bottom margin first.
-  if (ShouldApplyTopMargin(aState, aLine)) {
+  if (ShouldApplyTopMargin(aState, aLine, aLine->mFirstChild)) {
     aState.mY += aState.mPrevBottomMargin.get();
   }
   nsFlowAreaRect floatAvailableSpace = aState.GetFloatAvailableSpace();
 
   LineReflowStatus lineReflowStatus;
   do {
     nscoord availableSpaceHeight = 0;
     do {
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -634,17 +634,18 @@ protected:
   void DeleteLine(nsBlockReflowState& aState,
                   nsLineList::iterator aLine,
                   nsLineList::iterator aLineEnd);
 
   //----------------------------------------
   // Methods for individual frame reflow
 
   bool ShouldApplyTopMargin(nsBlockReflowState& aState,
-                              nsLineBox* aLine);
+                            nsLineBox* aLine,
+                            nsIFrame* aChildFrame);
 
   void ReflowBlockFrame(nsBlockReflowState& aState,
                         line_iterator aLine,
                         bool* aKeepGoing);
 
   void ReflowInlineFrames(nsBlockReflowState& aState,
                           line_iterator aLine,
                           bool* aKeepLineGoing);
--- a/layout/generic/nsBlockReflowState.cpp
+++ b/layout/generic/nsBlockReflowState.cpp
@@ -42,23 +42,26 @@ nsBlockReflowState::nsBlockReflowState(c
     mFloatBreakType(NS_STYLE_CLEAR_NONE),
     mConsumedHeight(aConsumedHeight)
 {
   SetFlag(BRS_ISFIRSTINFLOW, aFrame->GetPrevInFlow() == nullptr);
   SetFlag(BRS_ISOVERFLOWCONTAINER,
           IS_TRUE_OVERFLOW_CONTAINER(aFrame));
 
   mBorderPadding = mReflowState.ComputedPhysicalBorderPadding();
-  mBorderPadding.ApplySkipSides(aFrame->GetSkipSides(&aReflowState));
+  int skipSides = aFrame->GetSkipSides(&aReflowState);
+  mBorderPadding.ApplySkipSides(skipSides);
   mContainerWidth = aReflowState.ComputedWidth() + mBorderPadding.LeftRight();
 
-  if (aTopMarginRoot || 0 != mBorderPadding.top) {
+  if ((aTopMarginRoot && !(skipSides & (1 << NS_SIDE_TOP))) ||
+      0 != mBorderPadding.top) {
     SetFlag(BRS_ISTOPMARGINROOT, true);
   }
-  if (aBottomMarginRoot || 0 != mBorderPadding.bottom) {
+  if ((aBottomMarginRoot && !(skipSides & (1 << NS_SIDE_BOTTOM))) ||
+      0 != mBorderPadding.bottom) {
     SetFlag(BRS_ISBOTTOMMARGINROOT, true);
   }
   if (GetFlag(BRS_ISTOPMARGINROOT)) {
     SetFlag(BRS_APPLYTOPMARGIN, true);
   }
   if (aBlockNeedsFloatManager) {
     SetFlag(BRS_FLOAT_MGR, true);
   }
@@ -155,16 +158,29 @@ nsBlockReflowState::ComputeReplacedBlock
     rightOffset = std::max(rightFloatXOffset, frameMargin.right) -
                   frameMargin.right;
     rightOffset = std::max(rightOffset, 0); // in case of negative margin
   }
   aLeftResult = leftOffset;
   aRightResult = rightOffset;
 }
 
+static nscoord
+GetBottomMarginClone(nsIFrame* aFrame,
+                     nsRenderingContext* aRenderingContext,
+                     const nsRect& aContentArea)
+{
+  if (aFrame->StyleBorder()->mBoxDecorationBreak ==
+        NS_STYLE_BOX_DECORATION_BREAK_CLONE) {
+    nsCSSOffsetState os(aFrame, aRenderingContext, aContentArea.width);
+    return os.ComputedPhysicalMargin().bottom;
+  }
+  return 0;
+}
+
 // Compute the amount of available space for reflowing a block frame
 // at the current Y coordinate. This method assumes that
 // GetAvailableSpace has already been called.
 void
 nsBlockReflowState::ComputeBlockAvailSpace(nsIFrame* aFrame,
                                            const nsStyleDisplay* aDisplay,
                                            const nsFlowAreaRect& aFloatAvailableSpace,
                                            bool aBlockAvoidsFloats,
@@ -172,17 +188,18 @@ nsBlockReflowState::ComputeBlockAvailSpa
 {
 #ifdef REALLY_NOISY_REFLOW
   printf("CBAS frame=%p has floats %d\n",
          aFrame, aFloatAvailableSpace.mHasFloats);
 #endif
   aResult.y = mY;
   aResult.height = GetFlag(BRS_UNCONSTRAINEDHEIGHT)
     ? NS_UNCONSTRAINEDSIZE
-    : mReflowState.AvailableHeight() - mY;
+    : mReflowState.AvailableHeight() - mY
+      - GetBottomMarginClone(aFrame, mReflowState.rendContext, mContentArea);
   // mY might be greater than mBottomEdge if the block's top margin pushes
   // it off the page/column. Negative available height can confuse other code
   // and is nonsense in principle.
 
   // XXX Do we really want this condition to be this restrictive (i.e.,
   // more restrictive than it used to be)?  The |else| here is allowed
   // by the CSS spec, but only out of desperation given implementations,
   // and the behavior it leads to is quite undesirable (it can cause