From 6dcf85a892216edc9e93705cfa1a0ce3b36f52a4 Mon Sep 17 00:00:00 2001 From: "karnaze%netscape.com" Date: Wed, 10 Apr 2002 21:32:41 +0000 Subject: [PATCH] bug 125543 - Prevent row groups from splitting in the reflow preceeding a special height reflow. Cells are only notified that they should observe a percent height element if the element is inside the table's cell. Percent height elements inside the body will have a height based on the page height when printing. sr=kin, r=alexsavulov. git-svn-id: svn://10.0.0.236/trunk@118648 18797224-902f-48f8-a5cc-f745e15eee43 --- .../layout/base/nsIPercentHeightObserver.h | 8 ++- .../base/public/nsIPercentHeightObserver.h | 8 ++- mozilla/layout/generic/nsFrame.cpp | 10 +++- mozilla/layout/generic/nsHTMLReflowState.cpp | 33 ++++++++--- mozilla/layout/html/base/src/nsFrame.cpp | 10 +++- .../html/base/src/nsHTMLReflowState.cpp | 33 ++++++++--- .../html/table/src/nsTableCellFrame.cpp | 33 ++++++++--- .../layout/html/table/src/nsTableCellFrame.h | 4 +- .../layout/html/table/src/nsTableFrame.cpp | 59 ++++++++++--------- mozilla/layout/html/table/src/nsTableFrame.h | 18 +++++- .../layout/html/table/src/nsTableRowFrame.cpp | 10 ++-- .../html/table/src/nsTableRowGroupFrame.cpp | 10 ++-- mozilla/layout/tables/nsTableCellFrame.cpp | 33 ++++++++--- mozilla/layout/tables/nsTableCellFrame.h | 4 +- mozilla/layout/tables/nsTableFrame.cpp | 59 ++++++++++--------- mozilla/layout/tables/nsTableFrame.h | 18 +++++- mozilla/layout/tables/nsTableRowFrame.cpp | 10 ++-- .../layout/tables/nsTableRowGroupFrame.cpp | 10 ++-- 18 files changed, 250 insertions(+), 120 deletions(-) diff --git a/mozilla/layout/base/nsIPercentHeightObserver.h b/mozilla/layout/base/nsIPercentHeightObserver.h index 61c818af5a3..c411f219541 100644 --- a/mozilla/layout/base/nsIPercentHeightObserver.h +++ b/mozilla/layout/base/nsIPercentHeightObserver.h @@ -48,14 +48,18 @@ class nsIPresContext; /** * This interface is supported by frames that need to provide computed height * values to children during reflow which would otherwise not happen. Currently only - * tables support this. + * table cells support this. */ class nsIPercentHeightObserver : public nsISupports { public: NS_DEFINE_STATIC_IID_ACCESSOR(NS_IPERCENTHEIGHTOBSERVER_IID) - NS_IMETHOD NotifyPercentHeight(const nsHTMLReflowState& aReflowState) = 0; + // Notify the observer that aReflowState has no computed height, but it has a percent height + virtual void NotifyPercentHeight(const nsHTMLReflowState& aReflowState) = 0; + + // Ask the observer if it should observe aReflowState.frame + virtual PRBool NeedsToObserve(const nsHTMLReflowState& aReflowState) = 0; }; #endif // nsIPercentHeightObserver_h___ diff --git a/mozilla/layout/base/public/nsIPercentHeightObserver.h b/mozilla/layout/base/public/nsIPercentHeightObserver.h index 61c818af5a3..c411f219541 100644 --- a/mozilla/layout/base/public/nsIPercentHeightObserver.h +++ b/mozilla/layout/base/public/nsIPercentHeightObserver.h @@ -48,14 +48,18 @@ class nsIPresContext; /** * This interface is supported by frames that need to provide computed height * values to children during reflow which would otherwise not happen. Currently only - * tables support this. + * table cells support this. */ class nsIPercentHeightObserver : public nsISupports { public: NS_DEFINE_STATIC_IID_ACCESSOR(NS_IPERCENTHEIGHTOBSERVER_IID) - NS_IMETHOD NotifyPercentHeight(const nsHTMLReflowState& aReflowState) = 0; + // Notify the observer that aReflowState has no computed height, but it has a percent height + virtual void NotifyPercentHeight(const nsHTMLReflowState& aReflowState) = 0; + + // Ask the observer if it should observe aReflowState.frame + virtual PRBool NeedsToObserve(const nsHTMLReflowState& aReflowState) = 0; }; #endif // nsIPercentHeightObserver_h___ diff --git a/mozilla/layout/generic/nsFrame.cpp b/mozilla/layout/generic/nsFrame.cpp index c69c988af49..afcb51840ce 100644 --- a/mozilla/layout/generic/nsFrame.cpp +++ b/mozilla/layout/generic/nsFrame.cpp @@ -1828,20 +1828,24 @@ nsFrame::DidReflow(nsIPresContext* aPresContext, NS_FRAME_HAS_DIRTY_CHILDREN); } - // Notify the percent height observer if this is an initial or resize constrained reflow + // Notify the percent height observer if this is an initial or resize reflow (XXX + // it should probably be any type of reflow, but this would need further testing) // and there is a percent height but no computed height. The observer may be able to // initiate another reflow with a computed height. This happens in the case where a table // cell has no computed height but can fabricate one when the cell height is known. if (aReflowState && (aReflowState->mPercentHeightObserver) && // an observer ((eReflowReason_Initial == aReflowState->reason) || // initial or resize reflow (eReflowReason_Resize == aReflowState->reason)) && - (NS_UNCONSTRAINEDSIZE != aReflowState->availableWidth) && // constrained width reflow ((NS_UNCONSTRAINEDSIZE == aReflowState->mComputedHeight) || // no computed height (0 == aReflowState->mComputedHeight)) && aReflowState->mStylePosition && // percent height (eStyleUnit_Percent == aReflowState->mStylePosition->mHeight.GetUnit())) { - aReflowState->mPercentHeightObserver->NotifyPercentHeight(*aReflowState); + nsIFrame* prevInFlow; + GetPrevInFlow(&prevInFlow); + if (!prevInFlow) { // 1st in flow + aReflowState->mPercentHeightObserver->NotifyPercentHeight(*aReflowState); + } } return NS_OK; diff --git a/mozilla/layout/generic/nsHTMLReflowState.cpp b/mozilla/layout/generic/nsHTMLReflowState.cpp index 4dbea3aea0b..e489ba98d20 100644 --- a/mozilla/layout/generic/nsHTMLReflowState.cpp +++ b/mozilla/layout/generic/nsHTMLReflowState.cpp @@ -50,6 +50,7 @@ #include "nsImageFrame.h" #include "nsIPref.h" #include "nsIServiceManager.h" +#include "nsIPercentHeightObserver.h" #define IS_TABLE_CELL(frameType)\ ((nsLayoutAtoms::tableCellFrame == frameType) || (nsLayoutAtoms::bcTableCellFrame == frameType)) @@ -163,7 +164,9 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext, mSpaceManager = aParentReflowState.mSpaceManager; mLineLayout = aParentReflowState.mLineLayout; mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage; - mPercentHeightObserver = aParentReflowState.mPercentHeightObserver; + mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver && + aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this)) + ? aParentReflowState.mPercentHeightObserver : nsnull; mPercentHeightReflowInitiator = aParentReflowState.mPercentHeightReflowInitiator; if (aInit) { @@ -195,7 +198,9 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext, mSpaceManager = aParentReflowState.mSpaceManager; mLineLayout = aParentReflowState.mLineLayout; mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage; - mPercentHeightObserver = aParentReflowState.mPercentHeightObserver; + mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver && + aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this)) + ? aParentReflowState.mPercentHeightObserver : nsnull; mPercentHeightReflowInitiator = aParentReflowState.mPercentHeightReflowInitiator; Init(aPresContext); @@ -226,7 +231,9 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext, mSpaceManager = aParentReflowState.mSpaceManager; mLineLayout = aParentReflowState.mLineLayout; mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage; - mPercentHeightObserver = aParentReflowState.mPercentHeightObserver; + mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver && + aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this)) + ? aParentReflowState.mPercentHeightObserver : nsnull; mPercentHeightReflowInitiator = aParentReflowState.mPercentHeightReflowInitiator; Init(aPresContext, aContainingBlockWidth, aContainingBlockHeight); @@ -1367,7 +1374,7 @@ CalcQuirkContainingBlockHeight(const nsHTMLReflowState& aReflowState, nscoord result = 0; const nsHTMLReflowState* rs = &aReflowState; - for (; rs; rs = (nsHTMLReflowState *)(rs->parentReflowState)) { + for (; rs && rs->frame; rs = (nsHTMLReflowState *)(rs->parentReflowState)) { nsCOMPtr frameType; rs->frame->GetFrameType(getter_AddRefs(frameType)); // if the ancestor is auto height then skip it and continue up if it @@ -1405,18 +1412,28 @@ CalcQuirkContainingBlockHeight(const nsHTMLReflowState& aReflowState, rs = scrollState; } } + else if (nsLayoutAtoms::pageContentFrame == frameType.get()) { + nsIFrame* prevInFlow; + rs->frame->GetPrevInFlow(&prevInFlow); + // only use the page content frame for a height basis if it is the first in flow + if (prevInFlow) + break; + } else { break; } - // if the ancestor has a computed height, it is the percent base - result = rs->mComputedHeight; + // if the ancestor is the page content frame then the percent base is + // the avail height, otherwise it is the computed height + result = (nsLayoutAtoms::pageContentFrame == frameType.get()) + ? rs->availableHeight : rs->mComputedHeight; // if unconstrained - don't sutract borders - would result in huge height if (NS_AUTOHEIGHT == result) return result; - // if we got to the canvas frame, then subtract out + // if we got to the canvas or page content frame, then subtract out // margin/border/padding for the BODY and HTML elements - if (nsLayoutAtoms::canvasFrame == frameType.get()) { + if ((nsLayoutAtoms::canvasFrame == frameType.get()) || + (nsLayoutAtoms::pageContentFrame == frameType.get())) { result -= GetVerticalMarginBorderPadding(firstBlockRS); result -= GetVerticalMarginBorderPadding(firstAreaRS); diff --git a/mozilla/layout/html/base/src/nsFrame.cpp b/mozilla/layout/html/base/src/nsFrame.cpp index c69c988af49..afcb51840ce 100644 --- a/mozilla/layout/html/base/src/nsFrame.cpp +++ b/mozilla/layout/html/base/src/nsFrame.cpp @@ -1828,20 +1828,24 @@ nsFrame::DidReflow(nsIPresContext* aPresContext, NS_FRAME_HAS_DIRTY_CHILDREN); } - // Notify the percent height observer if this is an initial or resize constrained reflow + // Notify the percent height observer if this is an initial or resize reflow (XXX + // it should probably be any type of reflow, but this would need further testing) // and there is a percent height but no computed height. The observer may be able to // initiate another reflow with a computed height. This happens in the case where a table // cell has no computed height but can fabricate one when the cell height is known. if (aReflowState && (aReflowState->mPercentHeightObserver) && // an observer ((eReflowReason_Initial == aReflowState->reason) || // initial or resize reflow (eReflowReason_Resize == aReflowState->reason)) && - (NS_UNCONSTRAINEDSIZE != aReflowState->availableWidth) && // constrained width reflow ((NS_UNCONSTRAINEDSIZE == aReflowState->mComputedHeight) || // no computed height (0 == aReflowState->mComputedHeight)) && aReflowState->mStylePosition && // percent height (eStyleUnit_Percent == aReflowState->mStylePosition->mHeight.GetUnit())) { - aReflowState->mPercentHeightObserver->NotifyPercentHeight(*aReflowState); + nsIFrame* prevInFlow; + GetPrevInFlow(&prevInFlow); + if (!prevInFlow) { // 1st in flow + aReflowState->mPercentHeightObserver->NotifyPercentHeight(*aReflowState); + } } return NS_OK; diff --git a/mozilla/layout/html/base/src/nsHTMLReflowState.cpp b/mozilla/layout/html/base/src/nsHTMLReflowState.cpp index 4dbea3aea0b..e489ba98d20 100644 --- a/mozilla/layout/html/base/src/nsHTMLReflowState.cpp +++ b/mozilla/layout/html/base/src/nsHTMLReflowState.cpp @@ -50,6 +50,7 @@ #include "nsImageFrame.h" #include "nsIPref.h" #include "nsIServiceManager.h" +#include "nsIPercentHeightObserver.h" #define IS_TABLE_CELL(frameType)\ ((nsLayoutAtoms::tableCellFrame == frameType) || (nsLayoutAtoms::bcTableCellFrame == frameType)) @@ -163,7 +164,9 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext, mSpaceManager = aParentReflowState.mSpaceManager; mLineLayout = aParentReflowState.mLineLayout; mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage; - mPercentHeightObserver = aParentReflowState.mPercentHeightObserver; + mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver && + aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this)) + ? aParentReflowState.mPercentHeightObserver : nsnull; mPercentHeightReflowInitiator = aParentReflowState.mPercentHeightReflowInitiator; if (aInit) { @@ -195,7 +198,9 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext, mSpaceManager = aParentReflowState.mSpaceManager; mLineLayout = aParentReflowState.mLineLayout; mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage; - mPercentHeightObserver = aParentReflowState.mPercentHeightObserver; + mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver && + aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this)) + ? aParentReflowState.mPercentHeightObserver : nsnull; mPercentHeightReflowInitiator = aParentReflowState.mPercentHeightReflowInitiator; Init(aPresContext); @@ -226,7 +231,9 @@ nsHTMLReflowState::nsHTMLReflowState(nsIPresContext* aPresContext, mSpaceManager = aParentReflowState.mSpaceManager; mLineLayout = aParentReflowState.mLineLayout; mFlags.mIsTopOfPage = aParentReflowState.mFlags.mIsTopOfPage; - mPercentHeightObserver = aParentReflowState.mPercentHeightObserver; + mPercentHeightObserver = (aParentReflowState.mPercentHeightObserver && + aParentReflowState.mPercentHeightObserver->NeedsToObserve(*this)) + ? aParentReflowState.mPercentHeightObserver : nsnull; mPercentHeightReflowInitiator = aParentReflowState.mPercentHeightReflowInitiator; Init(aPresContext, aContainingBlockWidth, aContainingBlockHeight); @@ -1367,7 +1374,7 @@ CalcQuirkContainingBlockHeight(const nsHTMLReflowState& aReflowState, nscoord result = 0; const nsHTMLReflowState* rs = &aReflowState; - for (; rs; rs = (nsHTMLReflowState *)(rs->parentReflowState)) { + for (; rs && rs->frame; rs = (nsHTMLReflowState *)(rs->parentReflowState)) { nsCOMPtr frameType; rs->frame->GetFrameType(getter_AddRefs(frameType)); // if the ancestor is auto height then skip it and continue up if it @@ -1405,18 +1412,28 @@ CalcQuirkContainingBlockHeight(const nsHTMLReflowState& aReflowState, rs = scrollState; } } + else if (nsLayoutAtoms::pageContentFrame == frameType.get()) { + nsIFrame* prevInFlow; + rs->frame->GetPrevInFlow(&prevInFlow); + // only use the page content frame for a height basis if it is the first in flow + if (prevInFlow) + break; + } else { break; } - // if the ancestor has a computed height, it is the percent base - result = rs->mComputedHeight; + // if the ancestor is the page content frame then the percent base is + // the avail height, otherwise it is the computed height + result = (nsLayoutAtoms::pageContentFrame == frameType.get()) + ? rs->availableHeight : rs->mComputedHeight; // if unconstrained - don't sutract borders - would result in huge height if (NS_AUTOHEIGHT == result) return result; - // if we got to the canvas frame, then subtract out + // if we got to the canvas or page content frame, then subtract out // margin/border/padding for the BODY and HTML elements - if (nsLayoutAtoms::canvasFrame == frameType.get()) { + if ((nsLayoutAtoms::canvasFrame == frameType.get()) || + (nsLayoutAtoms::pageContentFrame == frameType.get())) { result -= GetVerticalMarginBorderPadding(firstBlockRS); result -= GetVerticalMarginBorderPadding(firstAreaRS); diff --git a/mozilla/layout/html/table/src/nsTableCellFrame.cpp b/mozilla/layout/html/table/src/nsTableCellFrame.cpp index b886557619c..540c09fc920 100644 --- a/mozilla/layout/html/table/src/nsTableCellFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableCellFrame.cpp @@ -156,7 +156,7 @@ NoComputedHeightBetween(const nsHTMLReflowState& aReflowState, // nsIPercentHeightObserver methods -nsresult +void nsTableCellFrame::NotifyPercentHeight(const nsHTMLReflowState& aReflowState) { if (!NeedSpecialReflow()) { @@ -166,17 +166,36 @@ nsTableCellFrame::NotifyPercentHeight(const nsHTMLReflowState& aReflowState) // initiating frame and the cell. for (const nsHTMLReflowState* rs = aReflowState.parentReflowState; rs; rs = rs->parentReflowState) { if ((NS_UNCONSTRAINEDSIZE != rs->mComputedHeight) && (0 != rs->mComputedHeight)) { - return NS_OK; + return; } // stop when we reach the cell frame if (rs->frame == this) { nsTableFrame::RequestSpecialHeightReflow(*rs); - return NS_OK; + return; } } NS_ASSERTION(PR_FALSE, "program error in NotifyPercentHeight"); } - return NS_OK; +} + +// The cell needs to observe its block and things inside its block but nothing below that +PRBool +nsTableCellFrame::NeedsToObserve(const nsHTMLReflowState& aReflowState) +{ + PRBool result = PR_FALSE; + const nsHTMLReflowState* parentRS = aReflowState.parentReflowState; + if (parentRS && (parentRS->mPercentHeightObserver == this)) { // cell observes the parent + result = PR_TRUE; + parentRS = parentRS->parentReflowState; + if (parentRS && (parentRS->mPercentHeightObserver == this)) { // cell observers the grand parent + parentRS = parentRS->parentReflowState; + if (parentRS && (parentRS->mPercentHeightObserver == this)) { + // cell observes the great grand parent, so we have gone too deep + result = PR_FALSE; + } + } + } + return result; } nsresult @@ -798,7 +817,8 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, nsresult rv = NS_OK; // see if a special height reflow needs to occur due to having a pct height - nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState); + if (!NeedSpecialReflow()) + nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState); // this should probably be cached somewhere nsCompatibility compatMode; @@ -883,8 +903,7 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, nscoord computedPaginatedHeight = 0; if (aReflowState.mFlags.mSpecialHeightReflow || - (HadSpecialReflow() && ((eReflowReason_Incremental == aReflowState.reason) || - (eReflowReason_Resize == aReflowState.reason)))) { + (HadSpecialReflow() && (eReflowReason_Incremental == aReflowState.reason))) { ((nsHTMLReflowState&)aReflowState).mComputedHeight = mRect.height - topInset - bottomInset; DISPLAY_REFLOW_CHANGE(); } diff --git a/mozilla/layout/html/table/src/nsTableCellFrame.h b/mozilla/layout/html/table/src/nsTableCellFrame.h index 80981862905..5298561720c 100644 --- a/mozilla/layout/html/table/src/nsTableCellFrame.h +++ b/mozilla/layout/html/table/src/nsTableCellFrame.h @@ -116,8 +116,10 @@ public: nsIAtom* aListName, nsIFrame* aOldFrame); - NS_IMETHOD NotifyPercentHeight(const nsHTMLReflowState& aReflowState); + virtual void NotifyPercentHeight(const nsHTMLReflowState& aReflowState); + virtual PRBool NeedsToObserve(const nsHTMLReflowState& aReflowState); + void InitCellFrame(PRInt32 aColIndex); diff --git a/mozilla/layout/html/table/src/nsTableFrame.cpp b/mozilla/layout/html/table/src/nsTableFrame.cpp index 315d33442e5..de1296dc175 100644 --- a/mozilla/layout/html/table/src/nsTableFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableFrame.cpp @@ -1898,11 +1898,10 @@ nsTableFrame::CheckRequestSpecialHeightReflow(const nsHTMLReflowState& aReflowSt nsIFrame* prevInFlow; aReflowState.frame->GetPrevInFlow(&prevInFlow); - if ((NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth) && // not first pass reflow - !prevInFlow && // 1st in flow && // 1st in flow + if (!prevInFlow && // 1st in flow && // 1st in flow ((NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) || // no computed height (0 == aReflowState.mComputedHeight)) && - ::IsPctStyleHeight(aReflowState.mStylePosition)) { // pct height + ::IsPctStyleHeight(aReflowState.mStylePosition)) { // pct height if (::AncestorsHaveStyleHeight(aReflowState)) { nsTableFrame::RequestSpecialHeightReflow(aReflowState); @@ -2056,6 +2055,10 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, } nsresult rv = NS_OK; + // see if a special height reflow needs to occur due to having a pct height + if (!NeedSpecialReflow()) + nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState); + // see if collapsing borders need to be calculated if (!mPrevInFlow && IsBorderCollapse() && NeedToCalcBCBorders()) { GET_TWIPS_TO_PIXELS(aPresContext, p2t); @@ -2132,35 +2135,33 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, // and other reflows which require either a strategy init or balance. This isn't done // during an unconstrained reflow because another reflow will be processed later. if (NeedsReflow(aReflowState) && (NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth)) { - if (!mPrevInFlow) { - // see if an extra reflow will be necessary when the table is nested, there is a pct height, - // no computed height, but a height on the containing table - if ( ((NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) || - (0 == aReflowState.mComputedHeight)) && - IsPctHeight(mStyleContext)) { - nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState); - } - // see if an extra reflow will be necessary in pagination mode when there is a specified table height - else if (isPaginated && (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight)) { - nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aPresContext, aReflowState); - if ((tableSpecifiedHeight > 0) && - (tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE)) { - SetNeedToInitiateSpecialReflow(PR_TRUE); - } + // see if an extra reflow will be necessary in pagination mode when there is a specified table height + if (isPaginated && !mPrevInFlow && (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight)) { + nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aPresContext, aReflowState); + if ((tableSpecifiedHeight > 0) && + (tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE)) { + SetNeedToInitiateSpecialReflow(PR_TRUE); } } - // if we need to reflow the table an extra time, then don't constrain the height of the previous reflow - nscoord availHeight = !aReflowState.mFlags.mSpecialHeightReflow && - (NeedSpecialReflow() | NeedToInitiateSpecialReflow()) - ? NS_UNCONSTRAINEDSIZE : aReflowState.availableHeight; + nsIFrame* lastChildReflowed = nsnull; + PRBool willInitiateSpecialReflow = + ((NeedToInitiateSpecialReflow() || InitiatedSpecialReflow()) && + (aReflowState.mFlags.mSpecialHeightReflow || !NeedSpecialReflow())); - nsIFrame* lastChildReflowed; - ReflowTable(aPresContext, aDesiredSize, aReflowState, availHeight, nextReason, - lastChildReflowed, doCollapse, balanced, aStatus); + // do the pass 2 reflow unless this is a special height reflow and we will be + // initiating a special height reflow + if (!(aReflowState.mFlags.mSpecialHeightReflow && willInitiateSpecialReflow)) { + // if we need to initiate a special height reflow, then don't constrain the + // height of the reflow before that + nscoord availHeight = (willInitiateSpecialReflow) + ? NS_UNCONSTRAINEDSIZE : aReflowState.availableHeight; - if (NeedToInitiateSpecialReflow() && - (aReflowState.mFlags.mSpecialHeightReflow || !NeedSpecialReflow())) { - aDesiredSize.height = CalcDesiredHeight(aPresContext, aReflowState); // distributes extra vertical space to rows + ReflowTable(aPresContext, aDesiredSize, aReflowState, availHeight, nextReason, + lastChildReflowed, doCollapse, balanced, aStatus); + } + if (willInitiateSpecialReflow && NS_FRAME_IS_COMPLETE(aStatus)) { + // distribute extra vertical space to rows + aDesiredSize.height = CalcDesiredHeight(aPresContext, aReflowState); ((nsHTMLReflowState::ReflowStateFlags&)aReflowState.mFlags).mSpecialHeightReflow = PR_TRUE; // save the previous special height reflow initiator, install us as the new one nsIFrame* specialReflowInitiator = aReflowState.mPercentHeightReflowInitiator; @@ -2171,6 +2172,8 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, nextReason, lastChildReflowed, doCollapse, balanced, aStatus); // restore the previous special height reflow initiator ((nsHTMLReflowState&)aReflowState).mPercentHeightReflowInitiator = specialReflowInitiator; + // XXX We should call SetInitiatedSpecialReflow(PR_FALSE) at some point, but it is difficult to tell when + SetInitiatedSpecialReflow(PR_TRUE); if (lastChildReflowed && NS_FRAME_IS_NOT_COMPLETE(aStatus)) { // if there is an incomplete child, then set the desired height to include it but not the next one diff --git a/mozilla/layout/html/table/src/nsTableFrame.h b/mozilla/layout/html/table/src/nsTableFrame.h index 717e47a97d9..3dbbfc6455c 100644 --- a/mozilla/layout/html/table/src/nsTableFrame.h +++ b/mozilla/layout/html/table/src/nsTableFrame.h @@ -554,9 +554,13 @@ public: PRBool NeedSpecialReflow() const; void SetNeedSpecialReflow(PRBool aValue); + PRBool NeedToInitiateSpecialReflow() const; void SetNeedToInitiateSpecialReflow(PRBool aValue); + PRBool InitiatedSpecialReflow() const; + void SetInitiatedSpecialReflow(PRBool aValue); + protected: /** protected constructor. @@ -955,8 +959,9 @@ protected: unsigned mRowInserted:1; unsigned mNeedSpecialReflow:1; unsigned mNeedToInitiateSpecialReflow:1; + unsigned mInitiatedSpecialReflow:1; unsigned mNeedToCalcBCBorders:1; - unsigned : 18; // unused + unsigned : 17; // unused } mBits; nsTableCellMap* mCellMap; // maintains the relationships between rows, cols, and cells @@ -1079,6 +1084,17 @@ inline void nsTableFrame::SetNeedToInitiateSpecialReflow(PRBool aValue) { mBits.mNeedToInitiateSpecialReflow = (unsigned)aValue; } + +inline PRBool nsTableFrame::InitiatedSpecialReflow() const +{ + return (PRBool)mBits.mInitiatedSpecialReflow; +} + +inline void nsTableFrame::SetInitiatedSpecialReflow(PRBool aValue) +{ + mBits.mInitiatedSpecialReflow = (unsigned)aValue; +} + inline PRBool nsTableFrame::IsRowInserted() const { return (PRBool)mBits.mRowInserted; diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.cpp b/mozilla/layout/html/table/src/nsTableRowFrame.cpp index 23a256078d4..acdc25708bc 100644 --- a/mozilla/layout/html/table/src/nsTableRowFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableRowFrame.cpp @@ -992,13 +992,14 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext, nsIFrame* kidNextInFlow; kidFrame->GetNextInFlow(&kidNextInFlow); nsSize cellDesiredSize = cellFrame->GetDesiredSize(); - if ((availCellWidth != cellFrame->GetPriorAvailWidth()) || + if ((availCellWidth != cellFrame->GetPriorAvailWidth()) || (cellDesiredSize.width > cellFrame->GetPriorAvailWidth()) || (eReflowReason_StyleChange == aReflowState.reason) || isPaginated || (aReflowState.mFlags.mSpecialHeightReflow && cellFrame->NeedSpecialReflow()) || - HasPctHeight() || - notifyStyleChange ){ + (!aReflowState.mFlags.mSpecialHeightReflow && cellFrame->HadSpecialReflow()) || + HasPctHeight() || + notifyStyleChange) { // Reflow the cell to fit the available width, height nsSize kidAvailSize(availColWidth, aReflowState.availableHeight); nsReflowReason reason = eReflowReason_Resize; @@ -1443,7 +1444,8 @@ nsTableRowFrame::Reflow(nsIPresContext* aPresContext, if (!tableFrame) return NS_ERROR_NULL_POINTER; // see if a special height reflow needs to occur due to having a pct height - nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState); + if (!NeedSpecialReflow()) + nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState); switch (aReflowState.reason) { case eReflowReason_Initial: diff --git a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp index 4b2f234b15c..08fa927b6c3 100644 --- a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp @@ -1186,16 +1186,14 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext, PRBool isPaginated; aPresContext->IsPaginated(&isPaginated); - // If this is a special height reflow, set our desired size to what is was previously and return - // if we will be getting another special height reflow. In paginated mode, SetNeedSpecialReflow(PR_TRUE) - // may not have been called if reflow was a result of having a height on the containing table - if (nsTableFrame::IsPrematureSpecialHeightReflow(aReflowState, mRect, NeedSpecialReflow() || isPaginated, aDesiredSize)) - return NS_OK; - nsTableFrame* tableFrame = nsnull; rv = nsTableFrame::GetTableFrame(this, tableFrame); if (!aPresContext || !tableFrame) return NS_ERROR_NULL_POINTER; + // see if a special height reflow needs to occur due to having a pct height + if (!NeedSpecialReflow()) + nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState); + nsRowGroupReflowState state(aReflowState, tableFrame); PRBool haveDesiredHeight = PR_FALSE; diff --git a/mozilla/layout/tables/nsTableCellFrame.cpp b/mozilla/layout/tables/nsTableCellFrame.cpp index b886557619c..540c09fc920 100644 --- a/mozilla/layout/tables/nsTableCellFrame.cpp +++ b/mozilla/layout/tables/nsTableCellFrame.cpp @@ -156,7 +156,7 @@ NoComputedHeightBetween(const nsHTMLReflowState& aReflowState, // nsIPercentHeightObserver methods -nsresult +void nsTableCellFrame::NotifyPercentHeight(const nsHTMLReflowState& aReflowState) { if (!NeedSpecialReflow()) { @@ -166,17 +166,36 @@ nsTableCellFrame::NotifyPercentHeight(const nsHTMLReflowState& aReflowState) // initiating frame and the cell. for (const nsHTMLReflowState* rs = aReflowState.parentReflowState; rs; rs = rs->parentReflowState) { if ((NS_UNCONSTRAINEDSIZE != rs->mComputedHeight) && (0 != rs->mComputedHeight)) { - return NS_OK; + return; } // stop when we reach the cell frame if (rs->frame == this) { nsTableFrame::RequestSpecialHeightReflow(*rs); - return NS_OK; + return; } } NS_ASSERTION(PR_FALSE, "program error in NotifyPercentHeight"); } - return NS_OK; +} + +// The cell needs to observe its block and things inside its block but nothing below that +PRBool +nsTableCellFrame::NeedsToObserve(const nsHTMLReflowState& aReflowState) +{ + PRBool result = PR_FALSE; + const nsHTMLReflowState* parentRS = aReflowState.parentReflowState; + if (parentRS && (parentRS->mPercentHeightObserver == this)) { // cell observes the parent + result = PR_TRUE; + parentRS = parentRS->parentReflowState; + if (parentRS && (parentRS->mPercentHeightObserver == this)) { // cell observers the grand parent + parentRS = parentRS->parentReflowState; + if (parentRS && (parentRS->mPercentHeightObserver == this)) { + // cell observes the great grand parent, so we have gone too deep + result = PR_FALSE; + } + } + } + return result; } nsresult @@ -798,7 +817,8 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, nsresult rv = NS_OK; // see if a special height reflow needs to occur due to having a pct height - nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState); + if (!NeedSpecialReflow()) + nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState); // this should probably be cached somewhere nsCompatibility compatMode; @@ -883,8 +903,7 @@ NS_METHOD nsTableCellFrame::Reflow(nsIPresContext* aPresContext, nscoord computedPaginatedHeight = 0; if (aReflowState.mFlags.mSpecialHeightReflow || - (HadSpecialReflow() && ((eReflowReason_Incremental == aReflowState.reason) || - (eReflowReason_Resize == aReflowState.reason)))) { + (HadSpecialReflow() && (eReflowReason_Incremental == aReflowState.reason))) { ((nsHTMLReflowState&)aReflowState).mComputedHeight = mRect.height - topInset - bottomInset; DISPLAY_REFLOW_CHANGE(); } diff --git a/mozilla/layout/tables/nsTableCellFrame.h b/mozilla/layout/tables/nsTableCellFrame.h index 80981862905..5298561720c 100644 --- a/mozilla/layout/tables/nsTableCellFrame.h +++ b/mozilla/layout/tables/nsTableCellFrame.h @@ -116,8 +116,10 @@ public: nsIAtom* aListName, nsIFrame* aOldFrame); - NS_IMETHOD NotifyPercentHeight(const nsHTMLReflowState& aReflowState); + virtual void NotifyPercentHeight(const nsHTMLReflowState& aReflowState); + virtual PRBool NeedsToObserve(const nsHTMLReflowState& aReflowState); + void InitCellFrame(PRInt32 aColIndex); diff --git a/mozilla/layout/tables/nsTableFrame.cpp b/mozilla/layout/tables/nsTableFrame.cpp index 315d33442e5..de1296dc175 100644 --- a/mozilla/layout/tables/nsTableFrame.cpp +++ b/mozilla/layout/tables/nsTableFrame.cpp @@ -1898,11 +1898,10 @@ nsTableFrame::CheckRequestSpecialHeightReflow(const nsHTMLReflowState& aReflowSt nsIFrame* prevInFlow; aReflowState.frame->GetPrevInFlow(&prevInFlow); - if ((NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth) && // not first pass reflow - !prevInFlow && // 1st in flow && // 1st in flow + if (!prevInFlow && // 1st in flow && // 1st in flow ((NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) || // no computed height (0 == aReflowState.mComputedHeight)) && - ::IsPctStyleHeight(aReflowState.mStylePosition)) { // pct height + ::IsPctStyleHeight(aReflowState.mStylePosition)) { // pct height if (::AncestorsHaveStyleHeight(aReflowState)) { nsTableFrame::RequestSpecialHeightReflow(aReflowState); @@ -2056,6 +2055,10 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, } nsresult rv = NS_OK; + // see if a special height reflow needs to occur due to having a pct height + if (!NeedSpecialReflow()) + nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState); + // see if collapsing borders need to be calculated if (!mPrevInFlow && IsBorderCollapse() && NeedToCalcBCBorders()) { GET_TWIPS_TO_PIXELS(aPresContext, p2t); @@ -2132,35 +2135,33 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, // and other reflows which require either a strategy init or balance. This isn't done // during an unconstrained reflow because another reflow will be processed later. if (NeedsReflow(aReflowState) && (NS_UNCONSTRAINEDSIZE != aReflowState.availableWidth)) { - if (!mPrevInFlow) { - // see if an extra reflow will be necessary when the table is nested, there is a pct height, - // no computed height, but a height on the containing table - if ( ((NS_UNCONSTRAINEDSIZE == aReflowState.mComputedHeight) || - (0 == aReflowState.mComputedHeight)) && - IsPctHeight(mStyleContext)) { - nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState); - } - // see if an extra reflow will be necessary in pagination mode when there is a specified table height - else if (isPaginated && (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight)) { - nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aPresContext, aReflowState); - if ((tableSpecifiedHeight > 0) && - (tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE)) { - SetNeedToInitiateSpecialReflow(PR_TRUE); - } + // see if an extra reflow will be necessary in pagination mode when there is a specified table height + if (isPaginated && !mPrevInFlow && (NS_UNCONSTRAINEDSIZE != aReflowState.availableHeight)) { + nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aPresContext, aReflowState); + if ((tableSpecifiedHeight > 0) && + (tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE)) { + SetNeedToInitiateSpecialReflow(PR_TRUE); } } - // if we need to reflow the table an extra time, then don't constrain the height of the previous reflow - nscoord availHeight = !aReflowState.mFlags.mSpecialHeightReflow && - (NeedSpecialReflow() | NeedToInitiateSpecialReflow()) - ? NS_UNCONSTRAINEDSIZE : aReflowState.availableHeight; + nsIFrame* lastChildReflowed = nsnull; + PRBool willInitiateSpecialReflow = + ((NeedToInitiateSpecialReflow() || InitiatedSpecialReflow()) && + (aReflowState.mFlags.mSpecialHeightReflow || !NeedSpecialReflow())); - nsIFrame* lastChildReflowed; - ReflowTable(aPresContext, aDesiredSize, aReflowState, availHeight, nextReason, - lastChildReflowed, doCollapse, balanced, aStatus); + // do the pass 2 reflow unless this is a special height reflow and we will be + // initiating a special height reflow + if (!(aReflowState.mFlags.mSpecialHeightReflow && willInitiateSpecialReflow)) { + // if we need to initiate a special height reflow, then don't constrain the + // height of the reflow before that + nscoord availHeight = (willInitiateSpecialReflow) + ? NS_UNCONSTRAINEDSIZE : aReflowState.availableHeight; - if (NeedToInitiateSpecialReflow() && - (aReflowState.mFlags.mSpecialHeightReflow || !NeedSpecialReflow())) { - aDesiredSize.height = CalcDesiredHeight(aPresContext, aReflowState); // distributes extra vertical space to rows + ReflowTable(aPresContext, aDesiredSize, aReflowState, availHeight, nextReason, + lastChildReflowed, doCollapse, balanced, aStatus); + } + if (willInitiateSpecialReflow && NS_FRAME_IS_COMPLETE(aStatus)) { + // distribute extra vertical space to rows + aDesiredSize.height = CalcDesiredHeight(aPresContext, aReflowState); ((nsHTMLReflowState::ReflowStateFlags&)aReflowState.mFlags).mSpecialHeightReflow = PR_TRUE; // save the previous special height reflow initiator, install us as the new one nsIFrame* specialReflowInitiator = aReflowState.mPercentHeightReflowInitiator; @@ -2171,6 +2172,8 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, nextReason, lastChildReflowed, doCollapse, balanced, aStatus); // restore the previous special height reflow initiator ((nsHTMLReflowState&)aReflowState).mPercentHeightReflowInitiator = specialReflowInitiator; + // XXX We should call SetInitiatedSpecialReflow(PR_FALSE) at some point, but it is difficult to tell when + SetInitiatedSpecialReflow(PR_TRUE); if (lastChildReflowed && NS_FRAME_IS_NOT_COMPLETE(aStatus)) { // if there is an incomplete child, then set the desired height to include it but not the next one diff --git a/mozilla/layout/tables/nsTableFrame.h b/mozilla/layout/tables/nsTableFrame.h index 717e47a97d9..3dbbfc6455c 100644 --- a/mozilla/layout/tables/nsTableFrame.h +++ b/mozilla/layout/tables/nsTableFrame.h @@ -554,9 +554,13 @@ public: PRBool NeedSpecialReflow() const; void SetNeedSpecialReflow(PRBool aValue); + PRBool NeedToInitiateSpecialReflow() const; void SetNeedToInitiateSpecialReflow(PRBool aValue); + PRBool InitiatedSpecialReflow() const; + void SetInitiatedSpecialReflow(PRBool aValue); + protected: /** protected constructor. @@ -955,8 +959,9 @@ protected: unsigned mRowInserted:1; unsigned mNeedSpecialReflow:1; unsigned mNeedToInitiateSpecialReflow:1; + unsigned mInitiatedSpecialReflow:1; unsigned mNeedToCalcBCBorders:1; - unsigned : 18; // unused + unsigned : 17; // unused } mBits; nsTableCellMap* mCellMap; // maintains the relationships between rows, cols, and cells @@ -1079,6 +1084,17 @@ inline void nsTableFrame::SetNeedToInitiateSpecialReflow(PRBool aValue) { mBits.mNeedToInitiateSpecialReflow = (unsigned)aValue; } + +inline PRBool nsTableFrame::InitiatedSpecialReflow() const +{ + return (PRBool)mBits.mInitiatedSpecialReflow; +} + +inline void nsTableFrame::SetInitiatedSpecialReflow(PRBool aValue) +{ + mBits.mInitiatedSpecialReflow = (unsigned)aValue; +} + inline PRBool nsTableFrame::IsRowInserted() const { return (PRBool)mBits.mRowInserted; diff --git a/mozilla/layout/tables/nsTableRowFrame.cpp b/mozilla/layout/tables/nsTableRowFrame.cpp index 23a256078d4..acdc25708bc 100644 --- a/mozilla/layout/tables/nsTableRowFrame.cpp +++ b/mozilla/layout/tables/nsTableRowFrame.cpp @@ -992,13 +992,14 @@ nsTableRowFrame::ReflowChildren(nsIPresContext* aPresContext, nsIFrame* kidNextInFlow; kidFrame->GetNextInFlow(&kidNextInFlow); nsSize cellDesiredSize = cellFrame->GetDesiredSize(); - if ((availCellWidth != cellFrame->GetPriorAvailWidth()) || + if ((availCellWidth != cellFrame->GetPriorAvailWidth()) || (cellDesiredSize.width > cellFrame->GetPriorAvailWidth()) || (eReflowReason_StyleChange == aReflowState.reason) || isPaginated || (aReflowState.mFlags.mSpecialHeightReflow && cellFrame->NeedSpecialReflow()) || - HasPctHeight() || - notifyStyleChange ){ + (!aReflowState.mFlags.mSpecialHeightReflow && cellFrame->HadSpecialReflow()) || + HasPctHeight() || + notifyStyleChange) { // Reflow the cell to fit the available width, height nsSize kidAvailSize(availColWidth, aReflowState.availableHeight); nsReflowReason reason = eReflowReason_Resize; @@ -1443,7 +1444,8 @@ nsTableRowFrame::Reflow(nsIPresContext* aPresContext, if (!tableFrame) return NS_ERROR_NULL_POINTER; // see if a special height reflow needs to occur due to having a pct height - nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState); + if (!NeedSpecialReflow()) + nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState); switch (aReflowState.reason) { case eReflowReason_Initial: diff --git a/mozilla/layout/tables/nsTableRowGroupFrame.cpp b/mozilla/layout/tables/nsTableRowGroupFrame.cpp index 4b2f234b15c..08fa927b6c3 100644 --- a/mozilla/layout/tables/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/tables/nsTableRowGroupFrame.cpp @@ -1186,16 +1186,14 @@ nsTableRowGroupFrame::Reflow(nsIPresContext* aPresContext, PRBool isPaginated; aPresContext->IsPaginated(&isPaginated); - // If this is a special height reflow, set our desired size to what is was previously and return - // if we will be getting another special height reflow. In paginated mode, SetNeedSpecialReflow(PR_TRUE) - // may not have been called if reflow was a result of having a height on the containing table - if (nsTableFrame::IsPrematureSpecialHeightReflow(aReflowState, mRect, NeedSpecialReflow() || isPaginated, aDesiredSize)) - return NS_OK; - nsTableFrame* tableFrame = nsnull; rv = nsTableFrame::GetTableFrame(this, tableFrame); if (!aPresContext || !tableFrame) return NS_ERROR_NULL_POINTER; + // see if a special height reflow needs to occur due to having a pct height + if (!NeedSpecialReflow()) + nsTableFrame::CheckRequestSpecialHeightReflow(aReflowState); + nsRowGroupReflowState state(aReflowState, tableFrame); PRBool haveDesiredHeight = PR_FALSE;