Bug 743402, Part 3: Refactor nsBlockFrame to utilize new calculations for paginated content. [r=roc]
authorScott Johnson <sjohnson@mozilla.com>
Thu, 25 Jul 2013 10:34:22 -0500
changeset 152302 f1bd0ed5fb4e958815404e88244080d7e5e83b6f
parent 152301 088bf371078a52f7cbcb39b319caa5385f469a1d
child 152303 352501d3f390a01f44036782973c154a13f7b9ad
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs743402
milestone25.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 743402, Part 3: Refactor nsBlockFrame to utilize new calculations for paginated content. [r=roc]
layout/generic/nsBlockFrame.cpp
layout/generic/nsBlockFrame.h
layout/generic/nsSplittableFrame.cpp
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -1333,67 +1333,34 @@ nsBlockFrame::ComputeFinalSize(const nsH
     // Include the float manager's state to properly account for the
     // bottom margin of any floated elements; e.g., inside a table cell.
     nscoord floatHeight =
       aState.ClearFloats(bottomEdgeOfChildren, NS_STYLE_CLEAR_LEFT_AND_RIGHT,
                          nullptr, nsFloatManager::DONT_CLEAR_PUSHED_FLOATS);
     bottomEdgeOfChildren = std::max(bottomEdgeOfChildren, floatHeight);
   }
 
-  // Compute final height
-  if (NS_UNCONSTRAINEDSIZE != aReflowState.ComputedHeight()) {
-    // Figure out how much of the computed height should be
-    // applied to this frame.
-    nscoord computedHeightLeftOver = GetEffectiveComputedHeight(aReflowState);
-    NS_ASSERTION(!( IS_TRUE_OVERFLOW_CONTAINER(this)
-                    && computedHeightLeftOver ),
-                 "overflow container must not have computedHeightLeftOver");
-
-    aMetrics.height =
-      NSCoordSaturatingAdd(NSCoordSaturatingAdd(borderPadding.top,
-                                                computedHeightLeftOver),
-                           borderPadding.bottom);
-
-    if (NS_FRAME_IS_NOT_COMPLETE(aState.mReflowStatus)
-        && aMetrics.height < aReflowState.availableHeight) {
-      // We ran out of height on this page but we're incomplete
-      // Set status to complete except for overflow
-      NS_FRAME_SET_OVERFLOW_INCOMPLETE(aState.mReflowStatus);
-    }
-
-    if (NS_FRAME_IS_COMPLETE(aState.mReflowStatus)) {
-      if (computedHeightLeftOver > 0 &&
-          NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight &&
-          aMetrics.height > aReflowState.availableHeight) {
-        if (ShouldAvoidBreakInside(aReflowState)) {
-          aState.mReflowStatus = NS_INLINE_LINE_BREAK_BEFORE();
-          return;
-        }
-        // We don't fit and we consumed some of the computed height,
-        // so we should consume all the available height and then
-        // break.  If our bottom border/padding straddles the break
-        // point, then this will increase our height and push the
-        // border/padding to the next page/column.
-        aMetrics.height = std::max(aReflowState.availableHeight,
-                                 aState.mY + nonCarriedOutVerticalMargin);
-        NS_FRAME_SET_INCOMPLETE(aState.mReflowStatus);
-        if (!GetNextInFlow())
-          aState.mReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
-      }
-    }
-    else {
+  if (NS_UNCONSTRAINEDSIZE != aReflowState.ComputedHeight()
+      && (mParent->GetType() != nsGkAtoms::columnSetFrame ||
+          aReflowState.parentReflowState->availableHeight == NS_UNCONSTRAINEDSIZE)) {
+    ComputeFinalHeight(aReflowState, &aState.mReflowStatus,
+                       aState.mY + nonCarriedOutVerticalMargin,
+                       borderPadding, aMetrics, aState.mConsumedHeight);
+    if (!NS_FRAME_IS_COMPLETE(aState.mReflowStatus)) {
       // Use the current height; continuations will take up the rest.
       // Do extend the height to at least consume the available
       // height, otherwise our left/right borders (for example) won't
       // extend all the way to the break.
       aMetrics.height = std::max(aReflowState.availableHeight,
                                aState.mY + nonCarriedOutVerticalMargin);
       // ... but don't take up more height than is available
+      nscoord effectiveComputedHeight =
+        GetEffectiveComputedHeight(aReflowState, aState.GetConsumedHeight());
       aMetrics.height = std::min(aMetrics.height,
-                               borderPadding.top + computedHeightLeftOver);
+                               borderPadding.top + effectiveComputedHeight);
       // XXX It's pretty wrong that our bottom border still gets drawn on
       // on its own on the last-in-flow, even if we ran out of height
       // here. We need GetSkipSides to check whether we ran out of content
       // height in the current frame, not whether it's last-in-flow.
     }
 
     // Don't carry out a bottom margin when our height is fixed.
     aMetrics.mCarriedOutBottomMargin.Zero();
@@ -7080,16 +7047,67 @@ nsBlockFrame::GetNearestAncestorBlock(ns
     }
     // Not a block. Check its parent next.
     aCandidate = aCandidate->GetParent();
   }
   NS_NOTREACHED("Fell off frame tree looking for ancestor block!");
   return nullptr;
 }
 
