Bug 743402, Part 1: Add a GetConsumedHeight() function to nsSplittableFrame in order to retrieve the portion of the computed height that was consumed by previous-in-flows. [r=roc]
☠☠ backed out by 91356879fbfd ☠ ☠
authorScott Johnson <sjohnson@mozilla.com>
Wed, 24 Jul 2013 12:47:01 -0500
changeset 152147 2edbbf6440c4d33150ef1788d408ad5d5ae1ccfe
parent 152146 60d5f08d0a71418f19f417143fd4c26eb7f4073f
child 152148 c7907c54187f551b6a5e605985771b33733155ad
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 1: Add a GetConsumedHeight() function to nsSplittableFrame in order to retrieve the portion of the computed height that was consumed by previous-in-flows. [r=roc]
layout/generic/nsBlockReflowState.cpp
layout/generic/nsBlockReflowState.h
layout/generic/nsHTMLReflowState.h
layout/generic/nsSplittableFrame.cpp
layout/generic/nsSplittableFrame.h
--- a/layout/generic/nsBlockReflowState.cpp
+++ b/layout/generic/nsBlockReflowState.cpp
@@ -30,26 +30,28 @@
 using namespace mozilla;
 using namespace mozilla::layout;
 
 nsBlockReflowState::nsBlockReflowState(const nsHTMLReflowState& aReflowState,
                                        nsPresContext* aPresContext,
                                        nsBlockFrame* aFrame,
                                        bool aTopMarginRoot,
                                        bool aBottomMarginRoot,
-                                       bool aBlockNeedsFloatManager)
+                                       bool aBlockNeedsFloatManager,
+                                       nscoord aConsumedHeight)
   : mBlock(aFrame),
     mPresContext(aPresContext),
     mReflowState(aReflowState),
     mPushedFloats(nullptr),
     mOverflowTracker(nullptr),
     mPrevBottomMargin(),
     mLineNumber(0),
     mFlags(0),
