From 6e737cd1b056a4aefc88f997129dfcc259c25715 Mon Sep 17 00:00:00 2001 From: "bmlk%gmx.de" Date: Sat, 3 Jul 2004 09:42:51 +0000 Subject: [PATCH] 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 --- layout/base/nsCSSFrameConstructor.cpp | 74 +++++++++++++++---- .../html/style/src/nsCSSFrameConstructor.cpp | 74 +++++++++++++++---- 2 files changed, 118 insertions(+), 30 deletions(-) diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp index 1570f875af8d..0ef58094b87b 100644 --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -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) { diff --git a/layout/html/style/src/nsCSSFrameConstructor.cpp b/layout/html/style/src/nsCSSFrameConstructor.cpp index 1570f875af8d..0ef58094b87b 100644 --- a/layout/html/style/src/nsCSSFrameConstructor.cpp +++ b/layout/html/style/src/nsCSSFrameConstructor.cpp @@ -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) {