+void
+nsBlockFrame::ComputeFinalHeight(const nsHTMLReflowState& aReflowState,
+                                      nsReflowStatus*          aStatus,
+                                      nscoord                  aContentHeight,
+                                      const nsMargin&          aBorderPadding,
+                                      nsHTMLReflowMetrics&     aMetrics,
+                                      nscoord                  aConsumed)
+{
+
+  // Figure out how much of the computed height should be
+  // applied to this frame.
+  nscoord computedHeightLeftOver = GetEffectiveComputedHeight(aReflowState,
+                                                              aConsumed);
+  NS_ASSERTION(!( IS_TRUE_OVERFLOW_CONTAINER(this)
+                  && computedHeightLeftOver ),
+               "overflow container must not have computedHeightLeftOver");
+
+  aMetrics.height =
+    NSCoordSaturatingAdd(NSCoordSaturatingAdd(aBorderPadding.top,
+                                              computedHeightLeftOver),
+                         aBorderPadding.bottom);
+
+  if (NS_FRAME_IS_NOT_COMPLETE(*aStatus)
+      && aMetrics.height < aReflowState.availableHeight) {
+    // We ran out of height on this page but we're incomplete
+    // Set status to complete except for overflow
+    NS_FRAME_SET_OVERFLOW_INCOMPLETE(*aStatus);
+  }
+
+  if (NS_FRAME_IS_COMPLETE(*aStatus)) {
+    if (computedHeightLeftOver > 0 &&
+        NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight &&
+        aMetrics.height > aReflowState.availableHeight) {
+      if (ShouldAvoidBreakInside(aReflowState)) {
+        *aStatus = NS_INLINE_LINE_BREAK_BEFORE();
+        return;
+      }
+      // We don't fit and we consumed some of the computed height,
+      // so we should consume all the available height and then
+      // break.  If our bottom border/padding straddles the break
+      // point, then this will increase our height and push the
+      // border/padding to the next page/column.
+      aMetrics.height = std::max(aReflowState.availableHeight,
+                                 aContentHeight);
+      NS_FRAME_SET_INCOMPLETE(*aStatus);
+      if (!GetNextInFlow())
+        *aStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
+    }
+  }
+}
+
 #ifdef IBMBIDI
 nsresult
 nsBlockFrame::ResolveBidi()
 {
   NS_ASSERTION(!GetPrevInFlow(),
                "ResolveBidi called on non-first continuation");
 
   nsPresContext* presContext = PresContext();
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -258,16 +258,42 @@ public:
 private:
   void CheckIntrinsicCacheAgainstShrinkWrapState();
 public:
   virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext);
   virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext);
 
   virtual nsRect ComputeTightBounds(gfxContext* aContext) const;
   
+  /**
+   * Compute the final height of this frame.
+   *
+   * @param aReflowState Data structure passed from parent during reflow.
+   * @param aReflowStatus A pointed to the reflow status for when we're finished
+   *        doing reflow. this will get set appropriately if the height causes
+   *        us to exceed the current available (page) height.
+   * @param aContentHeight The height of content, precomputed outside of this
+   *        function. The final height that is used in aMetrics will be set to
+   *        either this or the available height, whichever is larger, in the
+   *        case where our available height is constrained, and we overflow that
+   *        available height.
+   * @param aBorderPadding The margins representing the border padding for block
+   *        frames. Can be 0.
+   * @param aMetrics Out parameter for final height. Taken as an
+   *        nsHTMLReflowMetrics object so that aMetrics can be passed in
+   *        directly during reflow.
+   * @param aConsumed The height already consumed by our previous-in-flows.
+   */
+  void ComputeFinalHeight(const nsHTMLReflowState& aReflowState,
+                          nsReflowStatus*          aStatus,
+                          nscoord                  aContentHeight,
+                          const nsMargin&          aBorderPadding,
+                          nsHTMLReflowMetrics&     aMetrics,
+                          nscoord                  aConsumed);
+
   NS_IMETHOD Reflow(nsPresContext*          aPresContext,
                     nsHTMLReflowMetrics&     aDesiredSize,
                     const nsHTMLReflowState& aReflowState,
                     nsReflowStatus&          aStatus);
 
   NS_IMETHOD AttributeChanged(int32_t         aNameSpaceID,
                               nsIAtom*        aAttribute,
                               int32_t         aModType);
--- a/layout/generic/nsSplittableFrame.cpp
+++ b/layout/generic/nsSplittableFrame.cpp
@@ -227,17 +227,17 @@ nsSplittableFrame::GetEffectiveComputedH
   }
 
   if (aConsumedHeight == NS_INTRINSICSIZE) {
     aConsumedHeight = GetConsumedHeight();
   }
 
   height -= aConsumedHeight;
 
-  if (aConsumedHeight != NS_INTRINSICSIZE) {
+  if (aConsumedHeight != 0 && aConsumedHeight != NS_INTRINSICSIZE) {
     // We just subtracted our top-border padding, since it was included in the
     // first frame's height. Add it back to get the content height.
     height += aReflowState.mComputedBorderPadding.top;
   }
 
   // We may have stretched the frame beyond its computed height. Oh well.
   height = std::max(0, height);