-    mFloatBreakType(NS_STYLE_CLEAR_NONE)
+    mFloatBreakType(NS_STYLE_CLEAR_NONE),
+    mConsumedHeight(aConsumedHeight)
 {
   SetFlag(BRS_ISFIRSTINFLOW, aFrame->GetPrevInFlow() == nullptr);
   SetFlag(BRS_ISOVERFLOWCONTAINER,
           IS_TRUE_OVERFLOW_CONTAINER(aFrame));
 
   const nsMargin& borderPadding = BorderPadding();
 
   if (aTopMarginRoot || 0 != aReflowState.mComputedBorderPadding.top) {
@@ -108,16 +110,26 @@ nsBlockReflowState::nsBlockReflowState(c
   mY = mContentArea.y = borderPadding.top;
 
   mPrevChild = nullptr;
   mCurrentLine = aFrame->end_lines();
 
   mMinLineHeight = aReflowState.CalcLineHeight();
 }
 
+nscoord
+nsBlockReflowState::GetConsumedHeight()
+{
+  if (mConsumedHeight == NS_INTRINSICSIZE) {
+    mConsumedHeight = mBlock->GetConsumedHeight();
+  }
+
+  return mConsumedHeight;
+}
+
 void
 nsBlockReflowState::ComputeReplacedBlockOffsetsForFloats(nsIFrame* aFrame,
                                                          const nsRect& aFloatAvailableSpace,
                                                          nscoord& aLeftResult,
                                                          nscoord& aRightResult)
 {
   // The frame is clueless about the float manager and therefore we
   // only give it free space. An example is a table frame - the
--- a/layout/generic/nsBlockReflowState.h
+++ b/layout/generic/nsBlockReflowState.h
@@ -35,17 +35,18 @@ class nsOverflowContinuationTracker;
 #define BRS_LASTFLAG              BRS_PROPTABLE_FLOATCLIST
 
 class nsBlockReflowState {
 public:
   nsBlockReflowState(const nsHTMLReflowState& aReflowState,
                      nsPresContext* aPresContext,
                      nsBlockFrame* aFrame,
                      bool aTopMarginRoot, bool aBottomMarginRoot,
-                     bool aBlockNeedsFloatManager);
+                     bool aBlockNeedsFloatManager,
+                     nscoord aConsumedHeight = NS_INTRINSICSIZE);
 
   /**
    * Get the available reflow space (the area not occupied by floats)
    * for the current y coordinate. The available space is relative to
    * our coordinate system, which is the content box, with (0, 0) in the
    * upper left.
    *
    * Returns whether there are floats present at the given vertical
@@ -105,16 +106,21 @@ public:
       result.top = 0;
       if (mFlags & BRS_ISOVERFLOWCONTAINER) {
         result.bottom = 0;
       }
     }
     return result;
   }
 
+  /**
+   * Retrieve the height "consumed" by any previous-in-flows.
+   */
+  nscoord GetConsumedHeight();
+
   // Reconstruct the previous bottom margin that goes above |aLine|.
   void ReconstructMarginAbove(nsLineList::iterator aLine);
 
   // Caller must have called GetAvailableSpace for the correct position
   // (which need not be the current mY).
   void ComputeReplacedBlockOffsetsForFloats(nsIFrame* aFrame,
                                             const nsRect& aFloatAvailableSpace,
                                             nscoord& aLeftResult,
@@ -252,16 +258,19 @@ public:
   nscoord mMinLineHeight;
 
   int32_t mLineNumber;
 
   int16_t mFlags;
  
   uint8_t mFloatBreakType;
 
+  // The amount of computed height "consumed" by previous-in-flows.
+  nscoord mConsumedHeight;
+
   void SetFlag(uint32_t aFlag, bool aValue)
   {
     NS_ASSERTION(aFlag<=BRS_LASTFLAG, "bad flag");
     if (aValue) { // set flag
       mFlags |= aFlag;
     }
     else {        // unset flag
       mFlags &= ~aFlag;
--- a/layout/generic/nsHTMLReflowState.h
+++ b/layout/generic/nsHTMLReflowState.h
@@ -475,25 +475,38 @@ public:
    * size computed so far.
    */
   nscoord ApplyMinMaxWidth(nscoord aWidth) const {
     if (NS_UNCONSTRAINEDSIZE != mComputedMaxWidth) {
       aWidth = std::min(aWidth, mComputedMaxWidth);
     }
     return std::max(aWidth, mComputedMinWidth);
   }
+
   /**
    * Apply the mComputed(Min/Max)Height constraints to the content
    * size computed so far.
+   *
+   * @param aHeight The height that we've computed an to which we want to apply
+   *        min/max constraints.
+   * @param aConsumed The amount of the computed height that was consumed by
+   *        our prev-in-flows.
    */
-  nscoord ApplyMinMaxHeight(nscoord aHeight) const {
+  nscoord ApplyMinMaxHeight(nscoord aHeight, nscoord aConsumed = 0) const {
+    aHeight += aConsumed;
+
     if (NS_UNCONSTRAINEDSIZE != mComputedMaxHeight) {
       aHeight = std::min(aHeight, mComputedMaxHeight);
     }
-    return std::max(aHeight, mComputedMinHeight);
+
+    if (NS_UNCONSTRAINEDSIZE != mComputedMinHeight) {
+      aHeight = std::max(aHeight, mComputedMinHeight);
+    }
+
+    return aHeight - aConsumed;
   }
 
   bool ShouldReflowAllKids() const {
     // Note that we could make a stronger optimization for mVResize if
     // we use it in a ShouldReflowChild test that replaces the current
     // checks of NS_FRAME_IS_DIRTY | NS_FRAME_HAS_DIRTY_CHILDREN, if it
     // were tested there along with NS_FRAME_CONTAINS_RELATIVE_HEIGHT.
     // This would need to be combined with a slight change in which
--- a/layout/generic/nsSplittableFrame.cpp
+++ b/layout/generic/nsSplittableFrame.cpp
@@ -198,16 +198,29 @@ nsSplittableFrame::RemoveFromFlow(nsIFra
       nextContinuation->SetPrevContinuation(prevContinuation);
     }
   }
 
   aFrame->SetPrevInFlow(nullptr);
   aFrame->SetNextInFlow(nullptr);
 }
 
+nscoord
+nsSplittableFrame::GetConsumedHeight() const
+{
+  nscoord height = 0;
+
+  // Reduce the height by the computed height of prev-in-flows.
+  for (nsIFrame* prev = GetPrevInFlow(); prev; prev = prev->GetPrevInFlow()) {
+    height += prev->GetRect().height;
+  }
+
+  return height;
+}
+
 #ifdef DEBUG
 void
 nsSplittableFrame::DumpBaseRegressionData(nsPresContext* aPresContext, FILE* out, int32_t aIndent)
 {
   nsFrame::DumpBaseRegressionData(aPresContext, out, aIndent);
   if (nullptr != mNextContinuation) {
     IndentBy(out, aIndent);
     fprintf(out, "<next-continuation va=\"%p\"/>\n", (void*)mNextContinuation);
--- a/layout/generic/nsSplittableFrame.h
+++ b/layout/generic/nsSplittableFrame.h
@@ -71,16 +71,25 @@ public:
 
   // Remove the frame from the flow. Connects the frame's prev-in-flow
   // and its next-in-flow. This should only be called in frame Destroy() methods.
   static void RemoveFromFlow(nsIFrame* aFrame);
 
 protected:
   nsSplittableFrame(nsStyleContext* aContext) : nsFrame(aContext) {}
 
+  /**
+   * Determine the height consumed by our previous-in-flows.
+   *
+   * @note (bz) This makes laying out a splittable frame with N in-flows
+   *       O(N^2)! So, use this function with caution and minimize the number
+   *       of calls to this method.
+   */
+  nscoord GetConsumedHeight() const;
+
 #ifdef DEBUG
   virtual void DumpBaseRegressionData(nsPresContext* aPresContext, FILE* out, int32_t aIndent) MOZ_OVERRIDE;
 #endif
 
   nsIFrame*   mPrevContinuation;
   nsIFrame*   mNextContinuation;
 };