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 139862 2edbbf6440c4d33150ef1788d408ad5d5ae1ccfe
parent 139861 60d5f08d0a71418f19f417143fd4c26eb7f4073f
child 139863 c7907c54187f551b6a5e605985771b33733155ad
push idunknown
push userunknown
push dateunknown
reviewersroc
bugs743402
milestone25.0a1
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;
 };