Bug 274516. Tables should use the ordered rowgroup array to decide which children to push, not just follow the sibling list. Also, repeating footers should not be pushed. r=bernd, sr=bzbarsky, a=choffman

This commit is contained in:
roc+%cs.cmu.edu 2005-02-16 20:02:14 +00:00
parent 344cf0f06e
commit 996d1e3d9e
4 changed files with 46 additions and 20 deletions

View File

@ -177,7 +177,7 @@ nsFrameList::AppendFrame(nsIFrame* aParent, nsIFrame* aFrame)
}
PRBool
nsFrameList::RemoveFrame(nsIFrame* aFrame)
nsFrameList::RemoveFrame(nsIFrame* aFrame, nsIFrame* aPrevSiblingHint)
{
NS_PRECONDITION(nsnull != aFrame, "null ptr");
if (nsnull != aFrame) {
@ -188,7 +188,10 @@ nsFrameList::RemoveFrame(nsIFrame* aFrame)
return PR_TRUE;
}
else {
nsIFrame* prevSibling = GetPrevSiblingFor(aFrame);
nsIFrame* prevSibling = aPrevSiblingHint;
if (!prevSibling || prevSibling->GetNextSibling() != aFrame) {
prevSibling = GetPrevSiblingFor(aFrame);
}
if (prevSibling) {
prevSibling->SetNextSibling(nextFrame);
return PR_TRUE;

View File

@ -79,8 +79,10 @@ public:
// Take aFrame out of the frame list. This also disconnects aFrame
// from the sibling list. This will return PR_FALSE if aFrame is
// nsnull or if aFrame is not in the list.
PRBool RemoveFrame(nsIFrame* aFrame);
// nsnull or if aFrame is not in the list. The second frame is
// a hint for the prev-sibling of aFrame; if the hint is correct,
// then this is O(1) time.
PRBool RemoveFrame(nsIFrame* aFrame, nsIFrame* aPrevSiblingHint = nsnull);
// Remove the first child from the list. The caller is assumed to be
// holding a reference to the first child. This call is equivalent

View File

@ -2179,15 +2179,27 @@ nsTableFrame::GetFirstBodyRowGroupFrame()
// Table specific version that takes into account repeated header and footer
// frames when continuing table frames
void
nsTableFrame::PushChildren(nsIFrame* aFromChild,
nsIFrame* aPrevSibling)
nsTableFrame::PushChildren(const nsAutoVoidArray& aFrames,
PRInt32 aPushFrom)
{
NS_PRECONDITION(nsnull != aFromChild, "null pointer");
NS_PRECONDITION(nsnull != aPrevSibling, "pushing first child");
NS_PRECONDITION(aPrevSibling->GetNextSibling() == aFromChild, "bad prev sibling");
NS_PRECONDITION(aPushFrom > 0, "pushing first child");
// Disconnect aFromChild from its previous sibling
aPrevSibling->SetNextSibling(nsnull);
// extract the frames from the array into a sibling list
nsFrameList frames;
nsIFrame* lastFrame = nsnull;
PRUint32 childX;
nsIFrame* prevSiblingHint =
NS_STATIC_CAST(nsIFrame*, aFrames.ElementAt(aPushFrom - 1));
for (childX = aPushFrom; childX < aFrames.Count(); ++childX) {
nsIFrame* f = NS_STATIC_CAST(nsIFrame*, aFrames.FastElementAt(childX));
// Don't push repeatable frames, do push non-rowgroup frames
if (f->GetType() != nsLayoutAtoms::tableRowGroupFrame ||
!NS_STATIC_CAST(nsTableRowGroupFrame*, f)->IsRepeatable()) {
mFrames.RemoveFrame(f, prevSiblingHint);
frames.InsertFrame(nsnull, lastFrame, f);
lastFrame = f;
}
}
if (nsnull != mNextInFlow) {
nsTableFrame* nextInFlow = (nsTableFrame*)mNextInFlow;
@ -2200,14 +2212,14 @@ nsTableFrame::PushChildren(nsIFrame* aFromChild,
}
// When pushing and pulling frames we need to check for whether any
// views need to be reparented.
for (nsIFrame* f = aFromChild; f; f = f->GetNextSibling()) {
for (nsIFrame* f = frames.FirstChild(); f; f = f->GetNextSibling()) {
nsHTMLContainerFrame::ReparentFrameView(GetPresContext(), f, this, nextInFlow);
}
nextInFlow->mFrames.InsertFrames(mNextInFlow, prevSibling, aFromChild);
nextInFlow->mFrames.InsertFrames(mNextInFlow, prevSibling, frames.FirstChild());
}
else {
// Add the frames to our overflow list
SetOverflowFrames(GetPresContext(), aFromChild);
SetOverflowFrames(GetPresContext(), frames.FirstChild());
}
}
@ -3146,7 +3158,7 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState,
if (doReflowChild) {
if (pageBreak) {
PushChildren(kidFrame, prevKidFrame);
PushChildren(rowGroups, childX);
aStatus = NS_FRAME_NOT_COMPLETE;
break;
}
@ -3209,7 +3221,7 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState,
if (nextRowGroupFrame) {
PlaceChild(aReflowState, kidFrame, desiredSize);
aStatus = NS_FRAME_NOT_COMPLETE;
PushChildren(nextRowGroupFrame, kidFrame);
PushChildren(rowGroups, childX + 1);
aLastChildReflowed = kidFrame;
break;
}
@ -3218,7 +3230,7 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState,
else { // we are not on top, push this rowgroup onto the next page
if (prevKidFrame) { // we had a rowgroup before so push this
aStatus = NS_FRAME_NOT_COMPLETE;
PushChildren(kidFrame, prevKidFrame);
PushChildren(rowGroups, childX);
aLastChildReflowed = prevKidFrame;
break;
}
@ -3256,12 +3268,17 @@ nsTableFrame::ReflowChildren(nsTableReflowState& aReflowState,
// Add the continuing frame to the sibling list
continuingFrame->SetNextSibling(kidFrame->GetNextSibling());
kidFrame->SetNextSibling(continuingFrame);
// Update rowGroups with the new rowgroup, just as it
// would have been if we had called OrderRowGroups
// again. Note that rowGroups doesn't get used again after
// we PushChildren below, anyway.
rowGroups.InsertElementAt(continuingFrame, childX + 1);
}
// We've used up all of our available space so push the remaining
// children to the next-in-flow
nsIFrame* nextSibling = kidFrame->GetNextSibling();
if (nsnull != nextSibling) {
PushChildren(nextSibling, kidFrame);
PushChildren(rowGroups, childX + 1);
}
if (repeatedFooter) {
kidAvailSize.height = repeatedFooterHeight;

View File

@ -686,8 +686,12 @@ protected:
nsIFrame* GetFirstBodyRowGroupFrame();
PRBool MoveOverflowToChildList(nsPresContext* aPresContext);
void PushChildren(nsIFrame* aFromChild,
nsIFrame* aPrevSibling);
/**
* Push all our child frames from the aFrames array, in order, starting from the
* frame at aPushFrom to the end of the array. The frames are put on our overflow
* list or moved directly to our next-in-flow if one exists.
*/
void PushChildren(const nsAutoVoidArray& aFrames, PRInt32 aPushFrom);
public:
// put the children frames in the display order (e.g. thead before tbody before tfoot)