From 47f205f65fb553358741bb478921fc93f47b181e Mon Sep 17 00:00:00 2001 From: "karnaze%netscape.com" Date: Fri, 28 Apr 2000 21:05:31 +0000 Subject: [PATCH] new reflow/layout code for outer table to handle captions and margins. better % height handling. row groups and rows don't include external cellspacing in there dimensions. r=troy. git-svn-id: svn://10.0.0.236/trunk@67566 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/content/base/src/nsStyleContext.cpp | 5 +- mozilla/layout/base/nsCSSFrameConstructor.cpp | 170 ++- .../layout/base/public/nsHTMLReflowState.h | 14 +- mozilla/layout/base/src/nsStyleContext.cpp | 5 +- .../generic/nsAbsoluteContainingBlock.cpp | 3 +- mozilla/layout/generic/nsHTMLReflowState.cpp | 128 +- mozilla/layout/generic/nsHTMLReflowState.h | 14 +- .../base/src/nsAbsoluteContainingBlock.cpp | 3 +- .../html/base/src/nsHTMLReflowState.cpp | 128 +- mozilla/layout/html/document/src/html.css | 52 +- .../html/style/src/nsCSSFrameConstructor.cpp | 170 ++- mozilla/layout/html/table/src/nsCellMap.cpp | 13 +- .../layout/html/table/src/nsTableFrame.cpp | 416 +++--- mozilla/layout/html/table/src/nsTableFrame.h | 38 +- .../html/table/src/nsTableOuterFrame.cpp | 1300 ++++++++++------- .../layout/html/table/src/nsTableOuterFrame.h | 170 ++- .../layout/html/table/src/nsTableRowFrame.cpp | 90 +- .../layout/html/table/src/nsTableRowFrame.h | 2 - .../html/table/src/nsTableRowGroupFrame.cpp | 81 +- mozilla/layout/style/html.css | 52 +- mozilla/layout/style/nsStyleContext.cpp | 5 +- mozilla/layout/tables/nsCellMap.cpp | 13 +- mozilla/layout/tables/nsTableFrame.cpp | 416 +++--- mozilla/layout/tables/nsTableFrame.h | 38 +- mozilla/layout/tables/nsTableOuterFrame.cpp | 1300 ++++++++++------- mozilla/layout/tables/nsTableOuterFrame.h | 170 ++- mozilla/layout/tables/nsTableRowFrame.cpp | 90 +- mozilla/layout/tables/nsTableRowFrame.h | 2 - .../layout/tables/nsTableRowGroupFrame.cpp | 81 +- .../xul/base/src/nsBoxToBlockAdaptor.cpp | 12 +- .../layout/xul/base/src/nsTreeOuterFrame.cpp | 1 - .../xul/base/src/nsTreeRowGroupFrame.cpp | 6 + 32 files changed, 2911 insertions(+), 2077 deletions(-) diff --git a/mozilla/content/base/src/nsStyleContext.cpp b/mozilla/content/base/src/nsStyleContext.cpp index 0f7073218db..f527613733c 100644 --- a/mozilla/content/base/src/nsStyleContext.cpp +++ b/mozilla/content/base/src/nsStyleContext.cpp @@ -2287,8 +2287,9 @@ StyleContextImpl::RemapStyle(nsIPresContext* aPresContext, PRBool aRecurse) nsCompatibility quirkMode = eCompatibility_Standard; aPresContext->GetCompatibilityMode(&quirkMode); if (eCompatibility_NavQuirks == quirkMode) { - if ((mDisplay.mDisplay == NS_STYLE_DISPLAY_TABLE) || - (mDisplay.mDisplay == NS_STYLE_DISPLAY_TABLE_CAPTION)) { + if (((mDisplay.mDisplay == NS_STYLE_DISPLAY_TABLE) || + (mDisplay.mDisplay == NS_STYLE_DISPLAY_TABLE_CAPTION)) && + (nsnull == mPseudoTag)) { StyleContextImpl* holdParent = mParent; mParent = nsnull; // cut off all inheritance. this really blows diff --git a/mozilla/layout/base/nsCSSFrameConstructor.cpp b/mozilla/layout/base/nsCSSFrameConstructor.cpp index a2fb0349db8..584a6bd42a8 100644 --- a/mozilla/layout/base/nsCSSFrameConstructor.cpp +++ b/mozilla/layout/base/nsCSSFrameConstructor.cpp @@ -360,9 +360,6 @@ struct nsPseudoFrames { // the frame type of the most descendant pseudo frame, no AddRef nsIAtom* mLowestType; - // col groups are handled specially so if there is both a pseudo - // row group and col group, content order needs to be preserved - PRBool mColGroupBeforeRowGroup; nsPseudoFrames(); nsPseudoFrames& operator=(const nsPseudoFrames& aOther); @@ -389,8 +386,7 @@ nsPseudoFrameData::Reset() nsPseudoFrames::nsPseudoFrames() : mTableOuter(), mTableInner(), mRowGroup(), mColGroup(), - mRow(), mCellOuter(), mCellInner(), mLowestType(nsnull), - mColGroupBeforeRowGroup(PR_FALSE) + mRow(), mCellOuter(), mCellInner(), mLowestType(nsnull) {} nsPseudoFrames& nsPseudoFrames::operator=(const nsPseudoFrames& aOther) @@ -403,7 +399,6 @@ nsPseudoFrames& nsPseudoFrames::operator=(const nsPseudoFrames& aOther) mCellOuter = aOther.mCellOuter; mCellInner = aOther.mCellInner; mLowestType = aOther.mLowestType; - mColGroupBeforeRowGroup = aOther.mColGroupBeforeRowGroup; return *this; } @@ -422,7 +417,6 @@ nsPseudoFrames::Reset(nsPseudoFrames* aSave) mCellOuter.Reset(); mCellInner.Reset(); mLowestType = nsnull; - mColGroupBeforeRowGroup = PR_FALSE; } // ----------------------------------------------------------- @@ -699,15 +693,24 @@ nsMathMLmtableCreator::CreateTableCellInnerFrame(nsIFrame** aNewFrame) // ----------------------------------------------------------- // return the child list that aFrame belongs on. does not ADDREF -nsIAtom* GetChildListFor(const nsIFrame* aFrame) +PRBool GetCaptionAdjustedParent(nsIFrame* aParentFrame, + const nsIFrame* aChildFrame, + nsIFrame** aAdjParentFrame) { - nsIAtom* childList = nsnull; - nsCOMPtr frameType; - aFrame->GetFrameType(getter_AddRefs(frameType)); - if (nsLayoutAtoms::tableCaptionFrame == frameType.get()) { - childList = nsLayoutAtoms::captionList; + *aAdjParentFrame = aParentFrame; + PRBool haveCaption = PR_FALSE; + nsCOMPtr childFrameType; + aChildFrame->GetFrameType(getter_AddRefs(childFrameType)); + + if (nsLayoutAtoms::tableCaptionFrame == childFrameType.get()) { + haveCaption = PR_TRUE; + nsCOMPtr parentFrameType; + aParentFrame->GetFrameType(getter_AddRefs(parentFrameType)); + if (nsLayoutAtoms::tableFrame == parentFrameType.get()) { + aParentFrame->GetParent(aAdjParentFrame); + } } - return childList; + return haveCaption; } nsCSSFrameConstructor::nsCSSFrameConstructor(void) @@ -1803,7 +1806,8 @@ nsCSSFrameConstructor::CreatePseudoTableFrame(nsIPresShell* aPresShel parentFrame->GetStyleContext(getter_AddRefs(parentStyle)); parentFrame->GetContent(getter_AddRefs(parentContent)); - aPresContext->ResolvePseudoStyleContextFor(parentContent, nsHTMLAtoms::tableOuterPseudo, + // create the SC for the inner table which will be the parent of the outer table's SC + aPresContext->ResolvePseudoStyleContextFor(parentContent, nsHTMLAtoms::tablePseudo, parentStyle, PR_FALSE, getter_AddRefs(childStyle)); @@ -1910,15 +1914,13 @@ nsCSSFrameConstructor::CreatePseudoColGroupFrame(nsIPresShell* aPresS parentFrame, childStyle.get(), aTableCreator, PR_TRUE, items, pseudo.mFrame, pseudoParent); if (NS_FAILED(rv)) return rv; + ((nsTableColGroupFrame*)pseudo.mFrame)->SetType(eColGroupAnonymousCol); // set pseudo data for the parent if (aState.mPseudoFrames.mTableInner.mFrame) { aState.mPseudoFrames.mTableInner.mChildList.AddChild(pseudo.mFrame); } - if (!aState.mPseudoFrames.mRowGroup.mFrame) { - aState.mPseudoFrames.mColGroupBeforeRowGroup = PR_TRUE; - } return rv; } @@ -2322,6 +2324,17 @@ nsCSSFrameConstructor::GetParentFrame(nsIPresShell* aPresShell, } +void +FixUpOuterTableFloat(nsIStyleContext* aOuterSC, + nsIStyleContext* aInnerSC) +{ + nsStyleDisplay* outerStyleDisplay = (nsStyleDisplay*)aOuterSC->GetMutableStyleData(eStyleStruct_Display); + nsStyleDisplay* innerStyleDisplay = (nsStyleDisplay*)aInnerSC->GetStyleData(eStyleStruct_Display); + if (outerStyleDisplay->mFloats != innerStyleDisplay->mFloats) { + outerStyleDisplay->mFloats = innerStyleDisplay->mFloats; + } +} + // Construct the outer, inner table frames and the children frames for the table. nsresult nsCSSFrameConstructor::ConstructTableFrame(nsIPresShell* aPresShell, @@ -2357,12 +2370,19 @@ nsCSSFrameConstructor::ConstructTableFrame(nsIPresShell* aPresShell, } } + // create the pseudo SC for the outer table as a child of the inner SC + nsCOMPtr outerStyleContext; + aPresContext->ResolvePseudoStyleContextFor(aContent, nsHTMLAtoms::tableOuterPseudo, + aStyleContext, PR_FALSE, + getter_AddRefs(outerStyleContext)); + FixUpOuterTableFloat(outerStyleContext, aStyleContext); + // Init the table outer frame and see if we need to create a view, e.g. // the frame is absolutely positioned InitAndRestoreFrame(aPresContext, aState, aContent, - parentFrame, aStyleContext, nsnull, aNewOuterFrame); + parentFrame, outerStyleContext, nsnull, aNewOuterFrame); nsHTMLContainerFrame::CreateViewForFrame(aPresContext, aNewOuterFrame, - aStyleContext, PR_FALSE); + outerStyleContext, PR_FALSE); // Create the inner table frame aTableCreator.CreateTableFrame(&aNewInnerFrame); @@ -2787,34 +2807,22 @@ nsCSSFrameConstructor::MustGeneratePseudoParent(nsIPresContext* aPresContext, return !IsOnlyWhiteSpace(aContent); } - if ( (nsHTMLAtoms::img == aTag) || - (nsHTMLAtoms::hr == aTag) || - (nsHTMLAtoms::br == aTag) || - (nsHTMLAtoms::wbr == aTag) || - (nsHTMLAtoms::input == aTag) || - (nsHTMLAtoms::textarea == aTag) || - (nsHTMLAtoms::select == aTag) || - (nsHTMLAtoms::applet == aTag) || - (nsHTMLAtoms::embed == aTag) || - (nsHTMLAtoms::fieldset == aTag) || - (nsHTMLAtoms::legend == aTag) || - (nsHTMLAtoms::object == aTag) || - (nsHTMLAtoms::iframe == aTag) || - (nsHTMLAtoms::spacer == aTag) || - (nsHTMLAtoms::button == aTag) || - (nsHTMLAtoms::label == aTag) ) { - return PR_TRUE; + // exclude tags + if ( (nsLayoutAtoms::commentTagName == aTag) || + (nsHTMLAtoms::form == aTag) ) { + return PR_FALSE; } -// MathML Mod - DJF +// XXX DJF - when should pseudo frames be constructed for MathML? #ifdef MOZ_MATHML -// XXX should pseudo frames be created in this case? - if ( (nsMathMLAtoms::math == aTag) ) { + if ( (nsMathMLAtoms::math == aTag) ) { return PR_TRUE; } + else { + return PR_FALSE; + } #endif - - // we should check for display type as well - later + return PR_FALSE; } @@ -4570,16 +4578,15 @@ nsCSSFrameConstructor::ConstructFieldSetFrame(nsIPresShell* aPresShell, const nsStyleDisplay* styleDisplay; newFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) styleDisplay); - nsIFrame * areaFrame; - //NS_NewBlockFrame(shell, &areaFrame, flags); - NS_NewAreaFrame(shell, &areaFrame, flags | NS_BLOCK_SHRINK_WRAP);// | NS_BLOCK_MARGIN_ROOT); + nsIFrame * blkFrame; + NS_NewBlockFrame(shell, &blkFrame, flags); // Resolve style and initialize the frame nsIStyleContext* styleContext; aPresContext->ResolvePseudoStyleContextFor(aContent, nsHTMLAtoms::fieldsetContentPseudo, aStyleContext, PR_FALSE, &styleContext); InitAndRestoreFrame(aPresContext, aState, aContent, - newFrame, styleContext, nsnull, areaFrame); + newFrame, styleContext, nsnull, blkFrame); NS_RELEASE(styleContext); @@ -4589,7 +4596,7 @@ nsCSSFrameConstructor::ConstructFieldSetFrame(nsIPresShell* aPresShell, HaveSpecialBlockStyle(aPresContext, aContent, aStyleContext, &haveFirstLetterStyle, &haveFirstLineStyle); nsFrameConstructorSaveState floaterSaveState; - aState.PushFloaterContainingBlock(areaFrame, floaterSaveState, + aState.PushFloaterContainingBlock(blkFrame, floaterSaveState, haveFirstLetterStyle, haveFirstLineStyle); @@ -4602,10 +4609,10 @@ nsCSSFrameConstructor::ConstructFieldSetFrame(nsIPresShell* aPresShell, if (isPositionedContainingBlock) { // The area frame becomes a container for child frames that are // absolutely positioned - aState.PushAbsoluteContainingBlock(areaFrame, absoluteSaveState); + aState.PushAbsoluteContainingBlock(blkFrame, absoluteSaveState); } - ProcessChildren(aPresShell, aPresContext, aState, aContent, areaFrame, PR_FALSE, + ProcessChildren(aPresShell, aPresContext, aState, aContent, blkFrame, PR_FALSE, childItems, PR_TRUE); static NS_DEFINE_IID(kLegendFrameCID, NS_LEGEND_FRAME_CID); @@ -4619,7 +4626,7 @@ nsCSSFrameConstructor::ConstructFieldSetFrame(nsIPresShell* aPresShell, nsIFrame * nxt; legendFrame->GetNextSibling(&nxt); previous->SetNextSibling(nxt); - areaFrame->SetNextSibling(legendFrame); + blkFrame->SetNextSibling(legendFrame); legendFrame->SetParent(newFrame); legendFrame->SetNextSibling(nsnull); break; @@ -4627,7 +4634,7 @@ nsCSSFrameConstructor::ConstructFieldSetFrame(nsIPresShell* aPresShell, nsIFrame * nxt; legendFrame->GetNextSibling(&nxt); childItems.childList = nxt; - areaFrame->SetNextSibling(legendFrame); + blkFrame->SetNextSibling(legendFrame); legendFrame->SetParent(newFrame); legendFrame->SetNextSibling(nsnull); break; @@ -4638,21 +4645,21 @@ nsCSSFrameConstructor::ConstructFieldSetFrame(nsIPresShell* aPresShell, } // Set the scrolled frame's initial child lists - areaFrame->SetInitialChildList(aPresContext, nsnull, childItems.childList); + blkFrame->SetInitialChildList(aPresContext, nsnull, childItems.childList); if (isPositionedContainingBlock && aState.mAbsoluteItems.childList) { - areaFrame->SetInitialChildList(aPresContext, + blkFrame->SetInitialChildList(aPresContext, nsLayoutAtoms::absoluteList, aState.mAbsoluteItems.childList); } if (aState.mFloatedItems.childList) { - areaFrame->SetInitialChildList(aPresContext, + blkFrame->SetInitialChildList(aPresContext, nsLayoutAtoms::floaterList, aState.mFloatedItems.childList); } // Set the scroll frame's initial child list - newFrame->SetInitialChildList(aPresContext, nsnull, areaFrame); + newFrame->SetInitialChildList(aPresContext, nsnull, blkFrame); // our new frame retured is the top frame which is the list frame. aNewFrame = newFrame; @@ -5154,11 +5161,11 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsIPresShell* aPresShell, nsFrameConstructorState& aState, nsIContent* aParent, nsIDocument* aDocument, - nsIFrame* aParentFrame, + nsIFrame* aNewFrame, nsFrameItems& aChildItems) { - nsCOMPtr creator(do_QueryInterface(aParentFrame)); + nsCOMPtr creator(do_QueryInterface(aNewFrame)); if (!creator) return NS_OK; @@ -5182,14 +5189,8 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsIPresShell* aPresShell, content->SetParent(aParent); content->SetDocument(aDocument, PR_TRUE); - nsIFrame * newFrame = nsnull; - nsresult rv = creator->CreateFrameFor(aPresContext, content, &newFrame); - if (NS_SUCCEEDED(rv) && newFrame != nsnull) { - aChildItems.AddChild(newFrame); - } else { - // create the frame and attach it to our frame - ConstructFrame(aPresShell, aPresContext, aState, content, aParentFrame, aChildItems); - } + // create the frame and attach it to our frame + ConstructFrame(aPresShell, aPresContext, aState, content, aNewFrame, aChildItems); } return NS_OK; @@ -7515,8 +7516,16 @@ nsCSSFrameConstructor::AppendFrames(nsIPresContext* aPresContext, } else { // Append the frames to the end of the parent's child list - rv = aFrameManager->AppendFrames(aPresContext, *aPresShell, aParentFrame, - GetChildListFor(aFrameList), aFrameList); + // check for a table caption which goes on an additional child list with a different parent + nsIFrame* outerTableFrame; + if (GetCaptionAdjustedParent(aParentFrame, aFrameList, &outerTableFrame)) { + rv = aFrameManager->AppendFrames(aPresContext, *aPresShell, outerTableFrame, + nsLayoutAtoms::captionList, aFrameList); + } + else { + rv = aFrameManager->AppendFrames(aPresContext, *aPresShell, aParentFrame, + nsnull, aFrameList); + } } NS_IF_RELEASE(parentType); @@ -8296,11 +8305,15 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext, } } // check for a table caption which goes on an additional child list - nsIAtom* childList = GetChildListFor(newFrame); - rv = state.mFrameManager->InsertFrames(aPresContext, *shell, - parentFrame, - childList, prevSibling, - newFrame); + nsIFrame* outerTableFrame; + if (GetCaptionAdjustedParent(parentFrame, newFrame, &outerTableFrame)) { + rv = state.mFrameManager->AppendFrames(aPresContext, *shell, outerTableFrame, + nsLayoutAtoms::captionList, newFrame); + } + else { + rv = state.mFrameManager->InsertFrames(aPresContext, *shell, parentFrame, + nsnull, prevSibling, newFrame); + } } // If there are new absolutely positioned child frames, then notify @@ -8791,9 +8804,16 @@ nsCSSFrameConstructor::ContentRemoved(nsIPresContext* aPresContext, } else { // Notify the parent frame that it should delete the frame - nsIAtom* childList = GetChildListFor(childFrame); - rv = frameManager->RemoveFrame(aPresContext, *shell, parentFrame, - childList, childFrame); + // check for a table caption which goes on an additional child list with a different parent + nsIFrame* outerTableFrame; + if (GetCaptionAdjustedParent(parentFrame, childFrame, &outerTableFrame)) { + rv = frameManager->RemoveFrame(aPresContext, *shell, outerTableFrame, + nsLayoutAtoms::captionList, childFrame); + } + else { + rv = frameManager->RemoveFrame(aPresContext, *shell, parentFrame, + nsnull, childFrame); + } } } diff --git a/mozilla/layout/base/public/nsHTMLReflowState.h b/mozilla/layout/base/public/nsHTMLReflowState.h index 58c41ad5b4f..c1fc95623c1 100644 --- a/mozilla/layout/base/public/nsHTMLReflowState.h +++ b/mozilla/layout/base/public/nsHTMLReflowState.h @@ -305,9 +305,14 @@ struct nsHTMLReflowState { static nsCSSFrameType DetermineFrameType(nsIFrame* aFrame); - void ComputeContainingBlockRectangle(const nsHTMLReflowState* aContainingBlockRS, - nscoord& aContainingBlockWidth, - nscoord& aContainingBlockHeight); + void ComputeContainingBlockRectangle(nsIPresContext* aPresContext, + const nsHTMLReflowState* aContainingBlockRS, + nscoord& aContainingBlockWidth, + nscoord& aContainingBlockHeight); + + void CalculateBlockSideMargins(const nsHTMLReflowState* aContainingBlockRS, + nscoord aComputedWidth); + protected: // This method initializes various data members. It is automatically @@ -343,9 +348,6 @@ protected: nscoord aContainingBlockWidth, nscoord aContainingBlockHeight); - void CalculateBlockSideMargins(const nsHTMLReflowState* aContainingBlockRS, - nscoord aComputedWidth); - void ComputeHorizontalValue(nscoord aContainingBlockWidth, nsStyleUnit aUnit, const nsStyleCoord& aCoord, diff --git a/mozilla/layout/base/src/nsStyleContext.cpp b/mozilla/layout/base/src/nsStyleContext.cpp index 0f7073218db..f527613733c 100644 --- a/mozilla/layout/base/src/nsStyleContext.cpp +++ b/mozilla/layout/base/src/nsStyleContext.cpp @@ -2287,8 +2287,9 @@ StyleContextImpl::RemapStyle(nsIPresContext* aPresContext, PRBool aRecurse) nsCompatibility quirkMode = eCompatibility_Standard; aPresContext->GetCompatibilityMode(&quirkMode); if (eCompatibility_NavQuirks == quirkMode) { - if ((mDisplay.mDisplay == NS_STYLE_DISPLAY_TABLE) || - (mDisplay.mDisplay == NS_STYLE_DISPLAY_TABLE_CAPTION)) { + if (((mDisplay.mDisplay == NS_STYLE_DISPLAY_TABLE) || + (mDisplay.mDisplay == NS_STYLE_DISPLAY_TABLE_CAPTION)) && + (nsnull == mPseudoTag)) { StyleContextImpl* holdParent = mParent; mParent = nsnull; // cut off all inheritance. this really blows diff --git a/mozilla/layout/generic/nsAbsoluteContainingBlock.cpp b/mozilla/layout/generic/nsAbsoluteContainingBlock.cpp index db41a6e57d0..71354c153d5 100644 --- a/mozilla/layout/generic/nsAbsoluteContainingBlock.cpp +++ b/mozilla/layout/generic/nsAbsoluteContainingBlock.cpp @@ -421,7 +421,8 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat (NS_AUTOOFFSET == kidReflowState.mComputedOffsets.top)) { if (-1 == aContainingBlockWidth) { // Get the containing block width/height - kidReflowState.ComputeContainingBlockRectangle(&aReflowState, + kidReflowState.ComputeContainingBlockRectangle(aPresContext, + &aReflowState, aContainingBlockWidth, aContainingBlockHeight); } diff --git a/mozilla/layout/generic/nsHTMLReflowState.cpp b/mozilla/layout/generic/nsHTMLReflowState.cpp index 41aa48d65c0..d77786ab10f 100644 --- a/mozilla/layout/generic/nsHTMLReflowState.cpp +++ b/mozilla/layout/generic/nsHTMLReflowState.cpp @@ -1261,12 +1261,90 @@ IsInitialContainingBlock(nsIFrame* aFrame) return result; } +nscoord +GetVerticalMarginBorderPadding(const nsHTMLReflowState* aReflowState) +{ + nscoord result = 0; + if (!aReflowState) return result; + + // zero auto margins + nsMargin margin = aReflowState->mComputedMargin; + if (NS_AUTOMARGIN == margin.top) + margin.top = 0; + if (NS_AUTOMARGIN == margin.bottom) + margin.bottom = 0; + + result += margin.top + margin.bottom; + result += aReflowState->mComputedBorderPadding.top + + aReflowState->mComputedBorderPadding.bottom; + + return result; +} + +/* Get the height based on the viewport of the containing block specified + * in aReflowState when the containing block has mComputedHeight == NS_AUTOHEIGHT + * and it is the body. + */ +nscoord +CalcQuirkContainingBlockHeight(const nsHTMLReflowState& aReflowState) +{ + nsHTMLReflowState* firstBlockRS = nsnull; // a candidate for body frame + nsHTMLReflowState* firstAreaRS = nsnull; // a candidate for html frame + nscoord result = 0; + + const nsHTMLReflowState* rs = &aReflowState; + for (; rs; 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 + // is the first block/area frame and possibly the body/html + if (nsLayoutAtoms::blockFrame == frameType.get()) { + if (!firstBlockRS) { + firstBlockRS = (nsHTMLReflowState*)rs; + if (NS_AUTOHEIGHT == rs->mComputedHeight) continue; + } + else break; + } + else if (nsLayoutAtoms::areaFrame == frameType.get()) { + if (!firstAreaRS) { + firstAreaRS = (nsHTMLReflowState*)rs; + if (NS_AUTOHEIGHT == rs->mComputedHeight) continue; + } + else break; + } + else if (nsLayoutAtoms::canvasFrame != frameType.get()) { + break; + } + // the ancestor has a computed height, it is the percent base + result = rs->mComputedHeight; + // if we got to the canvas frame, then subtract out + // margin/border/padding for the BODY and HTML elements + if (nsLayoutAtoms::canvasFrame == frameType.get()) { + result -= GetVerticalMarginBorderPadding(firstBlockRS); + result -= GetVerticalMarginBorderPadding(firstAreaRS); + } + // if we got to the html frame, then subtract out + // margin/border/padding for the BODY element + else if (nsLayoutAtoms::areaFrame == frameType.get()) { + // make sure it is the body + nsCOMPtr fType; + rs->parentReflowState->frame->GetFrameType(getter_AddRefs(fType)); + if (nsLayoutAtoms::canvasFrame == fType.get()) { + result -= GetVerticalMarginBorderPadding(firstBlockRS); + } + } + break; + } + + return result; +} // Called by InitConstraints() to compute the containing block rectangle for // the element. Handles the special logic for absolutely positioned elements void -nsHTMLReflowState::ComputeContainingBlockRectangle(const nsHTMLReflowState* aContainingBlockRS, - nscoord& aContainingBlockWidth, - nscoord& aContainingBlockHeight) +nsHTMLReflowState::ComputeContainingBlockRectangle(nsIPresContext* aPresContext, + const nsHTMLReflowState* aContainingBlockRS, + nscoord& aContainingBlockWidth, + nscoord& aContainingBlockHeight) { // Unless the element is absolutely positioned, the containing block is // formed by the content edge of the nearest block-level ancestor @@ -1339,6 +1417,19 @@ nsHTMLReflowState::ComputeContainingBlockRectangle(const nsHTMLReflowState* aCon if (NS_UNCONSTRAINEDSIZE == availableWidth) { aContainingBlockWidth = NS_UNCONSTRAINEDSIZE; } + // a table in quirks mode gets a containing block based on the viewport (less + // body margins, border, padding) if the table is a child of the body. + if (NS_AUTOHEIGHT == aContainingBlockHeight) { + nsCOMPtr fType; + frame->GetFrameType(getter_AddRefs(fType)); + if (nsLayoutAtoms::tableFrame == fType.get()) { + nsCompatibility mode; + aPresContext->GetCompatibilityMode(&mode); + if (eCompatibility_NavQuirks == mode) { + aContainingBlockHeight = CalcQuirkContainingBlockHeight(*aContainingBlockRS); + } + } + } } } @@ -1370,7 +1461,8 @@ nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext, // If we weren't given a containing block width and height, then // compute one if (aContainingBlockWidth == -1) { - ComputeContainingBlockRectangle(cbrs, aContainingBlockWidth, aContainingBlockHeight); + ComputeContainingBlockRectangle(aPresContext, cbrs, aContainingBlockWidth, + aContainingBlockHeight); } // See if the element is relatively positioned @@ -1517,10 +1609,9 @@ nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext, mComputedWidth = NS_UNCONSTRAINEDSIZE; } else if (NS_STYLE_DISPLAY_TABLE == mStyleDisplay->mDisplay) { - // It's a table. The CSS spec says the computed width should be - // 0 so set it to 0. The table code will just chose whatever width - // it wants - mComputedWidth = 0; + // It's an outer table because an inner table is not positioned + // shrink wrap its width since the outer table is anonymous + mComputedWidth = NS_SHRINKWRAPWIDTH; } else { // The CSS2 spec says the computed width should be 0; however, that's @@ -1704,9 +1795,24 @@ nsHTMLReflowState::ComputeBlockBoxData(nsIPresContext* aPresContext, } } else { - mComputedWidth = availableWidth - mComputedMargin.left - - mComputedMargin.right - mComputedBorderPadding.left - - mComputedBorderPadding.right; + // tables act like replaced elements regarding mComputedWidth + nsCOMPtr fType; + frame->GetFrameType(getter_AddRefs(fType)); + if (nsLayoutAtoms::tableOuterFrame == fType.get()) { + mComputedWidth = NS_SHRINKWRAPWIDTH; + } else if (nsLayoutAtoms::tableFrame == fType.get()) { + mComputedWidth = NS_SHRINKWRAPWIDTH; + if (eStyleUnit_Auto == mStyleSpacing->mMargin.GetLeftUnit()) { + mComputedMargin.left = NS_AUTOMARGIN; + } + if (eStyleUnit_Auto == mStyleSpacing->mMargin.GetRightUnit()) { + mComputedMargin.right = NS_AUTOMARGIN; + } + } else { + mComputedWidth = availableWidth - mComputedMargin.left - + mComputedMargin.right - mComputedBorderPadding.left - + mComputedBorderPadding.right; + } // Take into account any min and max values if (mComputedWidth > mComputedMaxWidth) { diff --git a/mozilla/layout/generic/nsHTMLReflowState.h b/mozilla/layout/generic/nsHTMLReflowState.h index 58c41ad5b4f..c1fc95623c1 100644 --- a/mozilla/layout/generic/nsHTMLReflowState.h +++ b/mozilla/layout/generic/nsHTMLReflowState.h @@ -305,9 +305,14 @@ struct nsHTMLReflowState { static nsCSSFrameType DetermineFrameType(nsIFrame* aFrame); - void ComputeContainingBlockRectangle(const nsHTMLReflowState* aContainingBlockRS, - nscoord& aContainingBlockWidth, - nscoord& aContainingBlockHeight); + void ComputeContainingBlockRectangle(nsIPresContext* aPresContext, + const nsHTMLReflowState* aContainingBlockRS, + nscoord& aContainingBlockWidth, + nscoord& aContainingBlockHeight); + + void CalculateBlockSideMargins(const nsHTMLReflowState* aContainingBlockRS, + nscoord aComputedWidth); + protected: // This method initializes various data members. It is automatically @@ -343,9 +348,6 @@ protected: nscoord aContainingBlockWidth, nscoord aContainingBlockHeight); - void CalculateBlockSideMargins(const nsHTMLReflowState* aContainingBlockRS, - nscoord aComputedWidth); - void ComputeHorizontalValue(nscoord aContainingBlockWidth, nsStyleUnit aUnit, const nsStyleCoord& aCoord, diff --git a/mozilla/layout/html/base/src/nsAbsoluteContainingBlock.cpp b/mozilla/layout/html/base/src/nsAbsoluteContainingBlock.cpp index db41a6e57d0..71354c153d5 100644 --- a/mozilla/layout/html/base/src/nsAbsoluteContainingBlock.cpp +++ b/mozilla/layout/html/base/src/nsAbsoluteContainingBlock.cpp @@ -421,7 +421,8 @@ nsAbsoluteContainingBlock::ReflowAbsoluteFrame(nsIFrame* aDelegat (NS_AUTOOFFSET == kidReflowState.mComputedOffsets.top)) { if (-1 == aContainingBlockWidth) { // Get the containing block width/height - kidReflowState.ComputeContainingBlockRectangle(&aReflowState, + kidReflowState.ComputeContainingBlockRectangle(aPresContext, + &aReflowState, aContainingBlockWidth, aContainingBlockHeight); } diff --git a/mozilla/layout/html/base/src/nsHTMLReflowState.cpp b/mozilla/layout/html/base/src/nsHTMLReflowState.cpp index 41aa48d65c0..d77786ab10f 100644 --- a/mozilla/layout/html/base/src/nsHTMLReflowState.cpp +++ b/mozilla/layout/html/base/src/nsHTMLReflowState.cpp @@ -1261,12 +1261,90 @@ IsInitialContainingBlock(nsIFrame* aFrame) return result; } +nscoord +GetVerticalMarginBorderPadding(const nsHTMLReflowState* aReflowState) +{ + nscoord result = 0; + if (!aReflowState) return result; + + // zero auto margins + nsMargin margin = aReflowState->mComputedMargin; + if (NS_AUTOMARGIN == margin.top) + margin.top = 0; + if (NS_AUTOMARGIN == margin.bottom) + margin.bottom = 0; + + result += margin.top + margin.bottom; + result += aReflowState->mComputedBorderPadding.top + + aReflowState->mComputedBorderPadding.bottom; + + return result; +} + +/* Get the height based on the viewport of the containing block specified + * in aReflowState when the containing block has mComputedHeight == NS_AUTOHEIGHT + * and it is the body. + */ +nscoord +CalcQuirkContainingBlockHeight(const nsHTMLReflowState& aReflowState) +{ + nsHTMLReflowState* firstBlockRS = nsnull; // a candidate for body frame + nsHTMLReflowState* firstAreaRS = nsnull; // a candidate for html frame + nscoord result = 0; + + const nsHTMLReflowState* rs = &aReflowState; + for (; rs; 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 + // is the first block/area frame and possibly the body/html + if (nsLayoutAtoms::blockFrame == frameType.get()) { + if (!firstBlockRS) { + firstBlockRS = (nsHTMLReflowState*)rs; + if (NS_AUTOHEIGHT == rs->mComputedHeight) continue; + } + else break; + } + else if (nsLayoutAtoms::areaFrame == frameType.get()) { + if (!firstAreaRS) { + firstAreaRS = (nsHTMLReflowState*)rs; + if (NS_AUTOHEIGHT == rs->mComputedHeight) continue; + } + else break; + } + else if (nsLayoutAtoms::canvasFrame != frameType.get()) { + break; + } + // the ancestor has a computed height, it is the percent base + result = rs->mComputedHeight; + // if we got to the canvas frame, then subtract out + // margin/border/padding for the BODY and HTML elements + if (nsLayoutAtoms::canvasFrame == frameType.get()) { + result -= GetVerticalMarginBorderPadding(firstBlockRS); + result -= GetVerticalMarginBorderPadding(firstAreaRS); + } + // if we got to the html frame, then subtract out + // margin/border/padding for the BODY element + else if (nsLayoutAtoms::areaFrame == frameType.get()) { + // make sure it is the body + nsCOMPtr fType; + rs->parentReflowState->frame->GetFrameType(getter_AddRefs(fType)); + if (nsLayoutAtoms::canvasFrame == fType.get()) { + result -= GetVerticalMarginBorderPadding(firstBlockRS); + } + } + break; + } + + return result; +} // Called by InitConstraints() to compute the containing block rectangle for // the element. Handles the special logic for absolutely positioned elements void -nsHTMLReflowState::ComputeContainingBlockRectangle(const nsHTMLReflowState* aContainingBlockRS, - nscoord& aContainingBlockWidth, - nscoord& aContainingBlockHeight) +nsHTMLReflowState::ComputeContainingBlockRectangle(nsIPresContext* aPresContext, + const nsHTMLReflowState* aContainingBlockRS, + nscoord& aContainingBlockWidth, + nscoord& aContainingBlockHeight) { // Unless the element is absolutely positioned, the containing block is // formed by the content edge of the nearest block-level ancestor @@ -1339,6 +1417,19 @@ nsHTMLReflowState::ComputeContainingBlockRectangle(const nsHTMLReflowState* aCon if (NS_UNCONSTRAINEDSIZE == availableWidth) { aContainingBlockWidth = NS_UNCONSTRAINEDSIZE; } + // a table in quirks mode gets a containing block based on the viewport (less + // body margins, border, padding) if the table is a child of the body. + if (NS_AUTOHEIGHT == aContainingBlockHeight) { + nsCOMPtr fType; + frame->GetFrameType(getter_AddRefs(fType)); + if (nsLayoutAtoms::tableFrame == fType.get()) { + nsCompatibility mode; + aPresContext->GetCompatibilityMode(&mode); + if (eCompatibility_NavQuirks == mode) { + aContainingBlockHeight = CalcQuirkContainingBlockHeight(*aContainingBlockRS); + } + } + } } } @@ -1370,7 +1461,8 @@ nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext, // If we weren't given a containing block width and height, then // compute one if (aContainingBlockWidth == -1) { - ComputeContainingBlockRectangle(cbrs, aContainingBlockWidth, aContainingBlockHeight); + ComputeContainingBlockRectangle(aPresContext, cbrs, aContainingBlockWidth, + aContainingBlockHeight); } // See if the element is relatively positioned @@ -1517,10 +1609,9 @@ nsHTMLReflowState::InitConstraints(nsIPresContext* aPresContext, mComputedWidth = NS_UNCONSTRAINEDSIZE; } else if (NS_STYLE_DISPLAY_TABLE == mStyleDisplay->mDisplay) { - // It's a table. The CSS spec says the computed width should be - // 0 so set it to 0. The table code will just chose whatever width - // it wants - mComputedWidth = 0; + // It's an outer table because an inner table is not positioned + // shrink wrap its width since the outer table is anonymous + mComputedWidth = NS_SHRINKWRAPWIDTH; } else { // The CSS2 spec says the computed width should be 0; however, that's @@ -1704,9 +1795,24 @@ nsHTMLReflowState::ComputeBlockBoxData(nsIPresContext* aPresContext, } } else { - mComputedWidth = availableWidth - mComputedMargin.left - - mComputedMargin.right - mComputedBorderPadding.left - - mComputedBorderPadding.right; + // tables act like replaced elements regarding mComputedWidth + nsCOMPtr fType; + frame->GetFrameType(getter_AddRefs(fType)); + if (nsLayoutAtoms::tableOuterFrame == fType.get()) { + mComputedWidth = NS_SHRINKWRAPWIDTH; + } else if (nsLayoutAtoms::tableFrame == fType.get()) { + mComputedWidth = NS_SHRINKWRAPWIDTH; + if (eStyleUnit_Auto == mStyleSpacing->mMargin.GetLeftUnit()) { + mComputedMargin.left = NS_AUTOMARGIN; + } + if (eStyleUnit_Auto == mStyleSpacing->mMargin.GetRightUnit()) { + mComputedMargin.right = NS_AUTOMARGIN; + } + } else { + mComputedWidth = availableWidth - mComputedMargin.left - + mComputedMargin.right - mComputedBorderPadding.left - + mComputedBorderPadding.right; + } // Take into account any min and max values if (mComputedWidth > mComputedMaxWidth) { diff --git a/mozilla/layout/html/document/src/html.css b/mozilla/layout/html/document/src/html.css index 5b40cb18d58..2153d1c3f1e 100644 --- a/mozilla/layout/html/document/src/html.css +++ b/mozilla/layout/html/document/src/html.css @@ -179,6 +179,7 @@ th { caption { text-align: center; display: table-caption; + box-sizing: border-box; } tr { display: table-row; @@ -1084,6 +1085,35 @@ option[disabled] { background-color:rgb(204,204,204) !important; } +select option[disabled] { + color:rgb(153,153,153); + background-color:rgb(204,204,204); +} + +select[size] option[-moz-option-selected] { + color:white; + background-color:rgb(51,51,102); +} +select[size] option[-moz-option-selected-focus] { + color:white; + background-color:rgb(51,51,102); +} + +select[size][disabled] option[-moz-option-selected] { + color:rgb(153,153,153); + background-color:rgb(204,204,204); +} + +select[size="1"] option[-moz-option-selected] { + color:white; + background-color:rgb(51,51,102); +} + +select[size="1"] option[disabled][-moz-option-selected] { + color:rgb(153,153,153); + background-color:rgb(204,204,204); +} + optgroup { font-family: sans-serif; font-size: small; @@ -1290,14 +1320,22 @@ sourcetext { /* XXX should not be in HTML namespace */ :table { display: table; - border-style: inherit; - border-color: inherit; - margin-top: inherit; - margin-bottom: inherit; - background: inherit; + border-spacing: 2px; + border-collapse: separate; + margin-top: 0; + margin-bottom: 0; box-sizing: border-box; } +:table-outer { + display: table; + margin: 0px; + border: 0px; + padding: 0px; + float: inherit; + position: inherit; +} + :table-cell { display: table-cell; } @@ -1310,10 +1348,6 @@ sourcetext { /* XXX should not be in HTML namespace */ display: table-column-group; } -:table-outer { - display: table; -} - :table-row { display: table-row; } diff --git a/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp b/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp index a2fb0349db8..584a6bd42a8 100644 --- a/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp +++ b/mozilla/layout/html/style/src/nsCSSFrameConstructor.cpp @@ -360,9 +360,6 @@ struct nsPseudoFrames { // the frame type of the most descendant pseudo frame, no AddRef nsIAtom* mLowestType; - // col groups are handled specially so if there is both a pseudo - // row group and col group, content order needs to be preserved - PRBool mColGroupBeforeRowGroup; nsPseudoFrames(); nsPseudoFrames& operator=(const nsPseudoFrames& aOther); @@ -389,8 +386,7 @@ nsPseudoFrameData::Reset() nsPseudoFrames::nsPseudoFrames() : mTableOuter(), mTableInner(), mRowGroup(), mColGroup(), - mRow(), mCellOuter(), mCellInner(), mLowestType(nsnull), - mColGroupBeforeRowGroup(PR_FALSE) + mRow(), mCellOuter(), mCellInner(), mLowestType(nsnull) {} nsPseudoFrames& nsPseudoFrames::operator=(const nsPseudoFrames& aOther) @@ -403,7 +399,6 @@ nsPseudoFrames& nsPseudoFrames::operator=(const nsPseudoFrames& aOther) mCellOuter = aOther.mCellOuter; mCellInner = aOther.mCellInner; mLowestType = aOther.mLowestType; - mColGroupBeforeRowGroup = aOther.mColGroupBeforeRowGroup; return *this; } @@ -422,7 +417,6 @@ nsPseudoFrames::Reset(nsPseudoFrames* aSave) mCellOuter.Reset(); mCellInner.Reset(); mLowestType = nsnull; - mColGroupBeforeRowGroup = PR_FALSE; } // ----------------------------------------------------------- @@ -699,15 +693,24 @@ nsMathMLmtableCreator::CreateTableCellInnerFrame(nsIFrame** aNewFrame) // ----------------------------------------------------------- // return the child list that aFrame belongs on. does not ADDREF -nsIAtom* GetChildListFor(const nsIFrame* aFrame) +PRBool GetCaptionAdjustedParent(nsIFrame* aParentFrame, + const nsIFrame* aChildFrame, + nsIFrame** aAdjParentFrame) { - nsIAtom* childList = nsnull; - nsCOMPtr frameType; - aFrame->GetFrameType(getter_AddRefs(frameType)); - if (nsLayoutAtoms::tableCaptionFrame == frameType.get()) { - childList = nsLayoutAtoms::captionList; + *aAdjParentFrame = aParentFrame; + PRBool haveCaption = PR_FALSE; + nsCOMPtr childFrameType; + aChildFrame->GetFrameType(getter_AddRefs(childFrameType)); + + if (nsLayoutAtoms::tableCaptionFrame == childFrameType.get()) { + haveCaption = PR_TRUE; + nsCOMPtr parentFrameType; + aParentFrame->GetFrameType(getter_AddRefs(parentFrameType)); + if (nsLayoutAtoms::tableFrame == parentFrameType.get()) { + aParentFrame->GetParent(aAdjParentFrame); + } } - return childList; + return haveCaption; } nsCSSFrameConstructor::nsCSSFrameConstructor(void) @@ -1803,7 +1806,8 @@ nsCSSFrameConstructor::CreatePseudoTableFrame(nsIPresShell* aPresShel parentFrame->GetStyleContext(getter_AddRefs(parentStyle)); parentFrame->GetContent(getter_AddRefs(parentContent)); - aPresContext->ResolvePseudoStyleContextFor(parentContent, nsHTMLAtoms::tableOuterPseudo, + // create the SC for the inner table which will be the parent of the outer table's SC + aPresContext->ResolvePseudoStyleContextFor(parentContent, nsHTMLAtoms::tablePseudo, parentStyle, PR_FALSE, getter_AddRefs(childStyle)); @@ -1910,15 +1914,13 @@ nsCSSFrameConstructor::CreatePseudoColGroupFrame(nsIPresShell* aPresS parentFrame, childStyle.get(), aTableCreator, PR_TRUE, items, pseudo.mFrame, pseudoParent); if (NS_FAILED(rv)) return rv; + ((nsTableColGroupFrame*)pseudo.mFrame)->SetType(eColGroupAnonymousCol); // set pseudo data for the parent if (aState.mPseudoFrames.mTableInner.mFrame) { aState.mPseudoFrames.mTableInner.mChildList.AddChild(pseudo.mFrame); } - if (!aState.mPseudoFrames.mRowGroup.mFrame) { - aState.mPseudoFrames.mColGroupBeforeRowGroup = PR_TRUE; - } return rv; } @@ -2322,6 +2324,17 @@ nsCSSFrameConstructor::GetParentFrame(nsIPresShell* aPresShell, } +void +FixUpOuterTableFloat(nsIStyleContext* aOuterSC, + nsIStyleContext* aInnerSC) +{ + nsStyleDisplay* outerStyleDisplay = (nsStyleDisplay*)aOuterSC->GetMutableStyleData(eStyleStruct_Display); + nsStyleDisplay* innerStyleDisplay = (nsStyleDisplay*)aInnerSC->GetStyleData(eStyleStruct_Display); + if (outerStyleDisplay->mFloats != innerStyleDisplay->mFloats) { + outerStyleDisplay->mFloats = innerStyleDisplay->mFloats; + } +} + // Construct the outer, inner table frames and the children frames for the table. nsresult nsCSSFrameConstructor::ConstructTableFrame(nsIPresShell* aPresShell, @@ -2357,12 +2370,19 @@ nsCSSFrameConstructor::ConstructTableFrame(nsIPresShell* aPresShell, } } + // create the pseudo SC for the outer table as a child of the inner SC + nsCOMPtr outerStyleContext; + aPresContext->ResolvePseudoStyleContextFor(aContent, nsHTMLAtoms::tableOuterPseudo, + aStyleContext, PR_FALSE, + getter_AddRefs(outerStyleContext)); + FixUpOuterTableFloat(outerStyleContext, aStyleContext); + // Init the table outer frame and see if we need to create a view, e.g. // the frame is absolutely positioned InitAndRestoreFrame(aPresContext, aState, aContent, - parentFrame, aStyleContext, nsnull, aNewOuterFrame); + parentFrame, outerStyleContext, nsnull, aNewOuterFrame); nsHTMLContainerFrame::CreateViewForFrame(aPresContext, aNewOuterFrame, - aStyleContext, PR_FALSE); + outerStyleContext, PR_FALSE); // Create the inner table frame aTableCreator.CreateTableFrame(&aNewInnerFrame); @@ -2787,34 +2807,22 @@ nsCSSFrameConstructor::MustGeneratePseudoParent(nsIPresContext* aPresContext, return !IsOnlyWhiteSpace(aContent); } - if ( (nsHTMLAtoms::img == aTag) || - (nsHTMLAtoms::hr == aTag) || - (nsHTMLAtoms::br == aTag) || - (nsHTMLAtoms::wbr == aTag) || - (nsHTMLAtoms::input == aTag) || - (nsHTMLAtoms::textarea == aTag) || - (nsHTMLAtoms::select == aTag) || - (nsHTMLAtoms::applet == aTag) || - (nsHTMLAtoms::embed == aTag) || - (nsHTMLAtoms::fieldset == aTag) || - (nsHTMLAtoms::legend == aTag) || - (nsHTMLAtoms::object == aTag) || - (nsHTMLAtoms::iframe == aTag) || - (nsHTMLAtoms::spacer == aTag) || - (nsHTMLAtoms::button == aTag) || - (nsHTMLAtoms::label == aTag) ) { - return PR_TRUE; + // exclude tags + if ( (nsLayoutAtoms::commentTagName == aTag) || + (nsHTMLAtoms::form == aTag) ) { + return PR_FALSE; } -// MathML Mod - DJF +// XXX DJF - when should pseudo frames be constructed for MathML? #ifdef MOZ_MATHML -// XXX should pseudo frames be created in this case? - if ( (nsMathMLAtoms::math == aTag) ) { + if ( (nsMathMLAtoms::math == aTag) ) { return PR_TRUE; } + else { + return PR_FALSE; + } #endif - - // we should check for display type as well - later + return PR_FALSE; } @@ -4570,16 +4578,15 @@ nsCSSFrameConstructor::ConstructFieldSetFrame(nsIPresShell* aPresShell, const nsStyleDisplay* styleDisplay; newFrame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct*&) styleDisplay); - nsIFrame * areaFrame; - //NS_NewBlockFrame(shell, &areaFrame, flags); - NS_NewAreaFrame(shell, &areaFrame, flags | NS_BLOCK_SHRINK_WRAP);// | NS_BLOCK_MARGIN_ROOT); + nsIFrame * blkFrame; + NS_NewBlockFrame(shell, &blkFrame, flags); // Resolve style and initialize the frame nsIStyleContext* styleContext; aPresContext->ResolvePseudoStyleContextFor(aContent, nsHTMLAtoms::fieldsetContentPseudo, aStyleContext, PR_FALSE, &styleContext); InitAndRestoreFrame(aPresContext, aState, aContent, - newFrame, styleContext, nsnull, areaFrame); + newFrame, styleContext, nsnull, blkFrame); NS_RELEASE(styleContext); @@ -4589,7 +4596,7 @@ nsCSSFrameConstructor::ConstructFieldSetFrame(nsIPresShell* aPresShell, HaveSpecialBlockStyle(aPresContext, aContent, aStyleContext, &haveFirstLetterStyle, &haveFirstLineStyle); nsFrameConstructorSaveState floaterSaveState; - aState.PushFloaterContainingBlock(areaFrame, floaterSaveState, + aState.PushFloaterContainingBlock(blkFrame, floaterSaveState, haveFirstLetterStyle, haveFirstLineStyle); @@ -4602,10 +4609,10 @@ nsCSSFrameConstructor::ConstructFieldSetFrame(nsIPresShell* aPresShell, if (isPositionedContainingBlock) { // The area frame becomes a container for child frames that are // absolutely positioned - aState.PushAbsoluteContainingBlock(areaFrame, absoluteSaveState); + aState.PushAbsoluteContainingBlock(blkFrame, absoluteSaveState); } - ProcessChildren(aPresShell, aPresContext, aState, aContent, areaFrame, PR_FALSE, + ProcessChildren(aPresShell, aPresContext, aState, aContent, blkFrame, PR_FALSE, childItems, PR_TRUE); static NS_DEFINE_IID(kLegendFrameCID, NS_LEGEND_FRAME_CID); @@ -4619,7 +4626,7 @@ nsCSSFrameConstructor::ConstructFieldSetFrame(nsIPresShell* aPresShell, nsIFrame * nxt; legendFrame->GetNextSibling(&nxt); previous->SetNextSibling(nxt); - areaFrame->SetNextSibling(legendFrame); + blkFrame->SetNextSibling(legendFrame); legendFrame->SetParent(newFrame); legendFrame->SetNextSibling(nsnull); break; @@ -4627,7 +4634,7 @@ nsCSSFrameConstructor::ConstructFieldSetFrame(nsIPresShell* aPresShell, nsIFrame * nxt; legendFrame->GetNextSibling(&nxt); childItems.childList = nxt; - areaFrame->SetNextSibling(legendFrame); + blkFrame->SetNextSibling(legendFrame); legendFrame->SetParent(newFrame); legendFrame->SetNextSibling(nsnull); break; @@ -4638,21 +4645,21 @@ nsCSSFrameConstructor::ConstructFieldSetFrame(nsIPresShell* aPresShell, } // Set the scrolled frame's initial child lists - areaFrame->SetInitialChildList(aPresContext, nsnull, childItems.childList); + blkFrame->SetInitialChildList(aPresContext, nsnull, childItems.childList); if (isPositionedContainingBlock && aState.mAbsoluteItems.childList) { - areaFrame->SetInitialChildList(aPresContext, + blkFrame->SetInitialChildList(aPresContext, nsLayoutAtoms::absoluteList, aState.mAbsoluteItems.childList); } if (aState.mFloatedItems.childList) { - areaFrame->SetInitialChildList(aPresContext, + blkFrame->SetInitialChildList(aPresContext, nsLayoutAtoms::floaterList, aState.mFloatedItems.childList); } // Set the scroll frame's initial child list - newFrame->SetInitialChildList(aPresContext, nsnull, areaFrame); + newFrame->SetInitialChildList(aPresContext, nsnull, blkFrame); // our new frame retured is the top frame which is the list frame. aNewFrame = newFrame; @@ -5154,11 +5161,11 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsIPresShell* aPresShell, nsFrameConstructorState& aState, nsIContent* aParent, nsIDocument* aDocument, - nsIFrame* aParentFrame, + nsIFrame* aNewFrame, nsFrameItems& aChildItems) { - nsCOMPtr creator(do_QueryInterface(aParentFrame)); + nsCOMPtr creator(do_QueryInterface(aNewFrame)); if (!creator) return NS_OK; @@ -5182,14 +5189,8 @@ nsCSSFrameConstructor::CreateAnonymousFrames(nsIPresShell* aPresShell, content->SetParent(aParent); content->SetDocument(aDocument, PR_TRUE); - nsIFrame * newFrame = nsnull; - nsresult rv = creator->CreateFrameFor(aPresContext, content, &newFrame); - if (NS_SUCCEEDED(rv) && newFrame != nsnull) { - aChildItems.AddChild(newFrame); - } else { - // create the frame and attach it to our frame - ConstructFrame(aPresShell, aPresContext, aState, content, aParentFrame, aChildItems); - } + // create the frame and attach it to our frame + ConstructFrame(aPresShell, aPresContext, aState, content, aNewFrame, aChildItems); } return NS_OK; @@ -7515,8 +7516,16 @@ nsCSSFrameConstructor::AppendFrames(nsIPresContext* aPresContext, } else { // Append the frames to the end of the parent's child list - rv = aFrameManager->AppendFrames(aPresContext, *aPresShell, aParentFrame, - GetChildListFor(aFrameList), aFrameList); + // check for a table caption which goes on an additional child list with a different parent + nsIFrame* outerTableFrame; + if (GetCaptionAdjustedParent(aParentFrame, aFrameList, &outerTableFrame)) { + rv = aFrameManager->AppendFrames(aPresContext, *aPresShell, outerTableFrame, + nsLayoutAtoms::captionList, aFrameList); + } + else { + rv = aFrameManager->AppendFrames(aPresContext, *aPresShell, aParentFrame, + nsnull, aFrameList); + } } NS_IF_RELEASE(parentType); @@ -8296,11 +8305,15 @@ nsCSSFrameConstructor::ContentInserted(nsIPresContext* aPresContext, } } // check for a table caption which goes on an additional child list - nsIAtom* childList = GetChildListFor(newFrame); - rv = state.mFrameManager->InsertFrames(aPresContext, *shell, - parentFrame, - childList, prevSibling, - newFrame); + nsIFrame* outerTableFrame; + if (GetCaptionAdjustedParent(parentFrame, newFrame, &outerTableFrame)) { + rv = state.mFrameManager->AppendFrames(aPresContext, *shell, outerTableFrame, + nsLayoutAtoms::captionList, newFrame); + } + else { + rv = state.mFrameManager->InsertFrames(aPresContext, *shell, parentFrame, + nsnull, prevSibling, newFrame); + } } // If there are new absolutely positioned child frames, then notify @@ -8791,9 +8804,16 @@ nsCSSFrameConstructor::ContentRemoved(nsIPresContext* aPresContext, } else { // Notify the parent frame that it should delete the frame - nsIAtom* childList = GetChildListFor(childFrame); - rv = frameManager->RemoveFrame(aPresContext, *shell, parentFrame, - childList, childFrame); + // check for a table caption which goes on an additional child list with a different parent + nsIFrame* outerTableFrame; + if (GetCaptionAdjustedParent(parentFrame, childFrame, &outerTableFrame)) { + rv = frameManager->RemoveFrame(aPresContext, *shell, outerTableFrame, + nsLayoutAtoms::captionList, childFrame); + } + else { + rv = frameManager->RemoveFrame(aPresContext, *shell, parentFrame, + nsnull, childFrame); + } } } diff --git a/mozilla/layout/html/table/src/nsCellMap.cpp b/mozilla/layout/html/table/src/nsCellMap.cpp index 4265f73d295..0c0a6a0ea1a 100644 --- a/mozilla/layout/html/table/src/nsCellMap.cpp +++ b/mozilla/layout/html/table/src/nsCellMap.cpp @@ -855,8 +855,8 @@ void nsCellMap::InsertCells(nsTableCellMap& aMap, PRInt32 startColIndex; for (startColIndex = aColIndexBefore + 1; startColIndex < numCols; startColIndex++) { CellData* data = GetMapCellAt(aMap, aRowIndex, startColIndex, PR_TRUE); - if (data && data->IsOrig()) { - break; // we found the col index + if (!data || data->IsOrig()) { // stop unless it is a span + break; } } @@ -904,19 +904,20 @@ void nsCellMap::ExpandWithRows(nsIPresContext* aPresContext, nsTableCellMap& aMap, nsVoidArray& aRowFrames, - PRInt32 aStartRowIndex) + PRInt32 aStartRowIndexIn) { + PRInt32 startRowIndex = (aStartRowIndexIn >= 0) ? aStartRowIndexIn : 0; PRInt32 numNewRows = aRowFrames.Count(); - PRInt32 endRowIndex = aStartRowIndex + numNewRows - 1; + PRInt32 endRowIndex = startRowIndex + numNewRows - 1; // create the new rows first - if (!Grow(aMap, numNewRows, aStartRowIndex)) { + if (!Grow(aMap, numNewRows, startRowIndex)) { return; } mRowCount += numNewRows; PRInt32 newRowIndex = 0; - for (PRInt32 rowX = aStartRowIndex; rowX <= endRowIndex; rowX++) { + for (PRInt32 rowX = startRowIndex; rowX <= endRowIndex; rowX++) { nsTableRowFrame* rFrame = (nsTableRowFrame *)aRowFrames.ElementAt(newRowIndex); // append cells nsIFrame* cFrame = nsnull; diff --git a/mozilla/layout/html/table/src/nsTableFrame.cpp b/mozilla/layout/html/table/src/nsTableFrame.cpp index 7f14fc61b8c..96523b110dd 100644 --- a/mozilla/layout/html/table/src/nsTableFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableFrame.cpp @@ -135,6 +135,16 @@ struct InnerTableReflowState { } }; +const nsHTMLReflowState* +GetGrandParentReflowState(const nsHTMLReflowState& aInnerRS) +{ + const nsHTMLReflowState* rs = nsnull; + if (aInnerRS.parentReflowState) { + rs = aInnerRS.parentReflowState->parentReflowState; + } + return rs; +} + NS_IMETHODIMP nsTableFrame::GetFrameType(nsIAtom** aType) const @@ -1461,37 +1471,30 @@ nsTableFrame::SetColumnDimensions(nsIPresContext* aPresContext, { nscoord colHeight = aHeight -= aBorderPadding.top + aBorderPadding.bottom; nscoord cellSpacingX = GetCellSpacingX(); - nscoord halfCellSpacingX = NSToCoordRound(((float)cellSpacingX) / (float)2); nsIFrame* colGroupFrame = mColGroups.FirstChild(); PRInt32 colX = 0; - nsPoint colGroupOrigin(aBorderPadding.left, aBorderPadding.top); + nsPoint colGroupOrigin(aBorderPadding.left + cellSpacingX, aBorderPadding.top); PRInt32 numCols = GetColCount(); while (nsnull != colGroupFrame) { nscoord colGroupWidth = 0; nsIFrame* colFrame = nsnull; colGroupFrame->FirstChild(aPresContext, nsnull, &colFrame); - nsPoint colOrigin(0, 0); + nsPoint colOrigin(0,0); while (nsnull != colFrame) { const nsStyleDisplay* colDisplay; colFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)colDisplay)); if (NS_STYLE_DISPLAY_TABLE_COLUMN == colDisplay->mDisplay) { NS_ASSERTION(colX < numCols, "invalid number of columns"); nscoord colWidth = mColumnWidths[colX]; - if (numCols == 1) { - colWidth += cellSpacingX + cellSpacingX; - } - else if ((0 == colX) || (numCols - 1 == colX)) { - colWidth += cellSpacingX + halfCellSpacingX; - } - else if (GetNumCellsOriginatingInCol(colX) > 0) { - colWidth += cellSpacingX; - } - - colGroupWidth += colWidth; nsRect colRect(colOrigin.x, colOrigin.y, colWidth, colHeight); colFrame->SetRect(aPresContext, colRect); - colOrigin.x += colWidth; + colOrigin.x += colWidth + cellSpacingX; + + colGroupWidth += colWidth; + if (numCols - 1 != colX) { + colGroupWidth += cellSpacingX; + } colX++; } colFrame->GetNextSibling(&colFrame); @@ -1604,9 +1607,7 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, aDesiredSize.maxElementSize = nsnull; } rv = ResizeReflowPass2(aPresContext, aDesiredSize, reflowState, aStatus); - if (NS_FAILED(rv)) { - return rv; - } + if (NS_FAILED(rv)) return rv; aDesiredSize.width = PR_MIN(aDesiredSize.width, pass1Width); @@ -1704,7 +1705,7 @@ NS_METHOD nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, NS_ASSERTION(nsnull==mPrevInFlow, "illegal call, cannot call pass 1 on a continuing frame."); NS_ASSERTION(nsnull != mContent, "null content"); - nsresult rv=NS_OK; + nsresult rv = NS_OK; // set out params aStatus = NS_FRAME_COMPLETE; @@ -1713,23 +1714,22 @@ NS_METHOD nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, nsSize kidMaxSize(0,0); nsHTMLReflowMetrics kidSize(&kidMaxSize); nscoord y = 0; + nscoord cellSpacingY = GetCellSpacingY(); // Compute the insets (sum of border and padding) // XXX: since this is pass1 reflow and where we place the rowgroup frames is irrelevant, insets are probably a waste - if (IsAutoLayout(&aReflowState)) - { + if (IsAutoLayout(&aReflowState)) { nsIFrame* kidFrame = aStartingFrame; if (nsnull==kidFrame) - kidFrame=mFrames.FirstChild(); - for ( ; nsnull != kidFrame; kidFrame->GetNextSibling(&kidFrame)) - { + kidFrame = mFrames.FirstChild(); + for ( ; nsnull != kidFrame; kidFrame->GetNextSibling(&kidFrame)) { const nsStyleDisplay *childDisplay; kidFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); if ((NS_STYLE_DISPLAY_TABLE_HEADER_GROUP != childDisplay->mDisplay) && (NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP != childDisplay->mDisplay) && - (NS_STYLE_DISPLAY_TABLE_ROW_GROUP != childDisplay->mDisplay) ) - { // it's an unknown frame type, give it a generic reflow and ignore the results + (NS_STYLE_DISPLAY_TABLE_ROW_GROUP != childDisplay->mDisplay) ) { + // it's an unknown frame type, give it a generic reflow and ignore the results nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame, availSize, aReason); // rv intentionally not set here @@ -1738,7 +1738,7 @@ NS_METHOD nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, continue; } - // Get the row group's border padding + // Get the table's border padding nsMargin borderPadding; GetTableBorderForRowGroup(GetRowGroupFrameFor(kidFrame, childDisplay), borderPadding); const nsStyleSpacing* tableSpacing; @@ -1746,6 +1746,11 @@ NS_METHOD nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, nsMargin padding; tableSpacing->GetPadding(padding); borderPadding += padding; + + y += cellSpacingY; + if (kidFrame == mFrames.FirstChild()) { + y += borderPadding.top; + } // Reflow the child nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame, @@ -1754,12 +1759,12 @@ NS_METHOD nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, // isTopOfPage reflow state flag, because we're dealing with an unconstrained // height and it isn't an issue... ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, borderPadding.left, - borderPadding.top + y, 0, aStatus); + y, 0, aStatus); // Place the child since some of its content fit in us. FinishReflowChild(kidFrame, aPresContext, kidSize, borderPadding.left, borderPadding.top + y, 0); - if (NS_UNCONSTRAINEDSIZE==kidSize.height) + if (NS_UNCONSTRAINEDSIZE == kidSize.height) // XXX This is very suspicious. Why would a row group frame want // such a large height? y = NS_UNCONSTRAINEDSIZE; @@ -1777,16 +1782,14 @@ NS_METHOD nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, // up all of our available space (or needs us to split). break; } - if (PR_FALSE==aDoSiblingFrames) + if (!aDoSiblingFrames) break; } // if required, give the colgroups their initial reflows - if (PR_TRUE==aDoSiblingFrames) - { + if (aDoSiblingFrames) { kidFrame=mColGroups.FirstChild(); - for ( ; nsnull != kidFrame; kidFrame->GetNextSibling(&kidFrame)) - { + for ( ; nsnull != kidFrame; kidFrame->GetNextSibling(&kidFrame)) { nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame, availSize, aReason); ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, 0, 0, 0, aStatus); @@ -1946,6 +1949,7 @@ NS_METHOD nsTableFrame::ResizeReflowPass2(nsIPresContext* aPresContext, borderPadding += aReflowState.mComputedPadding; InnerTableReflowState state(aPresContext, aReflowState, borderPadding); + state.y = borderPadding.top; // XXX this should be set in the constructor, but incremental code is affected. // now that we've computed the column width information, reflow all children #ifdef NS_DEBUG @@ -1958,7 +1962,7 @@ NS_METHOD nsTableFrame::ResizeReflowPass2(nsIPresContext* aPresContext, // Reflow the existing frames if (mFrames.NotEmpty()) { - ComputePercentBasisForRows(aReflowState); + ComputePercentBasisForRows(aPresContext, aReflowState); rv = ReflowMappedChildren(aPresContext, aDesiredSize, state, aStatus); } @@ -1973,7 +1977,7 @@ NS_METHOD nsTableFrame::ResizeReflowPass2(nsIPresContext* aPresContext, // Return our size and our status aDesiredSize.width = ComputeDesiredWidth(aReflowState); - nscoord defaultHeight = state.y + borderPadding.top + borderPadding.bottom; + nscoord defaultHeight = state.y + GetCellSpacingY() + borderPadding.bottom; aDesiredSize.height = ComputeDesiredHeight(aPresContext, aReflowState, defaultHeight); AdjustForCollapsingRows(aPresContext, aDesiredSize.height); @@ -1994,16 +1998,15 @@ NS_METHOD nsTableFrame::ResizeReflowPass2(nsIPresContext* aPresContext, } -void nsTableFrame::ComputePercentBasisForRows(const nsHTMLReflowState& aReflowState) +void nsTableFrame::ComputePercentBasisForRows(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState) { - nscoord height = CalcBorderBoxHeight(aReflowState, PR_TRUE); + nscoord height = CalcBorderBoxHeight(aPresContext, aReflowState); if ((height > 0) && (height != NS_UNCONSTRAINEDSIZE)) { // exclude our border and padding nsMargin borderPadding = aReflowState.mComputedBorderPadding; height -= borderPadding.top + borderPadding.bottom; - // exclude cell spacing for all rows - height -= (1 + GetRowCount()) * GetCellSpacingY(); height = PR_MAX(0, height); } else { @@ -2786,10 +2789,9 @@ nscoord nsTableFrame::ComputeDesiredWidth(const nsHTMLReflowState& aReflowState) nscoord desiredWidth = aReflowState.availableWidth; // this is the biggest hack in the world. But there's no other rational way to handle nested percent tables const nsStylePosition* position; - PRBool isNested=IsNested(aReflowState, position); - if((eReflowReason_Initial==aReflowState.reason) && - (PR_TRUE==isNested) && (eStyleUnit_Percent==position->mWidth.GetUnit())) - { + PRBool isNested = IsNested(aReflowState, position); + if ((eReflowReason_Initial==aReflowState.reason) && + (isNested) && (eStyleUnit_Percent == position->mWidth.GetUnit())) { nsITableLayoutStrategy* tableLayoutStrategy = mTableLayoutStrategy; if (mPrevInFlow) { // Get the table layout strategy from the first-in-flow @@ -2823,36 +2825,30 @@ void nsTableFrame::PlaceChild(nsIPresContext* aPresContext, aReflowState.availSize.height -= aDesiredSize.height; } - // If this is a footer row group, remember it const nsStyleDisplay *childDisplay; aKidFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); // We only allow a single footer frame, and the footer frame must occur before // any body section row groups if ((NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay) && - !aReflowState.footerFrame && !aReflowState.firstBodySection) - { + !aReflowState.footerFrame && !aReflowState.firstBodySection) { aReflowState.footerFrame = aKidFrame; } - else if (aReflowState.footerFrame) - { - // Place the row group frame - nsSize footerSize; + else if (aReflowState.footerFrame) { + // put the non footer where the footer was nsPoint origin; - aKidFrame->GetOrigin(origin); - aReflowState.footerFrame->GetSize(footerSize); - origin.y -= footerSize.height; - aKidFrame->MoveTo(aPresContext, origin.x, origin.y); - - // Move the footer below the body row group frame aReflowState.footerFrame->GetOrigin(origin); - origin.y += aDesiredSize.height; + aKidFrame->MoveTo(aPresContext, origin.x, origin.y); + + // put the footer below the non footer + nsSize size; + aReflowState.footerFrame->GetSize(size); + origin.y = aReflowState.y - size.height; aReflowState.footerFrame->MoveTo(aPresContext, origin.x, origin.y); } //XXX: this should call into layout strategy to get the width field - if (nsnull != aMaxElementSize) - { + if (nsnull != aMaxElementSize) { const nsStyleSpacing* tableSpacing; GetStyleData(eStyleStruct_Spacing , ((const nsStyleStruct *&)tableSpacing)); nsMargin borderPadding; @@ -2865,6 +2861,39 @@ void nsTableFrame::PlaceChild(nsIPresContext* aPresContext, } } +void +nsTableFrame::GetSectionInfo(nsFrameList& aKidFrames, + PRBool& aHaveTHead, + PRBool& aHaveTBody, + PRBool& aHaveTFoot, + PRBool& aTHeadBeforeTFoot) +{ + aHaveTHead = aHaveTBody = aHaveTFoot = PR_FALSE; + aTHeadBeforeTFoot = PR_TRUE; + + nsIFrame* kidFrame = aKidFrames.FirstChild(); + while (kidFrame) { + const nsStyleDisplay* kidDisplay; + kidFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)kidDisplay)); + if (IsRowGroup(kidDisplay->mDisplay)) { + switch(kidDisplay->mDisplay) { + case NS_STYLE_DISPLAY_TABLE_HEADER_GROUP: + aHaveTHead = PR_TRUE; + break; + case NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP: + aHaveTFoot = PR_TRUE; + if (!aHaveTHead) { + aTHeadBeforeTFoot = PR_FALSE; + } + break; + default: + aHaveTBody = PR_TRUE; + } + } + kidFrame->GetNextSibling(&kidFrame); + } +} + /** * Reflow the frames we've already created * @@ -2873,22 +2902,21 @@ void nsTableFrame::PlaceChild(nsIPresContext* aPresContext, * @return true if we successfully reflowed all the mapped children and false * otherwise, e.g. we pushed children to the next in flow */ -NS_METHOD nsTableFrame::ReflowMappedChildren(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, +NS_METHOD nsTableFrame::ReflowMappedChildren(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, InnerTableReflowState& aReflowState, - nsReflowStatus& aStatus) + nsReflowStatus& aStatus) { NS_PRECONDITION(mFrames.NotEmpty(), "no children"); - PRInt32 childCount = 0; nsIFrame* prevKidFrame = nsnull; nsSize kidMaxElementSize(0,0); nsSize* pKidMaxElementSize = (nsnull != aDesiredSize.maxElementSize) ? &kidMaxElementSize : nsnull; nsresult rv = NS_OK; + nscoord cellSpacingY = GetCellSpacingY(); nsReflowReason reason; - if (!IsAutoLayout(&aReflowState.reflowState)) - { + if (!IsAutoLayout(&aReflowState.reflowState)) { reason = aReflowState.reflowState.reason; if (eReflowReason_Incremental==reason) { reason = eReflowReason_Resize; @@ -2898,22 +2926,26 @@ NS_METHOD nsTableFrame::ReflowMappedChildren(nsIPresContext* aPresContext, } } } - else + else { reason = eReflowReason_Resize; + } + + // determine what section elements are present + PRBool haveTHead, haveTBody, haveTFoot, tHeadBeforeTFoot; + GetSectionInfo(mFrames, haveTHead, haveTBody, haveTFoot, tHeadBeforeTFoot); // this never passes reflows down to colgroups - for (nsIFrame* kidFrame = mFrames.FirstChild(); nsnull != kidFrame; ) - { + nsIFrame* kidFrame = mFrames.FirstChild(); + while (kidFrame) { nsSize kidAvailSize(aReflowState.availSize); nsHTMLReflowMetrics desiredSize(pKidMaxElementSize); - desiredSize.width=desiredSize.height=desiredSize.ascent=desiredSize.descent=0; + desiredSize.width = desiredSize.height = desiredSize.ascent = desiredSize.descent = 0; - const nsStyleDisplay *childDisplay; + const nsStyleDisplay* childDisplay; kidFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - if (PR_TRUE==IsRowGroup(childDisplay->mDisplay)) - { + if (IsRowGroup(childDisplay->mDisplay)) { // Keep track of the first body section row group - if (nsnull == aReflowState.firstBodySection) { + if (!aReflowState.firstBodySection) { if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay) { aReflowState.firstBodySection = kidFrame; } @@ -2934,12 +2966,13 @@ NS_METHOD nsTableFrame::ReflowMappedChildren(nsIPresContext* aPresContext, kidReflowState.isTopOfPage = PR_FALSE; } + aReflowState.y += cellSpacingY; nscoord x = borderPadding.left; - nscoord y = borderPadding.top + aReflowState.y; + nscoord y = aReflowState.y; if (RowGroupsShouldBeConstrained()) { // Only applies to the tree widget. - nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aReflowState.reflowState, PR_TRUE); + nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aPresContext, aReflowState.reflowState); if ((tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE)) { kidReflowState.availableHeight = tableSpecifiedHeight - y; if (kidReflowState.availableHeight < 0) @@ -2961,11 +2994,10 @@ NS_METHOD nsTableFrame::ReflowMappedChildren(nsIPresContext* aPresContext, } // Place the child - if (PR_TRUE==IsRowGroup(childDisplay->mDisplay)) - { + if (IsRowGroup(childDisplay->mDisplay)) { // we don't want to adjust the maxElementSize if this is an initial reflow // it was set by the TableLayoutStrategy and shouldn't be changed. - nsSize *requestedMaxElementSize = nsnull; + nsSize* requestedMaxElementSize = nsnull; if (eReflowReason_Initial != aReflowState.reflowState.reason) requestedMaxElementSize = aDesiredSize.maxElementSize; PlaceChild(aPresContext, aReflowState, kidFrame, desiredSize, @@ -2973,7 +3005,6 @@ NS_METHOD nsTableFrame::ReflowMappedChildren(nsIPresContext* aPresContext, } else { kidFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); } - childCount++; // Remember where we just were in case we end up pushing children prevKidFrame = kidFrame; @@ -3014,23 +3045,20 @@ NS_METHOD nsTableFrame::ReflowMappedChildren(nsIPresContext* aPresContext, break; } } - else - {// it's an unknown frame type, give it a generic reflow and ignore the results - nsHTMLReflowState kidReflowState(aPresContext, - aReflowState.reflowState, kidFrame, - nsSize(0,0), eReflowReason_Resize); - nsHTMLReflowMetrics unusedDesiredSize(nsnull); - nsReflowStatus status; - ReflowChild(kidFrame, aPresContext, unusedDesiredSize, kidReflowState, - 0, 0, 0, status); - kidFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); + else {// it's an unknown frame type, give it a generic reflow and ignore the results + nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState, kidFrame, + nsSize(0,0), eReflowReason_Resize); + nsHTMLReflowMetrics unusedDesiredSize(nsnull); + nsReflowStatus status; + ReflowChild(kidFrame, aPresContext, unusedDesiredSize, kidReflowState, + 0, 0, 0, status); + kidFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); } // Get the next child kidFrame->GetNextSibling(&kidFrame); } - // Update the child count return rv; } @@ -3287,90 +3315,18 @@ void nsTableFrame::SetTableWidth(nsIPresContext* aPresContext, SetRect(aPresContext, tableSize); } -// XXX percentage based margin/border/padding -nscoord GetVerticalMarginBorderPadding(nsIFrame* aFrame, - const nsIID& aIID) +nscoord +GetVertMarginBorderPadding(const nsHTMLReflowState* aReflowState) { nscoord result = 0; - if (!aFrame) { - return result; - } - nsCOMPtr iContent; - nsresult rv = aFrame->GetContent(getter_AddRefs(iContent)); - if (NS_SUCCEEDED(rv)) { - nsIHTMLContent* htmlContent = nsnull; - rv = iContent->QueryInterface(aIID, (void **)&htmlContent); - if (htmlContent && NS_SUCCEEDED(rv)) { - nsCOMPtr styleContext; - aFrame->GetStyleContext(getter_AddRefs(styleContext)); - const nsStyleSpacing* spacing = - (const nsStyleSpacing*)styleContext->GetStyleData(eStyleStruct_Spacing); - nsMargin margin(0,0,0,0); - if (spacing->GetMargin(margin)) { - result += margin.top + margin.bottom; - } - if (spacing->GetBorderPadding(margin)) { - result += margin.top + margin.bottom; - } - NS_RELEASE(htmlContent); - } - } - return result; -} + if (!aReflowState) return result; -/* Get the height of the nearest ancestor of this table which has a height other than - * auto, except when there is an ancestor which is a table and that table does not have - * a coord height. It can be the case that the nearest such ancestor is a scroll frame - * or viewport frame; this provides backwards compatibility with Nav4.X and IE. - */ -nscoord nsTableFrame::GetEffectiveContainerHeight(const nsHTMLReflowState& aReflowState) -{ - nsIFrame* lastArea = nsnull; - nsIFrame* lastBlock = nsnull; - nsIAtom* frameType = nsnull; - nscoord result = -1; - const nsHTMLReflowState* rs = &aReflowState; + nsMargin margin = aReflowState->mComputedMargin; + nsTableOuterFrame::ZeroAutoMargin(margin); + result += margin.top + margin.bottom; + result += aReflowState->mComputedBorderPadding.top + + aReflowState->mComputedBorderPadding.bottom; - while (rs) { - const nsStyleDisplay* display; - rs->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)display); - if (NS_STYLE_DISPLAY_TABLE == display->mDisplay) { - const nsStylePosition* position; - rs->frame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)position); - nsStyleUnit unit = position->mHeight.GetUnit(); - if ((eStyleUnit_Null == unit) || (eStyleUnit_Auto == unit)) { - result = 0; - break; - } - } - if (NS_AUTOHEIGHT != rs->mComputedHeight) { - result = rs->mComputedHeight; - // if we get to the scroll frame or viewport frame, then subtract out - // margin/border/padding for the HTML and BODY elements - rs->frame->GetFrameType(&frameType); - if ((nsLayoutAtoms::viewportFrame == frameType) || - (nsLayoutAtoms::scrollFrame == frameType)) { - result -= GetVerticalMarginBorderPadding(lastArea, kIHTMLElementIID); - result -= GetVerticalMarginBorderPadding(lastBlock, kIBodyElementIID); - } - NS_IF_RELEASE(frameType); - break; - } - // keep track of the area and block frame on the way up because they could - // be the HTML and BODY elements - rs->frame->GetFrameType(&frameType); - if (nsLayoutAtoms::areaFrame == frameType) { - lastArea = rs->frame; - } - else if (nsLayoutAtoms::blockFrame == frameType) { - lastBlock = rs->frame; - } - NS_IF_RELEASE(frameType); - - // XXX: evil cast! - rs = (nsHTMLReflowState *)(rs->parentReflowState); - } - NS_ASSERTION(-1 != result, "bad state: no constrained height in reflow chain"); return result; } @@ -3405,34 +3361,33 @@ void nsTableFrame::DistributeSpaceToCells(nsIPresContext* aPresContext, void nsTableFrame::DistributeSpaceToRows(nsIPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsIFrame* aRowGroupFrame, - const nscoord& aSumOfRowHeights, - const nscoord& aExcess, - const nsStyleTable* aTableStyle, + nscoord aSumOfRowHeights, + nscoord aExcess, nscoord& aExcessForRowGroup, nscoord& aRowGroupYPos) { // the rows in rowGroupFrame need to be expanded by rowHeightDelta[i] // and the rowgroup itself needs to be expanded by SUM(row height deltas) + nscoord cellSpacingY = GetCellSpacingY(); nsTableRowGroupFrame* rowGroupFrame = (nsTableRowGroupFrame*)aRowGroupFrame; - nsIFrame * rowFrame = rowGroupFrame->GetFirstFrame(); - nscoord y = 0; - while (nsnull!=rowFrame) - { + nsIFrame* rowFrame = rowGroupFrame->GetFirstFrame(); + nscoord y = cellSpacingY; + while (rowFrame) { const nsStyleDisplay *rowDisplay; rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)rowDisplay)); if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == rowDisplay->mDisplay) { DistributeSpaceToRows(aPresContext, aReflowState, rowFrame, aSumOfRowHeights, - aExcess, aTableStyle, aExcessForRowGroup, y); + aExcess, aExcessForRowGroup, y); } - else if (NS_STYLE_DISPLAY_TABLE_ROW == rowDisplay->mDisplay) - { // the row needs to be expanded by the proportion this row contributed to the original height + else if (NS_STYLE_DISPLAY_TABLE_ROW == rowDisplay->mDisplay) { + // the row needs to be expanded by the proportion this row contributed to the original height nsRect rowRect; rowFrame->GetRect(rowRect); - float percent = ((float)(rowRect.height)) / ((float)(aSumOfRowHeights)); - nscoord excessForRow = NSToCoordRound((float)aExcess*percent); + float percent = ((float)(rowRect.height)) / (float)aSumOfRowHeights; + nscoord excessForRow = NSToCoordRound((float)aExcess * percent); if (rowGroupFrame->RowsDesireExcessSpace()) { - nsRect newRowRect(rowRect.x, y, rowRect.width, excessForRow+rowRect.height); + nsRect newRowRect(rowRect.x, y, rowRect.width, excessForRow + rowRect.height); rowFrame->SetRect(aPresContext, newRowRect); if ((NS_STYLE_BORDER_COLLAPSE == GetBorderCollapseStyle()) && mBorderCollapser) { PRInt32 rowIndex = ((nsTableRowFrame*)rowFrame)->GetRowIndex(); @@ -3440,13 +3395,13 @@ void nsTableFrame::DistributeSpaceToRows(nsIPresContext* aPresContext, mBorderCollapser->SetBorderEdgeLength(NS_SIDE_RIGHT, rowIndex, newRowRect.height); } // better if this were part of an overloaded row::SetRect - y += excessForRow+rowRect.height; + y += excessForRow + rowRect.height; } + y += cellSpacingY; aExcessForRowGroup += excessForRow; } - else - { + else { // XXX why nsRect rowRect; rowFrame->GetRect(rowRect); y += rowRect.height; @@ -3458,11 +3413,14 @@ void nsTableFrame::DistributeSpaceToRows(nsIPresContext* aPresContext, nsRect rowGroupRect; aRowGroupFrame->GetRect(rowGroupRect); if (rowGroupFrame->RowGroupDesiresExcessSpace()) { - nsRect newRowGroupRect(rowGroupRect.x, aRowGroupYPos, rowGroupRect.width, aExcessForRowGroup+rowGroupRect.height); + nsRect newRowGroupRect(rowGroupRect.x, aRowGroupYPos, rowGroupRect.width, + aExcessForRowGroup + rowGroupRect.height); aRowGroupFrame->SetRect(aPresContext, newRowGroupRect); aRowGroupYPos += aExcessForRowGroup + rowGroupRect.height; } - else aRowGroupYPos += rowGroupRect.height; + else { + aRowGroupYPos += rowGroupRect.height; + } DistributeSpaceToCells(aPresContext, aReflowState, aRowGroupFrame); } @@ -3478,7 +3436,7 @@ nscoord nsTableFrame::ComputeDesiredHeight(nsIPresContext* aPresContext } nscoord result = aDefaultHeight; - nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aReflowState, PR_TRUE); + nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aPresContext, aReflowState); if ((tableSpecifiedHeight > 0) && (tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE)) { if (tableSpecifiedHeight > aDefaultHeight) { result = tableSpecifiedHeight; @@ -3517,7 +3475,7 @@ nscoord nsTableFrame::ComputeDesiredHeight(nsIPresContext* aPresContext const nsStyleTable* tableStyle; GetStyleData(eStyleStruct_Table, (const nsStyleStruct *&)tableStyle); DistributeSpaceToRows(aPresContext, aReflowState, childFrame, sumOfRowHeights, - excess, tableStyle, excessForGroup, rowGroupYPos); + excess, excessForGroup, rowGroupYPos); // Make sure child views are properly positioned nsIView* view; @@ -3923,29 +3881,6 @@ nsTableFrame::GetPadding(const nsSize& aBasis, return padding; } -NS_METHOD nsTableFrame::GetCellMarginData(nsTableCellFrame* aKidFrame, nsMargin& aMargin) -{ - nsresult result = NS_ERROR_NOT_INITIALIZED; - - if (aKidFrame) { - nscoord spacingX = GetCellSpacingX(); - nscoord spacingY = GetCellSpacingY(); - PRInt32 rowIndex, colIndex; - aKidFrame->GetRowIndex(rowIndex); - aKidFrame->GetColIndex(colIndex); - // left/top margins only apply if the cell is a left/top border cell - // there used to be more complicated logic (rev 3.326) dealing with rowspans - // but failure to produce reasonable tests cases does not justify it. - aMargin.left = (0 == colIndex) ? spacingX : 0; - aMargin.top = (0 == rowIndex) ? spacingY : 0; - aMargin.right = spacingX; - aMargin.bottom = spacingY; - result = NS_OK; - } - - return result; -} - //XXX: ok, this looks dumb now. but in a very short time this will get filled in void nsTableFrame::GetTableBorder(nsMargin &aBorder) { @@ -4109,19 +4044,18 @@ NS_METHOD nsTableFrame::GetTableFrame(nsIFrame *aSourceFrame, nsTableFrame *& aT /* helper method for determining if this is a nested table or not */ // aReflowState must be the reflow state for this inner table frame, should have an assertion here for that -PRBool nsTableFrame::IsNested(const nsHTMLReflowState& aReflowState, const nsStylePosition *& aPosition) const +PRBool +nsTableFrame::IsNested(const nsHTMLReflowState& aReflowState, + const nsStylePosition*& aPosition) const { + aPosition = nsnull; PRBool result = PR_FALSE; // Walk up the reflow state chain until we find a cell or the root - const nsHTMLReflowState* rs = aReflowState.parentReflowState; // this is for the outer frame - if (rs) - rs = rs->parentReflowState; // and this is the parent of the outer frame - while (nsnull != rs) - { - const nsStyleDisplay *display; - rs->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)display); - if (NS_STYLE_DISPLAY_TABLE==display->mDisplay) - { + const nsHTMLReflowState* rs = GetGrandParentReflowState(aReflowState); + while (rs) { + nsCOMPtr frameType; + rs->frame->GetFrameType(getter_AddRefs(frameType)); + if (nsLayoutAtoms::tableFrame == frameType.get()) { result = PR_TRUE; rs->frame->GetStyleData(eStyleStruct_Position, ((const nsStyleStruct *&)aPosition)); break; @@ -4180,39 +4114,15 @@ nscoord nsTableFrame::CalcBorderBoxWidth(const nsHTMLReflowState& aState) return width; } -nscoord nsTableFrame::CalcBorderBoxHeight(const nsHTMLReflowState& aState, - PRBool aDoNavHack) +nscoord nsTableFrame::CalcBorderBoxHeight(nsIPresContext* aPresContext, + const nsHTMLReflowState& aState) { nscoord height = aState.mComputedHeight; - PRBool isAutoHeight = PR_FALSE; - PRBool isPercentHack = PR_FALSE; - - if (eStyleUnit_Auto == aState.mStylePosition->mHeight.GetUnit()) { - isAutoHeight = PR_TRUE; - } - else if (((0 == height) || (NS_UNCONSTRAINEDSIZE == height)) && - aDoNavHack && (eStyleUnit_Percent == aState.mStylePosition->mHeight.GetUnit())) { - nsIAtom* frameType; - aState.frame->GetFrameType(&frameType); - if (nsLayoutAtoms::tableFrame == frameType) { - float percent = aState.mStylePosition->mHeight.GetPercentValue(); - nscoord parentHeight = ((nsTableFrame*)aState.frame)->GetEffectiveContainerHeight(aState); - if ((NS_UNCONSTRAINEDSIZE != parentHeight) && (0 != parentHeight)) { - // css box-sizing not supported for this Nav hack - height = NSToCoordRound((float)parentHeight * percent); - isPercentHack = PR_TRUE; - } - } - NS_IF_RELEASE(frameType); - } - - height = PR_MAX(height, 0); - - if ((height != NS_UNCONSTRAINEDSIZE) && !isAutoHeight && !isPercentHack) { - nsMargin borderPadding(0,0,0,0); - aState.mStyleSpacing->GetBorderPadding(borderPadding); + if (NS_AUTOHEIGHT != height) { + nsMargin borderPadding = aState.mComputedBorderPadding; height += borderPadding.top + borderPadding.bottom; } + height = PR_MAX(0, height); return height; } diff --git a/mozilla/layout/html/table/src/nsTableFrame.h b/mozilla/layout/html/table/src/nsTableFrame.h index 241ae644db4..3fa0e0a2ecf 100644 --- a/mozilla/layout/html/table/src/nsTableFrame.h +++ b/mozilla/layout/html/table/src/nsTableFrame.h @@ -147,8 +147,8 @@ public: // calculate the height of aFrame including its border and padding given // its reflow state. - nscoord CalcBorderBoxHeight(const nsHTMLReflowState& aReflowState, - PRBool aDoNavHacks); + nscoord CalcBorderBoxHeight(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState); // Return the closest sibling of aPriorChildFrame (including aPriroChildFrame) // of type aChildType. @@ -292,10 +292,6 @@ public: /** helper to get the cell padding style value */ virtual nscoord GetCellPadding(); - - // Get cell margin information - NS_IMETHOD GetCellMarginData(nsTableCellFrame* aKidFrame, nsMargin& aMargin); - /** return the row span of a cell, taking into account row span magic at the bottom * of a table. The row span equals the number of rows spanned by aCell starting at * aStartRowIndex, and can be smaller if aStartRowIndex is greater than the row @@ -450,7 +446,8 @@ protected: * If not nested, undefined. * @return PR_TRUE if this table is nested inside another table. */ - PRBool IsNested(const nsHTMLReflowState& aReflowState, const nsStylePosition *& aPosition) const; + PRBool IsNested(const nsHTMLReflowState& aReflowState, + const nsStylePosition*& aPosition) const; // Sets the starting column index for aColGroupFrame and the siblings frames that // follow @@ -576,17 +573,16 @@ protected: /** The following two functions are helpers for ComputeDesiredHeight */ - void DistributeSpaceToCells(nsIPresContext* aPresContext, + void DistributeSpaceToCells(nsIPresContext* aPresContext, const nsHTMLReflowState& aReflowState, - nsIFrame* aRowGroupFrame); - void DistributeSpaceToRows(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - nsIFrame* aRowGroupFrame, const nscoord& aSumOfRowHeights, - const nscoord& aExcess, const nsStyleTable* aTableStyle, - nscoord& aExcessForRowGroup, - nscoord& aRowGroupYPos); - - nscoord GetEffectiveContainerHeight(const nsHTMLReflowState& aReflowState); + nsIFrame* aRowGroupFrame); + void DistributeSpaceToRows(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState, + nsIFrame* aRowGroupFrame, + nscoord aSumOfRowHeights, + nscoord aExcess, + nscoord& aExcessForRowGroup, + nscoord& aRowGroupYPos); void PlaceChild(nsIPresContext* aPresContext, InnerTableReflowState& aReflowState, @@ -653,6 +649,11 @@ protected: nsIFrame* aFromChild, nsIFrame* aPrevSibling); + void GetSectionInfo(nsFrameList& aKidFrames, + PRBool& aHaveTHead, + PRBool& aHaveTBody, + PRBool& aHaveTFoot, + PRBool& aTHeadBeforeTFoot); public: // Returns PR_TRUE if there are any cells above the row at // aRowIndex and spanning into the row at aRowIndex @@ -811,7 +812,8 @@ public: /* ----- Cell Map public methods ----- */ // compute the height of the table to be used as the basis for // percentage height cells - void ComputePercentBasisForRows(const nsHTMLReflowState& aReflowState); + void ComputePercentBasisForRows(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState); nscoord GetPercentBasisForRows(); diff --git a/mozilla/layout/html/table/src/nsTableOuterFrame.cpp b/mozilla/layout/html/table/src/nsTableOuterFrame.cpp index 13dc811fc90..2f4a59601ca 100644 --- a/mozilla/layout/html/table/src/nsTableOuterFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableOuterFrame.cpp @@ -40,6 +40,7 @@ /* ----------- nsTableCaptionFrame ---------- */ #define NS_TABLE_FRAME_CAPTION_LIST_INDEX 0 +#define NO_SIDE 100 // caption frame nsTableCaptionFrame::nsTableCaptionFrame() @@ -87,52 +88,6 @@ NS_NewTableCaptionFrame(nsIPresShell* aPresShell, return NS_OK; } -// OuterTableReflowState - -struct OuterTableReflowState { - - // The presentation context - nsIPresContext *pc; - - // Our reflow state - const nsHTMLReflowState& reflowState; - - // The total available size (computed from the parent) - nsSize availSize; - // The available size for the inner table frame - nsSize innerTableMaxSize; - - // Margin tracking information - nscoord prevMaxPosBottomMargin; - nscoord prevMaxNegBottomMargin; - - // Flags for whether the max size is unconstrained - PRBool unconstrainedWidth; - PRBool unconstrainedHeight; - - // Running y-offset - nscoord y; - - OuterTableReflowState(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState) - : reflowState(aReflowState) - { - pc = aPresContext; - availSize.width = reflowState.availableWidth; - availSize.height = reflowState.availableHeight; - prevMaxPosBottomMargin = 0; - prevMaxNegBottomMargin = 0; - y=0; // border/padding/margin??? - unconstrainedWidth = PRBool(aReflowState.availableWidth == NS_UNCONSTRAINEDSIZE); - unconstrainedHeight = PRBool(aReflowState.availableHeight == NS_UNCONSTRAINEDSIZE); - innerTableMaxSize.width=0; - innerTableMaxSize.height=0; - } - - ~OuterTableReflowState() { - } -}; - /* ----------- nsTableOuterFrame ---------- */ NS_IMPL_ADDREF_INHERITED(nsTableOuterFrame, nsHTMLContainerFrame) @@ -160,6 +115,27 @@ nsresult nsTableOuterFrame::QueryInterface(const nsIID& aIID, void** aInstancePt } } +// helper, should really be in nsFrame +void nsTableOuterFrame::PositionView(nsIPresContext* aPresContext, + nsIFrame* aFrame) +{ + nsIView* view; + aFrame->GetView(aPresContext, &view); + if (view) { + nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, aFrame, view, nsnull); + } + else { + nsContainerFrame::PositionChildViews(aPresContext, aFrame); + } +} + +NS_IMETHODIMP +nsTableOuterFrame::IsPercentageBase(PRBool& aBase) const +{ + aBase = PR_FALSE; + return NS_OK; +} + // tables change 0 width into auto, trees override this and do nothing NS_IMETHODIMP nsTableOuterFrame::AdjustZeroWidth() @@ -413,75 +389,550 @@ PRBool nsTableOuterFrame::NeedsReflow(const nsHTMLReflowState& aReflowState) return result; } -// Recover the reflow state to what it should be if aKidFrame is about -// to be reflowed -nsresult nsTableOuterFrame::RecoverState(OuterTableReflowState& aReflowState, - nsIFrame* aKidFrame) +// INCREMENTAL REFLOW HELPER FUNCTIONS + +nsSize +GetFrameSize(nsIFrame& aFrame) { - aReflowState.y = 0; + nsRect rect; + aFrame.GetRect(rect); + nsSize size(rect.width, rect.height); + return size; +} - // Set the inner table max size - nsSize innerTableSize(0,0); +void +nsTableOuterFrame::ZeroAutoMargin(nsMargin& aMargin) +{ + if (NS_AUTOMARGIN == aMargin.top) + aMargin.top = 0; + if (NS_AUTOMARGIN == aMargin.right) + aMargin.right = 0; + if (NS_AUTOMARGIN == aMargin.bottom) + aMargin.bottom = 0; + if (NS_AUTOMARGIN == aMargin.left) + aMargin.left = 0; +} - mInnerTableFrame->GetSize(innerTableSize); - aReflowState.innerTableMaxSize.width = innerTableSize.width; - aReflowState.innerTableMaxSize.height = aReflowState.reflowState.availableHeight; +void +FixAutoMargins(nsHTMLReflowState& aReflowState) +{ + nsMargin margin = aReflowState.mComputedMargin; + if ((margin.left == NS_AUTOMARGIN) || (margin.right == NS_AUTOMARGIN)) { + nsRect rect; + aReflowState.frame->GetRect(rect); + nscoord compWidth = rect.width - aReflowState.mComputedBorderPadding.left - + aReflowState.mComputedBorderPadding.right; + const nsHTMLReflowState* containRS = + nsHTMLReflowState::GetContainingBlockReflowState(aReflowState.parentReflowState); + + aReflowState.CalculateBlockSideMargins(containRS, compWidth); + } +} + +// get the margin and padding data. nsHTMLReflowState doesn't handle the +// case of auto margins +void +GetMarginPadding(nsIPresContext* aPresContext, + const nsHTMLReflowState& aOuterRS, + nsIFrame* aChildFrame, + nsMargin& aMargin, + nsMargin& aPadding, + PRBool aZeroAutoMargins = PR_FALSE) +{ + // construct a reflow state to compute margin and padding. Auto margins + // will not be computed at this time. + nsHTMLReflowState childRS(aPresContext, aOuterRS, aChildFrame, + nsSize(aOuterRS.availableWidth, aOuterRS.availableHeight), + eReflowReason_Resize); + if (aZeroAutoMargins) { + nsMargin adjMargin = childRS.mComputedMargin; + nsTableOuterFrame::ZeroAutoMargin(adjMargin); + aMargin = adjMargin; + } + else { + FixAutoMargins(childRS); + aMargin = childRS.mComputedMargin; + } + aPadding = childRS.mComputedPadding; +} + +nscoord CalcAutoMargin(nscoord aAutoMargin, + nscoord aOppositeMargin, + nscoord aContainBlockSize, + nscoord aFrameSize) +{ + nscoord margin; + if (NS_AUTOMARGIN == aOppositeMargin) { + margin = (aContainBlockSize - aFrameSize) / 2; + } + else { + margin = aContainBlockSize - aFrameSize - aOppositeMargin; + } + return PR_MAX(0, margin); +} + +nscoord +nsTableOuterFrame::GetChildAvailWidth(nsIPresContext* aPresContext, + nsIFrame* aChildFrame, + const nsHTMLReflowState& aOuterRS, + nscoord aOuterWidth, + nsMargin& aMargin, + nsMargin& aPadding) +{ + if (NS_UNCONSTRAINEDSIZE == aOuterWidth) return aOuterWidth; + + GetMarginPadding(aPresContext, aOuterRS, aChildFrame, aMargin, aPadding, PR_TRUE); + nscoord width = aOuterWidth; + if (NS_UNCONSTRAINEDSIZE != width) { + width = aOuterWidth - aMargin.left + aMargin.right; + width = PR_MAX(width, mMinCaptionWidth); + } + return width; +} + +void +MoveFrameTo(nsIPresContext* aPresContext, + nsIFrame* aFrame, + nscoord aX, + nscoord aY) +{ + nsRect oldRect; + aFrame->GetRect(oldRect); + if ((oldRect.x != aX) || (oldRect.y != aY)) { + aFrame->MoveTo(aPresContext, aX, aY); + nsTableOuterFrame::PositionView(aPresContext, aFrame); + } +} + +nsSize +GetContainingBlockSize(const nsHTMLReflowState& aOuterRS) +{ + nsSize size(0,0); + const nsHTMLReflowState* containRS = + nsHTMLReflowState::GetContainingBlockReflowState(aOuterRS.parentReflowState); + + if (containRS) { + size.width = containRS->mComputedWidth; + if (NS_UNCONSTRAINEDSIZE == size.width) { + size.width = 0; + } + size.height = containRS->mComputedHeight; + if (NS_UNCONSTRAINEDSIZE == size.height) { + size.height = 0; + } + } + return size; +} + +void +nsTableOuterFrame::InvalidateDamage(nsIPresContext* aPresContext, + PRUint8 aCaptionSide, + nsSize& aOuterSize, + PRBool aInnerChanged, + PRBool aCaptionChanged) +{ + nsRect damage; + if (aInnerChanged && aCaptionChanged) { + damage = nsRect(0, 0, aOuterSize.width, aOuterSize.height); + } + else { + nsRect innerRect, captionRect(0,0,0,0); + mInnerTableFrame->GetRect(innerRect); + if (mCaptionFrame) { + mCaptionFrame->GetRect(captionRect); + } + // only works for vertical captions { + damage.x = 0; + damage.width = aOuterSize.width; + switch(aCaptionSide) { + case NS_SIDE_TOP: + if (aCaptionChanged) { + damage.y = 0; + damage.height = innerRect.y; + } + else { + damage.y = captionRect.y; + damage.height = aOuterSize.height - damage.y; + } + break; + case NS_SIDE_BOTTOM: + default: + if (aCaptionChanged) { + damage.y = innerRect.y; + damage.height = aOuterSize.height - damage.y; + } + else { + damage.y = 0; + damage.height = captionRect.y; + } + } + } + Invalidate(aPresContext, damage); +} + +nscoord +nsTableOuterFrame::GetCaptionAvailWidth(nsIPresContext* aPresContext, + nsIFrame* aCaptionFrame, + const nsHTMLReflowState& aOuterRS, + nscoord* aInnerWidth, + const nsMargin* aInnerMargin) +{ + nscoord outerWidth; + if (aInnerWidth) { + nscoord innerWidth = *aInnerWidth; + if (NS_UNCONSTRAINEDSIZE == innerWidth) { + outerWidth = innerWidth; + } + else { + nsMargin innerMargin(0,0,0,0); + if (aInnerMargin) { + innerMargin = *aInnerMargin; + ZeroAutoMargin(innerMargin); + } + outerWidth = innerWidth + innerMargin.left + innerMargin.right; + } + } + else { + nsSize outerSize = GetFrameSize(*this); + outerWidth = outerSize.width; + } + + if (NS_UNCONSTRAINEDSIZE == outerWidth) { + return outerWidth; + } + else { + nsMargin capMargin, capPad; + return GetChildAvailWidth(aPresContext, aCaptionFrame, aOuterRS, + outerWidth, capMargin, capPad); + } +} + +nsSize +nsTableOuterFrame::GetMaxElementSize(const nsMargin& aInnerMargin, + const nsMargin& aInnerPadding, + const nsMargin& aCaptionMargin) +{ + nsSize size; + ((nsTableFrame *)mInnerTableFrame)->SetMaxElementSize(&size, aInnerPadding); + size.width += aInnerMargin.left + aInnerMargin.right; + + if (mCaptionFrame) { + nscoord capWidth = mMinCaptionWidth + aCaptionMargin.left + aCaptionMargin.right; + if (capWidth > size.width) { + size.width = capWidth; + } + } + size.height = 0; // max element height is not used for anything is it? + return size; +} + +nscoord +nsTableOuterFrame::GetMaxWidth(PRUint8 aCaptionSide, + const nsMargin& aInnerMargin, + const nsMargin& aCaptionMargin) +{ + nscoord maxWidth; + switch(aCaptionSide) { + case NS_SIDE_TOP: + case NS_SIDE_BOTTOM: + case NS_SIDE_LEFT: + case NS_SIDE_RIGHT: + default: // no caption + maxWidth = mInnerTableMaximumWidth + aInnerMargin.left + aInnerMargin.right; + if (mCaptionFrame) { + maxWidth = PR_MAX(maxWidth, mMinCaptionWidth + aCaptionMargin.left + aCaptionMargin.right); + } + } + return maxWidth; +} + + +PRUint8 +nsTableOuterFrame::GetCaptionSide() +{ + const nsStyleTable* tableStyle; + if (mCaptionFrame) { + mCaptionFrame->GetStyleData(eStyleStruct_Table, ((const nsStyleStruct *&)tableStyle)); + return tableStyle->mCaptionSide; + } + else { + return NO_SIDE; // no caption + } +} + + + +void +nsTableOuterFrame::SetDesiredSize(PRUint8 aCaptionSide, + const nsMargin& aInnerMargin, + const nsMargin& aCaptionMargin, + nscoord& aWidth, + nscoord& aHeight) +{ + aWidth = aHeight = 0; + + nsRect innerRect; + mInnerTableFrame->GetRect(innerRect); + + nsRect captionRect(0,0,0,0); + if (mCaptionFrame) { + mCaptionFrame->GetRect(captionRect); + } + + switch(aCaptionSide) { + case NS_SIDE_TOP: + case NS_SIDE_BOTTOM: + case NS_SIDE_LEFT: + case NS_SIDE_RIGHT: + default: // no caption + aWidth = innerRect.XMost() + aInnerMargin.right; + aWidth = PR_MAX(aWidth, captionRect.XMost() + aCaptionMargin.right); + break; + } + + switch(aCaptionSide) { + case NS_SIDE_BOTTOM: + case NS_SIDE_LEFT: + case NS_SIDE_RIGHT: + aHeight = captionRect.YMost() + aCaptionMargin.bottom; + break; + default: // top caption or no caption + aHeight = innerRect.YMost() + aInnerMargin.bottom; + } +} + + +nsresult +nsTableOuterFrame::GetCaptionOrigin(nsIPresContext* aPresContext, + PRUint32 aCaptionSide, + const nsSize& aContainBlockSize, + const nsSize& aInnerSize, + const nsMargin& aInnerMargin, + const nsSize& aCaptionSize, + nsMargin& aCaptionMargin, + nsPoint& aOrigin) +{ + aOrigin.x = aOrigin.y = 0; + if ((NS_UNCONSTRAINEDSIZE == aInnerSize.width) || (NS_UNCONSTRAINEDSIZE == aInnerSize.width) || + (NS_UNCONSTRAINEDSIZE == aCaptionSize.width) || (NS_UNCONSTRAINEDSIZE == aCaptionSize.width)) { + return NS_OK; + } + if (!mCaptionFrame) return NS_OK; + + switch(aCaptionSide) { + case NS_SIDE_TOP: + if (NS_AUTOMARGIN == aCaptionMargin.left) { + aCaptionMargin.left = CalcAutoMargin(aCaptionMargin.left, aCaptionMargin.right, + aContainBlockSize.width, aCaptionSize.width); + } + aOrigin.x = aCaptionMargin.left; + if (NS_AUTOMARGIN == aCaptionMargin.bottom) { + aCaptionMargin.bottom = 0; + } + if (NS_AUTOMARGIN == aCaptionMargin.top) { + nscoord collapseMargin = PR_MAX(aCaptionMargin.bottom, aInnerMargin.top); + nscoord height = aCaptionSize.height + collapseMargin + aInnerSize.height; + aCaptionMargin.top = CalcAutoMargin(aCaptionMargin.top, aInnerMargin.bottom, + aContainBlockSize.height, height); + } + aOrigin.y = aCaptionMargin.top; + break; + default: // all others are treated as bottom for now + if (NS_AUTOMARGIN == aCaptionMargin.left) { + aCaptionMargin.left = CalcAutoMargin(aCaptionMargin.left, aCaptionMargin.right, + aContainBlockSize.width, aCaptionSize.width); + } + aOrigin.x = aCaptionMargin.left; + if (NS_AUTOMARGIN == aCaptionMargin.top) { + aCaptionMargin.top = 0; + } + nscoord collapseMargin = PR_MAX(aCaptionMargin.top, aInnerMargin.bottom); + if (NS_AUTOMARGIN == aCaptionMargin.bottom) { + nscoord height = aInnerSize.height + collapseMargin + aCaptionSize.height; + aCaptionMargin.bottom = CalcAutoMargin(aCaptionMargin.bottom, aInnerMargin.top, + aContainBlockSize.height, height); + } + aOrigin.y = aInnerMargin.top + aInnerSize.height + collapseMargin; + break; + } return NS_OK; } -nsresult nsTableOuterFrame::IncrementalReflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus) +nsresult +nsTableOuterFrame::GetInnerOrigin(nsIPresContext* aPresContext, + PRUint32 aCaptionSide, + const nsSize& aContainBlockSize, + const nsSize& aCaptionSize, + const nsMargin& aCaptionMargin, + const nsSize& aInnerSize, + nsMargin& aInnerMargin, + nsPoint& aOrigin) +{ + aOrigin.x = aOrigin.y = 0; + if ((NS_UNCONSTRAINEDSIZE == aInnerSize.width) || (NS_UNCONSTRAINEDSIZE == aInnerSize.width) || + (NS_UNCONSTRAINEDSIZE == aCaptionSize.width) || (NS_UNCONSTRAINEDSIZE == aCaptionSize.width)) { + return NS_OK; + } + + nscoord collapseMargin; + switch(aCaptionSide) { + case NS_SIDE_TOP: + if (NS_AUTOMARGIN == aInnerMargin.left) { + aInnerMargin.left = CalcAutoMargin(aInnerMargin.left, aInnerMargin.right, + aContainBlockSize.width, aInnerSize.width); + } + aOrigin.x = aInnerMargin.left; + if (NS_AUTOMARGIN == aInnerMargin.top) { + aInnerMargin.top = 0; + } + collapseMargin = PR_MAX(aCaptionMargin.bottom, aInnerMargin.top); + if (NS_AUTOMARGIN == aInnerMargin.bottom) { + nscoord height = aCaptionSize.height + collapseMargin + aInnerSize.height; + aInnerMargin.bottom = CalcAutoMargin(aCaptionMargin.bottom, aInnerMargin.top, + aContainBlockSize.height, height); + } + aOrigin.y = aCaptionMargin.top + aCaptionSize.height + collapseMargin; + break; + default: // all others are treated as bottom for now + if (NS_AUTOMARGIN == aInnerMargin.left) { + aInnerMargin.left = CalcAutoMargin(aInnerMargin.left, aInnerMargin.right, + aContainBlockSize.width, aInnerSize.width); + } + aOrigin.x = aInnerMargin.left; + if (NS_AUTOMARGIN == aInnerMargin.bottom) { + aInnerMargin.bottom = 0; + } + if (NS_AUTOMARGIN == aInnerMargin.top) { + collapseMargin = PR_MAX(aInnerMargin.bottom, aCaptionMargin.top); + nscoord height = aInnerSize.height + collapseMargin + aCaptionSize.height; + aInnerMargin.top = CalcAutoMargin(aInnerMargin.top, aCaptionMargin.bottom, + aContainBlockSize.height, height); + } + aOrigin.y = aInnerMargin.top; + break; + } + return NS_OK; +} + +// eReflowReason_Resize was being used for incremental cases +nsresult +nsTableOuterFrame::OuterReflowChild(nsIPresContext* aPresContext, + nsIFrame* aChildFrame, + const nsHTMLReflowState& aOuterRS, + nsHTMLReflowMetrics& aMetrics, + nscoord* aAvailWidth, + nsSize& aDesiredSize, + nsMargin& aMargin, + nsMargin& aPadding, + nsReflowReason aReflowReason, + nsReflowStatus& aStatus) +{ + aMargin = aPadding = nsMargin(0,0,0,0); + + nscoord availWidth = GetChildAvailWidth(aPresContext, aChildFrame, aOuterRS, + aOuterRS.availableWidth, aMargin, aPadding); + if (aAvailWidth) { + availWidth = *aAvailWidth; + } + nsHTMLReflowState childRS(aPresContext, aOuterRS, aChildFrame, + nsSize(availWidth, aOuterRS.availableHeight)); + childRS.reason = aReflowReason; + + // Normally, the outer table's mComputed values are NS_INTRINSICSIZE since they + // depend on the caption and inner table. Boxes can force a size. + if (aOuterRS.mComputedWidth != NS_INTRINSICSIZE) { + childRS.mComputedWidth = aOuterRS.mComputedWidth - aMargin.left - childRS.mComputedBorderPadding.left - + childRS.mComputedBorderPadding.right - aMargin.right; + childRS.mComputedWidth = PR_MAX(0, childRS.mComputedWidth); + } + if (aOuterRS.mComputedHeight != NS_INTRINSICSIZE) { + childRS.mComputedHeight = aOuterRS.mComputedHeight - aMargin.top - childRS.mComputedBorderPadding.top - + childRS.mComputedBorderPadding.bottom - aMargin.bottom; + childRS.mComputedHeight = PR_MAX(0, childRS.mComputedHeight); + } + + // use the current position as a best guess for placement + nsRect childRect; + aChildFrame->GetRect(childRect); + nsresult rv = ReflowChild(aChildFrame, aPresContext, aMetrics, childRS, + childRect.x, childRect.y, NS_FRAME_NO_MOVE_FRAME, aStatus); + if (NS_FAILED(rv)) return rv; + + FixAutoMargins(childRS); + aMargin = childRS.mComputedMargin; + + aDesiredSize.width = aMetrics.width; + aDesiredSize.height = aMetrics.height; + + return rv; +} + +void +nsTableOuterFrame::UpdateReflowMetrics(PRUint8 aCaptionSide, + nsHTMLReflowMetrics& aMet, + const nsMargin& aInnerMargin, + const nsMargin& aInnerPadding, + const nsMargin& aCaptionMargin) +{ + SetDesiredSize(aCaptionSide, aInnerMargin, aCaptionMargin, aMet.width, aMet.height); + + // set maxElementSize width if requested + if (aMet.maxElementSize) { + *aMet.maxElementSize = GetMaxElementSize(aInnerMargin, aInnerPadding, aCaptionMargin); + } + // set maximum width if requested + if (aMet.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { + aMet.mMaximumWidth = GetMaxWidth(aCaptionSide, aInnerMargin, aCaptionMargin); + } + +} + +nsresult +nsTableOuterFrame::IncrementalReflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) { nsresult rv = NS_OK; // determine if this frame is the target or not nsIFrame* target=nsnull; - rv = aReflowState.reflowState.reflowCommand->GetTarget(target); - if ((PR_TRUE == NS_SUCCEEDED(rv)) && (nsnull != target)) { + rv = aReflowState.reflowCommand->GetTarget(target); + if (NS_SUCCEEDED(rv) && target) { if (this == target) { rv = IR_TargetIsMe(aPresContext, aDesiredSize, aReflowState, aStatus); } else { // Get the next frame in the reflow chain nsIFrame* nextFrame; - aReflowState.reflowState.reflowCommand->GetNext(nextFrame); + aReflowState.reflowCommand->GetNext(nextFrame); NS_ASSERTION(nextFrame, "next frame in reflow command is null"); - - // Recover our reflow state - RecoverState(aReflowState, nextFrame); rv = IR_TargetIsChild(aPresContext, aDesiredSize, aReflowState, aStatus, nextFrame); } } return rv; } -nsresult nsTableOuterFrame::IR_TargetIsChild(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus, - nsIFrame* aNextFrame) +nsresult +nsTableOuterFrame::IR_TargetIsChild(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus, + nsIFrame* aNextFrame) { nsresult rv; if (!aNextFrame) { // this will force Reflow to return the height of the last reflow rather than 0 - aReflowState.y = mRect.height; + aDesiredSize.height = mRect.height; return NS_OK; } if (aNextFrame == mInnerTableFrame) { rv = IR_TargetIsInnerTableFrame(aPresContext, aDesiredSize, aReflowState, aStatus); } - else if (aNextFrame==mCaptionFrame) { + else if (aNextFrame == mCaptionFrame) { rv = IR_TargetIsCaptionFrame(aPresContext, aDesiredSize, aReflowState, aStatus); - - // If we're supposed to update our maximum width, then just use the inner - // table's maximum width - if (aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { - aDesiredSize.mMaximumWidth = mInnerTableMaximumWidth; - } } else { const nsStyleDisplay* nextDisplay; @@ -500,183 +951,160 @@ nsresult nsTableOuterFrame::IR_TargetIsChild(nsIPresContext* aPresContext return rv; } -nsresult nsTableOuterFrame::IR_TargetIsInnerTableFrame(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus) +nsresult +nsTableOuterFrame::IR_TargetIsInnerTableFrame(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) { nsresult rv = IR_InnerTableReflow(aPresContext, aDesiredSize, aReflowState, aStatus); return rv; } -nsresult nsTableOuterFrame::IR_TargetIsCaptionFrame(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus) +nsresult +nsTableOuterFrame::IR_TargetIsCaptionFrame(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aOuterRS, + nsReflowStatus& aStatus) { - nsresult rv; - PRBool innerTableNeedsReflow = PR_FALSE; - // remember the old width and height - nsRect priorCaptionRect; - mCaptionFrame->GetRect(priorCaptionRect); - // if the reflow type is a style change, also remember the prior style + nsresult rv = NS_OK; + PRUint8 captionSide = GetCaptionSide(); + + nsSize captionSize, captionMES; + nsMargin captionMargin, captionPadding; + // reflow the caption frame, getting it's MES + nscoord availWidth = GetCaptionAvailWidth(aPresContext, mCaptionFrame, aOuterRS); + nsHTMLReflowMetrics captionMet(&captionMES); + OuterReflowChild(aPresContext, mCaptionFrame, aOuterRS, captionMet, &availWidth, captionSize, + captionMargin, captionPadding, eReflowReason_Incremental, aStatus); + + nsMargin innerMargin, innerPadding; + nsPoint innerOrigin; + nsSize containSize = GetContainingBlockSize(aOuterRS); + + // for now just reflow the table if a style changed. This should be improved nsIReflowCommand::ReflowType reflowCommandType; - aReflowState.reflowState.reflowCommand->GetType(reflowCommandType); - const nsStyleTable* priorCaptionTableStyle = nsnull; - if (nsIReflowCommand::StyleChanged == reflowCommandType) { - mCaptionFrame->GetStyleData(eStyleStruct_Table, ((const nsStyleStruct *&)priorCaptionTableStyle)); - } + aOuterRS.reflowCommand->GetType(reflowCommandType); + PRBool needInnerReflow = (nsIReflowCommand::StyleChanged == reflowCommandType) + ? PR_TRUE : PR_FALSE; - // pass along the reflow command to the caption - nsSize captionMES(0,0); - nsHTMLReflowMetrics captionSize(&captionMES); - nsHTMLReflowState captionReflowState(aPresContext, aReflowState.reflowState, mCaptionFrame, - nsSize(mRect.width, aReflowState.reflowState.availableHeight), - aReflowState.reflowState.reason); - captionReflowState.reflowCommand = aReflowState.reflowState.reflowCommand; - - rv = ReflowChild(mCaptionFrame, aPresContext, captionSize, captionReflowState, - 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus); - mCaptionFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); - if (NS_FAILED(rv)) { - return rv; - } if (mMinCaptionWidth != captionMES.width) { // set the new caption min width, and set state to reflow the inner table if necessary mMinCaptionWidth = captionMES.width; - if (mMinCaptionWidth > mRect.width) { - innerTableNeedsReflow=PR_TRUE; + // see if the captions min width could cause the table to be wider + // XXX this really only affects an auto width table + nsMargin capAdjMargin = captionMargin; + ZeroAutoMargin(capAdjMargin); + if ((mMinCaptionWidth + capAdjMargin.left + capAdjMargin.right) > mRect.width) { + needInnerReflow = PR_TRUE; } } - // check if the caption alignment changed axis - if (nsIReflowCommand::StyleChanged == reflowCommandType) { - const nsStyleTable* captionTableStyle; - mCaptionFrame->GetStyleData(eStyleStruct_Table, ((const nsStyleStruct *&)captionTableStyle)); - if (PR_TRUE == IR_CaptionChangedAxis(priorCaptionTableStyle, captionTableStyle)) { - innerTableNeedsReflow=PR_TRUE; - } - } + nsPoint captionOrigin; + if (needInnerReflow) { + nsSize innerSize; + nsHTMLReflowMetrics innerMet(nsnull); + OuterReflowChild(aPresContext, mInnerTableFrame, aOuterRS, innerMet, nsnull, innerSize, + innerMargin, innerPadding, eReflowReason_Resize, aStatus); - // if we've determined that the inner table needs to be reflowed, do it here - nsSize innerTableSize; - if (PR_TRUE == innerTableNeedsReflow) { - // Compute the width to use for the table. In the case of an auto sizing - // table this represents the maximum available width - nscoord tableWidth = ((nsTableFrame*)mInnerTableFrame)->CalcBorderBoxWidth(aReflowState.reflowState); - - // If the caption max element size is larger, then use it instead. - // XXX: caption align = left|right ignored here! - if (mMinCaptionWidth > tableWidth) { - tableWidth = mMinCaptionWidth; - } - nsHTMLReflowMetrics innerSize(aDesiredSize.maxElementSize); - nsHTMLReflowState innerReflowState(aPresContext, aReflowState.reflowState, mInnerTableFrame, - nsSize(tableWidth, aReflowState.reflowState.availableHeight), - eReflowReason_Resize); - rv = ReflowChild(mInnerTableFrame, aPresContext, innerSize, innerReflowState, - 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus); - mInnerTableFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); - if (NS_FAILED(rv)) { - return rv; - } - innerTableSize.SizeTo(innerSize.width, innerSize.height); - // set maxElementSize width if requested - if (nsnull != aDesiredSize.maxElementSize) { - ((nsTableFrame *)mInnerTableFrame)->SetMaxElementSize(aDesiredSize.maxElementSize, - aReflowState.reflowState.mComputedPadding); - if (mMinCaptionWidth > aDesiredSize.maxElementSize->width) { - aDesiredSize.maxElementSize->width = mMinCaptionWidth; - } - } + GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, + captionMargin, innerSize, innerMargin, innerOrigin); + rv = FinishReflowChild(mInnerTableFrame, aPresContext, innerMet, + innerOrigin.x, innerOrigin.y, 0); + if (NS_FAILED(rv)) return rv; + + GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, + innerMargin, captionSize, captionMargin, captionOrigin); } else { - nsRect innerTableRect; - mInnerTableFrame->GetRect(innerTableRect); - innerTableSize.SizeTo(innerTableRect.width, innerTableRect.height); + // reposition the inner frame if necessary and set the caption's origin + nsSize innerSize = GetFrameSize(*mInnerTableFrame); + GetMarginPadding(aPresContext, aOuterRS, mInnerTableFrame, innerMargin, + innerPadding); + GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, + captionMargin, innerSize, innerMargin, innerOrigin); + GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, + innerMargin, captionSize, captionMargin, captionOrigin); + MoveFrameTo(aPresContext, mInnerTableFrame, innerOrigin.x, innerOrigin.y); } - // regardless of what we've done up to this point, place the caption and inner table - rv = SizeAndPlaceChildren(aPresContext, innerTableSize, - nsSize (captionSize.width, captionSize.height), - aReflowState, captionReflowState.mComputedMargin); + rv = FinishReflowChild(mCaptionFrame, aPresContext, captionMet, + captionOrigin.x, captionOrigin.y, 0); + UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, innerPadding, captionMargin); + nsSize desSize(aDesiredSize.width, aDesiredSize.height); + InvalidateDamage(aPresContext, captionSide, desSize, needInnerReflow, PR_TRUE); return rv; } nsresult -nsTableOuterFrame::IR_ReflowDirty(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus) +nsTableOuterFrame::IR_ReflowDirty(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) { nsFrameState frameState; nsresult rv; - + PRBool sizeSet = PR_FALSE; // See if the caption frame is dirty. This would be because of a newly // inserted caption if (mCaptionFrame) { mCaptionFrame->GetFrameState(&frameState); if (frameState & NS_FRAME_IS_DIRTY) { rv = IR_CaptionInserted(aPresContext, aDesiredSize, aReflowState, aStatus); - - // Repaint our entire bounds - // XXX Improve this... - Invalidate(aPresContext, nsRect(0, 0, mRect.width, mRect.height)); + sizeSet = PR_TRUE; } } // See if the inner table frame is dirty mInnerTableFrame->GetFrameState(&frameState); if (frameState & NS_FRAME_IS_DIRTY) { - // Inner table is dirty so reflow it. Change the reflow state and set the - // reason to resize reflow. - ((nsHTMLReflowState&)aReflowState.reflowState).reason = eReflowReason_Resize; - ((nsHTMLReflowState&)aReflowState.reflowState).reflowCommand = nsnull; - - // Get the inner table frame's current bounds. We'll use that when - // repainting it - // XXX It should really do the repainting, but because it think it's - // getting a resize reflow it won't know to... - nsRect dirtyRect; - mInnerTableFrame->GetRect(dirtyRect); rv = IR_InnerTableReflow(aPresContext, aDesiredSize, aReflowState, aStatus); - - // Repaint the inner table frame's entire visible area - dirtyRect.x = dirtyRect.y = 0; - Invalidate(aPresContext, dirtyRect); - - } else if (!mCaptionFrame) { + sizeSet = PR_TRUE; + } + else if (!mCaptionFrame) { // The inner table isn't dirty so we don't need to reflow it, but make // sure it's placed correctly. It could be that we're dirty because the // caption was removed - mInnerTableFrame->MoveTo(aPresContext, 0,0); - - // Update our state so we calculate our desired size correctly - nsRect innerRect; + nsRect innerRect; mInnerTableFrame->GetRect(innerRect); - aReflowState.innerTableMaxSize.width = innerRect.width; - aReflowState.y = innerRect.height; - + nsSize innerSize(innerRect.width, innerRect.height); + nsPoint innerOrigin; + nsMargin innerMargin, innerPadding; + GetMarginPadding(aPresContext, aReflowState, mInnerTableFrame, innerMargin, + innerPadding); + nsSize containSize = GetContainingBlockSize(aReflowState); + GetInnerOrigin(aPresContext, NO_SIDE, containSize, nsSize(0,0), + nsMargin(0,0,0,0), innerSize, innerMargin, innerOrigin); + MoveFrameTo(aPresContext, mInnerTableFrame, innerOrigin.x, innerOrigin.y); + + aDesiredSize.width = innerRect.XMost() + innerMargin.right; + aDesiredSize.height = innerRect.YMost() + innerMargin.bottom; + sizeSet = PR_TRUE; // Repaint our entire bounds - // XXX Improve this... - Invalidate(aPresContext, nsRect(0, 0, mRect.width, mRect.height)); + Invalidate(aPresContext, nsRect(0, 0, aDesiredSize.width, aDesiredSize.height)); + } + if (!sizeSet) { + // set our desired size to what it was before + nsSize size = GetFrameSize(*this); + aDesiredSize.width = size.width; + aDesiredSize.height = size.height; } return rv; } // IR_TargetIsMe is free to foward the request to the inner table frame -nsresult nsTableOuterFrame::IR_TargetIsMe(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus) +nsresult nsTableOuterFrame::IR_TargetIsMe(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) { nsresult rv = NS_OK; nsIReflowCommand::ReflowType type; - aReflowState.reflowState.reflowCommand->GetType(type); + aReflowState.reflowCommand->GetType(type); nsIFrame* objectFrame; - aReflowState.reflowState.reflowCommand->GetChildFrame(objectFrame); + aReflowState.reflowCommand->GetChildFrame(objectFrame); switch (type) { case nsIReflowCommand::ReflowDirty: rv = IR_ReflowDirty(aPresContext, aDesiredSize, aReflowState, aStatus); @@ -700,186 +1128,164 @@ nsresult nsTableOuterFrame::IR_TargetIsMe(nsIPresContext* aPresContext, return rv; } -nsresult nsTableOuterFrame::IR_InnerTableReflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus) +nsresult +nsTableOuterFrame::IR_InnerTableReflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aOuterRS, + nsReflowStatus& aStatus) { - nsresult rv = NS_OK; - const nsStyleTable* captionTableStyle=nsnull; - // remember the old width and height - nsRect priorInnerTableRect; - mInnerTableFrame->GetRect(priorInnerTableRect); + PRUint8 captionSide = GetCaptionSide(); + + nsRect priorInnerRect; + mInnerTableFrame->GetRect(priorInnerRect); + + nsSize innerSize; + nsMargin innerMargin, innerPadding; + // pass along the reflow command to the inner table - nsHTMLReflowMetrics innerSize(aDesiredSize.maxElementSize); - nscoord tableMaxWidth = PR_MAX(aReflowState.reflowState.availableWidth, mMinCaptionWidth); - nsHTMLReflowState innerReflowState(aPresContext, aReflowState.reflowState, mInnerTableFrame, - nsSize(tableMaxWidth, aReflowState.reflowState.availableHeight)); - - // When the above reflow state is constructed, mComputedWidth and mComputedHeight get set - // to the table's styled width and height. Flex from XUL boxes can make the styled #s - // inaccurate, which means that mComputedWidth and mComputedHeight from the parent - // reflow state should be used instead. - - // The following function will patch the reflow state so that trees behave properly inside boxes. - // This might work for tables as well, but until regression tests can be run to make sure, - // I'm holding off on patching tables. - FixBadReflowState(aReflowState.reflowState, innerReflowState); + nsHTMLReflowMetrics innerMet(aDesiredSize.maxElementSize); - // Always request the maximum width if we are an auto layout table + // Always request the maximum width if we are an auto layout table XXX why? if (((nsTableFrame*)mInnerTableFrame)->IsAutoLayout()) { - innerSize.mFlags |= NS_REFLOW_CALC_MAX_WIDTH; + innerMet.mFlags |= NS_REFLOW_CALC_MAX_WIDTH; } - rv = ReflowChild(mInnerTableFrame, aPresContext, innerSize, innerReflowState, - 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus); - mInnerTableFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); - if (aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { - aDesiredSize.mMaximumWidth = innerSize.mMaximumWidth; + nsresult rv = OuterReflowChild(aPresContext, mInnerTableFrame, aOuterRS, innerMet, + nsnull, innerSize, innerMargin, innerPadding, + eReflowReason_Incremental, aStatus); + if (NS_FAILED(rv)) return rv; - // Update the cached value - mInnerTableMaximumWidth = innerSize.mMaximumWidth; + if (innerMet.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { + mInnerTableMaximumWidth = innerMet.mMaximumWidth; } + nsPoint innerOrigin(0,0); nsMargin captionMargin(0,0,0,0); - // if there is a caption and the width or height of the inner table changed from a successful reflow, - // then reflow or move the caption as needed - if ((nsnull != mCaptionFrame) && NS_SUCCEEDED(rv)) { - // remember the old caption height - nsRect oldCaptionRect; - mCaptionFrame->GetRect(oldCaptionRect); - nsHTMLReflowMetrics captionSize(nsnull); // don't ask for MES, it hasn't changed - PRBool captionDimChanged = PR_FALSE; - PRBool captionWasReflowed = PR_FALSE; - if (priorInnerTableRect.width != innerSize.width) { - // the table width changed, so reflow the caption - nsHTMLReflowState captionReflowState(aPresContext, aReflowState.reflowState, mCaptionFrame, - nsSize(innerSize.width, aReflowState.reflowState.availableHeight), - eReflowReason_Resize); - // reflow the caption - mCaptionFrame->WillReflow(aPresContext); - rv = mCaptionFrame->Reflow(aPresContext, captionSize, captionReflowState, aStatus); - mCaptionFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); - captionWasReflowed = PR_TRUE; - if ((oldCaptionRect.height != captionSize.height) || - (oldCaptionRect.width != captionSize.width)) { - captionDimChanged = PR_TRUE; - } - captionMargin = captionReflowState.mComputedMargin; + nsSize containSize = GetContainingBlockSize(aOuterRS); + PRBool reflowedCaption = PR_FALSE; + // if there is a caption and the width or height of the inner table changed + // from a reflow, then reflow or move the caption as needed + if (mCaptionFrame) { + if (priorInnerRect.width != innerMet.width) { + nsMargin ignorePadding; + // XXX only need to reflow if the caption is auto width + nsHTMLReflowMetrics captionMet(nsnull); // don't ask for MES, it hasn't changed + nsSize captionSize; + nscoord availWidth = GetCaptionAvailWidth(aPresContext, mCaptionFrame, aOuterRS, + &innerSize.width, &innerMargin); + rv = OuterReflowChild(aPresContext, mCaptionFrame, aOuterRS, captionMet, &availWidth, + captionSize, captionMargin, ignorePadding, eReflowReason_Resize, aStatus); + if (NS_FAILED(rv)) return rv; + + nsPoint captionOrigin; + GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, + innerMargin, captionSize, captionMargin, captionOrigin); + FinishReflowChild(mCaptionFrame, aPresContext, captionMet, + captionOrigin.x, captionOrigin.y, 0); + + GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, + captionMargin, innerSize, innerMargin, innerOrigin); + reflowedCaption = PR_TRUE; } - // XXX: should just call SizeAndPlaceChildren regardless - // find where to place the caption - mCaptionFrame->GetStyleData(eStyleStruct_Text, ((const nsStyleStruct *&)captionTableStyle)); - if ((priorInnerTableRect.height != innerSize.height) || captionDimChanged) { - if (!captionWasReflowed) { // get the computed margin by constructing a reflow state - nsHTMLReflowState rState(aPresContext, aReflowState.reflowState, mCaptionFrame, - nsSize(innerSize.width, aReflowState.reflowState.availableHeight), - eReflowReason_Resize); - captionMargin = rState.mComputedMargin; - } - // Compute the caption's y-origin - nscoord captionY = captionMargin.top; - if (NS_SIDE_BOTTOM == captionTableStyle->mCaptionSide) { - captionY += innerSize.height; - } - // Place the caption - nsRect captionRect(captionMargin.left, captionY, 0, 0); - if (PR_TRUE==captionWasReflowed) { - captionRect.SizeTo(captionSize.width, captionSize.height); - } - else { - captionRect.SizeTo(oldCaptionRect.width, oldCaptionRect.height); - } - mCaptionFrame->SetRect(aPresContext, captionRect); + else { + // reposition the caption frame if necessary and set the inner's origin + nsSize captionSize = GetFrameSize(*mCaptionFrame); + nsPoint captionOrigin; + nsMargin captionPadding; + GetMarginPadding(aPresContext, aOuterRS, mCaptionFrame, captionMargin, + captionPadding); + GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, + innerMargin, captionSize, captionMargin, captionOrigin); + GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, + captionMargin, innerSize, innerMargin, innerOrigin); + MoveFrameTo(aPresContext, mCaptionFrame, captionOrigin.x, captionOrigin.y); } } - // if anything above failed, we just want to return an error at this point - if (NS_FAILED(rv)) { - return rv; - } - // Place the inner table - nsRect updatedCaptionRect(0,0,0,0); - if (nsnull != mCaptionFrame) { - mCaptionFrame->GetRect(updatedCaptionRect); - } - nscoord innerY; // innerY is the y-offset of the inner table - if (nsnull != mCaptionFrame) { - // factor in caption and it's margin - // we're guaranteed that captionMargin and captionTableStyle are set at this point - if (NS_SIDE_BOTTOM != captionTableStyle->mCaptionSide) { - // top caption - innerY = 0; // the inner table goes at the top of the outer table - // the total v-space consumed is the inner table height + the caption height + the margin between them - aReflowState.y = innerSize.height + updatedCaptionRect.YMost() + captionMargin.top; - } - else { // bottom caption - innerY = updatedCaptionRect.YMost() + captionMargin.bottom; - // the total v-space consumed is the inner table height + the caption height + the margin between them - aReflowState.y = innerY + innerSize.height; - } - } - else { // no caption - innerY=0; - aReflowState.y = innerSize.height; - } - nsRect innerRect(0, innerY, innerSize.width, innerSize.height); - mInnerTableFrame->SetRect(aPresContext, innerRect); + FinishReflowChild(mInnerTableFrame, aPresContext, innerMet, + innerOrigin.x, innerOrigin.y, 0); + + UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, innerPadding, captionMargin); + nsSize desSize(aDesiredSize.width, aDesiredSize.height); + InvalidateDamage(aPresContext, captionSide, desSize, PR_TRUE, reflowedCaption); - aReflowState.innerTableMaxSize.width = innerSize.width; return rv; } - - /* the only difference between an insert and a replace is a replace checks the old maxElementSize and reflows the table only if it has changed */ -nsresult nsTableOuterFrame::IR_CaptionInserted(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - nsresult rv = NS_OK; +nsresult +nsTableOuterFrame::IR_CaptionInserted(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aOuterRS, + nsReflowStatus& aStatus) +{ + PRUint8 captionSide = GetCaptionSide(); // reflow the caption frame, getting it's MES - nsSize maxElementSize; - nsHTMLReflowMetrics captionSize(&maxElementSize); - nsHTMLReflowState captionReflowState(aPresContext, aReflowState.reflowState, mCaptionFrame, - nsSize(mRect.width, aReflowState.reflowState.availableHeight), - eReflowReason_Initial); - // initial reflow of the caption - mCaptionFrame->WillReflow(aPresContext); - rv = mCaptionFrame->Reflow(aPresContext, captionSize, captionReflowState, aStatus); + nsSize captionSize; + nsMargin captionMargin, ignorePadding; + nsSize maxElementSize(0,0); + nsHTMLReflowMetrics captionMet(&maxElementSize); + // reflow the caption + nscoord availWidth = GetCaptionAvailWidth(aPresContext, mCaptionFrame, aOuterRS); + nsresult rv = OuterReflowChild(aPresContext, mCaptionFrame, aOuterRS, captionMet, + &availWidth, captionSize, captionMargin, ignorePadding, + eReflowReason_Initial, aStatus); + + if (NS_FAILED(rv)) return rv; + mMinCaptionWidth = maxElementSize.width; + + nsPoint captionOrigin(0,0); + nsMargin capAdjMargin = captionMargin; + ZeroAutoMargin(capAdjMargin); + + nsMargin innerMargin, innerPadding; + nsSize containSize = GetContainingBlockSize(aOuterRS); + PRBool reflowedInner = PR_FALSE; // XXX: caption align = left|right ignored here! - // if the caption's MES > table width, reflow the inner table - nsHTMLReflowMetrics innerSize(aDesiredSize.maxElementSize); - if (mMinCaptionWidth > mRect.width) { - nsHTMLReflowState innerReflowState(aPresContext, aReflowState.reflowState, mInnerTableFrame, - nsSize(mMinCaptionWidth, aReflowState.reflowState.availableHeight), - eReflowReason_Resize); - rv = ReflowChild(mInnerTableFrame, aPresContext, innerSize, innerReflowState, - 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus); - mInnerTableFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); + // if the caption's MES + margins > outer width, reflow the inner table + if (mMinCaptionWidth + capAdjMargin.left + capAdjMargin.right > mRect.width) { + nsHTMLReflowMetrics innerMet(aDesiredSize.maxElementSize); + nsSize innerSize; + + rv = OuterReflowChild(aPresContext, mInnerTableFrame, aOuterRS, innerMet, + nsnull, innerSize, innerMargin, innerPadding, + eReflowReason_Resize, aStatus); + if (NS_FAILED(rv)) return rv; + + nsPoint innerOrigin; + GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, + captionMargin, innerSize, innerMargin, innerOrigin); + rv = FinishReflowChild(mInnerTableFrame, aPresContext, innerMet, + innerOrigin.x, innerOrigin.y, 0); + if (NS_FAILED(rv)) return rv; + GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, + innerMargin, captionSize, captionMargin, captionOrigin); + reflowedInner = PR_TRUE; } - else { // set innerSize as if the inner table were reflowed - innerSize.height = mRect.height; - innerSize.width = mRect.width; - } - // set maxElementSize width if requested - if (nsnull != aDesiredSize.maxElementSize) { - ((nsTableFrame *)mInnerTableFrame)->SetMaxElementSize(aDesiredSize.maxElementSize, - aReflowState.reflowState.mComputedPadding); - if (mMinCaptionWidth > aDesiredSize.maxElementSize->width) { - aDesiredSize.maxElementSize->width = mMinCaptionWidth; - } + else { + // reposition the inner frame if necessary and set the caption's origin + nsSize innerSize = GetFrameSize(*mInnerTableFrame); + GetMarginPadding(aPresContext, aOuterRS, mInnerTableFrame, innerMargin, + innerPadding); + nsPoint innerOrigin; + GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, + captionMargin, innerSize, innerMargin, innerOrigin); + GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, + innerMargin, captionSize, captionMargin, captionOrigin); + MoveFrameTo(aPresContext, mInnerTableFrame, innerOrigin.x, innerOrigin.y); } - rv = SizeAndPlaceChildren(aPresContext, - nsSize (innerSize.width, innerSize.height), - nsSize (captionSize.width, captionSize.height), - aReflowState, captionReflowState.mComputedMargin); + rv = FinishReflowChild(mCaptionFrame, aPresContext, captionMet, + captionOrigin.x, captionOrigin.y, 0); + + UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, innerPadding, captionMargin); + nsSize desSize(aDesiredSize.width, aDesiredSize.height); + InvalidateDamage(aPresContext, captionSide, desSize, reflowedInner, PR_TRUE); + return rv; } @@ -891,42 +1297,8 @@ PRBool nsTableOuterFrame::IR_CaptionChangedAxis(const nsStyleTable* aOldStyle, return result; } -nsresult nsTableOuterFrame::SizeAndPlaceChildren(nsIPresContext* aPresContext, - const nsSize& aInnerSize, - const nsSize& aCaptionSize, - OuterTableReflowState& aReflowState, - const nsMargin& aCaptionMargin) -{ - nsresult rv = NS_OK; - // find where to place the caption - // Compute the caption's y-origin - nscoord captionY = aCaptionMargin.top; - const nsStyleTable* captionTableStyle; - mCaptionFrame->GetStyleData(eStyleStruct_Table, ((const nsStyleStruct *&)captionTableStyle)); - if (NS_SIDE_BOTTOM == captionTableStyle->mCaptionSide) { - captionY += aInnerSize.height; - } - // Place the caption - nsRect captionRect(aCaptionMargin.left, captionY, 0, 0); - captionRect.SizeTo(aCaptionSize.width, aCaptionSize.height); - mCaptionFrame->SetRect(aPresContext, captionRect); - // Place the inner table - nscoord innerY; - if (NS_SIDE_BOTTOM == captionTableStyle->mCaptionSide) { - // bottom caption - innerY = 0; - aReflowState.y = captionRect.YMost() + aCaptionMargin.bottom; - } - else { // top caption - innerY = captionRect.YMost() + aCaptionMargin.bottom; - aReflowState.y = innerY + aInnerSize.height; - } - nsRect innerRect(0, innerY, aInnerSize.width, aInnerSize.height); - mInnerTableFrame->SetRect(aPresContext, innerRect); - aReflowState.innerTableMaxSize.width = aInnerSize.width; - return rv; -} + /** * Reflow is a multi-step process. @@ -945,29 +1317,28 @@ nsresult nsTableOuterFrame::SizeAndPlaceChildren(nsIPresContext* aPresCon */ NS_METHOD nsTableOuterFrame::Reflow(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, + const nsHTMLReflowState& aOuterRS, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsTableOuterFrame", aReflowState.reason); - if (nsDebugTable::gRflTableOuter) nsTableFrame::DebugReflow("TO::Rfl en", this, &aReflowState, nsnull); + if (nsDebugTable::gRflTableOuter) nsTableFrame::DebugReflow("TO::Rfl en", this, &aOuterRS, nsnull); + nsresult rv = NS_OK; + PRUint8 captionSide = GetCaptionSide(); + // Initialize out parameters - aDesiredSize.width = 0; - aDesiredSize.height = 0; + aDesiredSize.width = aDesiredSize.height = 0; if (nsnull != aDesiredSize.maxElementSize) { - aDesiredSize.maxElementSize->width = 0; + aDesiredSize.maxElementSize->width = 0; aDesiredSize.maxElementSize->height = 0; } aStatus = NS_FRAME_COMPLETE; - nsHTMLReflowMetrics captionSize(nsnull); - - // Initialize our local reflow state - OuterTableReflowState state(aPresContext, aReflowState); - if (eReflowReason_Incremental == aReflowState.reason) { - rv = IncrementalReflow(aPresContext, aDesiredSize, state, aStatus); - } else { - if (eReflowReason_Initial == aReflowState.reason) { + if (eReflowReason_Incremental == aOuterRS.reason) { + rv = IncrementalReflow(aPresContext, aDesiredSize, aOuterRS, aStatus); + } + else { + if (eReflowReason_Initial == aOuterRS.reason) { // Set up our kids. They're already present, on an overflow list, // or there are none so we'll create them now MoveOverflowToChildList(aPresContext); @@ -975,123 +1346,76 @@ NS_METHOD nsTableOuterFrame::Reflow(nsIPresContext* aPresContext, // Lay out the caption and get its maximum element size if (nsnull != mCaptionFrame) { nsSize maxElementSize; - captionSize.maxElementSize = &maxElementSize; - nsHTMLReflowState captionReflowState(aPresContext, aReflowState, mCaptionFrame, + nsHTMLReflowMetrics captionMet(&maxElementSize); + captionMet.maxElementSize = &maxElementSize; + nsHTMLReflowState captionReflowState(aPresContext, aOuterRS, mCaptionFrame, nsSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE), eReflowReason_Initial); mCaptionFrame->WillReflow(aPresContext); - rv = mCaptionFrame->Reflow(aPresContext, captionSize, captionReflowState, aStatus); + rv = mCaptionFrame->Reflow(aPresContext, captionMet, captionReflowState, aStatus); mCaptionFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); mMinCaptionWidth = maxElementSize.width; - captionSize.maxElementSize = nsnull; } } // At this point, we must have an inner table frame, and we might have a caption - NS_ASSERTION(mFrames.NotEmpty(), "no children"); - NS_ASSERTION(nsnull != mInnerTableFrame, "no mInnerTableFrame"); - - nscoord availWidth = aReflowState.availableWidth; - - // If the caption max element size is larger, then use it instead. - // XXX: caption align = left|right ignored here! - if (mMinCaptionWidth > availWidth) { - availWidth = mMinCaptionWidth; - } + NS_ASSERTION(mFrames.NotEmpty() && mInnerTableFrame, "incomplete children"); + nsSize innerSize; + nsMargin innerMargin, innerPadding; // First reflow the inner table - nsHTMLReflowState innerReflowState(aPresContext, aReflowState, mInnerTableFrame, - nsSize(availWidth, aReflowState.availableHeight)); - innerReflowState.mComputedWidth = PR_MAX(aReflowState.mComputedWidth, mMinCaptionWidth); - innerReflowState.mComputedHeight = aReflowState.mComputedHeight; + nsHTMLReflowMetrics innerMet(aDesiredSize.maxElementSize); + rv = OuterReflowChild(aPresContext, mInnerTableFrame, aOuterRS, innerMet, + nsnull, innerSize, innerMargin, innerPadding, aOuterRS.reason, aStatus); + if (NS_FAILED(rv)) return rv; - nsHTMLReflowMetrics innerSize(aDesiredSize.maxElementSize); - // XXX To do this efficiently we really need to know where the inner - // table will be placed. In the case of a top caption that means - // reflowing the caption first and getting its desired height... - rv = ReflowChild(mInnerTableFrame, aPresContext, innerSize, innerReflowState, - 0, 0, 0, aStatus); - - if (NS_UNCONSTRAINEDSIZE == innerReflowState.availableWidth) { + if (NS_UNCONSTRAINEDSIZE == aOuterRS.availableWidth) { // Remember the inner table's maximum width - mInnerTableMaximumWidth = innerSize.width; + mInnerTableMaximumWidth = innerMet.width; } - // Table's max element size is the MAX of the caption's max element size - // and the inner table's max element size... - if (nsnull != aDesiredSize.maxElementSize) { - if (mMinCaptionWidth > aDesiredSize.maxElementSize->width) { - aDesiredSize.maxElementSize->width = mMinCaptionWidth; - } - } - state.innerTableMaxSize.width = innerSize.width; + nsPoint innerOrigin(0,0); + nsMargin captionMargin(0,0,0,0), ignorePadding; + nsSize captionSize(0,0); + nsSize containSize = GetContainingBlockSize(aOuterRS); // Now that we know the table width we can reflow the caption, and // place the caption and the inner table - nscoord innerY = 0; - if (nsnull != mCaptionFrame) { - // construct the caption reflow state - nscoord captionAvailWidth = PR_MAX(innerSize.width, mMinCaptionWidth); - nsHTMLReflowState captionReflowState(aPresContext, state.reflowState, mCaptionFrame, - nsSize(captionAvailWidth, NS_UNCONSTRAINEDSIZE), - eReflowReason_Resize); - // Compute the caption's y-origin - nscoord captionY = (NS_AUTOMARGIN == captionReflowState.mComputedMargin.top) - ? 0 : captionReflowState.mComputedMargin.top; - const nsStyleTable* captionTableStyle; - mCaptionFrame->GetStyleData(eStyleStruct_Table, ((const nsStyleStruct *&)captionTableStyle)); - if (NS_SIDE_BOTTOM == captionTableStyle->mCaptionSide) { - captionY += innerSize.height; - } + if (mCaptionFrame) { + // reflow the caption + nscoord availWidth = GetCaptionAvailWidth(aPresContext, mCaptionFrame, aOuterRS, + &innerSize.width, &innerMargin); + nsHTMLReflowMetrics captionMet(nsnull); + rv = OuterReflowChild(aPresContext, mCaptionFrame, aOuterRS, captionMet, + &availWidth, captionSize, captionMargin, ignorePadding, + aOuterRS.reason, aStatus); + if (NS_FAILED(rv)) return rv; - // Reflow the caption. Let it be as high as it wants - nscoord leftCapMargin = (NS_AUTOMARGIN == captionReflowState.mComputedMargin.left) - ? 0 : captionReflowState.mComputedMargin.left; - nsRect captionRect(leftCapMargin, captionY, 0, 0); - nsReflowStatus captionStatus; - captionSize.maxElementSize = nsnull; - ReflowChild(mCaptionFrame, aPresContext, captionSize, captionReflowState, - captionRect.x, captionRect.y, 0, captionStatus); - NS_ASSERTION(NS_FRAME_IS_COMPLETE(captionStatus), "unexpected reflow status"); + nsPoint captionOrigin; - // XXX If the height is constrained then we need to check whether the inner - // table still fits... + GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, + innerMargin, captionSize, captionMargin, captionOrigin); + FinishReflowChild(mCaptionFrame, aPresContext, captionMet, + captionOrigin.x, captionOrigin.y, 0); - // Place the caption - captionRect.SizeTo(captionSize.width, captionSize.height); - FinishReflowChild(mCaptionFrame, aPresContext, captionSize, - captionRect.x, captionRect.y, 0); - - // Place the inner table - nscoord bottomCapMargin = (NS_AUTOMARGIN == captionReflowState.mComputedMargin.bottom) - ? 0 : captionReflowState.mComputedMargin.bottom; - if (NS_SIDE_BOTTOM != captionTableStyle->mCaptionSide) { - // top caption - innerY = captionRect.YMost() + bottomCapMargin; - state.y = innerY + innerSize.height; - } - else { - // bottom caption - innerY = 0; - state.y = captionRect.YMost() + bottomCapMargin; - } + GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, + captionMargin, innerSize, innerMargin, innerOrigin); + // XXX If the height is constrained then we need to check whether the inner table still fits... } else { - // Place the inner table at 0 - innerY = 0; - state.y = innerSize.height; + GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, + captionMargin, innerSize, innerMargin, innerOrigin); } - // Finish the inner table reflow - FinishReflowChild(mInnerTableFrame, aPresContext, innerSize, - 0, innerY, 0); + FinishReflowChild(mInnerTableFrame, aPresContext, innerMet, + innerOrigin.x, innerOrigin.y, 0); + + UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, innerPadding, captionMargin); } // Return our desired rect - aDesiredSize.width = PR_MAX(state.innerTableMaxSize.width, captionSize.width); - aDesiredSize.height = state.y; aDesiredSize.ascent = aDesiredSize.height; aDesiredSize.descent = 0; diff --git a/mozilla/layout/html/table/src/nsTableOuterFrame.h b/mozilla/layout/html/table/src/nsTableOuterFrame.h index 267e23dcf87..b7afd9857d7 100644 --- a/mozilla/layout/html/table/src/nsTableOuterFrame.h +++ b/mozilla/layout/html/table/src/nsTableOuterFrame.h @@ -27,7 +27,6 @@ #include "nsBlockFrame.h" #include "nsITableLayout.h" -struct OuterTableReflowState; struct nsStyleTable; class nsTableCaptionFrame : public nsBlockFrame @@ -74,6 +73,8 @@ public: NS_IMETHOD Destroy(nsIPresContext* aPresContext); + NS_IMETHOD IsPercentageBase(PRBool& aBase) const; + NS_IMETHOD AdjustZeroWidth(); /** @see nsIFrame::SetInitialChildList */ @@ -158,6 +159,11 @@ public: /** @see nsITableFrame::GetTableSize */ NS_IMETHOD GetTableSize(PRInt32& aRowCount, PRInt32& aColCount); + static void PositionView(nsIPresContext* aPresContext, + nsIFrame* aFrame); + + static void ZeroAutoMargin(nsMargin& aMargin); + protected: @@ -197,61 +203,59 @@ protected: virtual void DeleteChildsNextInFlow(nsIPresContext* aPresContext, nsIFrame* aChild); // begin Incremental Reflow methods - /** prepare aReflowState for an incremental reflow */ - NS_IMETHOD RecoverState(OuterTableReflowState& aReflowState, nsIFrame* aKidFrame); /** process an incremental reflow command */ - NS_IMETHOD IncrementalReflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus); + NS_IMETHOD IncrementalReflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); /** process an incremental reflow command targeted at a child of this frame. */ - NS_IMETHOD IR_TargetIsChild(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus, - nsIFrame * aNextFrame); + NS_IMETHOD IR_TargetIsChild(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus, + nsIFrame * aNextFrame); /** process an incremental reflow command targeted at the table inner frame. */ - NS_IMETHOD IR_TargetIsInnerTableFrame(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus); + NS_IMETHOD IR_TargetIsInnerTableFrame(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); /** process an incremental reflow command targeted at the caption. */ - NS_IMETHOD IR_TargetIsCaptionFrame(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus); + NS_IMETHOD IR_TargetIsCaptionFrame(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); /** process an incremental reflow command targeted at this frame. * many incremental reflows that are targeted at this outer frame * are actually handled by the inner frame. The logic to decide this * is here. */ - NS_IMETHOD IR_TargetIsMe(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus); + NS_IMETHOD IR_TargetIsMe(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); /** pass along the incremental reflow command to the inner table. */ - NS_IMETHOD IR_InnerTableReflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus); + NS_IMETHOD IR_InnerTableReflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); /** handle incremental reflow notification that a caption was inserted. */ - NS_IMETHOD IR_CaptionInserted(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus); + NS_IMETHOD IR_CaptionInserted(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); /** handle incremental reflow notification that we have dirty child frames */ - NS_IMETHOD IR_ReflowDirty(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus); + NS_IMETHOD IR_ReflowDirty(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); /** handle incremental reflow notification that the caption style was changed * such that it is now left|right instead of top|bottom, or vice versa. @@ -259,25 +263,93 @@ protected: PRBool IR_CaptionChangedAxis(const nsStyleTable* aOldStyle, const nsStyleTable* aNewStyle) const; - /** set the size and the location of both the inner table frame and the caption. */ - NS_IMETHOD SizeAndPlaceChildren(nsIPresContext* aPresContext, - const nsSize& aInnerSize, - const nsSize& aCaptionSize, - OuterTableReflowState& aReflowState, - const nsMargin& aCaptionMargin); + // end Incremental Reflow methods -// end Incremental Reflow methods - - // The following function at least lets the tree widget work - // inside boxes. It repairs the reflow state after it's been - // screwed up by the nsHTMLReflowState code. + // When the reflow state is constructed, mComputedWidth and mComputedHeight get set + // to the table's styled width and height. Flex from XUL boxes can make the styled #s + // inaccurate, which means that mComputedWidth and mComputedHeight from the parent + // reflow state should be used instead. + + // The following function will patch the reflow state so that trees behave properly inside boxes. + // This might work for tables as well, but not until regression tests can be run to make sure, NS_IMETHOD FixBadReflowState(const nsHTMLReflowState& aParentReflowState, nsHTMLReflowState& aChildReflowState) { return NS_OK; }; + nsSize GetMaxElementSize(const nsMargin& aInnerMargin, + const nsMargin& aInnerPadding, + const nsMargin& aCaptionMargin); + + nscoord GetMaxWidth(PRUint8 aCaptionSide, + const nsMargin& aInnerMargin, + const nsMargin& aCaptionMargin); + + PRUint8 GetCaptionSide(); + + void SetDesiredSize(PRUint8 aCaptionSide, + const nsMargin& aInnerMargin, + const nsMargin& aCaptionMargin, + nscoord& aWidth, + nscoord& aHeight); + + NS_IMETHOD GetCaptionOrigin(nsIPresContext* aPresContext, + PRUint32 aCaptionSide, + const nsSize& aContainBlockSize, + const nsSize& aInnerSize, + const nsMargin& aInnerMargin, + const nsSize& aCaptionSize, + nsMargin& aCaptionMargin, + nsPoint& aOrigin); + + NS_IMETHOD GetInnerOrigin(nsIPresContext* aPresContext, + PRUint32 aCaptionSide, + const nsSize& aContainBlockSize, + const nsSize& aCaptionSize, + const nsMargin& aCaptionMargin, + const nsSize& aInnerSize, + nsMargin& aInnerMargin, + nsPoint& aOrigin); + + nscoord GetChildAvailWidth(nsIPresContext* aPresContext, + nsIFrame* aChildFrame, + const nsHTMLReflowState& aOuterRS, + nscoord aOuterWidth, + nsMargin& aMargin, + nsMargin& aPadding); + + nscoord GetCaptionAvailWidth(nsIPresContext* aPresContext, + nsIFrame* aCaptionFrame, + const nsHTMLReflowState& aReflowState, + nscoord* aInnerWidth = nsnull, + const nsMargin* aInnerMargin = nsnull); + + NS_IMETHOD OuterReflowChild(nsIPresContext* aPresContext, + nsIFrame* aChildFrame, + const nsHTMLReflowState& aOuterRS, + nsHTMLReflowMetrics& aMetrics, + nscoord* aAvailWidth, + nsSize& aDesiredSize, + nsMargin& aMargin, + nsMargin& aPadding, + nsReflowReason aReflowReason, + nsReflowStatus& aStatus); + + void UpdateReflowMetrics(PRUint8 aCaptionSide, + nsHTMLReflowMetrics& aMet, + const nsMargin& aInnerMargin, + const nsMargin& aInnerPadding, + const nsMargin& aCaptionPadding); + + void InvalidateDamage(nsIPresContext* aPresContext, + PRUint8 aCaptionSide, + nsSize& aOuterSize, + PRBool aInnerChanged, + PRBool aCaptionChanged); + + private: /** used to keep track of this frame's children */ - nsIFrame *mInnerTableFrame; // XXX this is redundant, mFrames holds the same - nsIFrame *mCaptionFrame; + nsIFrame* mInnerTableFrame; // XXX this is redundant, mFrames holds the same + nsIFrame* mCaptionFrame; /** used to track caption max element size */ PRInt32 mMinCaptionWidth; diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.cpp b/mozilla/layout/html/table/src/nsTableRowFrame.cpp index 21a9fe1d0be..e7415d4880c 100644 --- a/mozilla/layout/html/table/src/nsTableRowFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableRowFrame.cpp @@ -244,11 +244,10 @@ nsTableRowFrame::DidResize(nsIPresContext* aPresContext, const nsHTMLReflowState& aReflowState) { // Resize and re-align the cell frames based on our row height - nscoord cellMaxTopMargin = GetTopMargin(); - nscoord cellMaxBottomMargin = GetBottomMargin(); - nscoord rowCellHeight = mRect.height - cellMaxTopMargin - cellMaxBottomMargin; nsTableFrame* tableFrame; nsTableFrame::GetTableFrame(this, tableFrame); + if (!tableFrame) return; + nscoord cellSpacingY = tableFrame->GetCellSpacingY(); nsTableIterator iter(aPresContext, *this, eTableDIR); nsIFrame* cellFrame = iter.First(); @@ -258,7 +257,7 @@ nsTableRowFrame::DidResize(nsIPresContext* aPresContext, cellFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)kidDisplay)); if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay) { PRInt32 rowSpan = tableFrame->GetEffectiveRowSpan((nsTableCellFrame &)*cellFrame); - nscoord cellHeight = rowCellHeight; + nscoord cellHeight = mRect.height; // add in height of rows spanned beyond the 1st one nsIFrame* nextRow = nsnull; GetNextSibling(&nextRow); @@ -271,6 +270,7 @@ nsTableRowFrame::DidResize(nsIPresContext* aPresContext, cellHeight += rect.height; i++; } + cellHeight += cellSpacingY; nextRow->GetNextSibling(&nextRow); } @@ -365,20 +365,8 @@ NS_METHOD nsTableRowFrame::Paint(nsIPresContext* aPresContext, return rv; } nscoord cellSpacingX = tableFrame->GetCellSpacingX(); - nscoord halfCellSpacingY = - NSToCoordRound(((float)tableFrame->GetCellSpacingY()) / (float)2); // every row is short by the ending cell spacing X nsRect rect(0, 0, mRect.width + cellSpacingX, mRect.height); - // first row may have gotten too much cell spacing Y - if (tableFrame->GetRowCount() != 1) { - if (IsFirstRow(aPresContext, *tableFrame, *this)) { - rect.height -= halfCellSpacingY; - } - else { - rect.height += halfCellSpacingY; - rect.y -= halfCellSpacingY; - } - } nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this, aDirtyRect, rect, *color, *spacing, 0, 0); @@ -514,24 +502,6 @@ nscoord nsTableRowFrame::GetTallestChild() const return mTallestCell; } -nscoord nsTableRowFrame::GetTopMargin() const -{ - nsTableFrame *tableFrame; - nsTableFrame::GetTableFrame((nsIFrame*)this, tableFrame); - - // Only cells in the first row have a top margin - return (GetRowIndex() == 0) ? tableFrame->GetCellSpacingY() : 0; -} - -nscoord nsTableRowFrame::GetBottomMargin() const -{ - nsTableFrame *tableFrame; - nsTableFrame::GetTableFrame((nsIFrame*)this, tableFrame); - - // All cells have the same bottom margin - return tableFrame->GetCellSpacingY(); -} - /* GetMinRowSpan is needed for deviant cases where every cell in a row has a rowspan > 1. * It sets mMinRowSpan, which is used in FixMinCellHeight and PlaceChild */ @@ -636,14 +606,7 @@ void nsTableRowFrame::PlaceChild(nsIPresContext* aPresContext, aReflowState.maxCellHeight = aDesiredSize.height; // Update maxCellVertSpace - nsMargin margin; - - if (aReflowState.tableFrame->GetCellMarginData((nsTableCellFrame *)aKidFrame, margin) == NS_OK) { - nscoord height = aDesiredSize.height + margin.top + margin.bottom; - - if (height > aReflowState.maxCellVertSpace) - aReflowState.maxCellVertSpace = height; - } + aReflowState.maxCellVertSpace = PR_MAX(aDesiredSize.height, aReflowState.maxCellVertSpace); } #endif } @@ -880,7 +843,7 @@ NS_METHOD nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext, reason); nsReflowStatus status; rv = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, - aReflowState.x, GetTopMargin(), 0, status); + aReflowState.x, 0, 0, status); #ifdef NS_DEBUG if (desiredSize.width > availWidth) { @@ -935,7 +898,7 @@ NS_METHOD nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext, // Place the child PlaceChild(aPresContext, aReflowState, kidFrame, desiredSize, - aReflowState.x, GetTopMargin(), + aReflowState.x, 0, aDesiredSize.maxElementSize, kidMaxElementSize); } @@ -996,6 +959,7 @@ nsTableRowFrame::InitialReflow(nsIPresContext* aPresContext, nscoord x = 0; nsTableFrame* table = aReflowState.tableFrame; PRBool isAutoLayout = table->IsAutoLayout(&aReflowState.reflowState); + nscoord cellSpacingX = table->GetCellSpacingX(); nsIFrame* kidFrame; if (nsnull==aStartFrame) @@ -1003,29 +967,20 @@ nsTableRowFrame::InitialReflow(nsIPresContext* aPresContext, else kidFrame = aStartFrame; - for ( ; nsnull != kidFrame; kidFrame->GetNextSibling(&kidFrame)) - { + for ( ; nsnull != kidFrame; kidFrame->GetNextSibling(&kidFrame)) { const nsStyleDisplay *kidDisplay; kidFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)kidDisplay)); - if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay) - { - // Get the child's margins - // Get the frame's margins - nsMargin kidMargin; - aReflowState.tableFrame->GetCellMarginData((nsTableCellFrame *)kidFrame, kidMargin); - + if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay) { // For the initial reflow always allow the child to be as high as it // wants. The default available width is also unconstrained so we can // get the child's maximum width nsSize kidAvailSize; nsHTMLReflowMetrics kidSize(nsnull); - if (isAutoLayout) - { + if (isAutoLayout) { kidAvailSize.SizeTo(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); kidSize.maxElementSize=&kidMaxElementSize; } - else - { + else { PRInt32 colIndex; ((nsTableCellFrame *)kidFrame)->GetColIndex(colIndex); kidAvailSize.SizeTo(table->GetColumnWidth(colIndex), NS_UNCONSTRAINEDSIZE); @@ -1037,7 +992,7 @@ nsTableRowFrame::InitialReflow(nsIPresContext* aPresContext, eReflowReason_Initial); rv = ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, - x + kidMargin.left, kidMargin.top, 0, aStatus); + x + cellSpacingX, 0, 0, aStatus); // the following signals bugs in the content frames. if (kidMaxElementSize.width > kidSize.width) { @@ -1056,10 +1011,10 @@ nsTableRowFrame::InitialReflow(nsIPresContext* aPresContext, NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "unexpected child reflow status"); // Place the child - x += kidMargin.left; - PlaceChild(aPresContext, aReflowState, kidFrame, kidSize, x, kidMargin.top, + x += cellSpacingX; + PlaceChild(aPresContext, aReflowState, kidFrame, kidSize, x, 0, aDesiredSize.maxElementSize, &kidMaxElementSize); - x += kidSize.width + kidMargin.right; + x += kidSize.width + cellSpacingX; } else {// it's an unknown frame type, give it a generic reflow and ignore the results @@ -1108,10 +1063,6 @@ NS_METHOD nsTableRowFrame::RecoverState(nsIPresContext* aPresContext, frame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)kidDisplay)); if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay) { - // Get the child's margins - nsMargin kidMargin; - aReflowState.tableFrame->GetCellMarginData((nsTableCellFrame *)frame, kidMargin); - // Update maxCellHeight and maxVertCellSpace. When determining this we // don't include cells that span rows PRInt32 rowSpan = aReflowState.tableFrame->GetEffectiveRowSpan((nsTableCellFrame &)*frame); @@ -1130,10 +1081,7 @@ NS_METHOD nsTableRowFrame::RecoverState(nsIPresContext* aPresContext, } // Update maxCellVertHeight - nscoord vertHeight = desiredSize.height + kidMargin.top + kidMargin.bottom; - if (vertHeight > aReflowState.maxCellVertSpace) { - aReflowState.maxCellVertSpace = vertHeight; - } + aReflowState.maxCellVertSpace = PR_MAX(desiredSize.height, aReflowState.maxCellVertSpace); } // Recover the max element size if requested @@ -1293,7 +1241,7 @@ NS_METHOD nsTableRowFrame::IR_TargetIsChild(nsIPresContext* aPresContext, // in a max width of NS_UNCONSTRAINEDSIZE, because the max width must match // the width of the previous reflow... rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, - aReflowState.x, GetTopMargin(), 0, aStatus); + aReflowState.x, 0, 0, aStatus); // Update the cell layout data.. If the cell's maximum width changed, // then inform the table that its maximum width needs to be recomputed @@ -1334,7 +1282,7 @@ NS_METHOD nsTableRowFrame::IR_TargetIsChild(nsIPresContext* aPresContext, // Now place the child PlaceChild(aPresContext, aReflowState, aNextFrame, desiredSize, aReflowState.x, - GetTopMargin(), aDesiredSize.maxElementSize, &kidMaxElementSize); + 0, aDesiredSize.maxElementSize, &kidMaxElementSize); SetMaxChildHeight(aReflowState.maxCellHeight); diff --git a/mozilla/layout/html/table/src/nsTableRowFrame.h b/mozilla/layout/html/table/src/nsTableRowFrame.h index 44b3bff517a..892a04b45d6 100644 --- a/mozilla/layout/html/table/src/nsTableRowFrame.h +++ b/mozilla/layout/html/table/src/nsTableRowFrame.h @@ -168,8 +168,6 @@ public: /** returns the tallest child in this row (ignoring any cell with rowspans) */ nscoord GetTallestChild() const; - nscoord GetTopMargin() const; - nscoord GetBottomMargin() const; /** returns the ordinal position of this row in its table */ virtual PRInt32 GetRowIndex() const; diff --git a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp index 303a57734ea..5e33ffd6485 100644 --- a/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/html/table/src/nsTableRowGroupFrame.cpp @@ -181,23 +181,7 @@ NS_METHOD nsTableRowGroupFrame::Paint(nsIPresContext* aPresContext, if (NS_FAILED(rv) || (nsnull == tableFrame)) { return rv; } - nscoord halfCellSpacingY = - NSToCoordRound(((float)tableFrame->GetCellSpacingY()) / (float)2); - // every row group is short by the ending cell spacing X - nsRect rect(0, 0, mRect.width, mRect.height); - nsIFrame* firstRowGroup = nsnull; - tableFrame->FirstChild(aPresContext, nsnull, &firstRowGroup); - // first row group may have gotten too much cell spacing Y - if (tableFrame->GetRowCount() != 1) { - if (this == firstRowGroup) { - rect.height -= halfCellSpacingY; - } - else { - rect.height += halfCellSpacingY; - rect.y -= halfCellSpacingY; - } - } - + nsRect rect(0,0,mRect.width, mRect.height); nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this, aDirtyRect, rect, *color, *spacing, 0, 0); } @@ -335,7 +319,12 @@ NS_METHOD nsTableRowGroupFrame::ReflowMappedChildren(nsIPresContext* aPresC { nsSize kidMaxElementSize; nsSize* pKidMaxElementSize = (nsnull != aDesiredSize.maxElementSize) ? &kidMaxElementSize : nsnull; - nsresult rv = NS_OK; + + nsTableFrame* tableFrame = nsnull; + nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); + if (NS_FAILED(rv) || !tableFrame) return rv; + + nscoord cellSpacingY = tableFrame->GetCellSpacingY(); if (!ContinueReflow(nsnull, aPresContext, aReflowState.y, aReflowState.availSize.height)) return rv; @@ -413,12 +402,11 @@ NS_METHOD nsTableRowGroupFrame::ReflowMappedChildren(nsIPresContext* aPresC /* if the table has collapsing borders, we need to reset the length of the shared vertical borders * for the table and the cells that overlap this row */ - if ((eReflowReason_Initial != aReflowState.reflowState.reason) && (NS_STYLE_BORDER_COLLAPSE==borderStyle)) - { + if ((eReflowReason_Initial != aReflowState.reflowState.reason) && + (NS_STYLE_BORDER_COLLAPSE==borderStyle)) { const nsStyleDisplay *childDisplay; kidFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay) - { + if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay) { PRInt32 rowIndex = ((nsTableRowFrame*)kidFrame)->GetRowIndex(); aReflowState.tableFrame->SetBorderEdgeLength(NS_SIDE_LEFT, rowIndex, @@ -446,13 +434,14 @@ NS_METHOD nsTableRowGroupFrame::ReflowMappedChildren(nsIPresContext* aPresC } } } + aReflowState.y += cellSpacingY; } else { // Adjust the running y-offset so we know where the next row should // be placed nsSize kidSize; kidFrame->GetSize(kidSize); - aReflowState.y += kidSize.height; + aReflowState.y += kidSize.height + cellSpacingY; } if (PR_FALSE==aDoSiblings) @@ -555,8 +544,8 @@ AllocateSpecialHeight(nsIPresContext* aPresContext, * Actual row heights are ultimately determined by the table, when the table * height attribute is factored in. */ -void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, +void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState) { nsTableFrame* tableFrame = nsnull; @@ -597,11 +586,7 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, startRowIndex = ((nsTableRowFrame*)rowFrame)->GetRowIndex(); } // get the height of the tallest cell in the row (excluding cells that span rows) - nscoord maxCellHeight = ((nsTableRowFrame*)rowFrame)->GetTallestChild(); - nscoord topMargin = ((nsTableRowFrame*)rowFrame)->GetTopMargin(); - nscoord bottomMargin = ((nsTableRowFrame*)rowFrame)->GetBottomMargin(); - nscoord maxRowHeight = maxCellHeight + topMargin + bottomMargin; - rowHeights[rowIndex] = maxRowHeight; + rowHeights[rowIndex] = ((nsTableRowFrame*)rowFrame)->GetTallestChild(); // See if a cell spans into the row. If so we'll have to do step 2 if (!hasRowSpanningCell) { if (tableFrame->RowIsSpannedInto(rowIndex + startRowIndex)) { @@ -649,6 +634,7 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, if (rowSpan > 1) { // found a cell with rowspan > 1, determine the height // of the rows it spans nscoord heightOfRowsSpanned = 0; + nscoord cellSpacingOfRowsSpanned = 0; PRInt32 spanX; PRBool cellsOrigInSpan = PR_FALSE; // do any cells originate in the spanned rows for (spanX = 0; spanX < rowSpan; spanX++) { @@ -658,9 +644,11 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, heightOfRowsSpanned += rowHeights[rowIndex + spanX]; cellsOrigInSpan = PR_TRUE; } + if (0 != spanX) { + cellSpacingOfRowsSpanned += cellSpacingY; + } } - // reduce the height by top and bottom margins - nscoord availHeightOfRowsSpanned = heightOfRowsSpanned - cellSpacingY - cellSpacingY; + nscoord availHeightOfRowsSpanned = heightOfRowsSpanned + cellSpacingOfRowsSpanned; // see if the cell's height fits within the rows it spans. If this is // pass 1 then use the cell's desired height and not the current height @@ -675,7 +663,7 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, } if (availHeightOfRowsSpanned >= cellFrameSize.height) { - // yes the cell's height fits with the available space of the rows it + // the cell's height fits with the available space of the rows it // spans. Set the cell frame's height cellFrame->SizeTo(aPresContext, cellFrameSize.width, availHeightOfRowsSpanned); // Realign cell content based on new height @@ -800,6 +788,9 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, nsSize rowSize; rowFrame->GetSize(rowSize); rowGroupHeight += rowSize.height; + if (0 != rowIndex) { + rowGroupHeight += cellSpacingY; + } GetNextFrame(rowFrame, &rowFrame); // Get the next row rowIndex++; @@ -1371,24 +1362,28 @@ NS_METHOD nsTableRowGroupFrame::IR_TargetIsMe(nsIPresContext* aPresContext, return rv; } -NS_METHOD nsTableRowGroupFrame::GetHeightOfRows(nsIPresContext* aPresContext, nscoord& aResult) +NS_METHOD nsTableRowGroupFrame::GetHeightOfRows(nsIPresContext* aPresContext, + nscoord& aResult) { + nsTableFrame* tableFrame = nsnull; + nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); + if (NS_FAILED(rv) || !tableFrame) return rv; + + nscoord cellSpacingY = tableFrame->GetCellSpacingY(); + // the rows in rowGroupFrame need to be expanded by rowHeightDelta[i] // and the rowgroup itself needs to be expanded by SUM(row height deltas) - nsIFrame * rowFrame=nsnull; - nsresult rv = FirstChild(aPresContext, nsnull, &rowFrame); - while ((NS_SUCCEEDED(rv)) && (nsnull!=rowFrame)) - { - const nsStyleDisplay *rowDisplay; + nsIFrame* rowFrame = nsnull; + rv = FirstChild(aPresContext, nsnull, &rowFrame); + while ((NS_SUCCEEDED(rv)) && (nsnull!=rowFrame)) { + const nsStyleDisplay* rowDisplay; rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)rowDisplay)); - if (NS_STYLE_DISPLAY_TABLE_ROW == rowDisplay->mDisplay) - { + if (NS_STYLE_DISPLAY_TABLE_ROW == rowDisplay->mDisplay) { nsRect rowRect; rowFrame->GetRect(rowRect); aResult += rowRect.height; } - else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == rowDisplay->mDisplay) - { + else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == rowDisplay->mDisplay) { ((nsTableRowGroupFrame*)rowFrame)->GetHeightOfRows(aPresContext, aResult); } GetNextFrame(rowFrame, &rowFrame); diff --git a/mozilla/layout/style/html.css b/mozilla/layout/style/html.css index 5b40cb18d58..2153d1c3f1e 100644 --- a/mozilla/layout/style/html.css +++ b/mozilla/layout/style/html.css @@ -179,6 +179,7 @@ th { caption { text-align: center; display: table-caption; + box-sizing: border-box; } tr { display: table-row; @@ -1084,6 +1085,35 @@ option[disabled] { background-color:rgb(204,204,204) !important; } +select option[disabled] { + color:rgb(153,153,153); + background-color:rgb(204,204,204); +} + +select[size] option[-moz-option-selected] { + color:white; + background-color:rgb(51,51,102); +} +select[size] option[-moz-option-selected-focus] { + color:white; + background-color:rgb(51,51,102); +} + +select[size][disabled] option[-moz-option-selected] { + color:rgb(153,153,153); + background-color:rgb(204,204,204); +} + +select[size="1"] option[-moz-option-selected] { + color:white; + background-color:rgb(51,51,102); +} + +select[size="1"] option[disabled][-moz-option-selected] { + color:rgb(153,153,153); + background-color:rgb(204,204,204); +} + optgroup { font-family: sans-serif; font-size: small; @@ -1290,14 +1320,22 @@ sourcetext { /* XXX should not be in HTML namespace */ :table { display: table; - border-style: inherit; - border-color: inherit; - margin-top: inherit; - margin-bottom: inherit; - background: inherit; + border-spacing: 2px; + border-collapse: separate; + margin-top: 0; + margin-bottom: 0; box-sizing: border-box; } +:table-outer { + display: table; + margin: 0px; + border: 0px; + padding: 0px; + float: inherit; + position: inherit; +} + :table-cell { display: table-cell; } @@ -1310,10 +1348,6 @@ sourcetext { /* XXX should not be in HTML namespace */ display: table-column-group; } -:table-outer { - display: table; -} - :table-row { display: table-row; } diff --git a/mozilla/layout/style/nsStyleContext.cpp b/mozilla/layout/style/nsStyleContext.cpp index 0f7073218db..f527613733c 100644 --- a/mozilla/layout/style/nsStyleContext.cpp +++ b/mozilla/layout/style/nsStyleContext.cpp @@ -2287,8 +2287,9 @@ StyleContextImpl::RemapStyle(nsIPresContext* aPresContext, PRBool aRecurse) nsCompatibility quirkMode = eCompatibility_Standard; aPresContext->GetCompatibilityMode(&quirkMode); if (eCompatibility_NavQuirks == quirkMode) { - if ((mDisplay.mDisplay == NS_STYLE_DISPLAY_TABLE) || - (mDisplay.mDisplay == NS_STYLE_DISPLAY_TABLE_CAPTION)) { + if (((mDisplay.mDisplay == NS_STYLE_DISPLAY_TABLE) || + (mDisplay.mDisplay == NS_STYLE_DISPLAY_TABLE_CAPTION)) && + (nsnull == mPseudoTag)) { StyleContextImpl* holdParent = mParent; mParent = nsnull; // cut off all inheritance. this really blows diff --git a/mozilla/layout/tables/nsCellMap.cpp b/mozilla/layout/tables/nsCellMap.cpp index 4265f73d295..0c0a6a0ea1a 100644 --- a/mozilla/layout/tables/nsCellMap.cpp +++ b/mozilla/layout/tables/nsCellMap.cpp @@ -855,8 +855,8 @@ void nsCellMap::InsertCells(nsTableCellMap& aMap, PRInt32 startColIndex; for (startColIndex = aColIndexBefore + 1; startColIndex < numCols; startColIndex++) { CellData* data = GetMapCellAt(aMap, aRowIndex, startColIndex, PR_TRUE); - if (data && data->IsOrig()) { - break; // we found the col index + if (!data || data->IsOrig()) { // stop unless it is a span + break; } } @@ -904,19 +904,20 @@ void nsCellMap::ExpandWithRows(nsIPresContext* aPresContext, nsTableCellMap& aMap, nsVoidArray& aRowFrames, - PRInt32 aStartRowIndex) + PRInt32 aStartRowIndexIn) { + PRInt32 startRowIndex = (aStartRowIndexIn >= 0) ? aStartRowIndexIn : 0; PRInt32 numNewRows = aRowFrames.Count(); - PRInt32 endRowIndex = aStartRowIndex + numNewRows - 1; + PRInt32 endRowIndex = startRowIndex + numNewRows - 1; // create the new rows first - if (!Grow(aMap, numNewRows, aStartRowIndex)) { + if (!Grow(aMap, numNewRows, startRowIndex)) { return; } mRowCount += numNewRows; PRInt32 newRowIndex = 0; - for (PRInt32 rowX = aStartRowIndex; rowX <= endRowIndex; rowX++) { + for (PRInt32 rowX = startRowIndex; rowX <= endRowIndex; rowX++) { nsTableRowFrame* rFrame = (nsTableRowFrame *)aRowFrames.ElementAt(newRowIndex); // append cells nsIFrame* cFrame = nsnull; diff --git a/mozilla/layout/tables/nsTableFrame.cpp b/mozilla/layout/tables/nsTableFrame.cpp index 7f14fc61b8c..96523b110dd 100644 --- a/mozilla/layout/tables/nsTableFrame.cpp +++ b/mozilla/layout/tables/nsTableFrame.cpp @@ -135,6 +135,16 @@ struct InnerTableReflowState { } }; +const nsHTMLReflowState* +GetGrandParentReflowState(const nsHTMLReflowState& aInnerRS) +{ + const nsHTMLReflowState* rs = nsnull; + if (aInnerRS.parentReflowState) { + rs = aInnerRS.parentReflowState->parentReflowState; + } + return rs; +} + NS_IMETHODIMP nsTableFrame::GetFrameType(nsIAtom** aType) const @@ -1461,37 +1471,30 @@ nsTableFrame::SetColumnDimensions(nsIPresContext* aPresContext, { nscoord colHeight = aHeight -= aBorderPadding.top + aBorderPadding.bottom; nscoord cellSpacingX = GetCellSpacingX(); - nscoord halfCellSpacingX = NSToCoordRound(((float)cellSpacingX) / (float)2); nsIFrame* colGroupFrame = mColGroups.FirstChild(); PRInt32 colX = 0; - nsPoint colGroupOrigin(aBorderPadding.left, aBorderPadding.top); + nsPoint colGroupOrigin(aBorderPadding.left + cellSpacingX, aBorderPadding.top); PRInt32 numCols = GetColCount(); while (nsnull != colGroupFrame) { nscoord colGroupWidth = 0; nsIFrame* colFrame = nsnull; colGroupFrame->FirstChild(aPresContext, nsnull, &colFrame); - nsPoint colOrigin(0, 0); + nsPoint colOrigin(0,0); while (nsnull != colFrame) { const nsStyleDisplay* colDisplay; colFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)colDisplay)); if (NS_STYLE_DISPLAY_TABLE_COLUMN == colDisplay->mDisplay) { NS_ASSERTION(colX < numCols, "invalid number of columns"); nscoord colWidth = mColumnWidths[colX]; - if (numCols == 1) { - colWidth += cellSpacingX + cellSpacingX; - } - else if ((0 == colX) || (numCols - 1 == colX)) { - colWidth += cellSpacingX + halfCellSpacingX; - } - else if (GetNumCellsOriginatingInCol(colX) > 0) { - colWidth += cellSpacingX; - } - - colGroupWidth += colWidth; nsRect colRect(colOrigin.x, colOrigin.y, colWidth, colHeight); colFrame->SetRect(aPresContext, colRect); - colOrigin.x += colWidth; + colOrigin.x += colWidth + cellSpacingX; + + colGroupWidth += colWidth; + if (numCols - 1 != colX) { + colGroupWidth += cellSpacingX; + } colX++; } colFrame->GetNextSibling(&colFrame); @@ -1604,9 +1607,7 @@ NS_METHOD nsTableFrame::Reflow(nsIPresContext* aPresContext, aDesiredSize.maxElementSize = nsnull; } rv = ResizeReflowPass2(aPresContext, aDesiredSize, reflowState, aStatus); - if (NS_FAILED(rv)) { - return rv; - } + if (NS_FAILED(rv)) return rv; aDesiredSize.width = PR_MIN(aDesiredSize.width, pass1Width); @@ -1704,7 +1705,7 @@ NS_METHOD nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, NS_ASSERTION(nsnull==mPrevInFlow, "illegal call, cannot call pass 1 on a continuing frame."); NS_ASSERTION(nsnull != mContent, "null content"); - nsresult rv=NS_OK; + nsresult rv = NS_OK; // set out params aStatus = NS_FRAME_COMPLETE; @@ -1713,23 +1714,22 @@ NS_METHOD nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, nsSize kidMaxSize(0,0); nsHTMLReflowMetrics kidSize(&kidMaxSize); nscoord y = 0; + nscoord cellSpacingY = GetCellSpacingY(); // Compute the insets (sum of border and padding) // XXX: since this is pass1 reflow and where we place the rowgroup frames is irrelevant, insets are probably a waste - if (IsAutoLayout(&aReflowState)) - { + if (IsAutoLayout(&aReflowState)) { nsIFrame* kidFrame = aStartingFrame; if (nsnull==kidFrame) - kidFrame=mFrames.FirstChild(); - for ( ; nsnull != kidFrame; kidFrame->GetNextSibling(&kidFrame)) - { + kidFrame = mFrames.FirstChild(); + for ( ; nsnull != kidFrame; kidFrame->GetNextSibling(&kidFrame)) { const nsStyleDisplay *childDisplay; kidFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); if ((NS_STYLE_DISPLAY_TABLE_HEADER_GROUP != childDisplay->mDisplay) && (NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP != childDisplay->mDisplay) && - (NS_STYLE_DISPLAY_TABLE_ROW_GROUP != childDisplay->mDisplay) ) - { // it's an unknown frame type, give it a generic reflow and ignore the results + (NS_STYLE_DISPLAY_TABLE_ROW_GROUP != childDisplay->mDisplay) ) { + // it's an unknown frame type, give it a generic reflow and ignore the results nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame, availSize, aReason); // rv intentionally not set here @@ -1738,7 +1738,7 @@ NS_METHOD nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, continue; } - // Get the row group's border padding + // Get the table's border padding nsMargin borderPadding; GetTableBorderForRowGroup(GetRowGroupFrameFor(kidFrame, childDisplay), borderPadding); const nsStyleSpacing* tableSpacing; @@ -1746,6 +1746,11 @@ NS_METHOD nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, nsMargin padding; tableSpacing->GetPadding(padding); borderPadding += padding; + + y += cellSpacingY; + if (kidFrame == mFrames.FirstChild()) { + y += borderPadding.top; + } // Reflow the child nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame, @@ -1754,12 +1759,12 @@ NS_METHOD nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, // isTopOfPage reflow state flag, because we're dealing with an unconstrained // height and it isn't an issue... ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, borderPadding.left, - borderPadding.top + y, 0, aStatus); + y, 0, aStatus); // Place the child since some of its content fit in us. FinishReflowChild(kidFrame, aPresContext, kidSize, borderPadding.left, borderPadding.top + y, 0); - if (NS_UNCONSTRAINEDSIZE==kidSize.height) + if (NS_UNCONSTRAINEDSIZE == kidSize.height) // XXX This is very suspicious. Why would a row group frame want // such a large height? y = NS_UNCONSTRAINEDSIZE; @@ -1777,16 +1782,14 @@ NS_METHOD nsTableFrame::ResizeReflowPass1(nsIPresContext* aPresContext, // up all of our available space (or needs us to split). break; } - if (PR_FALSE==aDoSiblingFrames) + if (!aDoSiblingFrames) break; } // if required, give the colgroups their initial reflows - if (PR_TRUE==aDoSiblingFrames) - { + if (aDoSiblingFrames) { kidFrame=mColGroups.FirstChild(); - for ( ; nsnull != kidFrame; kidFrame->GetNextSibling(&kidFrame)) - { + for ( ; nsnull != kidFrame; kidFrame->GetNextSibling(&kidFrame)) { nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame, availSize, aReason); ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, 0, 0, 0, aStatus); @@ -1946,6 +1949,7 @@ NS_METHOD nsTableFrame::ResizeReflowPass2(nsIPresContext* aPresContext, borderPadding += aReflowState.mComputedPadding; InnerTableReflowState state(aPresContext, aReflowState, borderPadding); + state.y = borderPadding.top; // XXX this should be set in the constructor, but incremental code is affected. // now that we've computed the column width information, reflow all children #ifdef NS_DEBUG @@ -1958,7 +1962,7 @@ NS_METHOD nsTableFrame::ResizeReflowPass2(nsIPresContext* aPresContext, // Reflow the existing frames if (mFrames.NotEmpty()) { - ComputePercentBasisForRows(aReflowState); + ComputePercentBasisForRows(aPresContext, aReflowState); rv = ReflowMappedChildren(aPresContext, aDesiredSize, state, aStatus); } @@ -1973,7 +1977,7 @@ NS_METHOD nsTableFrame::ResizeReflowPass2(nsIPresContext* aPresContext, // Return our size and our status aDesiredSize.width = ComputeDesiredWidth(aReflowState); - nscoord defaultHeight = state.y + borderPadding.top + borderPadding.bottom; + nscoord defaultHeight = state.y + GetCellSpacingY() + borderPadding.bottom; aDesiredSize.height = ComputeDesiredHeight(aPresContext, aReflowState, defaultHeight); AdjustForCollapsingRows(aPresContext, aDesiredSize.height); @@ -1994,16 +1998,15 @@ NS_METHOD nsTableFrame::ResizeReflowPass2(nsIPresContext* aPresContext, } -void nsTableFrame::ComputePercentBasisForRows(const nsHTMLReflowState& aReflowState) +void nsTableFrame::ComputePercentBasisForRows(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState) { - nscoord height = CalcBorderBoxHeight(aReflowState, PR_TRUE); + nscoord height = CalcBorderBoxHeight(aPresContext, aReflowState); if ((height > 0) && (height != NS_UNCONSTRAINEDSIZE)) { // exclude our border and padding nsMargin borderPadding = aReflowState.mComputedBorderPadding; height -= borderPadding.top + borderPadding.bottom; - // exclude cell spacing for all rows - height -= (1 + GetRowCount()) * GetCellSpacingY(); height = PR_MAX(0, height); } else { @@ -2786,10 +2789,9 @@ nscoord nsTableFrame::ComputeDesiredWidth(const nsHTMLReflowState& aReflowState) nscoord desiredWidth = aReflowState.availableWidth; // this is the biggest hack in the world. But there's no other rational way to handle nested percent tables const nsStylePosition* position; - PRBool isNested=IsNested(aReflowState, position); - if((eReflowReason_Initial==aReflowState.reason) && - (PR_TRUE==isNested) && (eStyleUnit_Percent==position->mWidth.GetUnit())) - { + PRBool isNested = IsNested(aReflowState, position); + if ((eReflowReason_Initial==aReflowState.reason) && + (isNested) && (eStyleUnit_Percent == position->mWidth.GetUnit())) { nsITableLayoutStrategy* tableLayoutStrategy = mTableLayoutStrategy; if (mPrevInFlow) { // Get the table layout strategy from the first-in-flow @@ -2823,36 +2825,30 @@ void nsTableFrame::PlaceChild(nsIPresContext* aPresContext, aReflowState.availSize.height -= aDesiredSize.height; } - // If this is a footer row group, remember it const nsStyleDisplay *childDisplay; aKidFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); // We only allow a single footer frame, and the footer frame must occur before // any body section row groups if ((NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP == childDisplay->mDisplay) && - !aReflowState.footerFrame && !aReflowState.firstBodySection) - { + !aReflowState.footerFrame && !aReflowState.firstBodySection) { aReflowState.footerFrame = aKidFrame; } - else if (aReflowState.footerFrame) - { - // Place the row group frame - nsSize footerSize; + else if (aReflowState.footerFrame) { + // put the non footer where the footer was nsPoint origin; - aKidFrame->GetOrigin(origin); - aReflowState.footerFrame->GetSize(footerSize); - origin.y -= footerSize.height; - aKidFrame->MoveTo(aPresContext, origin.x, origin.y); - - // Move the footer below the body row group frame aReflowState.footerFrame->GetOrigin(origin); - origin.y += aDesiredSize.height; + aKidFrame->MoveTo(aPresContext, origin.x, origin.y); + + // put the footer below the non footer + nsSize size; + aReflowState.footerFrame->GetSize(size); + origin.y = aReflowState.y - size.height; aReflowState.footerFrame->MoveTo(aPresContext, origin.x, origin.y); } //XXX: this should call into layout strategy to get the width field - if (nsnull != aMaxElementSize) - { + if (nsnull != aMaxElementSize) { const nsStyleSpacing* tableSpacing; GetStyleData(eStyleStruct_Spacing , ((const nsStyleStruct *&)tableSpacing)); nsMargin borderPadding; @@ -2865,6 +2861,39 @@ void nsTableFrame::PlaceChild(nsIPresContext* aPresContext, } } +void +nsTableFrame::GetSectionInfo(nsFrameList& aKidFrames, + PRBool& aHaveTHead, + PRBool& aHaveTBody, + PRBool& aHaveTFoot, + PRBool& aTHeadBeforeTFoot) +{ + aHaveTHead = aHaveTBody = aHaveTFoot = PR_FALSE; + aTHeadBeforeTFoot = PR_TRUE; + + nsIFrame* kidFrame = aKidFrames.FirstChild(); + while (kidFrame) { + const nsStyleDisplay* kidDisplay; + kidFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)kidDisplay)); + if (IsRowGroup(kidDisplay->mDisplay)) { + switch(kidDisplay->mDisplay) { + case NS_STYLE_DISPLAY_TABLE_HEADER_GROUP: + aHaveTHead = PR_TRUE; + break; + case NS_STYLE_DISPLAY_TABLE_FOOTER_GROUP: + aHaveTFoot = PR_TRUE; + if (!aHaveTHead) { + aTHeadBeforeTFoot = PR_FALSE; + } + break; + default: + aHaveTBody = PR_TRUE; + } + } + kidFrame->GetNextSibling(&kidFrame); + } +} + /** * Reflow the frames we've already created * @@ -2873,22 +2902,21 @@ void nsTableFrame::PlaceChild(nsIPresContext* aPresContext, * @return true if we successfully reflowed all the mapped children and false * otherwise, e.g. we pushed children to the next in flow */ -NS_METHOD nsTableFrame::ReflowMappedChildren(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, +NS_METHOD nsTableFrame::ReflowMappedChildren(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, InnerTableReflowState& aReflowState, - nsReflowStatus& aStatus) + nsReflowStatus& aStatus) { NS_PRECONDITION(mFrames.NotEmpty(), "no children"); - PRInt32 childCount = 0; nsIFrame* prevKidFrame = nsnull; nsSize kidMaxElementSize(0,0); nsSize* pKidMaxElementSize = (nsnull != aDesiredSize.maxElementSize) ? &kidMaxElementSize : nsnull; nsresult rv = NS_OK; + nscoord cellSpacingY = GetCellSpacingY(); nsReflowReason reason; - if (!IsAutoLayout(&aReflowState.reflowState)) - { + if (!IsAutoLayout(&aReflowState.reflowState)) { reason = aReflowState.reflowState.reason; if (eReflowReason_Incremental==reason) { reason = eReflowReason_Resize; @@ -2898,22 +2926,26 @@ NS_METHOD nsTableFrame::ReflowMappedChildren(nsIPresContext* aPresContext, } } } - else + else { reason = eReflowReason_Resize; + } + + // determine what section elements are present + PRBool haveTHead, haveTBody, haveTFoot, tHeadBeforeTFoot; + GetSectionInfo(mFrames, haveTHead, haveTBody, haveTFoot, tHeadBeforeTFoot); // this never passes reflows down to colgroups - for (nsIFrame* kidFrame = mFrames.FirstChild(); nsnull != kidFrame; ) - { + nsIFrame* kidFrame = mFrames.FirstChild(); + while (kidFrame) { nsSize kidAvailSize(aReflowState.availSize); nsHTMLReflowMetrics desiredSize(pKidMaxElementSize); - desiredSize.width=desiredSize.height=desiredSize.ascent=desiredSize.descent=0; + desiredSize.width = desiredSize.height = desiredSize.ascent = desiredSize.descent = 0; - const nsStyleDisplay *childDisplay; + const nsStyleDisplay* childDisplay; kidFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - if (PR_TRUE==IsRowGroup(childDisplay->mDisplay)) - { + if (IsRowGroup(childDisplay->mDisplay)) { // Keep track of the first body section row group - if (nsnull == aReflowState.firstBodySection) { + if (!aReflowState.firstBodySection) { if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == childDisplay->mDisplay) { aReflowState.firstBodySection = kidFrame; } @@ -2934,12 +2966,13 @@ NS_METHOD nsTableFrame::ReflowMappedChildren(nsIPresContext* aPresContext, kidReflowState.isTopOfPage = PR_FALSE; } + aReflowState.y += cellSpacingY; nscoord x = borderPadding.left; - nscoord y = borderPadding.top + aReflowState.y; + nscoord y = aReflowState.y; if (RowGroupsShouldBeConstrained()) { // Only applies to the tree widget. - nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aReflowState.reflowState, PR_TRUE); + nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aPresContext, aReflowState.reflowState); if ((tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE)) { kidReflowState.availableHeight = tableSpecifiedHeight - y; if (kidReflowState.availableHeight < 0) @@ -2961,11 +2994,10 @@ NS_METHOD nsTableFrame::ReflowMappedChildren(nsIPresContext* aPresContext, } // Place the child - if (PR_TRUE==IsRowGroup(childDisplay->mDisplay)) - { + if (IsRowGroup(childDisplay->mDisplay)) { // we don't want to adjust the maxElementSize if this is an initial reflow // it was set by the TableLayoutStrategy and shouldn't be changed. - nsSize *requestedMaxElementSize = nsnull; + nsSize* requestedMaxElementSize = nsnull; if (eReflowReason_Initial != aReflowState.reflowState.reason) requestedMaxElementSize = aDesiredSize.maxElementSize; PlaceChild(aPresContext, aReflowState, kidFrame, desiredSize, @@ -2973,7 +3005,6 @@ NS_METHOD nsTableFrame::ReflowMappedChildren(nsIPresContext* aPresContext, } else { kidFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); } - childCount++; // Remember where we just were in case we end up pushing children prevKidFrame = kidFrame; @@ -3014,23 +3045,20 @@ NS_METHOD nsTableFrame::ReflowMappedChildren(nsIPresContext* aPresContext, break; } } - else - {// it's an unknown frame type, give it a generic reflow and ignore the results - nsHTMLReflowState kidReflowState(aPresContext, - aReflowState.reflowState, kidFrame, - nsSize(0,0), eReflowReason_Resize); - nsHTMLReflowMetrics unusedDesiredSize(nsnull); - nsReflowStatus status; - ReflowChild(kidFrame, aPresContext, unusedDesiredSize, kidReflowState, - 0, 0, 0, status); - kidFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); + else {// it's an unknown frame type, give it a generic reflow and ignore the results + nsHTMLReflowState kidReflowState(aPresContext, aReflowState.reflowState, kidFrame, + nsSize(0,0), eReflowReason_Resize); + nsHTMLReflowMetrics unusedDesiredSize(nsnull); + nsReflowStatus status; + ReflowChild(kidFrame, aPresContext, unusedDesiredSize, kidReflowState, + 0, 0, 0, status); + kidFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); } // Get the next child kidFrame->GetNextSibling(&kidFrame); } - // Update the child count return rv; } @@ -3287,90 +3315,18 @@ void nsTableFrame::SetTableWidth(nsIPresContext* aPresContext, SetRect(aPresContext, tableSize); } -// XXX percentage based margin/border/padding -nscoord GetVerticalMarginBorderPadding(nsIFrame* aFrame, - const nsIID& aIID) +nscoord +GetVertMarginBorderPadding(const nsHTMLReflowState* aReflowState) { nscoord result = 0; - if (!aFrame) { - return result; - } - nsCOMPtr iContent; - nsresult rv = aFrame->GetContent(getter_AddRefs(iContent)); - if (NS_SUCCEEDED(rv)) { - nsIHTMLContent* htmlContent = nsnull; - rv = iContent->QueryInterface(aIID, (void **)&htmlContent); - if (htmlContent && NS_SUCCEEDED(rv)) { - nsCOMPtr styleContext; - aFrame->GetStyleContext(getter_AddRefs(styleContext)); - const nsStyleSpacing* spacing = - (const nsStyleSpacing*)styleContext->GetStyleData(eStyleStruct_Spacing); - nsMargin margin(0,0,0,0); - if (spacing->GetMargin(margin)) { - result += margin.top + margin.bottom; - } - if (spacing->GetBorderPadding(margin)) { - result += margin.top + margin.bottom; - } - NS_RELEASE(htmlContent); - } - } - return result; -} + if (!aReflowState) return result; -/* Get the height of the nearest ancestor of this table which has a height other than - * auto, except when there is an ancestor which is a table and that table does not have - * a coord height. It can be the case that the nearest such ancestor is a scroll frame - * or viewport frame; this provides backwards compatibility with Nav4.X and IE. - */ -nscoord nsTableFrame::GetEffectiveContainerHeight(const nsHTMLReflowState& aReflowState) -{ - nsIFrame* lastArea = nsnull; - nsIFrame* lastBlock = nsnull; - nsIAtom* frameType = nsnull; - nscoord result = -1; - const nsHTMLReflowState* rs = &aReflowState; + nsMargin margin = aReflowState->mComputedMargin; + nsTableOuterFrame::ZeroAutoMargin(margin); + result += margin.top + margin.bottom; + result += aReflowState->mComputedBorderPadding.top + + aReflowState->mComputedBorderPadding.bottom; - while (rs) { - const nsStyleDisplay* display; - rs->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)display); - if (NS_STYLE_DISPLAY_TABLE == display->mDisplay) { - const nsStylePosition* position; - rs->frame->GetStyleData(eStyleStruct_Position, (const nsStyleStruct *&)position); - nsStyleUnit unit = position->mHeight.GetUnit(); - if ((eStyleUnit_Null == unit) || (eStyleUnit_Auto == unit)) { - result = 0; - break; - } - } - if (NS_AUTOHEIGHT != rs->mComputedHeight) { - result = rs->mComputedHeight; - // if we get to the scroll frame or viewport frame, then subtract out - // margin/border/padding for the HTML and BODY elements - rs->frame->GetFrameType(&frameType); - if ((nsLayoutAtoms::viewportFrame == frameType) || - (nsLayoutAtoms::scrollFrame == frameType)) { - result -= GetVerticalMarginBorderPadding(lastArea, kIHTMLElementIID); - result -= GetVerticalMarginBorderPadding(lastBlock, kIBodyElementIID); - } - NS_IF_RELEASE(frameType); - break; - } - // keep track of the area and block frame on the way up because they could - // be the HTML and BODY elements - rs->frame->GetFrameType(&frameType); - if (nsLayoutAtoms::areaFrame == frameType) { - lastArea = rs->frame; - } - else if (nsLayoutAtoms::blockFrame == frameType) { - lastBlock = rs->frame; - } - NS_IF_RELEASE(frameType); - - // XXX: evil cast! - rs = (nsHTMLReflowState *)(rs->parentReflowState); - } - NS_ASSERTION(-1 != result, "bad state: no constrained height in reflow chain"); return result; } @@ -3405,34 +3361,33 @@ void nsTableFrame::DistributeSpaceToCells(nsIPresContext* aPresContext, void nsTableFrame::DistributeSpaceToRows(nsIPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsIFrame* aRowGroupFrame, - const nscoord& aSumOfRowHeights, - const nscoord& aExcess, - const nsStyleTable* aTableStyle, + nscoord aSumOfRowHeights, + nscoord aExcess, nscoord& aExcessForRowGroup, nscoord& aRowGroupYPos) { // the rows in rowGroupFrame need to be expanded by rowHeightDelta[i] // and the rowgroup itself needs to be expanded by SUM(row height deltas) + nscoord cellSpacingY = GetCellSpacingY(); nsTableRowGroupFrame* rowGroupFrame = (nsTableRowGroupFrame*)aRowGroupFrame; - nsIFrame * rowFrame = rowGroupFrame->GetFirstFrame(); - nscoord y = 0; - while (nsnull!=rowFrame) - { + nsIFrame* rowFrame = rowGroupFrame->GetFirstFrame(); + nscoord y = cellSpacingY; + while (rowFrame) { const nsStyleDisplay *rowDisplay; rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)rowDisplay)); if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == rowDisplay->mDisplay) { DistributeSpaceToRows(aPresContext, aReflowState, rowFrame, aSumOfRowHeights, - aExcess, aTableStyle, aExcessForRowGroup, y); + aExcess, aExcessForRowGroup, y); } - else if (NS_STYLE_DISPLAY_TABLE_ROW == rowDisplay->mDisplay) - { // the row needs to be expanded by the proportion this row contributed to the original height + else if (NS_STYLE_DISPLAY_TABLE_ROW == rowDisplay->mDisplay) { + // the row needs to be expanded by the proportion this row contributed to the original height nsRect rowRect; rowFrame->GetRect(rowRect); - float percent = ((float)(rowRect.height)) / ((float)(aSumOfRowHeights)); - nscoord excessForRow = NSToCoordRound((float)aExcess*percent); + float percent = ((float)(rowRect.height)) / (float)aSumOfRowHeights; + nscoord excessForRow = NSToCoordRound((float)aExcess * percent); if (rowGroupFrame->RowsDesireExcessSpace()) { - nsRect newRowRect(rowRect.x, y, rowRect.width, excessForRow+rowRect.height); + nsRect newRowRect(rowRect.x, y, rowRect.width, excessForRow + rowRect.height); rowFrame->SetRect(aPresContext, newRowRect); if ((NS_STYLE_BORDER_COLLAPSE == GetBorderCollapseStyle()) && mBorderCollapser) { PRInt32 rowIndex = ((nsTableRowFrame*)rowFrame)->GetRowIndex(); @@ -3440,13 +3395,13 @@ void nsTableFrame::DistributeSpaceToRows(nsIPresContext* aPresContext, mBorderCollapser->SetBorderEdgeLength(NS_SIDE_RIGHT, rowIndex, newRowRect.height); } // better if this were part of an overloaded row::SetRect - y += excessForRow+rowRect.height; + y += excessForRow + rowRect.height; } + y += cellSpacingY; aExcessForRowGroup += excessForRow; } - else - { + else { // XXX why nsRect rowRect; rowFrame->GetRect(rowRect); y += rowRect.height; @@ -3458,11 +3413,14 @@ void nsTableFrame::DistributeSpaceToRows(nsIPresContext* aPresContext, nsRect rowGroupRect; aRowGroupFrame->GetRect(rowGroupRect); if (rowGroupFrame->RowGroupDesiresExcessSpace()) { - nsRect newRowGroupRect(rowGroupRect.x, aRowGroupYPos, rowGroupRect.width, aExcessForRowGroup+rowGroupRect.height); + nsRect newRowGroupRect(rowGroupRect.x, aRowGroupYPos, rowGroupRect.width, + aExcessForRowGroup + rowGroupRect.height); aRowGroupFrame->SetRect(aPresContext, newRowGroupRect); aRowGroupYPos += aExcessForRowGroup + rowGroupRect.height; } - else aRowGroupYPos += rowGroupRect.height; + else { + aRowGroupYPos += rowGroupRect.height; + } DistributeSpaceToCells(aPresContext, aReflowState, aRowGroupFrame); } @@ -3478,7 +3436,7 @@ nscoord nsTableFrame::ComputeDesiredHeight(nsIPresContext* aPresContext } nscoord result = aDefaultHeight; - nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aReflowState, PR_TRUE); + nscoord tableSpecifiedHeight = CalcBorderBoxHeight(aPresContext, aReflowState); if ((tableSpecifiedHeight > 0) && (tableSpecifiedHeight != NS_UNCONSTRAINEDSIZE)) { if (tableSpecifiedHeight > aDefaultHeight) { result = tableSpecifiedHeight; @@ -3517,7 +3475,7 @@ nscoord nsTableFrame::ComputeDesiredHeight(nsIPresContext* aPresContext const nsStyleTable* tableStyle; GetStyleData(eStyleStruct_Table, (const nsStyleStruct *&)tableStyle); DistributeSpaceToRows(aPresContext, aReflowState, childFrame, sumOfRowHeights, - excess, tableStyle, excessForGroup, rowGroupYPos); + excess, excessForGroup, rowGroupYPos); // Make sure child views are properly positioned nsIView* view; @@ -3923,29 +3881,6 @@ nsTableFrame::GetPadding(const nsSize& aBasis, return padding; } -NS_METHOD nsTableFrame::GetCellMarginData(nsTableCellFrame* aKidFrame, nsMargin& aMargin) -{ - nsresult result = NS_ERROR_NOT_INITIALIZED; - - if (aKidFrame) { - nscoord spacingX = GetCellSpacingX(); - nscoord spacingY = GetCellSpacingY(); - PRInt32 rowIndex, colIndex; - aKidFrame->GetRowIndex(rowIndex); - aKidFrame->GetColIndex(colIndex); - // left/top margins only apply if the cell is a left/top border cell - // there used to be more complicated logic (rev 3.326) dealing with rowspans - // but failure to produce reasonable tests cases does not justify it. - aMargin.left = (0 == colIndex) ? spacingX : 0; - aMargin.top = (0 == rowIndex) ? spacingY : 0; - aMargin.right = spacingX; - aMargin.bottom = spacingY; - result = NS_OK; - } - - return result; -} - //XXX: ok, this looks dumb now. but in a very short time this will get filled in void nsTableFrame::GetTableBorder(nsMargin &aBorder) { @@ -4109,19 +4044,18 @@ NS_METHOD nsTableFrame::GetTableFrame(nsIFrame *aSourceFrame, nsTableFrame *& aT /* helper method for determining if this is a nested table or not */ // aReflowState must be the reflow state for this inner table frame, should have an assertion here for that -PRBool nsTableFrame::IsNested(const nsHTMLReflowState& aReflowState, const nsStylePosition *& aPosition) const +PRBool +nsTableFrame::IsNested(const nsHTMLReflowState& aReflowState, + const nsStylePosition*& aPosition) const { + aPosition = nsnull; PRBool result = PR_FALSE; // Walk up the reflow state chain until we find a cell or the root - const nsHTMLReflowState* rs = aReflowState.parentReflowState; // this is for the outer frame - if (rs) - rs = rs->parentReflowState; // and this is the parent of the outer frame - while (nsnull != rs) - { - const nsStyleDisplay *display; - rs->frame->GetStyleData(eStyleStruct_Display, (const nsStyleStruct *&)display); - if (NS_STYLE_DISPLAY_TABLE==display->mDisplay) - { + const nsHTMLReflowState* rs = GetGrandParentReflowState(aReflowState); + while (rs) { + nsCOMPtr frameType; + rs->frame->GetFrameType(getter_AddRefs(frameType)); + if (nsLayoutAtoms::tableFrame == frameType.get()) { result = PR_TRUE; rs->frame->GetStyleData(eStyleStruct_Position, ((const nsStyleStruct *&)aPosition)); break; @@ -4180,39 +4114,15 @@ nscoord nsTableFrame::CalcBorderBoxWidth(const nsHTMLReflowState& aState) return width; } -nscoord nsTableFrame::CalcBorderBoxHeight(const nsHTMLReflowState& aState, - PRBool aDoNavHack) +nscoord nsTableFrame::CalcBorderBoxHeight(nsIPresContext* aPresContext, + const nsHTMLReflowState& aState) { nscoord height = aState.mComputedHeight; - PRBool isAutoHeight = PR_FALSE; - PRBool isPercentHack = PR_FALSE; - - if (eStyleUnit_Auto == aState.mStylePosition->mHeight.GetUnit()) { - isAutoHeight = PR_TRUE; - } - else if (((0 == height) || (NS_UNCONSTRAINEDSIZE == height)) && - aDoNavHack && (eStyleUnit_Percent == aState.mStylePosition->mHeight.GetUnit())) { - nsIAtom* frameType; - aState.frame->GetFrameType(&frameType); - if (nsLayoutAtoms::tableFrame == frameType) { - float percent = aState.mStylePosition->mHeight.GetPercentValue(); - nscoord parentHeight = ((nsTableFrame*)aState.frame)->GetEffectiveContainerHeight(aState); - if ((NS_UNCONSTRAINEDSIZE != parentHeight) && (0 != parentHeight)) { - // css box-sizing not supported for this Nav hack - height = NSToCoordRound((float)parentHeight * percent); - isPercentHack = PR_TRUE; - } - } - NS_IF_RELEASE(frameType); - } - - height = PR_MAX(height, 0); - - if ((height != NS_UNCONSTRAINEDSIZE) && !isAutoHeight && !isPercentHack) { - nsMargin borderPadding(0,0,0,0); - aState.mStyleSpacing->GetBorderPadding(borderPadding); + if (NS_AUTOHEIGHT != height) { + nsMargin borderPadding = aState.mComputedBorderPadding; height += borderPadding.top + borderPadding.bottom; } + height = PR_MAX(0, height); return height; } diff --git a/mozilla/layout/tables/nsTableFrame.h b/mozilla/layout/tables/nsTableFrame.h index 241ae644db4..3fa0e0a2ecf 100644 --- a/mozilla/layout/tables/nsTableFrame.h +++ b/mozilla/layout/tables/nsTableFrame.h @@ -147,8 +147,8 @@ public: // calculate the height of aFrame including its border and padding given // its reflow state. - nscoord CalcBorderBoxHeight(const nsHTMLReflowState& aReflowState, - PRBool aDoNavHacks); + nscoord CalcBorderBoxHeight(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState); // Return the closest sibling of aPriorChildFrame (including aPriroChildFrame) // of type aChildType. @@ -292,10 +292,6 @@ public: /** helper to get the cell padding style value */ virtual nscoord GetCellPadding(); - - // Get cell margin information - NS_IMETHOD GetCellMarginData(nsTableCellFrame* aKidFrame, nsMargin& aMargin); - /** return the row span of a cell, taking into account row span magic at the bottom * of a table. The row span equals the number of rows spanned by aCell starting at * aStartRowIndex, and can be smaller if aStartRowIndex is greater than the row @@ -450,7 +446,8 @@ protected: * If not nested, undefined. * @return PR_TRUE if this table is nested inside another table. */ - PRBool IsNested(const nsHTMLReflowState& aReflowState, const nsStylePosition *& aPosition) const; + PRBool IsNested(const nsHTMLReflowState& aReflowState, + const nsStylePosition*& aPosition) const; // Sets the starting column index for aColGroupFrame and the siblings frames that // follow @@ -576,17 +573,16 @@ protected: /** The following two functions are helpers for ComputeDesiredHeight */ - void DistributeSpaceToCells(nsIPresContext* aPresContext, + void DistributeSpaceToCells(nsIPresContext* aPresContext, const nsHTMLReflowState& aReflowState, - nsIFrame* aRowGroupFrame); - void DistributeSpaceToRows(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState, - nsIFrame* aRowGroupFrame, const nscoord& aSumOfRowHeights, - const nscoord& aExcess, const nsStyleTable* aTableStyle, - nscoord& aExcessForRowGroup, - nscoord& aRowGroupYPos); - - nscoord GetEffectiveContainerHeight(const nsHTMLReflowState& aReflowState); + nsIFrame* aRowGroupFrame); + void DistributeSpaceToRows(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState, + nsIFrame* aRowGroupFrame, + nscoord aSumOfRowHeights, + nscoord aExcess, + nscoord& aExcessForRowGroup, + nscoord& aRowGroupYPos); void PlaceChild(nsIPresContext* aPresContext, InnerTableReflowState& aReflowState, @@ -653,6 +649,11 @@ protected: nsIFrame* aFromChild, nsIFrame* aPrevSibling); + void GetSectionInfo(nsFrameList& aKidFrames, + PRBool& aHaveTHead, + PRBool& aHaveTBody, + PRBool& aHaveTFoot, + PRBool& aTHeadBeforeTFoot); public: // Returns PR_TRUE if there are any cells above the row at // aRowIndex and spanning into the row at aRowIndex @@ -811,7 +812,8 @@ public: /* ----- Cell Map public methods ----- */ // compute the height of the table to be used as the basis for // percentage height cells - void ComputePercentBasisForRows(const nsHTMLReflowState& aReflowState); + void ComputePercentBasisForRows(nsIPresContext* aPresContext, + const nsHTMLReflowState& aReflowState); nscoord GetPercentBasisForRows(); diff --git a/mozilla/layout/tables/nsTableOuterFrame.cpp b/mozilla/layout/tables/nsTableOuterFrame.cpp index 13dc811fc90..2f4a59601ca 100644 --- a/mozilla/layout/tables/nsTableOuterFrame.cpp +++ b/mozilla/layout/tables/nsTableOuterFrame.cpp @@ -40,6 +40,7 @@ /* ----------- nsTableCaptionFrame ---------- */ #define NS_TABLE_FRAME_CAPTION_LIST_INDEX 0 +#define NO_SIDE 100 // caption frame nsTableCaptionFrame::nsTableCaptionFrame() @@ -87,52 +88,6 @@ NS_NewTableCaptionFrame(nsIPresShell* aPresShell, return NS_OK; } -// OuterTableReflowState - -struct OuterTableReflowState { - - // The presentation context - nsIPresContext *pc; - - // Our reflow state - const nsHTMLReflowState& reflowState; - - // The total available size (computed from the parent) - nsSize availSize; - // The available size for the inner table frame - nsSize innerTableMaxSize; - - // Margin tracking information - nscoord prevMaxPosBottomMargin; - nscoord prevMaxNegBottomMargin; - - // Flags for whether the max size is unconstrained - PRBool unconstrainedWidth; - PRBool unconstrainedHeight; - - // Running y-offset - nscoord y; - - OuterTableReflowState(nsIPresContext* aPresContext, - const nsHTMLReflowState& aReflowState) - : reflowState(aReflowState) - { - pc = aPresContext; - availSize.width = reflowState.availableWidth; - availSize.height = reflowState.availableHeight; - prevMaxPosBottomMargin = 0; - prevMaxNegBottomMargin = 0; - y=0; // border/padding/margin??? - unconstrainedWidth = PRBool(aReflowState.availableWidth == NS_UNCONSTRAINEDSIZE); - unconstrainedHeight = PRBool(aReflowState.availableHeight == NS_UNCONSTRAINEDSIZE); - innerTableMaxSize.width=0; - innerTableMaxSize.height=0; - } - - ~OuterTableReflowState() { - } -}; - /* ----------- nsTableOuterFrame ---------- */ NS_IMPL_ADDREF_INHERITED(nsTableOuterFrame, nsHTMLContainerFrame) @@ -160,6 +115,27 @@ nsresult nsTableOuterFrame::QueryInterface(const nsIID& aIID, void** aInstancePt } } +// helper, should really be in nsFrame +void nsTableOuterFrame::PositionView(nsIPresContext* aPresContext, + nsIFrame* aFrame) +{ + nsIView* view; + aFrame->GetView(aPresContext, &view); + if (view) { + nsContainerFrame::SyncFrameViewAfterReflow(aPresContext, aFrame, view, nsnull); + } + else { + nsContainerFrame::PositionChildViews(aPresContext, aFrame); + } +} + +NS_IMETHODIMP +nsTableOuterFrame::IsPercentageBase(PRBool& aBase) const +{ + aBase = PR_FALSE; + return NS_OK; +} + // tables change 0 width into auto, trees override this and do nothing NS_IMETHODIMP nsTableOuterFrame::AdjustZeroWidth() @@ -413,75 +389,550 @@ PRBool nsTableOuterFrame::NeedsReflow(const nsHTMLReflowState& aReflowState) return result; } -// Recover the reflow state to what it should be if aKidFrame is about -// to be reflowed -nsresult nsTableOuterFrame::RecoverState(OuterTableReflowState& aReflowState, - nsIFrame* aKidFrame) +// INCREMENTAL REFLOW HELPER FUNCTIONS + +nsSize +GetFrameSize(nsIFrame& aFrame) { - aReflowState.y = 0; + nsRect rect; + aFrame.GetRect(rect); + nsSize size(rect.width, rect.height); + return size; +} - // Set the inner table max size - nsSize innerTableSize(0,0); +void +nsTableOuterFrame::ZeroAutoMargin(nsMargin& aMargin) +{ + if (NS_AUTOMARGIN == aMargin.top) + aMargin.top = 0; + if (NS_AUTOMARGIN == aMargin.right) + aMargin.right = 0; + if (NS_AUTOMARGIN == aMargin.bottom) + aMargin.bottom = 0; + if (NS_AUTOMARGIN == aMargin.left) + aMargin.left = 0; +} - mInnerTableFrame->GetSize(innerTableSize); - aReflowState.innerTableMaxSize.width = innerTableSize.width; - aReflowState.innerTableMaxSize.height = aReflowState.reflowState.availableHeight; +void +FixAutoMargins(nsHTMLReflowState& aReflowState) +{ + nsMargin margin = aReflowState.mComputedMargin; + if ((margin.left == NS_AUTOMARGIN) || (margin.right == NS_AUTOMARGIN)) { + nsRect rect; + aReflowState.frame->GetRect(rect); + nscoord compWidth = rect.width - aReflowState.mComputedBorderPadding.left - + aReflowState.mComputedBorderPadding.right; + const nsHTMLReflowState* containRS = + nsHTMLReflowState::GetContainingBlockReflowState(aReflowState.parentReflowState); + + aReflowState.CalculateBlockSideMargins(containRS, compWidth); + } +} + +// get the margin and padding data. nsHTMLReflowState doesn't handle the +// case of auto margins +void +GetMarginPadding(nsIPresContext* aPresContext, + const nsHTMLReflowState& aOuterRS, + nsIFrame* aChildFrame, + nsMargin& aMargin, + nsMargin& aPadding, + PRBool aZeroAutoMargins = PR_FALSE) +{ + // construct a reflow state to compute margin and padding. Auto margins + // will not be computed at this time. + nsHTMLReflowState childRS(aPresContext, aOuterRS, aChildFrame, + nsSize(aOuterRS.availableWidth, aOuterRS.availableHeight), + eReflowReason_Resize); + if (aZeroAutoMargins) { + nsMargin adjMargin = childRS.mComputedMargin; + nsTableOuterFrame::ZeroAutoMargin(adjMargin); + aMargin = adjMargin; + } + else { + FixAutoMargins(childRS); + aMargin = childRS.mComputedMargin; + } + aPadding = childRS.mComputedPadding; +} + +nscoord CalcAutoMargin(nscoord aAutoMargin, + nscoord aOppositeMargin, + nscoord aContainBlockSize, + nscoord aFrameSize) +{ + nscoord margin; + if (NS_AUTOMARGIN == aOppositeMargin) { + margin = (aContainBlockSize - aFrameSize) / 2; + } + else { + margin = aContainBlockSize - aFrameSize - aOppositeMargin; + } + return PR_MAX(0, margin); +} + +nscoord +nsTableOuterFrame::GetChildAvailWidth(nsIPresContext* aPresContext, + nsIFrame* aChildFrame, + const nsHTMLReflowState& aOuterRS, + nscoord aOuterWidth, + nsMargin& aMargin, + nsMargin& aPadding) +{ + if (NS_UNCONSTRAINEDSIZE == aOuterWidth) return aOuterWidth; + + GetMarginPadding(aPresContext, aOuterRS, aChildFrame, aMargin, aPadding, PR_TRUE); + nscoord width = aOuterWidth; + if (NS_UNCONSTRAINEDSIZE != width) { + width = aOuterWidth - aMargin.left + aMargin.right; + width = PR_MAX(width, mMinCaptionWidth); + } + return width; +} + +void +MoveFrameTo(nsIPresContext* aPresContext, + nsIFrame* aFrame, + nscoord aX, + nscoord aY) +{ + nsRect oldRect; + aFrame->GetRect(oldRect); + if ((oldRect.x != aX) || (oldRect.y != aY)) { + aFrame->MoveTo(aPresContext, aX, aY); + nsTableOuterFrame::PositionView(aPresContext, aFrame); + } +} + +nsSize +GetContainingBlockSize(const nsHTMLReflowState& aOuterRS) +{ + nsSize size(0,0); + const nsHTMLReflowState* containRS = + nsHTMLReflowState::GetContainingBlockReflowState(aOuterRS.parentReflowState); + + if (containRS) { + size.width = containRS->mComputedWidth; + if (NS_UNCONSTRAINEDSIZE == size.width) { + size.width = 0; + } + size.height = containRS->mComputedHeight; + if (NS_UNCONSTRAINEDSIZE == size.height) { + size.height = 0; + } + } + return size; +} + +void +nsTableOuterFrame::InvalidateDamage(nsIPresContext* aPresContext, + PRUint8 aCaptionSide, + nsSize& aOuterSize, + PRBool aInnerChanged, + PRBool aCaptionChanged) +{ + nsRect damage; + if (aInnerChanged && aCaptionChanged) { + damage = nsRect(0, 0, aOuterSize.width, aOuterSize.height); + } + else { + nsRect innerRect, captionRect(0,0,0,0); + mInnerTableFrame->GetRect(innerRect); + if (mCaptionFrame) { + mCaptionFrame->GetRect(captionRect); + } + // only works for vertical captions { + damage.x = 0; + damage.width = aOuterSize.width; + switch(aCaptionSide) { + case NS_SIDE_TOP: + if (aCaptionChanged) { + damage.y = 0; + damage.height = innerRect.y; + } + else { + damage.y = captionRect.y; + damage.height = aOuterSize.height - damage.y; + } + break; + case NS_SIDE_BOTTOM: + default: + if (aCaptionChanged) { + damage.y = innerRect.y; + damage.height = aOuterSize.height - damage.y; + } + else { + damage.y = 0; + damage.height = captionRect.y; + } + } + } + Invalidate(aPresContext, damage); +} + +nscoord +nsTableOuterFrame::GetCaptionAvailWidth(nsIPresContext* aPresContext, + nsIFrame* aCaptionFrame, + const nsHTMLReflowState& aOuterRS, + nscoord* aInnerWidth, + const nsMargin* aInnerMargin) +{ + nscoord outerWidth; + if (aInnerWidth) { + nscoord innerWidth = *aInnerWidth; + if (NS_UNCONSTRAINEDSIZE == innerWidth) { + outerWidth = innerWidth; + } + else { + nsMargin innerMargin(0,0,0,0); + if (aInnerMargin) { + innerMargin = *aInnerMargin; + ZeroAutoMargin(innerMargin); + } + outerWidth = innerWidth + innerMargin.left + innerMargin.right; + } + } + else { + nsSize outerSize = GetFrameSize(*this); + outerWidth = outerSize.width; + } + + if (NS_UNCONSTRAINEDSIZE == outerWidth) { + return outerWidth; + } + else { + nsMargin capMargin, capPad; + return GetChildAvailWidth(aPresContext, aCaptionFrame, aOuterRS, + outerWidth, capMargin, capPad); + } +} + +nsSize +nsTableOuterFrame::GetMaxElementSize(const nsMargin& aInnerMargin, + const nsMargin& aInnerPadding, + const nsMargin& aCaptionMargin) +{ + nsSize size; + ((nsTableFrame *)mInnerTableFrame)->SetMaxElementSize(&size, aInnerPadding); + size.width += aInnerMargin.left + aInnerMargin.right; + + if (mCaptionFrame) { + nscoord capWidth = mMinCaptionWidth + aCaptionMargin.left + aCaptionMargin.right; + if (capWidth > size.width) { + size.width = capWidth; + } + } + size.height = 0; // max element height is not used for anything is it? + return size; +} + +nscoord +nsTableOuterFrame::GetMaxWidth(PRUint8 aCaptionSide, + const nsMargin& aInnerMargin, + const nsMargin& aCaptionMargin) +{ + nscoord maxWidth; + switch(aCaptionSide) { + case NS_SIDE_TOP: + case NS_SIDE_BOTTOM: + case NS_SIDE_LEFT: + case NS_SIDE_RIGHT: + default: // no caption + maxWidth = mInnerTableMaximumWidth + aInnerMargin.left + aInnerMargin.right; + if (mCaptionFrame) { + maxWidth = PR_MAX(maxWidth, mMinCaptionWidth + aCaptionMargin.left + aCaptionMargin.right); + } + } + return maxWidth; +} + + +PRUint8 +nsTableOuterFrame::GetCaptionSide() +{ + const nsStyleTable* tableStyle; + if (mCaptionFrame) { + mCaptionFrame->GetStyleData(eStyleStruct_Table, ((const nsStyleStruct *&)tableStyle)); + return tableStyle->mCaptionSide; + } + else { + return NO_SIDE; // no caption + } +} + + + +void +nsTableOuterFrame::SetDesiredSize(PRUint8 aCaptionSide, + const nsMargin& aInnerMargin, + const nsMargin& aCaptionMargin, + nscoord& aWidth, + nscoord& aHeight) +{ + aWidth = aHeight = 0; + + nsRect innerRect; + mInnerTableFrame->GetRect(innerRect); + + nsRect captionRect(0,0,0,0); + if (mCaptionFrame) { + mCaptionFrame->GetRect(captionRect); + } + + switch(aCaptionSide) { + case NS_SIDE_TOP: + case NS_SIDE_BOTTOM: + case NS_SIDE_LEFT: + case NS_SIDE_RIGHT: + default: // no caption + aWidth = innerRect.XMost() + aInnerMargin.right; + aWidth = PR_MAX(aWidth, captionRect.XMost() + aCaptionMargin.right); + break; + } + + switch(aCaptionSide) { + case NS_SIDE_BOTTOM: + case NS_SIDE_LEFT: + case NS_SIDE_RIGHT: + aHeight = captionRect.YMost() + aCaptionMargin.bottom; + break; + default: // top caption or no caption + aHeight = innerRect.YMost() + aInnerMargin.bottom; + } +} + + +nsresult +nsTableOuterFrame::GetCaptionOrigin(nsIPresContext* aPresContext, + PRUint32 aCaptionSide, + const nsSize& aContainBlockSize, + const nsSize& aInnerSize, + const nsMargin& aInnerMargin, + const nsSize& aCaptionSize, + nsMargin& aCaptionMargin, + nsPoint& aOrigin) +{ + aOrigin.x = aOrigin.y = 0; + if ((NS_UNCONSTRAINEDSIZE == aInnerSize.width) || (NS_UNCONSTRAINEDSIZE == aInnerSize.width) || + (NS_UNCONSTRAINEDSIZE == aCaptionSize.width) || (NS_UNCONSTRAINEDSIZE == aCaptionSize.width)) { + return NS_OK; + } + if (!mCaptionFrame) return NS_OK; + + switch(aCaptionSide) { + case NS_SIDE_TOP: + if (NS_AUTOMARGIN == aCaptionMargin.left) { + aCaptionMargin.left = CalcAutoMargin(aCaptionMargin.left, aCaptionMargin.right, + aContainBlockSize.width, aCaptionSize.width); + } + aOrigin.x = aCaptionMargin.left; + if (NS_AUTOMARGIN == aCaptionMargin.bottom) { + aCaptionMargin.bottom = 0; + } + if (NS_AUTOMARGIN == aCaptionMargin.top) { + nscoord collapseMargin = PR_MAX(aCaptionMargin.bottom, aInnerMargin.top); + nscoord height = aCaptionSize.height + collapseMargin + aInnerSize.height; + aCaptionMargin.top = CalcAutoMargin(aCaptionMargin.top, aInnerMargin.bottom, + aContainBlockSize.height, height); + } + aOrigin.y = aCaptionMargin.top; + break; + default: // all others are treated as bottom for now + if (NS_AUTOMARGIN == aCaptionMargin.left) { + aCaptionMargin.left = CalcAutoMargin(aCaptionMargin.left, aCaptionMargin.right, + aContainBlockSize.width, aCaptionSize.width); + } + aOrigin.x = aCaptionMargin.left; + if (NS_AUTOMARGIN == aCaptionMargin.top) { + aCaptionMargin.top = 0; + } + nscoord collapseMargin = PR_MAX(aCaptionMargin.top, aInnerMargin.bottom); + if (NS_AUTOMARGIN == aCaptionMargin.bottom) { + nscoord height = aInnerSize.height + collapseMargin + aCaptionSize.height; + aCaptionMargin.bottom = CalcAutoMargin(aCaptionMargin.bottom, aInnerMargin.top, + aContainBlockSize.height, height); + } + aOrigin.y = aInnerMargin.top + aInnerSize.height + collapseMargin; + break; + } return NS_OK; } -nsresult nsTableOuterFrame::IncrementalReflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus) +nsresult +nsTableOuterFrame::GetInnerOrigin(nsIPresContext* aPresContext, + PRUint32 aCaptionSide, + const nsSize& aContainBlockSize, + const nsSize& aCaptionSize, + const nsMargin& aCaptionMargin, + const nsSize& aInnerSize, + nsMargin& aInnerMargin, + nsPoint& aOrigin) +{ + aOrigin.x = aOrigin.y = 0; + if ((NS_UNCONSTRAINEDSIZE == aInnerSize.width) || (NS_UNCONSTRAINEDSIZE == aInnerSize.width) || + (NS_UNCONSTRAINEDSIZE == aCaptionSize.width) || (NS_UNCONSTRAINEDSIZE == aCaptionSize.width)) { + return NS_OK; + } + + nscoord collapseMargin; + switch(aCaptionSide) { + case NS_SIDE_TOP: + if (NS_AUTOMARGIN == aInnerMargin.left) { + aInnerMargin.left = CalcAutoMargin(aInnerMargin.left, aInnerMargin.right, + aContainBlockSize.width, aInnerSize.width); + } + aOrigin.x = aInnerMargin.left; + if (NS_AUTOMARGIN == aInnerMargin.top) { + aInnerMargin.top = 0; + } + collapseMargin = PR_MAX(aCaptionMargin.bottom, aInnerMargin.top); + if (NS_AUTOMARGIN == aInnerMargin.bottom) { + nscoord height = aCaptionSize.height + collapseMargin + aInnerSize.height; + aInnerMargin.bottom = CalcAutoMargin(aCaptionMargin.bottom, aInnerMargin.top, + aContainBlockSize.height, height); + } + aOrigin.y = aCaptionMargin.top + aCaptionSize.height + collapseMargin; + break; + default: // all others are treated as bottom for now + if (NS_AUTOMARGIN == aInnerMargin.left) { + aInnerMargin.left = CalcAutoMargin(aInnerMargin.left, aInnerMargin.right, + aContainBlockSize.width, aInnerSize.width); + } + aOrigin.x = aInnerMargin.left; + if (NS_AUTOMARGIN == aInnerMargin.bottom) { + aInnerMargin.bottom = 0; + } + if (NS_AUTOMARGIN == aInnerMargin.top) { + collapseMargin = PR_MAX(aInnerMargin.bottom, aCaptionMargin.top); + nscoord height = aInnerSize.height + collapseMargin + aCaptionSize.height; + aInnerMargin.top = CalcAutoMargin(aInnerMargin.top, aCaptionMargin.bottom, + aContainBlockSize.height, height); + } + aOrigin.y = aInnerMargin.top; + break; + } + return NS_OK; +} + +// eReflowReason_Resize was being used for incremental cases +nsresult +nsTableOuterFrame::OuterReflowChild(nsIPresContext* aPresContext, + nsIFrame* aChildFrame, + const nsHTMLReflowState& aOuterRS, + nsHTMLReflowMetrics& aMetrics, + nscoord* aAvailWidth, + nsSize& aDesiredSize, + nsMargin& aMargin, + nsMargin& aPadding, + nsReflowReason aReflowReason, + nsReflowStatus& aStatus) +{ + aMargin = aPadding = nsMargin(0,0,0,0); + + nscoord availWidth = GetChildAvailWidth(aPresContext, aChildFrame, aOuterRS, + aOuterRS.availableWidth, aMargin, aPadding); + if (aAvailWidth) { + availWidth = *aAvailWidth; + } + nsHTMLReflowState childRS(aPresContext, aOuterRS, aChildFrame, + nsSize(availWidth, aOuterRS.availableHeight)); + childRS.reason = aReflowReason; + + // Normally, the outer table's mComputed values are NS_INTRINSICSIZE since they + // depend on the caption and inner table. Boxes can force a size. + if (aOuterRS.mComputedWidth != NS_INTRINSICSIZE) { + childRS.mComputedWidth = aOuterRS.mComputedWidth - aMargin.left - childRS.mComputedBorderPadding.left - + childRS.mComputedBorderPadding.right - aMargin.right; + childRS.mComputedWidth = PR_MAX(0, childRS.mComputedWidth); + } + if (aOuterRS.mComputedHeight != NS_INTRINSICSIZE) { + childRS.mComputedHeight = aOuterRS.mComputedHeight - aMargin.top - childRS.mComputedBorderPadding.top - + childRS.mComputedBorderPadding.bottom - aMargin.bottom; + childRS.mComputedHeight = PR_MAX(0, childRS.mComputedHeight); + } + + // use the current position as a best guess for placement + nsRect childRect; + aChildFrame->GetRect(childRect); + nsresult rv = ReflowChild(aChildFrame, aPresContext, aMetrics, childRS, + childRect.x, childRect.y, NS_FRAME_NO_MOVE_FRAME, aStatus); + if (NS_FAILED(rv)) return rv; + + FixAutoMargins(childRS); + aMargin = childRS.mComputedMargin; + + aDesiredSize.width = aMetrics.width; + aDesiredSize.height = aMetrics.height; + + return rv; +} + +void +nsTableOuterFrame::UpdateReflowMetrics(PRUint8 aCaptionSide, + nsHTMLReflowMetrics& aMet, + const nsMargin& aInnerMargin, + const nsMargin& aInnerPadding, + const nsMargin& aCaptionMargin) +{ + SetDesiredSize(aCaptionSide, aInnerMargin, aCaptionMargin, aMet.width, aMet.height); + + // set maxElementSize width if requested + if (aMet.maxElementSize) { + *aMet.maxElementSize = GetMaxElementSize(aInnerMargin, aInnerPadding, aCaptionMargin); + } + // set maximum width if requested + if (aMet.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { + aMet.mMaximumWidth = GetMaxWidth(aCaptionSide, aInnerMargin, aCaptionMargin); + } + +} + +nsresult +nsTableOuterFrame::IncrementalReflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) { nsresult rv = NS_OK; // determine if this frame is the target or not nsIFrame* target=nsnull; - rv = aReflowState.reflowState.reflowCommand->GetTarget(target); - if ((PR_TRUE == NS_SUCCEEDED(rv)) && (nsnull != target)) { + rv = aReflowState.reflowCommand->GetTarget(target); + if (NS_SUCCEEDED(rv) && target) { if (this == target) { rv = IR_TargetIsMe(aPresContext, aDesiredSize, aReflowState, aStatus); } else { // Get the next frame in the reflow chain nsIFrame* nextFrame; - aReflowState.reflowState.reflowCommand->GetNext(nextFrame); + aReflowState.reflowCommand->GetNext(nextFrame); NS_ASSERTION(nextFrame, "next frame in reflow command is null"); - - // Recover our reflow state - RecoverState(aReflowState, nextFrame); rv = IR_TargetIsChild(aPresContext, aDesiredSize, aReflowState, aStatus, nextFrame); } } return rv; } -nsresult nsTableOuterFrame::IR_TargetIsChild(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus, - nsIFrame* aNextFrame) +nsresult +nsTableOuterFrame::IR_TargetIsChild(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus, + nsIFrame* aNextFrame) { nsresult rv; if (!aNextFrame) { // this will force Reflow to return the height of the last reflow rather than 0 - aReflowState.y = mRect.height; + aDesiredSize.height = mRect.height; return NS_OK; } if (aNextFrame == mInnerTableFrame) { rv = IR_TargetIsInnerTableFrame(aPresContext, aDesiredSize, aReflowState, aStatus); } - else if (aNextFrame==mCaptionFrame) { + else if (aNextFrame == mCaptionFrame) { rv = IR_TargetIsCaptionFrame(aPresContext, aDesiredSize, aReflowState, aStatus); - - // If we're supposed to update our maximum width, then just use the inner - // table's maximum width - if (aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { - aDesiredSize.mMaximumWidth = mInnerTableMaximumWidth; - } } else { const nsStyleDisplay* nextDisplay; @@ -500,183 +951,160 @@ nsresult nsTableOuterFrame::IR_TargetIsChild(nsIPresContext* aPresContext return rv; } -nsresult nsTableOuterFrame::IR_TargetIsInnerTableFrame(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus) +nsresult +nsTableOuterFrame::IR_TargetIsInnerTableFrame(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) { nsresult rv = IR_InnerTableReflow(aPresContext, aDesiredSize, aReflowState, aStatus); return rv; } -nsresult nsTableOuterFrame::IR_TargetIsCaptionFrame(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus) +nsresult +nsTableOuterFrame::IR_TargetIsCaptionFrame(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aOuterRS, + nsReflowStatus& aStatus) { - nsresult rv; - PRBool innerTableNeedsReflow = PR_FALSE; - // remember the old width and height - nsRect priorCaptionRect; - mCaptionFrame->GetRect(priorCaptionRect); - // if the reflow type is a style change, also remember the prior style + nsresult rv = NS_OK; + PRUint8 captionSide = GetCaptionSide(); + + nsSize captionSize, captionMES; + nsMargin captionMargin, captionPadding; + // reflow the caption frame, getting it's MES + nscoord availWidth = GetCaptionAvailWidth(aPresContext, mCaptionFrame, aOuterRS); + nsHTMLReflowMetrics captionMet(&captionMES); + OuterReflowChild(aPresContext, mCaptionFrame, aOuterRS, captionMet, &availWidth, captionSize, + captionMargin, captionPadding, eReflowReason_Incremental, aStatus); + + nsMargin innerMargin, innerPadding; + nsPoint innerOrigin; + nsSize containSize = GetContainingBlockSize(aOuterRS); + + // for now just reflow the table if a style changed. This should be improved nsIReflowCommand::ReflowType reflowCommandType; - aReflowState.reflowState.reflowCommand->GetType(reflowCommandType); - const nsStyleTable* priorCaptionTableStyle = nsnull; - if (nsIReflowCommand::StyleChanged == reflowCommandType) { - mCaptionFrame->GetStyleData(eStyleStruct_Table, ((const nsStyleStruct *&)priorCaptionTableStyle)); - } + aOuterRS.reflowCommand->GetType(reflowCommandType); + PRBool needInnerReflow = (nsIReflowCommand::StyleChanged == reflowCommandType) + ? PR_TRUE : PR_FALSE; - // pass along the reflow command to the caption - nsSize captionMES(0,0); - nsHTMLReflowMetrics captionSize(&captionMES); - nsHTMLReflowState captionReflowState(aPresContext, aReflowState.reflowState, mCaptionFrame, - nsSize(mRect.width, aReflowState.reflowState.availableHeight), - aReflowState.reflowState.reason); - captionReflowState.reflowCommand = aReflowState.reflowState.reflowCommand; - - rv = ReflowChild(mCaptionFrame, aPresContext, captionSize, captionReflowState, - 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus); - mCaptionFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); - if (NS_FAILED(rv)) { - return rv; - } if (mMinCaptionWidth != captionMES.width) { // set the new caption min width, and set state to reflow the inner table if necessary mMinCaptionWidth = captionMES.width; - if (mMinCaptionWidth > mRect.width) { - innerTableNeedsReflow=PR_TRUE; + // see if the captions min width could cause the table to be wider + // XXX this really only affects an auto width table + nsMargin capAdjMargin = captionMargin; + ZeroAutoMargin(capAdjMargin); + if ((mMinCaptionWidth + capAdjMargin.left + capAdjMargin.right) > mRect.width) { + needInnerReflow = PR_TRUE; } } - // check if the caption alignment changed axis - if (nsIReflowCommand::StyleChanged == reflowCommandType) { - const nsStyleTable* captionTableStyle; - mCaptionFrame->GetStyleData(eStyleStruct_Table, ((const nsStyleStruct *&)captionTableStyle)); - if (PR_TRUE == IR_CaptionChangedAxis(priorCaptionTableStyle, captionTableStyle)) { - innerTableNeedsReflow=PR_TRUE; - } - } + nsPoint captionOrigin; + if (needInnerReflow) { + nsSize innerSize; + nsHTMLReflowMetrics innerMet(nsnull); + OuterReflowChild(aPresContext, mInnerTableFrame, aOuterRS, innerMet, nsnull, innerSize, + innerMargin, innerPadding, eReflowReason_Resize, aStatus); - // if we've determined that the inner table needs to be reflowed, do it here - nsSize innerTableSize; - if (PR_TRUE == innerTableNeedsReflow) { - // Compute the width to use for the table. In the case of an auto sizing - // table this represents the maximum available width - nscoord tableWidth = ((nsTableFrame*)mInnerTableFrame)->CalcBorderBoxWidth(aReflowState.reflowState); - - // If the caption max element size is larger, then use it instead. - // XXX: caption align = left|right ignored here! - if (mMinCaptionWidth > tableWidth) { - tableWidth = mMinCaptionWidth; - } - nsHTMLReflowMetrics innerSize(aDesiredSize.maxElementSize); - nsHTMLReflowState innerReflowState(aPresContext, aReflowState.reflowState, mInnerTableFrame, - nsSize(tableWidth, aReflowState.reflowState.availableHeight), - eReflowReason_Resize); - rv = ReflowChild(mInnerTableFrame, aPresContext, innerSize, innerReflowState, - 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus); - mInnerTableFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); - if (NS_FAILED(rv)) { - return rv; - } - innerTableSize.SizeTo(innerSize.width, innerSize.height); - // set maxElementSize width if requested - if (nsnull != aDesiredSize.maxElementSize) { - ((nsTableFrame *)mInnerTableFrame)->SetMaxElementSize(aDesiredSize.maxElementSize, - aReflowState.reflowState.mComputedPadding); - if (mMinCaptionWidth > aDesiredSize.maxElementSize->width) { - aDesiredSize.maxElementSize->width = mMinCaptionWidth; - } - } + GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, + captionMargin, innerSize, innerMargin, innerOrigin); + rv = FinishReflowChild(mInnerTableFrame, aPresContext, innerMet, + innerOrigin.x, innerOrigin.y, 0); + if (NS_FAILED(rv)) return rv; + + GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, + innerMargin, captionSize, captionMargin, captionOrigin); } else { - nsRect innerTableRect; - mInnerTableFrame->GetRect(innerTableRect); - innerTableSize.SizeTo(innerTableRect.width, innerTableRect.height); + // reposition the inner frame if necessary and set the caption's origin + nsSize innerSize = GetFrameSize(*mInnerTableFrame); + GetMarginPadding(aPresContext, aOuterRS, mInnerTableFrame, innerMargin, + innerPadding); + GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, + captionMargin, innerSize, innerMargin, innerOrigin); + GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, + innerMargin, captionSize, captionMargin, captionOrigin); + MoveFrameTo(aPresContext, mInnerTableFrame, innerOrigin.x, innerOrigin.y); } - // regardless of what we've done up to this point, place the caption and inner table - rv = SizeAndPlaceChildren(aPresContext, innerTableSize, - nsSize (captionSize.width, captionSize.height), - aReflowState, captionReflowState.mComputedMargin); + rv = FinishReflowChild(mCaptionFrame, aPresContext, captionMet, + captionOrigin.x, captionOrigin.y, 0); + UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, innerPadding, captionMargin); + nsSize desSize(aDesiredSize.width, aDesiredSize.height); + InvalidateDamage(aPresContext, captionSide, desSize, needInnerReflow, PR_TRUE); return rv; } nsresult -nsTableOuterFrame::IR_ReflowDirty(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus) +nsTableOuterFrame::IR_ReflowDirty(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) { nsFrameState frameState; nsresult rv; - + PRBool sizeSet = PR_FALSE; // See if the caption frame is dirty. This would be because of a newly // inserted caption if (mCaptionFrame) { mCaptionFrame->GetFrameState(&frameState); if (frameState & NS_FRAME_IS_DIRTY) { rv = IR_CaptionInserted(aPresContext, aDesiredSize, aReflowState, aStatus); - - // Repaint our entire bounds - // XXX Improve this... - Invalidate(aPresContext, nsRect(0, 0, mRect.width, mRect.height)); + sizeSet = PR_TRUE; } } // See if the inner table frame is dirty mInnerTableFrame->GetFrameState(&frameState); if (frameState & NS_FRAME_IS_DIRTY) { - // Inner table is dirty so reflow it. Change the reflow state and set the - // reason to resize reflow. - ((nsHTMLReflowState&)aReflowState.reflowState).reason = eReflowReason_Resize; - ((nsHTMLReflowState&)aReflowState.reflowState).reflowCommand = nsnull; - - // Get the inner table frame's current bounds. We'll use that when - // repainting it - // XXX It should really do the repainting, but because it think it's - // getting a resize reflow it won't know to... - nsRect dirtyRect; - mInnerTableFrame->GetRect(dirtyRect); rv = IR_InnerTableReflow(aPresContext, aDesiredSize, aReflowState, aStatus); - - // Repaint the inner table frame's entire visible area - dirtyRect.x = dirtyRect.y = 0; - Invalidate(aPresContext, dirtyRect); - - } else if (!mCaptionFrame) { + sizeSet = PR_TRUE; + } + else if (!mCaptionFrame) { // The inner table isn't dirty so we don't need to reflow it, but make // sure it's placed correctly. It could be that we're dirty because the // caption was removed - mInnerTableFrame->MoveTo(aPresContext, 0,0); - - // Update our state so we calculate our desired size correctly - nsRect innerRect; + nsRect innerRect; mInnerTableFrame->GetRect(innerRect); - aReflowState.innerTableMaxSize.width = innerRect.width; - aReflowState.y = innerRect.height; - + nsSize innerSize(innerRect.width, innerRect.height); + nsPoint innerOrigin; + nsMargin innerMargin, innerPadding; + GetMarginPadding(aPresContext, aReflowState, mInnerTableFrame, innerMargin, + innerPadding); + nsSize containSize = GetContainingBlockSize(aReflowState); + GetInnerOrigin(aPresContext, NO_SIDE, containSize, nsSize(0,0), + nsMargin(0,0,0,0), innerSize, innerMargin, innerOrigin); + MoveFrameTo(aPresContext, mInnerTableFrame, innerOrigin.x, innerOrigin.y); + + aDesiredSize.width = innerRect.XMost() + innerMargin.right; + aDesiredSize.height = innerRect.YMost() + innerMargin.bottom; + sizeSet = PR_TRUE; // Repaint our entire bounds - // XXX Improve this... - Invalidate(aPresContext, nsRect(0, 0, mRect.width, mRect.height)); + Invalidate(aPresContext, nsRect(0, 0, aDesiredSize.width, aDesiredSize.height)); + } + if (!sizeSet) { + // set our desired size to what it was before + nsSize size = GetFrameSize(*this); + aDesiredSize.width = size.width; + aDesiredSize.height = size.height; } return rv; } // IR_TargetIsMe is free to foward the request to the inner table frame -nsresult nsTableOuterFrame::IR_TargetIsMe(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus) +nsresult nsTableOuterFrame::IR_TargetIsMe(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) { nsresult rv = NS_OK; nsIReflowCommand::ReflowType type; - aReflowState.reflowState.reflowCommand->GetType(type); + aReflowState.reflowCommand->GetType(type); nsIFrame* objectFrame; - aReflowState.reflowState.reflowCommand->GetChildFrame(objectFrame); + aReflowState.reflowCommand->GetChildFrame(objectFrame); switch (type) { case nsIReflowCommand::ReflowDirty: rv = IR_ReflowDirty(aPresContext, aDesiredSize, aReflowState, aStatus); @@ -700,186 +1128,164 @@ nsresult nsTableOuterFrame::IR_TargetIsMe(nsIPresContext* aPresContext, return rv; } -nsresult nsTableOuterFrame::IR_InnerTableReflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus) +nsresult +nsTableOuterFrame::IR_InnerTableReflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aOuterRS, + nsReflowStatus& aStatus) { - nsresult rv = NS_OK; - const nsStyleTable* captionTableStyle=nsnull; - // remember the old width and height - nsRect priorInnerTableRect; - mInnerTableFrame->GetRect(priorInnerTableRect); + PRUint8 captionSide = GetCaptionSide(); + + nsRect priorInnerRect; + mInnerTableFrame->GetRect(priorInnerRect); + + nsSize innerSize; + nsMargin innerMargin, innerPadding; + // pass along the reflow command to the inner table - nsHTMLReflowMetrics innerSize(aDesiredSize.maxElementSize); - nscoord tableMaxWidth = PR_MAX(aReflowState.reflowState.availableWidth, mMinCaptionWidth); - nsHTMLReflowState innerReflowState(aPresContext, aReflowState.reflowState, mInnerTableFrame, - nsSize(tableMaxWidth, aReflowState.reflowState.availableHeight)); - - // When the above reflow state is constructed, mComputedWidth and mComputedHeight get set - // to the table's styled width and height. Flex from XUL boxes can make the styled #s - // inaccurate, which means that mComputedWidth and mComputedHeight from the parent - // reflow state should be used instead. - - // The following function will patch the reflow state so that trees behave properly inside boxes. - // This might work for tables as well, but until regression tests can be run to make sure, - // I'm holding off on patching tables. - FixBadReflowState(aReflowState.reflowState, innerReflowState); + nsHTMLReflowMetrics innerMet(aDesiredSize.maxElementSize); - // Always request the maximum width if we are an auto layout table + // Always request the maximum width if we are an auto layout table XXX why? if (((nsTableFrame*)mInnerTableFrame)->IsAutoLayout()) { - innerSize.mFlags |= NS_REFLOW_CALC_MAX_WIDTH; + innerMet.mFlags |= NS_REFLOW_CALC_MAX_WIDTH; } - rv = ReflowChild(mInnerTableFrame, aPresContext, innerSize, innerReflowState, - 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus); - mInnerTableFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); - if (aDesiredSize.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { - aDesiredSize.mMaximumWidth = innerSize.mMaximumWidth; + nsresult rv = OuterReflowChild(aPresContext, mInnerTableFrame, aOuterRS, innerMet, + nsnull, innerSize, innerMargin, innerPadding, + eReflowReason_Incremental, aStatus); + if (NS_FAILED(rv)) return rv; - // Update the cached value - mInnerTableMaximumWidth = innerSize.mMaximumWidth; + if (innerMet.mFlags & NS_REFLOW_CALC_MAX_WIDTH) { + mInnerTableMaximumWidth = innerMet.mMaximumWidth; } + nsPoint innerOrigin(0,0); nsMargin captionMargin(0,0,0,0); - // if there is a caption and the width or height of the inner table changed from a successful reflow, - // then reflow or move the caption as needed - if ((nsnull != mCaptionFrame) && NS_SUCCEEDED(rv)) { - // remember the old caption height - nsRect oldCaptionRect; - mCaptionFrame->GetRect(oldCaptionRect); - nsHTMLReflowMetrics captionSize(nsnull); // don't ask for MES, it hasn't changed - PRBool captionDimChanged = PR_FALSE; - PRBool captionWasReflowed = PR_FALSE; - if (priorInnerTableRect.width != innerSize.width) { - // the table width changed, so reflow the caption - nsHTMLReflowState captionReflowState(aPresContext, aReflowState.reflowState, mCaptionFrame, - nsSize(innerSize.width, aReflowState.reflowState.availableHeight), - eReflowReason_Resize); - // reflow the caption - mCaptionFrame->WillReflow(aPresContext); - rv = mCaptionFrame->Reflow(aPresContext, captionSize, captionReflowState, aStatus); - mCaptionFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); - captionWasReflowed = PR_TRUE; - if ((oldCaptionRect.height != captionSize.height) || - (oldCaptionRect.width != captionSize.width)) { - captionDimChanged = PR_TRUE; - } - captionMargin = captionReflowState.mComputedMargin; + nsSize containSize = GetContainingBlockSize(aOuterRS); + PRBool reflowedCaption = PR_FALSE; + // if there is a caption and the width or height of the inner table changed + // from a reflow, then reflow or move the caption as needed + if (mCaptionFrame) { + if (priorInnerRect.width != innerMet.width) { + nsMargin ignorePadding; + // XXX only need to reflow if the caption is auto width + nsHTMLReflowMetrics captionMet(nsnull); // don't ask for MES, it hasn't changed + nsSize captionSize; + nscoord availWidth = GetCaptionAvailWidth(aPresContext, mCaptionFrame, aOuterRS, + &innerSize.width, &innerMargin); + rv = OuterReflowChild(aPresContext, mCaptionFrame, aOuterRS, captionMet, &availWidth, + captionSize, captionMargin, ignorePadding, eReflowReason_Resize, aStatus); + if (NS_FAILED(rv)) return rv; + + nsPoint captionOrigin; + GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, + innerMargin, captionSize, captionMargin, captionOrigin); + FinishReflowChild(mCaptionFrame, aPresContext, captionMet, + captionOrigin.x, captionOrigin.y, 0); + + GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, + captionMargin, innerSize, innerMargin, innerOrigin); + reflowedCaption = PR_TRUE; } - // XXX: should just call SizeAndPlaceChildren regardless - // find where to place the caption - mCaptionFrame->GetStyleData(eStyleStruct_Text, ((const nsStyleStruct *&)captionTableStyle)); - if ((priorInnerTableRect.height != innerSize.height) || captionDimChanged) { - if (!captionWasReflowed) { // get the computed margin by constructing a reflow state - nsHTMLReflowState rState(aPresContext, aReflowState.reflowState, mCaptionFrame, - nsSize(innerSize.width, aReflowState.reflowState.availableHeight), - eReflowReason_Resize); - captionMargin = rState.mComputedMargin; - } - // Compute the caption's y-origin - nscoord captionY = captionMargin.top; - if (NS_SIDE_BOTTOM == captionTableStyle->mCaptionSide) { - captionY += innerSize.height; - } - // Place the caption - nsRect captionRect(captionMargin.left, captionY, 0, 0); - if (PR_TRUE==captionWasReflowed) { - captionRect.SizeTo(captionSize.width, captionSize.height); - } - else { - captionRect.SizeTo(oldCaptionRect.width, oldCaptionRect.height); - } - mCaptionFrame->SetRect(aPresContext, captionRect); + else { + // reposition the caption frame if necessary and set the inner's origin + nsSize captionSize = GetFrameSize(*mCaptionFrame); + nsPoint captionOrigin; + nsMargin captionPadding; + GetMarginPadding(aPresContext, aOuterRS, mCaptionFrame, captionMargin, + captionPadding); + GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, + innerMargin, captionSize, captionMargin, captionOrigin); + GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, + captionMargin, innerSize, innerMargin, innerOrigin); + MoveFrameTo(aPresContext, mCaptionFrame, captionOrigin.x, captionOrigin.y); } } - // if anything above failed, we just want to return an error at this point - if (NS_FAILED(rv)) { - return rv; - } - // Place the inner table - nsRect updatedCaptionRect(0,0,0,0); - if (nsnull != mCaptionFrame) { - mCaptionFrame->GetRect(updatedCaptionRect); - } - nscoord innerY; // innerY is the y-offset of the inner table - if (nsnull != mCaptionFrame) { - // factor in caption and it's margin - // we're guaranteed that captionMargin and captionTableStyle are set at this point - if (NS_SIDE_BOTTOM != captionTableStyle->mCaptionSide) { - // top caption - innerY = 0; // the inner table goes at the top of the outer table - // the total v-space consumed is the inner table height + the caption height + the margin between them - aReflowState.y = innerSize.height + updatedCaptionRect.YMost() + captionMargin.top; - } - else { // bottom caption - innerY = updatedCaptionRect.YMost() + captionMargin.bottom; - // the total v-space consumed is the inner table height + the caption height + the margin between them - aReflowState.y = innerY + innerSize.height; - } - } - else { // no caption - innerY=0; - aReflowState.y = innerSize.height; - } - nsRect innerRect(0, innerY, innerSize.width, innerSize.height); - mInnerTableFrame->SetRect(aPresContext, innerRect); + FinishReflowChild(mInnerTableFrame, aPresContext, innerMet, + innerOrigin.x, innerOrigin.y, 0); + + UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, innerPadding, captionMargin); + nsSize desSize(aDesiredSize.width, aDesiredSize.height); + InvalidateDamage(aPresContext, captionSide, desSize, PR_TRUE, reflowedCaption); - aReflowState.innerTableMaxSize.width = innerSize.width; return rv; } - - /* the only difference between an insert and a replace is a replace checks the old maxElementSize and reflows the table only if it has changed */ -nsresult nsTableOuterFrame::IR_CaptionInserted(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus) -{ - nsresult rv = NS_OK; +nsresult +nsTableOuterFrame::IR_CaptionInserted(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aOuterRS, + nsReflowStatus& aStatus) +{ + PRUint8 captionSide = GetCaptionSide(); // reflow the caption frame, getting it's MES - nsSize maxElementSize; - nsHTMLReflowMetrics captionSize(&maxElementSize); - nsHTMLReflowState captionReflowState(aPresContext, aReflowState.reflowState, mCaptionFrame, - nsSize(mRect.width, aReflowState.reflowState.availableHeight), - eReflowReason_Initial); - // initial reflow of the caption - mCaptionFrame->WillReflow(aPresContext); - rv = mCaptionFrame->Reflow(aPresContext, captionSize, captionReflowState, aStatus); + nsSize captionSize; + nsMargin captionMargin, ignorePadding; + nsSize maxElementSize(0,0); + nsHTMLReflowMetrics captionMet(&maxElementSize); + // reflow the caption + nscoord availWidth = GetCaptionAvailWidth(aPresContext, mCaptionFrame, aOuterRS); + nsresult rv = OuterReflowChild(aPresContext, mCaptionFrame, aOuterRS, captionMet, + &availWidth, captionSize, captionMargin, ignorePadding, + eReflowReason_Initial, aStatus); + + if (NS_FAILED(rv)) return rv; + mMinCaptionWidth = maxElementSize.width; + + nsPoint captionOrigin(0,0); + nsMargin capAdjMargin = captionMargin; + ZeroAutoMargin(capAdjMargin); + + nsMargin innerMargin, innerPadding; + nsSize containSize = GetContainingBlockSize(aOuterRS); + PRBool reflowedInner = PR_FALSE; // XXX: caption align = left|right ignored here! - // if the caption's MES > table width, reflow the inner table - nsHTMLReflowMetrics innerSize(aDesiredSize.maxElementSize); - if (mMinCaptionWidth > mRect.width) { - nsHTMLReflowState innerReflowState(aPresContext, aReflowState.reflowState, mInnerTableFrame, - nsSize(mMinCaptionWidth, aReflowState.reflowState.availableHeight), - eReflowReason_Resize); - rv = ReflowChild(mInnerTableFrame, aPresContext, innerSize, innerReflowState, - 0, 0, NS_FRAME_NO_MOVE_FRAME, aStatus); - mInnerTableFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); + // if the caption's MES + margins > outer width, reflow the inner table + if (mMinCaptionWidth + capAdjMargin.left + capAdjMargin.right > mRect.width) { + nsHTMLReflowMetrics innerMet(aDesiredSize.maxElementSize); + nsSize innerSize; + + rv = OuterReflowChild(aPresContext, mInnerTableFrame, aOuterRS, innerMet, + nsnull, innerSize, innerMargin, innerPadding, + eReflowReason_Resize, aStatus); + if (NS_FAILED(rv)) return rv; + + nsPoint innerOrigin; + GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, + captionMargin, innerSize, innerMargin, innerOrigin); + rv = FinishReflowChild(mInnerTableFrame, aPresContext, innerMet, + innerOrigin.x, innerOrigin.y, 0); + if (NS_FAILED(rv)) return rv; + GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, + innerMargin, captionSize, captionMargin, captionOrigin); + reflowedInner = PR_TRUE; } - else { // set innerSize as if the inner table were reflowed - innerSize.height = mRect.height; - innerSize.width = mRect.width; - } - // set maxElementSize width if requested - if (nsnull != aDesiredSize.maxElementSize) { - ((nsTableFrame *)mInnerTableFrame)->SetMaxElementSize(aDesiredSize.maxElementSize, - aReflowState.reflowState.mComputedPadding); - if (mMinCaptionWidth > aDesiredSize.maxElementSize->width) { - aDesiredSize.maxElementSize->width = mMinCaptionWidth; - } + else { + // reposition the inner frame if necessary and set the caption's origin + nsSize innerSize = GetFrameSize(*mInnerTableFrame); + GetMarginPadding(aPresContext, aOuterRS, mInnerTableFrame, innerMargin, + innerPadding); + nsPoint innerOrigin; + GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, + captionMargin, innerSize, innerMargin, innerOrigin); + GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, + innerMargin, captionSize, captionMargin, captionOrigin); + MoveFrameTo(aPresContext, mInnerTableFrame, innerOrigin.x, innerOrigin.y); } - rv = SizeAndPlaceChildren(aPresContext, - nsSize (innerSize.width, innerSize.height), - nsSize (captionSize.width, captionSize.height), - aReflowState, captionReflowState.mComputedMargin); + rv = FinishReflowChild(mCaptionFrame, aPresContext, captionMet, + captionOrigin.x, captionOrigin.y, 0); + + UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, innerPadding, captionMargin); + nsSize desSize(aDesiredSize.width, aDesiredSize.height); + InvalidateDamage(aPresContext, captionSide, desSize, reflowedInner, PR_TRUE); + return rv; } @@ -891,42 +1297,8 @@ PRBool nsTableOuterFrame::IR_CaptionChangedAxis(const nsStyleTable* aOldStyle, return result; } -nsresult nsTableOuterFrame::SizeAndPlaceChildren(nsIPresContext* aPresContext, - const nsSize& aInnerSize, - const nsSize& aCaptionSize, - OuterTableReflowState& aReflowState, - const nsMargin& aCaptionMargin) -{ - nsresult rv = NS_OK; - // find where to place the caption - // Compute the caption's y-origin - nscoord captionY = aCaptionMargin.top; - const nsStyleTable* captionTableStyle; - mCaptionFrame->GetStyleData(eStyleStruct_Table, ((const nsStyleStruct *&)captionTableStyle)); - if (NS_SIDE_BOTTOM == captionTableStyle->mCaptionSide) { - captionY += aInnerSize.height; - } - // Place the caption - nsRect captionRect(aCaptionMargin.left, captionY, 0, 0); - captionRect.SizeTo(aCaptionSize.width, aCaptionSize.height); - mCaptionFrame->SetRect(aPresContext, captionRect); - // Place the inner table - nscoord innerY; - if (NS_SIDE_BOTTOM == captionTableStyle->mCaptionSide) { - // bottom caption - innerY = 0; - aReflowState.y = captionRect.YMost() + aCaptionMargin.bottom; - } - else { // top caption - innerY = captionRect.YMost() + aCaptionMargin.bottom; - aReflowState.y = innerY + aInnerSize.height; - } - nsRect innerRect(0, innerY, aInnerSize.width, aInnerSize.height); - mInnerTableFrame->SetRect(aPresContext, innerRect); - aReflowState.innerTableMaxSize.width = aInnerSize.width; - return rv; -} + /** * Reflow is a multi-step process. @@ -945,29 +1317,28 @@ nsresult nsTableOuterFrame::SizeAndPlaceChildren(nsIPresContext* aPresCon */ NS_METHOD nsTableOuterFrame::Reflow(nsIPresContext* aPresContext, nsHTMLReflowMetrics& aDesiredSize, - const nsHTMLReflowState& aReflowState, + const nsHTMLReflowState& aOuterRS, nsReflowStatus& aStatus) { DO_GLOBAL_REFLOW_COUNT("nsTableOuterFrame", aReflowState.reason); - if (nsDebugTable::gRflTableOuter) nsTableFrame::DebugReflow("TO::Rfl en", this, &aReflowState, nsnull); + if (nsDebugTable::gRflTableOuter) nsTableFrame::DebugReflow("TO::Rfl en", this, &aOuterRS, nsnull); + nsresult rv = NS_OK; + PRUint8 captionSide = GetCaptionSide(); + // Initialize out parameters - aDesiredSize.width = 0; - aDesiredSize.height = 0; + aDesiredSize.width = aDesiredSize.height = 0; if (nsnull != aDesiredSize.maxElementSize) { - aDesiredSize.maxElementSize->width = 0; + aDesiredSize.maxElementSize->width = 0; aDesiredSize.maxElementSize->height = 0; } aStatus = NS_FRAME_COMPLETE; - nsHTMLReflowMetrics captionSize(nsnull); - - // Initialize our local reflow state - OuterTableReflowState state(aPresContext, aReflowState); - if (eReflowReason_Incremental == aReflowState.reason) { - rv = IncrementalReflow(aPresContext, aDesiredSize, state, aStatus); - } else { - if (eReflowReason_Initial == aReflowState.reason) { + if (eReflowReason_Incremental == aOuterRS.reason) { + rv = IncrementalReflow(aPresContext, aDesiredSize, aOuterRS, aStatus); + } + else { + if (eReflowReason_Initial == aOuterRS.reason) { // Set up our kids. They're already present, on an overflow list, // or there are none so we'll create them now MoveOverflowToChildList(aPresContext); @@ -975,123 +1346,76 @@ NS_METHOD nsTableOuterFrame::Reflow(nsIPresContext* aPresContext, // Lay out the caption and get its maximum element size if (nsnull != mCaptionFrame) { nsSize maxElementSize; - captionSize.maxElementSize = &maxElementSize; - nsHTMLReflowState captionReflowState(aPresContext, aReflowState, mCaptionFrame, + nsHTMLReflowMetrics captionMet(&maxElementSize); + captionMet.maxElementSize = &maxElementSize; + nsHTMLReflowState captionReflowState(aPresContext, aOuterRS, mCaptionFrame, nsSize(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE), eReflowReason_Initial); mCaptionFrame->WillReflow(aPresContext); - rv = mCaptionFrame->Reflow(aPresContext, captionSize, captionReflowState, aStatus); + rv = mCaptionFrame->Reflow(aPresContext, captionMet, captionReflowState, aStatus); mCaptionFrame->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); mMinCaptionWidth = maxElementSize.width; - captionSize.maxElementSize = nsnull; } } // At this point, we must have an inner table frame, and we might have a caption - NS_ASSERTION(mFrames.NotEmpty(), "no children"); - NS_ASSERTION(nsnull != mInnerTableFrame, "no mInnerTableFrame"); - - nscoord availWidth = aReflowState.availableWidth; - - // If the caption max element size is larger, then use it instead. - // XXX: caption align = left|right ignored here! - if (mMinCaptionWidth > availWidth) { - availWidth = mMinCaptionWidth; - } + NS_ASSERTION(mFrames.NotEmpty() && mInnerTableFrame, "incomplete children"); + nsSize innerSize; + nsMargin innerMargin, innerPadding; // First reflow the inner table - nsHTMLReflowState innerReflowState(aPresContext, aReflowState, mInnerTableFrame, - nsSize(availWidth, aReflowState.availableHeight)); - innerReflowState.mComputedWidth = PR_MAX(aReflowState.mComputedWidth, mMinCaptionWidth); - innerReflowState.mComputedHeight = aReflowState.mComputedHeight; + nsHTMLReflowMetrics innerMet(aDesiredSize.maxElementSize); + rv = OuterReflowChild(aPresContext, mInnerTableFrame, aOuterRS, innerMet, + nsnull, innerSize, innerMargin, innerPadding, aOuterRS.reason, aStatus); + if (NS_FAILED(rv)) return rv; - nsHTMLReflowMetrics innerSize(aDesiredSize.maxElementSize); - // XXX To do this efficiently we really need to know where the inner - // table will be placed. In the case of a top caption that means - // reflowing the caption first and getting its desired height... - rv = ReflowChild(mInnerTableFrame, aPresContext, innerSize, innerReflowState, - 0, 0, 0, aStatus); - - if (NS_UNCONSTRAINEDSIZE == innerReflowState.availableWidth) { + if (NS_UNCONSTRAINEDSIZE == aOuterRS.availableWidth) { // Remember the inner table's maximum width - mInnerTableMaximumWidth = innerSize.width; + mInnerTableMaximumWidth = innerMet.width; } - // Table's max element size is the MAX of the caption's max element size - // and the inner table's max element size... - if (nsnull != aDesiredSize.maxElementSize) { - if (mMinCaptionWidth > aDesiredSize.maxElementSize->width) { - aDesiredSize.maxElementSize->width = mMinCaptionWidth; - } - } - state.innerTableMaxSize.width = innerSize.width; + nsPoint innerOrigin(0,0); + nsMargin captionMargin(0,0,0,0), ignorePadding; + nsSize captionSize(0,0); + nsSize containSize = GetContainingBlockSize(aOuterRS); // Now that we know the table width we can reflow the caption, and // place the caption and the inner table - nscoord innerY = 0; - if (nsnull != mCaptionFrame) { - // construct the caption reflow state - nscoord captionAvailWidth = PR_MAX(innerSize.width, mMinCaptionWidth); - nsHTMLReflowState captionReflowState(aPresContext, state.reflowState, mCaptionFrame, - nsSize(captionAvailWidth, NS_UNCONSTRAINEDSIZE), - eReflowReason_Resize); - // Compute the caption's y-origin - nscoord captionY = (NS_AUTOMARGIN == captionReflowState.mComputedMargin.top) - ? 0 : captionReflowState.mComputedMargin.top; - const nsStyleTable* captionTableStyle; - mCaptionFrame->GetStyleData(eStyleStruct_Table, ((const nsStyleStruct *&)captionTableStyle)); - if (NS_SIDE_BOTTOM == captionTableStyle->mCaptionSide) { - captionY += innerSize.height; - } + if (mCaptionFrame) { + // reflow the caption + nscoord availWidth = GetCaptionAvailWidth(aPresContext, mCaptionFrame, aOuterRS, + &innerSize.width, &innerMargin); + nsHTMLReflowMetrics captionMet(nsnull); + rv = OuterReflowChild(aPresContext, mCaptionFrame, aOuterRS, captionMet, + &availWidth, captionSize, captionMargin, ignorePadding, + aOuterRS.reason, aStatus); + if (NS_FAILED(rv)) return rv; - // Reflow the caption. Let it be as high as it wants - nscoord leftCapMargin = (NS_AUTOMARGIN == captionReflowState.mComputedMargin.left) - ? 0 : captionReflowState.mComputedMargin.left; - nsRect captionRect(leftCapMargin, captionY, 0, 0); - nsReflowStatus captionStatus; - captionSize.maxElementSize = nsnull; - ReflowChild(mCaptionFrame, aPresContext, captionSize, captionReflowState, - captionRect.x, captionRect.y, 0, captionStatus); - NS_ASSERTION(NS_FRAME_IS_COMPLETE(captionStatus), "unexpected reflow status"); + nsPoint captionOrigin; - // XXX If the height is constrained then we need to check whether the inner - // table still fits... + GetCaptionOrigin(aPresContext, captionSide, containSize, innerSize, + innerMargin, captionSize, captionMargin, captionOrigin); + FinishReflowChild(mCaptionFrame, aPresContext, captionMet, + captionOrigin.x, captionOrigin.y, 0); - // Place the caption - captionRect.SizeTo(captionSize.width, captionSize.height); - FinishReflowChild(mCaptionFrame, aPresContext, captionSize, - captionRect.x, captionRect.y, 0); - - // Place the inner table - nscoord bottomCapMargin = (NS_AUTOMARGIN == captionReflowState.mComputedMargin.bottom) - ? 0 : captionReflowState.mComputedMargin.bottom; - if (NS_SIDE_BOTTOM != captionTableStyle->mCaptionSide) { - // top caption - innerY = captionRect.YMost() + bottomCapMargin; - state.y = innerY + innerSize.height; - } - else { - // bottom caption - innerY = 0; - state.y = captionRect.YMost() + bottomCapMargin; - } + GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, + captionMargin, innerSize, innerMargin, innerOrigin); + // XXX If the height is constrained then we need to check whether the inner table still fits... } else { - // Place the inner table at 0 - innerY = 0; - state.y = innerSize.height; + GetInnerOrigin(aPresContext, captionSide, containSize, captionSize, + captionMargin, innerSize, innerMargin, innerOrigin); } - // Finish the inner table reflow - FinishReflowChild(mInnerTableFrame, aPresContext, innerSize, - 0, innerY, 0); + FinishReflowChild(mInnerTableFrame, aPresContext, innerMet, + innerOrigin.x, innerOrigin.y, 0); + + UpdateReflowMetrics(captionSide, aDesiredSize, innerMargin, innerPadding, captionMargin); } // Return our desired rect - aDesiredSize.width = PR_MAX(state.innerTableMaxSize.width, captionSize.width); - aDesiredSize.height = state.y; aDesiredSize.ascent = aDesiredSize.height; aDesiredSize.descent = 0; diff --git a/mozilla/layout/tables/nsTableOuterFrame.h b/mozilla/layout/tables/nsTableOuterFrame.h index 267e23dcf87..b7afd9857d7 100644 --- a/mozilla/layout/tables/nsTableOuterFrame.h +++ b/mozilla/layout/tables/nsTableOuterFrame.h @@ -27,7 +27,6 @@ #include "nsBlockFrame.h" #include "nsITableLayout.h" -struct OuterTableReflowState; struct nsStyleTable; class nsTableCaptionFrame : public nsBlockFrame @@ -74,6 +73,8 @@ public: NS_IMETHOD Destroy(nsIPresContext* aPresContext); + NS_IMETHOD IsPercentageBase(PRBool& aBase) const; + NS_IMETHOD AdjustZeroWidth(); /** @see nsIFrame::SetInitialChildList */ @@ -158,6 +159,11 @@ public: /** @see nsITableFrame::GetTableSize */ NS_IMETHOD GetTableSize(PRInt32& aRowCount, PRInt32& aColCount); + static void PositionView(nsIPresContext* aPresContext, + nsIFrame* aFrame); + + static void ZeroAutoMargin(nsMargin& aMargin); + protected: @@ -197,61 +203,59 @@ protected: virtual void DeleteChildsNextInFlow(nsIPresContext* aPresContext, nsIFrame* aChild); // begin Incremental Reflow methods - /** prepare aReflowState for an incremental reflow */ - NS_IMETHOD RecoverState(OuterTableReflowState& aReflowState, nsIFrame* aKidFrame); /** process an incremental reflow command */ - NS_IMETHOD IncrementalReflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus); + NS_IMETHOD IncrementalReflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); /** process an incremental reflow command targeted at a child of this frame. */ - NS_IMETHOD IR_TargetIsChild(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus, - nsIFrame * aNextFrame); + NS_IMETHOD IR_TargetIsChild(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus, + nsIFrame * aNextFrame); /** process an incremental reflow command targeted at the table inner frame. */ - NS_IMETHOD IR_TargetIsInnerTableFrame(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus); + NS_IMETHOD IR_TargetIsInnerTableFrame(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); /** process an incremental reflow command targeted at the caption. */ - NS_IMETHOD IR_TargetIsCaptionFrame(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus); + NS_IMETHOD IR_TargetIsCaptionFrame(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); /** process an incremental reflow command targeted at this frame. * many incremental reflows that are targeted at this outer frame * are actually handled by the inner frame. The logic to decide this * is here. */ - NS_IMETHOD IR_TargetIsMe(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus); + NS_IMETHOD IR_TargetIsMe(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); /** pass along the incremental reflow command to the inner table. */ - NS_IMETHOD IR_InnerTableReflow(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus); + NS_IMETHOD IR_InnerTableReflow(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); /** handle incremental reflow notification that a caption was inserted. */ - NS_IMETHOD IR_CaptionInserted(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus); + NS_IMETHOD IR_CaptionInserted(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); /** handle incremental reflow notification that we have dirty child frames */ - NS_IMETHOD IR_ReflowDirty(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, - OuterTableReflowState& aReflowState, - nsReflowStatus& aStatus); + NS_IMETHOD IR_ReflowDirty(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); /** handle incremental reflow notification that the caption style was changed * such that it is now left|right instead of top|bottom, or vice versa. @@ -259,25 +263,93 @@ protected: PRBool IR_CaptionChangedAxis(const nsStyleTable* aOldStyle, const nsStyleTable* aNewStyle) const; - /** set the size and the location of both the inner table frame and the caption. */ - NS_IMETHOD SizeAndPlaceChildren(nsIPresContext* aPresContext, - const nsSize& aInnerSize, - const nsSize& aCaptionSize, - OuterTableReflowState& aReflowState, - const nsMargin& aCaptionMargin); + // end Incremental Reflow methods -// end Incremental Reflow methods - - // The following function at least lets the tree widget work - // inside boxes. It repairs the reflow state after it's been - // screwed up by the nsHTMLReflowState code. + // When the reflow state is constructed, mComputedWidth and mComputedHeight get set + // to the table's styled width and height. Flex from XUL boxes can make the styled #s + // inaccurate, which means that mComputedWidth and mComputedHeight from the parent + // reflow state should be used instead. + + // The following function will patch the reflow state so that trees behave properly inside boxes. + // This might work for tables as well, but not until regression tests can be run to make sure, NS_IMETHOD FixBadReflowState(const nsHTMLReflowState& aParentReflowState, nsHTMLReflowState& aChildReflowState) { return NS_OK; }; + nsSize GetMaxElementSize(const nsMargin& aInnerMargin, + const nsMargin& aInnerPadding, + const nsMargin& aCaptionMargin); + + nscoord GetMaxWidth(PRUint8 aCaptionSide, + const nsMargin& aInnerMargin, + const nsMargin& aCaptionMargin); + + PRUint8 GetCaptionSide(); + + void SetDesiredSize(PRUint8 aCaptionSide, + const nsMargin& aInnerMargin, + const nsMargin& aCaptionMargin, + nscoord& aWidth, + nscoord& aHeight); + + NS_IMETHOD GetCaptionOrigin(nsIPresContext* aPresContext, + PRUint32 aCaptionSide, + const nsSize& aContainBlockSize, + const nsSize& aInnerSize, + const nsMargin& aInnerMargin, + const nsSize& aCaptionSize, + nsMargin& aCaptionMargin, + nsPoint& aOrigin); + + NS_IMETHOD GetInnerOrigin(nsIPresContext* aPresContext, + PRUint32 aCaptionSide, + const nsSize& aContainBlockSize, + const nsSize& aCaptionSize, + const nsMargin& aCaptionMargin, + const nsSize& aInnerSize, + nsMargin& aInnerMargin, + nsPoint& aOrigin); + + nscoord GetChildAvailWidth(nsIPresContext* aPresContext, + nsIFrame* aChildFrame, + const nsHTMLReflowState& aOuterRS, + nscoord aOuterWidth, + nsMargin& aMargin, + nsMargin& aPadding); + + nscoord GetCaptionAvailWidth(nsIPresContext* aPresContext, + nsIFrame* aCaptionFrame, + const nsHTMLReflowState& aReflowState, + nscoord* aInnerWidth = nsnull, + const nsMargin* aInnerMargin = nsnull); + + NS_IMETHOD OuterReflowChild(nsIPresContext* aPresContext, + nsIFrame* aChildFrame, + const nsHTMLReflowState& aOuterRS, + nsHTMLReflowMetrics& aMetrics, + nscoord* aAvailWidth, + nsSize& aDesiredSize, + nsMargin& aMargin, + nsMargin& aPadding, + nsReflowReason aReflowReason, + nsReflowStatus& aStatus); + + void UpdateReflowMetrics(PRUint8 aCaptionSide, + nsHTMLReflowMetrics& aMet, + const nsMargin& aInnerMargin, + const nsMargin& aInnerPadding, + const nsMargin& aCaptionPadding); + + void InvalidateDamage(nsIPresContext* aPresContext, + PRUint8 aCaptionSide, + nsSize& aOuterSize, + PRBool aInnerChanged, + PRBool aCaptionChanged); + + private: /** used to keep track of this frame's children */ - nsIFrame *mInnerTableFrame; // XXX this is redundant, mFrames holds the same - nsIFrame *mCaptionFrame; + nsIFrame* mInnerTableFrame; // XXX this is redundant, mFrames holds the same + nsIFrame* mCaptionFrame; /** used to track caption max element size */ PRInt32 mMinCaptionWidth; diff --git a/mozilla/layout/tables/nsTableRowFrame.cpp b/mozilla/layout/tables/nsTableRowFrame.cpp index 21a9fe1d0be..e7415d4880c 100644 --- a/mozilla/layout/tables/nsTableRowFrame.cpp +++ b/mozilla/layout/tables/nsTableRowFrame.cpp @@ -244,11 +244,10 @@ nsTableRowFrame::DidResize(nsIPresContext* aPresContext, const nsHTMLReflowState& aReflowState) { // Resize and re-align the cell frames based on our row height - nscoord cellMaxTopMargin = GetTopMargin(); - nscoord cellMaxBottomMargin = GetBottomMargin(); - nscoord rowCellHeight = mRect.height - cellMaxTopMargin - cellMaxBottomMargin; nsTableFrame* tableFrame; nsTableFrame::GetTableFrame(this, tableFrame); + if (!tableFrame) return; + nscoord cellSpacingY = tableFrame->GetCellSpacingY(); nsTableIterator iter(aPresContext, *this, eTableDIR); nsIFrame* cellFrame = iter.First(); @@ -258,7 +257,7 @@ nsTableRowFrame::DidResize(nsIPresContext* aPresContext, cellFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)kidDisplay)); if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay) { PRInt32 rowSpan = tableFrame->GetEffectiveRowSpan((nsTableCellFrame &)*cellFrame); - nscoord cellHeight = rowCellHeight; + nscoord cellHeight = mRect.height; // add in height of rows spanned beyond the 1st one nsIFrame* nextRow = nsnull; GetNextSibling(&nextRow); @@ -271,6 +270,7 @@ nsTableRowFrame::DidResize(nsIPresContext* aPresContext, cellHeight += rect.height; i++; } + cellHeight += cellSpacingY; nextRow->GetNextSibling(&nextRow); } @@ -365,20 +365,8 @@ NS_METHOD nsTableRowFrame::Paint(nsIPresContext* aPresContext, return rv; } nscoord cellSpacingX = tableFrame->GetCellSpacingX(); - nscoord halfCellSpacingY = - NSToCoordRound(((float)tableFrame->GetCellSpacingY()) / (float)2); // every row is short by the ending cell spacing X nsRect rect(0, 0, mRect.width + cellSpacingX, mRect.height); - // first row may have gotten too much cell spacing Y - if (tableFrame->GetRowCount() != 1) { - if (IsFirstRow(aPresContext, *tableFrame, *this)) { - rect.height -= halfCellSpacingY; - } - else { - rect.height += halfCellSpacingY; - rect.y -= halfCellSpacingY; - } - } nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this, aDirtyRect, rect, *color, *spacing, 0, 0); @@ -514,24 +502,6 @@ nscoord nsTableRowFrame::GetTallestChild() const return mTallestCell; } -nscoord nsTableRowFrame::GetTopMargin() const -{ - nsTableFrame *tableFrame; - nsTableFrame::GetTableFrame((nsIFrame*)this, tableFrame); - - // Only cells in the first row have a top margin - return (GetRowIndex() == 0) ? tableFrame->GetCellSpacingY() : 0; -} - -nscoord nsTableRowFrame::GetBottomMargin() const -{ - nsTableFrame *tableFrame; - nsTableFrame::GetTableFrame((nsIFrame*)this, tableFrame); - - // All cells have the same bottom margin - return tableFrame->GetCellSpacingY(); -} - /* GetMinRowSpan is needed for deviant cases where every cell in a row has a rowspan > 1. * It sets mMinRowSpan, which is used in FixMinCellHeight and PlaceChild */ @@ -636,14 +606,7 @@ void nsTableRowFrame::PlaceChild(nsIPresContext* aPresContext, aReflowState.maxCellHeight = aDesiredSize.height; // Update maxCellVertSpace - nsMargin margin; - - if (aReflowState.tableFrame->GetCellMarginData((nsTableCellFrame *)aKidFrame, margin) == NS_OK) { - nscoord height = aDesiredSize.height + margin.top + margin.bottom; - - if (height > aReflowState.maxCellVertSpace) - aReflowState.maxCellVertSpace = height; - } + aReflowState.maxCellVertSpace = PR_MAX(aDesiredSize.height, aReflowState.maxCellVertSpace); } #endif } @@ -880,7 +843,7 @@ NS_METHOD nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext, reason); nsReflowStatus status; rv = ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, - aReflowState.x, GetTopMargin(), 0, status); + aReflowState.x, 0, 0, status); #ifdef NS_DEBUG if (desiredSize.width > availWidth) { @@ -935,7 +898,7 @@ NS_METHOD nsTableRowFrame::ResizeReflow(nsIPresContext* aPresContext, // Place the child PlaceChild(aPresContext, aReflowState, kidFrame, desiredSize, - aReflowState.x, GetTopMargin(), + aReflowState.x, 0, aDesiredSize.maxElementSize, kidMaxElementSize); } @@ -996,6 +959,7 @@ nsTableRowFrame::InitialReflow(nsIPresContext* aPresContext, nscoord x = 0; nsTableFrame* table = aReflowState.tableFrame; PRBool isAutoLayout = table->IsAutoLayout(&aReflowState.reflowState); + nscoord cellSpacingX = table->GetCellSpacingX(); nsIFrame* kidFrame; if (nsnull==aStartFrame) @@ -1003,29 +967,20 @@ nsTableRowFrame::InitialReflow(nsIPresContext* aPresContext, else kidFrame = aStartFrame; - for ( ; nsnull != kidFrame; kidFrame->GetNextSibling(&kidFrame)) - { + for ( ; nsnull != kidFrame; kidFrame->GetNextSibling(&kidFrame)) { const nsStyleDisplay *kidDisplay; kidFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)kidDisplay)); - if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay) - { - // Get the child's margins - // Get the frame's margins - nsMargin kidMargin; - aReflowState.tableFrame->GetCellMarginData((nsTableCellFrame *)kidFrame, kidMargin); - + if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay) { // For the initial reflow always allow the child to be as high as it // wants. The default available width is also unconstrained so we can // get the child's maximum width nsSize kidAvailSize; nsHTMLReflowMetrics kidSize(nsnull); - if (isAutoLayout) - { + if (isAutoLayout) { kidAvailSize.SizeTo(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE); kidSize.maxElementSize=&kidMaxElementSize; } - else - { + else { PRInt32 colIndex; ((nsTableCellFrame *)kidFrame)->GetColIndex(colIndex); kidAvailSize.SizeTo(table->GetColumnWidth(colIndex), NS_UNCONSTRAINEDSIZE); @@ -1037,7 +992,7 @@ nsTableRowFrame::InitialReflow(nsIPresContext* aPresContext, eReflowReason_Initial); rv = ReflowChild(kidFrame, aPresContext, kidSize, kidReflowState, - x + kidMargin.left, kidMargin.top, 0, aStatus); + x + cellSpacingX, 0, 0, aStatus); // the following signals bugs in the content frames. if (kidMaxElementSize.width > kidSize.width) { @@ -1056,10 +1011,10 @@ nsTableRowFrame::InitialReflow(nsIPresContext* aPresContext, NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "unexpected child reflow status"); // Place the child - x += kidMargin.left; - PlaceChild(aPresContext, aReflowState, kidFrame, kidSize, x, kidMargin.top, + x += cellSpacingX; + PlaceChild(aPresContext, aReflowState, kidFrame, kidSize, x, 0, aDesiredSize.maxElementSize, &kidMaxElementSize); - x += kidSize.width + kidMargin.right; + x += kidSize.width + cellSpacingX; } else {// it's an unknown frame type, give it a generic reflow and ignore the results @@ -1108,10 +1063,6 @@ NS_METHOD nsTableRowFrame::RecoverState(nsIPresContext* aPresContext, frame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)kidDisplay)); if (NS_STYLE_DISPLAY_TABLE_CELL == kidDisplay->mDisplay) { - // Get the child's margins - nsMargin kidMargin; - aReflowState.tableFrame->GetCellMarginData((nsTableCellFrame *)frame, kidMargin); - // Update maxCellHeight and maxVertCellSpace. When determining this we // don't include cells that span rows PRInt32 rowSpan = aReflowState.tableFrame->GetEffectiveRowSpan((nsTableCellFrame &)*frame); @@ -1130,10 +1081,7 @@ NS_METHOD nsTableRowFrame::RecoverState(nsIPresContext* aPresContext, } // Update maxCellVertHeight - nscoord vertHeight = desiredSize.height + kidMargin.top + kidMargin.bottom; - if (vertHeight > aReflowState.maxCellVertSpace) { - aReflowState.maxCellVertSpace = vertHeight; - } + aReflowState.maxCellVertSpace = PR_MAX(desiredSize.height, aReflowState.maxCellVertSpace); } // Recover the max element size if requested @@ -1293,7 +1241,7 @@ NS_METHOD nsTableRowFrame::IR_TargetIsChild(nsIPresContext* aPresContext, // in a max width of NS_UNCONSTRAINEDSIZE, because the max width must match // the width of the previous reflow... rv = ReflowChild(aNextFrame, aPresContext, desiredSize, kidReflowState, - aReflowState.x, GetTopMargin(), 0, aStatus); + aReflowState.x, 0, 0, aStatus); // Update the cell layout data.. If the cell's maximum width changed, // then inform the table that its maximum width needs to be recomputed @@ -1334,7 +1282,7 @@ NS_METHOD nsTableRowFrame::IR_TargetIsChild(nsIPresContext* aPresContext, // Now place the child PlaceChild(aPresContext, aReflowState, aNextFrame, desiredSize, aReflowState.x, - GetTopMargin(), aDesiredSize.maxElementSize, &kidMaxElementSize); + 0, aDesiredSize.maxElementSize, &kidMaxElementSize); SetMaxChildHeight(aReflowState.maxCellHeight); diff --git a/mozilla/layout/tables/nsTableRowFrame.h b/mozilla/layout/tables/nsTableRowFrame.h index 44b3bff517a..892a04b45d6 100644 --- a/mozilla/layout/tables/nsTableRowFrame.h +++ b/mozilla/layout/tables/nsTableRowFrame.h @@ -168,8 +168,6 @@ public: /** returns the tallest child in this row (ignoring any cell with rowspans) */ nscoord GetTallestChild() const; - nscoord GetTopMargin() const; - nscoord GetBottomMargin() const; /** returns the ordinal position of this row in its table */ virtual PRInt32 GetRowIndex() const; diff --git a/mozilla/layout/tables/nsTableRowGroupFrame.cpp b/mozilla/layout/tables/nsTableRowGroupFrame.cpp index 303a57734ea..5e33ffd6485 100644 --- a/mozilla/layout/tables/nsTableRowGroupFrame.cpp +++ b/mozilla/layout/tables/nsTableRowGroupFrame.cpp @@ -181,23 +181,7 @@ NS_METHOD nsTableRowGroupFrame::Paint(nsIPresContext* aPresContext, if (NS_FAILED(rv) || (nsnull == tableFrame)) { return rv; } - nscoord halfCellSpacingY = - NSToCoordRound(((float)tableFrame->GetCellSpacingY()) / (float)2); - // every row group is short by the ending cell spacing X - nsRect rect(0, 0, mRect.width, mRect.height); - nsIFrame* firstRowGroup = nsnull; - tableFrame->FirstChild(aPresContext, nsnull, &firstRowGroup); - // first row group may have gotten too much cell spacing Y - if (tableFrame->GetRowCount() != 1) { - if (this == firstRowGroup) { - rect.height -= halfCellSpacingY; - } - else { - rect.height += halfCellSpacingY; - rect.y -= halfCellSpacingY; - } - } - + nsRect rect(0,0,mRect.width, mRect.height); nsCSSRendering::PaintBackground(aPresContext, aRenderingContext, this, aDirtyRect, rect, *color, *spacing, 0, 0); } @@ -335,7 +319,12 @@ NS_METHOD nsTableRowGroupFrame::ReflowMappedChildren(nsIPresContext* aPresC { nsSize kidMaxElementSize; nsSize* pKidMaxElementSize = (nsnull != aDesiredSize.maxElementSize) ? &kidMaxElementSize : nsnull; - nsresult rv = NS_OK; + + nsTableFrame* tableFrame = nsnull; + nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); + if (NS_FAILED(rv) || !tableFrame) return rv; + + nscoord cellSpacingY = tableFrame->GetCellSpacingY(); if (!ContinueReflow(nsnull, aPresContext, aReflowState.y, aReflowState.availSize.height)) return rv; @@ -413,12 +402,11 @@ NS_METHOD nsTableRowGroupFrame::ReflowMappedChildren(nsIPresContext* aPresC /* if the table has collapsing borders, we need to reset the length of the shared vertical borders * for the table and the cells that overlap this row */ - if ((eReflowReason_Initial != aReflowState.reflowState.reason) && (NS_STYLE_BORDER_COLLAPSE==borderStyle)) - { + if ((eReflowReason_Initial != aReflowState.reflowState.reason) && + (NS_STYLE_BORDER_COLLAPSE==borderStyle)) { const nsStyleDisplay *childDisplay; kidFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)childDisplay)); - if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay) - { + if (NS_STYLE_DISPLAY_TABLE_ROW == childDisplay->mDisplay) { PRInt32 rowIndex = ((nsTableRowFrame*)kidFrame)->GetRowIndex(); aReflowState.tableFrame->SetBorderEdgeLength(NS_SIDE_LEFT, rowIndex, @@ -446,13 +434,14 @@ NS_METHOD nsTableRowGroupFrame::ReflowMappedChildren(nsIPresContext* aPresC } } } + aReflowState.y += cellSpacingY; } else { // Adjust the running y-offset so we know where the next row should // be placed nsSize kidSize; kidFrame->GetSize(kidSize); - aReflowState.y += kidSize.height; + aReflowState.y += kidSize.height + cellSpacingY; } if (PR_FALSE==aDoSiblings) @@ -555,8 +544,8 @@ AllocateSpecialHeight(nsIPresContext* aPresContext, * Actual row heights are ultimately determined by the table, when the table * height attribute is factored in. */ -void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, - nsHTMLReflowMetrics& aDesiredSize, +void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, + nsHTMLReflowMetrics& aDesiredSize, const nsHTMLReflowState& aReflowState) { nsTableFrame* tableFrame = nsnull; @@ -597,11 +586,7 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, startRowIndex = ((nsTableRowFrame*)rowFrame)->GetRowIndex(); } // get the height of the tallest cell in the row (excluding cells that span rows) - nscoord maxCellHeight = ((nsTableRowFrame*)rowFrame)->GetTallestChild(); - nscoord topMargin = ((nsTableRowFrame*)rowFrame)->GetTopMargin(); - nscoord bottomMargin = ((nsTableRowFrame*)rowFrame)->GetBottomMargin(); - nscoord maxRowHeight = maxCellHeight + topMargin + bottomMargin; - rowHeights[rowIndex] = maxRowHeight; + rowHeights[rowIndex] = ((nsTableRowFrame*)rowFrame)->GetTallestChild(); // See if a cell spans into the row. If so we'll have to do step 2 if (!hasRowSpanningCell) { if (tableFrame->RowIsSpannedInto(rowIndex + startRowIndex)) { @@ -649,6 +634,7 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, if (rowSpan > 1) { // found a cell with rowspan > 1, determine the height // of the rows it spans nscoord heightOfRowsSpanned = 0; + nscoord cellSpacingOfRowsSpanned = 0; PRInt32 spanX; PRBool cellsOrigInSpan = PR_FALSE; // do any cells originate in the spanned rows for (spanX = 0; spanX < rowSpan; spanX++) { @@ -658,9 +644,11 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, heightOfRowsSpanned += rowHeights[rowIndex + spanX]; cellsOrigInSpan = PR_TRUE; } + if (0 != spanX) { + cellSpacingOfRowsSpanned += cellSpacingY; + } } - // reduce the height by top and bottom margins - nscoord availHeightOfRowsSpanned = heightOfRowsSpanned - cellSpacingY - cellSpacingY; + nscoord availHeightOfRowsSpanned = heightOfRowsSpanned + cellSpacingOfRowsSpanned; // see if the cell's height fits within the rows it spans. If this is // pass 1 then use the cell's desired height and not the current height @@ -675,7 +663,7 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, } if (availHeightOfRowsSpanned >= cellFrameSize.height) { - // yes the cell's height fits with the available space of the rows it + // the cell's height fits with the available space of the rows it // spans. Set the cell frame's height cellFrame->SizeTo(aPresContext, cellFrameSize.width, availHeightOfRowsSpanned); // Realign cell content based on new height @@ -800,6 +788,9 @@ void nsTableRowGroupFrame::CalculateRowHeights(nsIPresContext* aPresContext, nsSize rowSize; rowFrame->GetSize(rowSize); rowGroupHeight += rowSize.height; + if (0 != rowIndex) { + rowGroupHeight += cellSpacingY; + } GetNextFrame(rowFrame, &rowFrame); // Get the next row rowIndex++; @@ -1371,24 +1362,28 @@ NS_METHOD nsTableRowGroupFrame::IR_TargetIsMe(nsIPresContext* aPresContext, return rv; } -NS_METHOD nsTableRowGroupFrame::GetHeightOfRows(nsIPresContext* aPresContext, nscoord& aResult) +NS_METHOD nsTableRowGroupFrame::GetHeightOfRows(nsIPresContext* aPresContext, + nscoord& aResult) { + nsTableFrame* tableFrame = nsnull; + nsresult rv = nsTableFrame::GetTableFrame(this, tableFrame); + if (NS_FAILED(rv) || !tableFrame) return rv; + + nscoord cellSpacingY = tableFrame->GetCellSpacingY(); + // the rows in rowGroupFrame need to be expanded by rowHeightDelta[i] // and the rowgroup itself needs to be expanded by SUM(row height deltas) - nsIFrame * rowFrame=nsnull; - nsresult rv = FirstChild(aPresContext, nsnull, &rowFrame); - while ((NS_SUCCEEDED(rv)) && (nsnull!=rowFrame)) - { - const nsStyleDisplay *rowDisplay; + nsIFrame* rowFrame = nsnull; + rv = FirstChild(aPresContext, nsnull, &rowFrame); + while ((NS_SUCCEEDED(rv)) && (nsnull!=rowFrame)) { + const nsStyleDisplay* rowDisplay; rowFrame->GetStyleData(eStyleStruct_Display, ((const nsStyleStruct *&)rowDisplay)); - if (NS_STYLE_DISPLAY_TABLE_ROW == rowDisplay->mDisplay) - { + if (NS_STYLE_DISPLAY_TABLE_ROW == rowDisplay->mDisplay) { nsRect rowRect; rowFrame->GetRect(rowRect); aResult += rowRect.height; } - else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == rowDisplay->mDisplay) - { + else if (NS_STYLE_DISPLAY_TABLE_ROW_GROUP == rowDisplay->mDisplay) { ((nsTableRowGroupFrame*)rowFrame)->GetHeightOfRows(aPresContext, aResult); } GetNextFrame(rowFrame, &rowFrame); diff --git a/mozilla/layout/xul/base/src/nsBoxToBlockAdaptor.cpp b/mozilla/layout/xul/base/src/nsBoxToBlockAdaptor.cpp index 3c759279910..98e6f3efa3c 100644 --- a/mozilla/layout/xul/base/src/nsBoxToBlockAdaptor.cpp +++ b/mozilla/layout/xul/base/src/nsBoxToBlockAdaptor.cpp @@ -593,12 +593,6 @@ nsBoxToBlockAdaptor::Reflow(nsBoxLayoutState& aState, printf(" reason=%s %s",reflowReasonString,ch); #endif - - nsHTMLReflowState reflowState(aPresContext, aReflowState, mFrame, nsSize(size.width, NS_INTRINSICSIZE)); - reflowState.reason = reason; - if (reason != eReflowReason_Incremental) - reflowState.reflowCommand = nsnull; - if (size.height != NS_INTRINSICSIZE) { size.height -= (border.top + border.bottom); NS_ASSERTION(size.height >= 0,"Error top bottom border too large"); @@ -609,6 +603,12 @@ nsBoxToBlockAdaptor::Reflow(nsBoxLayoutState& aState, NS_ASSERTION(size.height >= 0,"Error left right border too large"); } + nsHTMLReflowState reflowState(aPresContext, aReflowState, mFrame, nsSize(size.width, NS_INTRINSICSIZE)); + reflowState.reason = reason; + if (reason != eReflowReason_Incremental) + reflowState.reflowCommand = nsnull; + + // XXX this needs to subtract out the border and padding of mFrame since it is content size reflowState.mComputedWidth = size.width; reflowState.mComputedHeight = size.height; #ifdef DEBUG_REFLOW diff --git a/mozilla/layout/xul/base/src/nsTreeOuterFrame.cpp b/mozilla/layout/xul/base/src/nsTreeOuterFrame.cpp index 13d7db22820..faa8ae68fd7 100644 --- a/mozilla/layout/xul/base/src/nsTreeOuterFrame.cpp +++ b/mozilla/layout/xul/base/src/nsTreeOuterFrame.cpp @@ -122,7 +122,6 @@ nsTreeOuterFrame::Reflow(nsIPresContext* aPresContext, return Reflow(aPresContext, aDesiredSize, goodState, aStatus); } - if (aReflowState.mComputedWidth == NS_UNCONSTRAINEDSIZE) { NS_WARNING("Inefficient XUL: Reflowing outer tree frame with unconstrained width, try giving it a width in CSS!"); nsHTMLReflowState goodState(aReflowState); diff --git a/mozilla/layout/xul/base/src/nsTreeRowGroupFrame.cpp b/mozilla/layout/xul/base/src/nsTreeRowGroupFrame.cpp index e551d4ede19..b39503c443d 100644 --- a/mozilla/layout/xul/base/src/nsTreeRowGroupFrame.cpp +++ b/mozilla/layout/xul/base/src/nsTreeRowGroupFrame.cpp @@ -1632,7 +1632,13 @@ nsTreeRowGroupFrame::ReflowScrollbar(nsIPresContext* aPresContext) nsXULAtoms::maxpos, value); if(value != maxpos){ + // mark as having dirty children to avoid generating a reflow on SetAttribute + PRBool dirtyChildren(mState & NS_FRAME_HAS_DIRTY_CHILDREN); + mState |= NS_FRAME_HAS_DIRTY_CHILDREN; scrollbarContent->SetAttribute(kNameSpaceID_None, nsXULAtoms::maxpos, maxpos, PR_TRUE); + if (!dirtyChildren) { + mState &= ~NS_FRAME_HAS_DIRTY_CHILDREN; + } } }