fix a crash in table pseudo frame handling, where colgroups need a special handling as they hold only columns and and can not be parents of other frames , bug 239294 r/sr=dbaron

This commit is contained in:
bmlk%gmx.de 2004-07-03 09:42:51 +00:00
parent f297e8a3b0
commit 6e737cd1b0
2 changed files with 118 additions and 30 deletions

View File

@ -632,11 +632,40 @@ nsAbsoluteItems::AddChild(nsIFrame* aChild)
// Structures used to record the creation of pseudo table frames where
// the content belongs to some ancestor.
// PseudoFrames are necessary when the childframe cannot be the direct
// ancestor of the content based parent frame. The amount of necessary pseudo
// frames is limited as the worst case would be table frame nested directly
// into another table frame. So the member structures of nsPseudoFrames can be
// viewed as a ring buffer where you start with the necessary frame type and
// add higher frames as long as necessary to fit into the initial parent frame.
// mLowestType is some sort of stack pointer which shows the start of the
// ringbuffer. The insertion of pseudo frames can happen between every
// two frames so we need to push and pop the pseudo frame data when children
// of a frame are created.
// The colgroup frame is special as it can harbour only col children.
// Once all children of given frame are known, the pseudo frames can be
// processed that means attached to the corresponding parent frames.
// The behaviour is in general described at
// http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes
// however there are implementation details that extend the CSS 2.1
// specification:
// 1. every table frame is wrapped in an outer table frame, which is always a
// pseudo frame.
// 2. the outer table frame will be also created to hold a caption.
// 3. each table cell will have a pseudo inner table cell frame.
// 4. a colgroup frame is created between a column and a table
// 5. a rowgroup frame is created between a row and a table
// A table frame can only have rowgroups or column groups as children.
// A outer table frame can only have one caption and one table frame
// as children.
// Every table even if all table frames are specified will require the
// creation of two types of pseudo frames: the outer table frame and the inner
// table cell frames.
struct nsPseudoFrameData {
nsIFrame* mFrame;
nsFrameItems mChildList;
nsFrameItems mChildList2;
nsIFrame* mFrame; // created pseudo frame
nsFrameItems mChildList; // child frames pending to be added to the pseudo
nsFrameItems mChildList2; // child frames pending to be added to the pseudo
nsPseudoFrameData();
nsPseudoFrameData(nsPseudoFrameData& aOther);
@ -1808,7 +1837,8 @@ ProcessPseudoCellFrame(nsIPresContext* aPresContext,
return rv;
}
// limit the processing up to the frame type indicated by aHighestType.
// make a complete processing when aHighestType is null
static nsresult
ProcessPseudoFrames(nsIPresContext* aPresContext,
nsPseudoFrames& aPseudoFrames,
@ -1821,6 +1851,16 @@ ProcessPseudoFrames(nsIPresContext* aPresContext,
aHighestFrame = nsnull;
if (nsLayoutAtoms::tableFrame == aPseudoFrames.mLowestType) {
// if the processing should be limited to the colgroup frame and the
// table frame is the lowest type of created pseudo frames that
// can have pseudo frame children, process only the colgroup pseudo frames
// and leave the table frame untouched.
if (nsLayoutAtoms::tableColGroupFrame == aHighestType) {
if (aPseudoFrames.mColGroup.mFrame) {
rv = ProcessPseudoFrame(aPresContext, aPseudoFrames.mColGroup, aHighestFrame);
}
return rv;
}
rv = ProcessPseudoTableFrame(aPresContext, aPseudoFrames, aHighestFrame);
if (nsLayoutAtoms::tableOuterFrame == aHighestType) return rv;
@ -2046,6 +2086,10 @@ nsCSSFrameConstructor::CreatePseudoColGroupFrame(nsIPresShell* aPresS
if (NS_FAILED(rv)) return rv;
((nsTableColGroupFrame*)pseudo.mFrame)->SetColType(eColGroupAnonymousCol);
// Do not set aState.mPseudoFrames.mLowestType here as colgroup frame will
// be always below a table frame but we can not descent any further as col
// frames can not have children and will not wrap table foreign frames.
// set pseudo data for the parent
if (aState.mPseudoFrames.mTableInner.mFrame) {
aState.mPseudoFrames.mTableInner.mChildList.AddChild(pseudo.mFrame);
@ -2962,11 +3006,8 @@ nsCSSFrameConstructor::ConstructTableForeignFrame(nsIPresShell* aPres
nsIFrame* parentFrame = nsnull;
aIsPseudoParent = PR_FALSE;
// XXX form code needs to be fixed so that the forms can work
// without a frame.
nsIAtom *tag = aContent->Tag();
// Do not construct pseudo frames for trees
if (MustGeneratePseudoParent(aPresContext, aParentFrameIn, tag, aContent,
aStyleContext)) {
// this frame may have a pseudo parent, use block frame type to
@ -2976,21 +3017,24 @@ nsCSSFrameConstructor::ConstructTableForeignFrame(nsIPresShell* aPres
if (!aIsPseudoParent && !aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aPresContext, aState.mPseudoFrames, aChildItems);
}
//char buf[256];
//sprintf(buf, "anonymous frame constructed for %s", tag.get());
//NS_WARN_IF_FALSE(PR_FALSE, buf);
}
if (!parentFrame) return rv; // if pseudo frame wasn't created
NS_ASSERTION(parentFrame == aState.mPseudoFrames.mCellInner.mFrame,
// there are two situations where table related frames will wrap around
// foreign frames
// a) inner table cell, which is a pseudo frame
// b) caption frame which will be always a real frame.
NS_ASSERTION(nsLayoutAtoms::tableCaptionFrame == parentFrame->GetType() ||
parentFrame == aState.mPseudoFrames.mCellInner.mFrame,
"Weird parent in ConstructTableForeignFrame");
// Push the parent as the floater containing block
nsFrameConstructorSaveState saveState;
aState.PushFloatContainingBlock(parentFrame, saveState, PR_FALSE, PR_FALSE);
// save the pseudo frame state XXX - why
// save the pseudo frame state now, as descendants of the child frame may require
// other pseudo frame creations
nsPseudoFrames prevPseudoFrames;
aState.mPseudoFrames.Reset(&prevPseudoFrames);
@ -2998,7 +3042,7 @@ nsCSSFrameConstructor::ConstructTableForeignFrame(nsIPresShell* aPres
rv = ConstructFrame(aPresShell, aPresContext, aState, aContent, parentFrame, items);
aNewFrame = items.childList;
// restore the pseudo frame state XXX - why
// restore the pseudo frame state
aState.mPseudoFrames = prevPseudoFrames;
if (aIsPseudoParent) {

View File

@ -632,11 +632,40 @@ nsAbsoluteItems::AddChild(nsIFrame* aChild)
// Structures used to record the creation of pseudo table frames where
// the content belongs to some ancestor.
// PseudoFrames are necessary when the childframe cannot be the direct
// ancestor of the content based parent frame. The amount of necessary pseudo
// frames is limited as the worst case would be table frame nested directly
// into another table frame. So the member structures of nsPseudoFrames can be
// viewed as a ring buffer where you start with the necessary frame type and
// add higher frames as long as necessary to fit into the initial parent frame.
// mLowestType is some sort of stack pointer which shows the start of the
// ringbuffer. The insertion of pseudo frames can happen between every
// two frames so we need to push and pop the pseudo frame data when children
// of a frame are created.
// The colgroup frame is special as it can harbour only col children.
// Once all children of given frame are known, the pseudo frames can be
// processed that means attached to the corresponding parent frames.
// The behaviour is in general described at
// http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes
// however there are implementation details that extend the CSS 2.1
// specification:
// 1. every table frame is wrapped in an outer table frame, which is always a
// pseudo frame.
// 2. the outer table frame will be also created to hold a caption.
// 3. each table cell will have a pseudo inner table cell frame.
// 4. a colgroup frame is created between a column and a table
// 5. a rowgroup frame is created between a row and a table
// A table frame can only have rowgroups or column groups as children.
// A outer table frame can only have one caption and one table frame
// as children.
// Every table even if all table frames are specified will require the
// creation of two types of pseudo frames: the outer table frame and the inner
// table cell frames.
struct nsPseudoFrameData {
nsIFrame* mFrame;
nsFrameItems mChildList;
nsFrameItems mChildList2;
nsIFrame* mFrame; // created pseudo frame
nsFrameItems mChildList; // child frames pending to be added to the pseudo
nsFrameItems mChildList2; // child frames pending to be added to the pseudo
nsPseudoFrameData();
nsPseudoFrameData(nsPseudoFrameData& aOther);
@ -1808,7 +1837,8 @@ ProcessPseudoCellFrame(nsIPresContext* aPresContext,
return rv;
}
// limit the processing up to the frame type indicated by aHighestType.
// make a complete processing when aHighestType is null
static nsresult
ProcessPseudoFrames(nsIPresContext* aPresContext,
nsPseudoFrames& aPseudoFrames,
@ -1821,6 +1851,16 @@ ProcessPseudoFrames(nsIPresContext* aPresContext,
aHighestFrame = nsnull;
if (nsLayoutAtoms::tableFrame == aPseudoFrames.mLowestType) {
// if the processing should be limited to the colgroup frame and the
// table frame is the lowest type of created pseudo frames that
// can have pseudo frame children, process only the colgroup pseudo frames
// and leave the table frame untouched.
if (nsLayoutAtoms::tableColGroupFrame == aHighestType) {
if (aPseudoFrames.mColGroup.mFrame) {
rv = ProcessPseudoFrame(aPresContext, aPseudoFrames.mColGroup, aHighestFrame);
}
return rv;
}
rv = ProcessPseudoTableFrame(aPresContext, aPseudoFrames, aHighestFrame);
if (nsLayoutAtoms::tableOuterFrame == aHighestType) return rv;
@ -2046,6 +2086,10 @@ nsCSSFrameConstructor::CreatePseudoColGroupFrame(nsIPresShell* aPresS
if (NS_FAILED(rv)) return rv;
((nsTableColGroupFrame*)pseudo.mFrame)->SetColType(eColGroupAnonymousCol);
// Do not set aState.mPseudoFrames.mLowestType here as colgroup frame will
// be always below a table frame but we can not descent any further as col
// frames can not have children and will not wrap table foreign frames.
// set pseudo data for the parent
if (aState.mPseudoFrames.mTableInner.mFrame) {
aState.mPseudoFrames.mTableInner.mChildList.AddChild(pseudo.mFrame);
@ -2962,11 +3006,8 @@ nsCSSFrameConstructor::ConstructTableForeignFrame(nsIPresShell* aPres
nsIFrame* parentFrame = nsnull;
aIsPseudoParent = PR_FALSE;
// XXX form code needs to be fixed so that the forms can work
// without a frame.
nsIAtom *tag = aContent->Tag();
// Do not construct pseudo frames for trees
if (MustGeneratePseudoParent(aPresContext, aParentFrameIn, tag, aContent,
aStyleContext)) {
// this frame may have a pseudo parent, use block frame type to
@ -2976,21 +3017,24 @@ nsCSSFrameConstructor::ConstructTableForeignFrame(nsIPresShell* aPres
if (!aIsPseudoParent && !aState.mPseudoFrames.IsEmpty()) {
ProcessPseudoFrames(aPresContext, aState.mPseudoFrames, aChildItems);
}
//char buf[256];
//sprintf(buf, "anonymous frame constructed for %s", tag.get());
//NS_WARN_IF_FALSE(PR_FALSE, buf);
}
if (!parentFrame) return rv; // if pseudo frame wasn't created
NS_ASSERTION(parentFrame == aState.mPseudoFrames.mCellInner.mFrame,
// there are two situations where table related frames will wrap around
// foreign frames
// a) inner table cell, which is a pseudo frame
// b) caption frame which will be always a real frame.
NS_ASSERTION(nsLayoutAtoms::tableCaptionFrame == parentFrame->GetType() ||
parentFrame == aState.mPseudoFrames.mCellInner.mFrame,
"Weird parent in ConstructTableForeignFrame");
// Push the parent as the floater containing block
nsFrameConstructorSaveState saveState;
aState.PushFloatContainingBlock(parentFrame, saveState, PR_FALSE, PR_FALSE);
// save the pseudo frame state XXX - why
// save the pseudo frame state now, as descendants of the child frame may require
// other pseudo frame creations
nsPseudoFrames prevPseudoFrames;
aState.mPseudoFrames.Reset(&prevPseudoFrames);
@ -2998,7 +3042,7 @@ nsCSSFrameConstructor::ConstructTableForeignFrame(nsIPresShell* aPres
rv = ConstructFrame(aPresShell, aPresContext, aState, aContent, parentFrame, items);
aNewFrame = items.childList;
// restore the pseudo frame state XXX - why
// restore the pseudo frame state
aState.mPseudoFrames = prevPseudoFrames;
if (aIsPseudoParent) {