Bug 243519. Rework root element frame construction and the CanvasFrame so that the CanvasFrame is an abs-pos container and the root element frame can be positioned. r=fantasai,sr=dbaron

This commit is contained in:
Robert O'Callahan 2008-09-08 20:13:17 +12:00
parent 5afba26158
commit 311213e939
17 changed files with 463 additions and 371 deletions

View File

@ -3,6 +3,7 @@ load 143862-1.html
load 143862-2.html
load 243159-1.html
load 243159-2.xhtml
load 243519-1.html
load 306940-1.html
load 310267-1.xml
load 310638-1.svg

View File

@ -1806,9 +1806,9 @@ nsCSSFrameConstructor::nsCSSFrameConstructor(nsIDocument *aDocument,
, mUpdateCount(0)
, mQuotesDirty(PR_FALSE)
, mCountersDirty(PR_FALSE)
, mInitialContainingBlockIsAbsPosContainer(PR_FALSE)
, mIsDestroyingFrameTree(PR_FALSE)
, mRebuildAllStyleData(PR_FALSE)
, mHasRootAbsPosContainingBlock(PR_FALSE)
{
if (!gGotXBLFormPrefs) {
gGotXBLFormPrefs = PR_TRUE;
@ -3972,32 +3972,6 @@ nsCSSFrameConstructor::GetDisplay(nsIFrame* aFrame)
* END TABLE SECTION
***********************************************/
nsresult
nsCSSFrameConstructor::ConstructDocElementTableFrame(nsIContent* aDocElement,
nsIFrame* aParentFrame,
nsIFrame** aNewTableFrame,
nsFrameConstructorState& aState)
{
nsFrameItems frameItems;
// XXXbz this is wrong. We should at least be setting the fixed container in
// the framestate here. Better yet, we should pass through aState
// unmodified. Can't do that, though, because then a fixed or absolute
// positioned root table with auto offsets would look for a block to compute
// its hypothetical box and crash. So we just disable fixed positioning
// altogether in documents where the root is a table. Oh, well.
nsFrameConstructorState state(mPresShell, nsnull, nsnull, nsnull,
aState.mFrameState);
ConstructFrame(state, aDocElement, aParentFrame, frameItems);
*aNewTableFrame = frameItems.childList;
if (!*aNewTableFrame) {
NS_WARNING("cannot get table contentFrame");
// XXXbz maybe better to return the error from ConstructFrame?
return NS_ERROR_FAILURE;
}
return NS_OK;
}
static PRBool CheckOverflow(nsPresContext* aPresContext,
const nsStyleDisplay* aDisplay)
{
@ -4093,29 +4067,6 @@ nsCSSFrameConstructor::ConstructDocElementFrame(nsFrameConstructorState& aState,
nsIFrame* aParentFrame,
nsIFrame** aNewFrame)
{
// how the root frame hierarchy should look
/*
---------------No Scrollbars------
AreaFrame or BoxFrame (InitialContainingBlock)
---------------Gfx Scrollbars ------
ScrollFrame
^
|
|
AreaFrame or BoxFrame (InitialContainingBlock)
*/
*aNewFrame = nsnull;
if (!mTempFrameTreeState)
@ -4189,8 +4140,13 @@ nsCSSFrameConstructor::ConstructDocElementFrame(nsFrameConstructorState& aState,
"Scrollbars should have been propagated to the viewport");
#endif
nsIFrame* contentFrame = nsnull;
PRBool isBlockFrame = PR_FALSE;
nsFrameConstructorSaveState absoluteSaveState;
if (mHasRootAbsPosContainingBlock) {
// Push the absolute containing block now so we can absolutely position
// the root element
aState.PushAbsoluteContainingBlock(mDocElementContainingBlock, absoluteSaveState);
}
nsresult rv;
// The rules from CSS 2.1, section 9.2.4, have already been applied
@ -4202,19 +4158,40 @@ nsCSSFrameConstructor::ConstructDocElementFrame(nsFrameConstructorState& aState,
aDocElement->GetNameSpaceID(),
styleContext);
// contentFrame is the primary frame for the root element. *aNewFrame
// is the frame that will be the child of the initial containing block.
// These are usually the same frame but they can be different, in
// particular if the root frame is positioned, in which case
// contentFrame is the out-of-flow frame and *aNewFrame is the
// placeholder.
nsIFrame* contentFrame;
PRBool processChildren = PR_FALSE;
if (docElemIsTable) {
nsIFrame* innerTableFrame;
nsFrameItems frameItems;
// if the document is a table then just populate it.
rv = ConstructDocElementTableFrame(aDocElement, aParentFrame, &contentFrame,
aState);
if (NS_FAILED(rv)) {
rv = ConstructTableFrame(aState, aDocElement,
aParentFrame, styleContext,
kNameSpaceID_None, PR_FALSE, frameItems, contentFrame,
innerTableFrame);
if (NS_FAILED(rv))
return rv;
}
styleContext = contentFrame->GetStyleContext();
if (!contentFrame || !frameItems.childList)
return NS_ERROR_FAILURE;
*aNewFrame = frameItems.childList;
NS_ASSERTION(!frameItems.childList->GetNextSibling(),
"multiple root element frames");
} else {
// otherwise build a box or a block
#ifdef MOZ_XUL
if (aDocElement->IsNodeOfType(nsINode::eXUL)) {
contentFrame = NS_NewDocElementBoxFrame(mPresShell, styleContext);
if (NS_UNLIKELY(!contentFrame)) {
return NS_ERROR_OUT_OF_MEMORY;
}
InitAndRestoreFrame(aState, aDocElement, aParentFrame, nsnull, contentFrame);
*aNewFrame = contentFrame;
processChildren = PR_TRUE;
}
else
#endif
@ -4222,6 +4199,26 @@ nsCSSFrameConstructor::ConstructDocElementFrame(nsFrameConstructorState& aState,
if (aDocElement->GetNameSpaceID() == kNameSpaceID_SVG) {
if (aDocElement->Tag() == nsGkAtoms::svg && NS_SVGEnabled()) {
contentFrame = NS_NewSVGOuterSVGFrame(mPresShell, aDocElement, styleContext);
if (NS_UNLIKELY(!contentFrame)) {
return NS_ERROR_OUT_OF_MEMORY;
}
InitAndRestoreFrame(aState, aDocElement,
aState.GetGeometricParent(display, aParentFrame),
nsnull, contentFrame);
// AddChild takes care of transforming the frame tree for fixed-pos
// or abs-pos situations
nsFrameItems frameItems;
rv = aState.AddChild(contentFrame, frameItems, aDocElement,
styleContext, aParentFrame);
if (NS_FAILED(rv) || !frameItems.childList) {
return rv;
}
*aNewFrame = frameItems.childList;
processChildren = PR_TRUE;
// See if we need to create a view, e.g. the frame is absolutely positioned
nsHTMLContainerFrame::CreateViewForFrame(contentFrame, aParentFrame, PR_FALSE);
} else {
return NS_ERROR_FAILURE;
}
@ -4229,25 +4226,27 @@ nsCSSFrameConstructor::ConstructDocElementFrame(nsFrameConstructorState& aState,
else
#endif
{
contentFrame = NS_NewDocumentElementFrame(mPresShell, styleContext);
isBlockFrame = PR_TRUE;
contentFrame = NS_NewBlockFrame(mPresShell, styleContext,
NS_BLOCK_SPACE_MGR|NS_BLOCK_MARGIN_ROOT);
if (!contentFrame)
return NS_ERROR_OUT_OF_MEMORY;
nsFrameItems frameItems;
rv = ConstructBlock(aState, display, aDocElement,
aState.GetGeometricParent(display, aParentFrame),
aParentFrame, styleContext, &contentFrame,
frameItems, display->IsPositioned());
if (NS_FAILED(rv) || !frameItems.childList)
return rv;
*aNewFrame = frameItems.childList;
NS_ASSERTION(!frameItems.childList->GetNextSibling(),
"multiple root element frames");
}
if (NS_UNLIKELY(!contentFrame)) {
return NS_ERROR_OUT_OF_MEMORY;
}
// initialize the child
InitAndRestoreFrame(aState, aDocElement, aParentFrame, nsnull, contentFrame);
}
// set the primary frame
aState.mFrameManager->SetPrimaryFrameFor(aDocElement, contentFrame);
*aNewFrame = contentFrame;
mInitialContainingBlock = contentFrame;
mInitialContainingBlockIsAbsPosContainer = PR_FALSE;
// Figure out which frame has the main style for the document element,
// assigning it to mRootElementStyleFrame.
@ -4259,31 +4258,19 @@ nsCSSFrameConstructor::ConstructDocElementFrame(nsFrameConstructorState& aState,
mRootElementStyleFrame = mInitialContainingBlock;
}
// if it was a table then we don't need to process our children.
if (!docElemIsTable) {
// Process the child content
nsFrameConstructorSaveState absoluteSaveState;
nsFrameConstructorSaveState floatSaveState;
nsFrameItems childItems;
if (isBlockFrame) {
PRBool haveFirstLetterStyle, haveFirstLineStyle;
ShouldHaveSpecialBlockStyle(aDocElement, styleContext,
&haveFirstLetterStyle, &haveFirstLineStyle);
mInitialContainingBlockIsAbsPosContainer = PR_TRUE;
aState.PushAbsoluteContainingBlock(contentFrame, absoluteSaveState);
aState.PushFloatContainingBlock(contentFrame, floatSaveState,
haveFirstLetterStyle,
haveFirstLineStyle);
}
if (processChildren) {
// Still need to process the child content
nsFrameItems childItems;
// Create any anonymous frames the doc element frame requires
// This must happen before ProcessChildren to ensure that popups are
// never constructed before the popupset.
CreateAnonymousFrames(nsnull, aState, aDocElement, contentFrame,
PR_FALSE, childItems, PR_TRUE);
NS_ASSERTION(!nsLayoutUtils::GetAsBlock(contentFrame),
"Only XUL and SVG frames should reach here");
ProcessChildren(aState, aDocElement, contentFrame, PR_TRUE, childItems,
isBlockFrame);
PR_FALSE);
// Set the initial child lists
contentFrame->SetInitialChildList(nsnull, childItems.childList);
@ -4300,36 +4287,62 @@ nsCSSFrameConstructor::ConstructRootFrame(nsIContent* aDocElement,
AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
NS_PRECONDITION(aNewFrame, "null out param");
// how the root frame hierarchy should look
/*
how the root frame hierarchy should look
---------------No Scrollbars------
ViewPortFrame (FixedContainingBlock) <---- RootView
^
|
RootFrame(DocElementContainingBlock)
Galley presentation, non-XUL, with scrolling (i.e. not a frameset):
ViewportFrame [fixed-cb]
nsHTMLScrollFrame
CanvasFrame [abs-cb]
root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
nsTableOuterFrame, nsPlaceholderFrame)
Galley presentation, non-XUL, without scrolling (i.e. a frameset):
ViewportFrame [fixed-cb]
CanvasFrame [abs-cb]
root element frame (nsBlockFrame)
---------------Gfx Scrollbars ------
Galley presentation, XUL
ViewportFrame [fixed-cb]
nsRootBoxFrame
root element frame (nsDocElementBoxFrame)
Print presentation, non-XUL
ViewPortFrame (FixedContainingBlock) <---- RootView
ViewportFrame
nsSimplePageSequenceFrame
nsPageFrame [fixed-cb]
nsPageContentFrame
CanvasFrame [abs-cb]
root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
nsTableOuterFrame, nsPlaceholderFrame)
^
|
ScrollFrame
Print-preview presentation, non-XUL
^
|
RootFrame(DocElementContainingBlock)
*/
ViewportFrame
nsHTMLScrollFrame
nsSimplePageSequenceFrame
nsPageFrame [fixed-cb]
nsPageContentFrame
CanvasFrame [abs-cb]
root element frame (nsBlockFrame, nsSVGOuterSVGFrame,
nsTableOuterFrame, nsPlaceholderFrame)
Print/print preview of XUL is not supported.
[fixed-cb]: the default containing block for fixed-pos content
[abs-cb]: the default containing block for abs-pos content
Meaning of nsCSSFrameConstructor fields:
mInitialContainingBlock is "root element frame".
mDocElementContainingBlock is the parent of mInitialContainingBlock
(i.e. CanvasFrame or nsRootBoxFrame)
mFixedContainingBlock is the [fixed-cb]
mGfxScrollFrame is the nsHTMLScrollFrame mentioned above, or null if there isn't one
mPageSequenceFrame is the nsSimplePageSequenceFrame, or null if there isn't one
*/
// Set up our style rule observer.
{
@ -4394,6 +4407,7 @@ nsCSSFrameConstructor::ConstructRootFrame(nsIContent* aDocElement,
{
// pass a temporary stylecontext, the correct one will be set later
rootFrame = NS_NewCanvasFrame(mPresShell, viewportPseudoStyle);
mHasRootAbsPosContainingBlock = PR_TRUE;
}
rootPseudo = nsCSSAnonBoxes::canvas;
@ -4522,14 +4536,15 @@ nsCSSFrameConstructor::ConstructRootFrame(nsIContent* aDocElement,
if (isPaginated) { // paginated
// Create the first page
// Set the initial child lists
nsIFrame *pageFrame, *pageContentFrame;
nsIFrame *pageFrame, *canvasFrame;
ConstructPageFrame(mPresShell, presContext, rootFrame, nsnull,
pageFrame, pageContentFrame);
pageFrame, canvasFrame);
rootFrame->SetInitialChildList(nsnull, pageFrame);
// The eventual parent of the document element frame.
// XXX should this be set for every new page (in ConstructPageFrame)?
mDocElementContainingBlock = pageContentFrame;
mDocElementContainingBlock = canvasFrame;
mHasRootAbsPosContainingBlock = PR_TRUE;
}
viewportFrame->SetInitialChildList(nsnull, newFrame);
@ -4540,12 +4555,12 @@ nsCSSFrameConstructor::ConstructRootFrame(nsIContent* aDocElement,
}
nsresult
nsCSSFrameConstructor::ConstructPageFrame(nsIPresShell* aPresShell,
nsCSSFrameConstructor::ConstructPageFrame(nsIPresShell* aPresShell,
nsPresContext* aPresContext,
nsIFrame* aParentFrame,
nsIFrame* aPrevPageFrame,
nsIFrame*& aPageFrame,
nsIFrame*& aPageContentFrame)
nsIFrame* aParentFrame,
nsIFrame* aPrevPageFrame,
nsIFrame*& aPageFrame,
nsIFrame*& aCanvasFrame)
{
nsStyleContext* parentStyleContext = aParentFrame->GetStyleContext();
nsStyleSet *styleSet = aPresShell->StyleSet();
@ -4568,8 +4583,8 @@ nsCSSFrameConstructor::ConstructPageFrame(nsIPresShell* aPresShell,
nsCSSAnonBoxes::pageContent,
pagePseudoStyle);
aPageContentFrame = NS_NewPageContentFrame(aPresShell, pageContentPseudoStyle);
if (NS_UNLIKELY(!aPageContentFrame))
nsIFrame* pageContentFrame = NS_NewPageContentFrame(aPresShell, pageContentPseudoStyle);
if (NS_UNLIKELY(!pageContentFrame))
return NS_ERROR_OUT_OF_MEMORY;
// Initialize the page content frame and force it to have a view. Also make it the
@ -4579,10 +4594,26 @@ nsCSSFrameConstructor::ConstructPageFrame(nsIPresShell* aPresShell,
prevPageContentFrame = aPrevPageFrame->GetFirstChild(nsnull);
NS_ASSERTION(prevPageContentFrame, "missing page content frame");
}
aPageContentFrame->Init(nsnull, aPageFrame, prevPageContentFrame);
mFixedContainingBlock = aPageContentFrame;
pageContentFrame->Init(nsnull, aPageFrame, prevPageContentFrame);
aPageFrame->SetInitialChildList(nsnull, pageContentFrame);
mFixedContainingBlock = pageContentFrame;
aPageFrame->SetInitialChildList(nsnull, aPageContentFrame);
nsRefPtr<nsStyleContext> canvasPseudoStyle;
canvasPseudoStyle = styleSet->ResolvePseudoStyleFor(nsnull,
nsCSSAnonBoxes::canvas,
pageContentPseudoStyle);
aCanvasFrame = NS_NewCanvasFrame(aPresShell, canvasPseudoStyle);
if (NS_UNLIKELY(!aCanvasFrame))
return NS_ERROR_OUT_OF_MEMORY;
nsIFrame* prevCanvasFrame = nsnull;
if (prevPageContentFrame) {
prevCanvasFrame = prevPageContentFrame->GetFirstChild(nsnull);
NS_ASSERTION(prevCanvasFrame, "missing canvas frame");
}
aCanvasFrame->Init(nsnull, pageContentFrame, prevCanvasFrame);
pageContentFrame->SetInitialChildList(nsnull, aCanvasFrame);
return NS_OK;
}
@ -6681,17 +6712,24 @@ already_AddRefed<nsStyleContext>
nsCSSFrameConstructor::ResolveStyleContext(nsIFrame* aParentFrame,
nsIContent* aContent)
{
nsStyleContext* parentStyleContext;
nsStyleContext* parentStyleContext = nsnull;
if (aContent->GetParent()) {
aParentFrame = nsFrame::CorrectStyleParentFrame(aParentFrame, nsnull);
// Resolve the style context based on the content object and the parent
// style context
parentStyleContext = aParentFrame->GetStyleContext();
if (aParentFrame) {
// Resolve the style context based on the content object and the parent
// style context
parentStyleContext = aParentFrame->GetStyleContext();
} else {
// Perhaps aParentFrame is a canvasFrame and we're replicating
// fixed-pos frames.
// XXX should we create a way to tell ConstructFrame which style
// context to use, and pass it the style context for the
// previous page's fixed-pos frame?
}
} else {
// This has got to be a call from ConstructDocElementTableFrame.
// Not sure how best to asserrt that here.
parentStyleContext = nsnull;
// Not sure how best to assert that here.
}
nsStyleSet *styleSet = mPresShell->StyleSet();
@ -7507,23 +7545,40 @@ nsCSSFrameConstructor::ReconstructDocElementHierarchyInternal()
nsIContent *rootContent = mDocument->GetRootContent();
if (rootContent) {
// Before removing the frames associated with the content object, ask them to save their
// state onto a temporary state object.
CaptureStateForFramesOf(rootContent, mTempFrameTreeState);
nsFrameConstructorState state(mPresShell, mFixedContainingBlock,
nsnull, nsnull, mTempFrameTreeState);
// Before removing the frames associated with the content object, ask them to save their
// state onto a temporary state object.
CaptureStateFor(state.mFrameManager->GetRootFrame(), mTempFrameTreeState);
// Get the frame that corresponds to the document element
nsIFrame* docElementFrame =
state.mFrameManager->GetPrimaryFrameFor(rootContent, -1);
if (docElementFrame) {
// Destroy out-of-flow frames that might not be in the frame subtree
// rooted at docElementFrame
::DeletingFrameSubtree(state.mFrameManager, docElementFrame);
}
// Remove any existing fixed items: they are always on the
// FixedContainingBlock. Note that this has to be done before we call
// ClearPlaceholderFrameMap(), since RemoveFixedItems uses the
// placeholder frame map.
rv = RemoveFixedItems(state);
rv = RemoveFixedItems(state, docElementFrame);
if (NS_SUCCEEDED(rv)) {
nsPlaceholderFrame* placeholderFrame = nsnull;
if (docElementFrame &&
(docElementFrame->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) {
// Get the placeholder frame now, before we tear down the
// placeholder frame map
placeholderFrame =
state.mFrameManager->GetPlaceholderFrameFor(docElementFrame);
NS_ASSERTION(placeholderFrame, "No placeholder for out-of-flow?");
}
// Clear the hash tables that map from content to frame and out-of-flow
// frame to placeholder frame
state.mFrameManager->ClearPrimaryFrameMap();
@ -7532,20 +7587,24 @@ nsCSSFrameConstructor::ReconstructDocElementHierarchyInternal()
if (docElementFrame) {
// Take the docElementFrame, and remove it from its parent.
// XXXbz So why can't we reuse ContentRemoved?
NS_ASSERTION(docElementFrame->GetParent() == mDocElementContainingBlock,
"Unexpected doc element parent frame");
// Notify self that we will destroy the entire frame tree, this blocks
// RemoveMappingsForFrameSubtree() which would otherwise lead to a
// crash since we cleared the placeholder map above (bug 398982).
PRBool wasDestroyingFrameTree = mIsDestroyingFrameTree;
WillDestroyFrameTree();
// Remove the old document element hieararchy
rv = state.mFrameManager->RemoveFrame(mDocElementContainingBlock,
nsnull, docElementFrame);
rv = state.mFrameManager->RemoveFrame(docElementFrame->GetParent(),
GetChildListNameFor(docElementFrame), docElementFrame);
if (placeholderFrame) {
// Remove the placeholder frame first (XXX second for now) (so
// that it doesn't retain a dangling pointer to memory)
rv |= state.mFrameManager->RemoveFrame(placeholderFrame->GetParent(),
nsnull, placeholderFrame);
}
mIsDestroyingFrameTree = wasDestroyingFrameTree;
if (NS_FAILED(rv)) {
return rv;
@ -7642,9 +7701,8 @@ nsCSSFrameConstructor::GetAbsoluteContainingBlock(nsIFrame* aFrame)
if (containingBlock)
return AdjustAbsoluteContainingBlock(containingBlock);
// If we didn't find it, then use the initial containing block if it
// supports abs pos kids.
return mInitialContainingBlockIsAbsPosContainer ? mInitialContainingBlock : nsnull;
// If we didn't find it, then use the document element containing block
return mHasRootAbsPosContainingBlock ? mDocElementContainingBlock : nsnull;
}
nsIFrame*
@ -10229,9 +10287,9 @@ nsCSSFrameConstructor::CreateContinuingFrame(nsPresContext* aPresContext,
}
} else if (nsGkAtoms::pageFrame == frameType) {
nsIFrame* pageContentFrame;
nsIFrame* canvasFrame;
rv = ConstructPageFrame(shell, aPresContext, aParentFrame, aFrame,
newFrame, pageContentFrame);
newFrame, canvasFrame);
} else if (nsGkAtoms::tableOuterFrame == frameType) {
rv = CreateContinuingOuterTableFrame(shell, aPresContext, aFrame, aParentFrame,
content, styleContext, &newFrame);
@ -10420,17 +10478,17 @@ nsCSSFrameConstructor::CreateContinuingFrame(nsPresContext* aPresContext,
nsresult
nsCSSFrameConstructor::ReplicateFixedFrames(nsPageContentFrame* aParentFrame)
{
// Now deal with fixed-pos things.... They should appear on all pages, and
// the placeholders must be kids of a block, so we want to move over the
// placeholders when processing the child of the pageContentFrame.
// Now deal with fixed-pos things.... They should appear on all pages,
// so we want to move over the placeholders when processing the child
// of the pageContentFrame.
nsIFrame* prevPageContentFrame = aParentFrame->GetPrevInFlow();
if (!prevPageContentFrame) {
return NS_OK;
}
nsIFrame* docRootFrame = aParentFrame->GetFirstChild(nsnull);
nsIFrame* prevDocRootFrame = prevPageContentFrame->GetFirstChild(nsnull);
if (!docRootFrame || !prevDocRootFrame) {
nsIFrame* canvasFrame = aParentFrame->GetFirstChild(nsnull);
nsIFrame* prevCanvasFrame = prevPageContentFrame->GetFirstChild(nsnull);
if (!canvasFrame || !prevCanvasFrame) {
// document's root element frame missing
return NS_ERROR_UNEXPECTED;
}
@ -10458,19 +10516,19 @@ nsCSSFrameConstructor::ReplicateFixedFrames(nsPageContentFrame* aParentFrame)
nsIFrame* prevPlaceholder = nsnull;
mPresShell->GetPlaceholderFrameFor(fixed, &prevPlaceholder);
if (prevPlaceholder &&
nsLayoutUtils::IsProperAncestorFrame(prevDocRootFrame, prevPlaceholder)) {
nsLayoutUtils::IsProperAncestorFrame(prevCanvasFrame, prevPlaceholder)) {
nsresult rv = ConstructFrame(state, fixed->GetContent(),
docRootFrame, fixedPlaceholders);
canvasFrame, fixedPlaceholders);
NS_ENSURE_SUCCESS(rv, rv);
}
}
// Add the placeholders to our primary child list.
// XXXbz this is a little screwed up, since the fixed frames will have the
// wrong parent block and hence auto-positioning will be broken. Oh, well.
NS_ASSERTION(!docRootFrame->GetFirstChild(nsnull),
// XXXbz this is a little screwed up, since the fixed frames will have
// broken auto-positioning. Oh, well.
NS_ASSERTION(!canvasFrame->GetFirstChild(nsnull),
"leaking frames; doc root continuation must be empty");
docRootFrame->SetInitialChildList(nsnull, fixedPlaceholders.childList);
canvasFrame->SetInitialChildList(nsnull, fixedPlaceholders.childList);
return NS_OK;
}
@ -12801,7 +12859,9 @@ nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame)
return ReconstructDocElementHierarchyInternal();
}
nsresult nsCSSFrameConstructor::RemoveFixedItems(const nsFrameConstructorState& aState)
nsresult
nsCSSFrameConstructor::RemoveFixedItems(const nsFrameConstructorState& aState,
nsIFrame *aRootElementFrame)
{
nsresult rv=NS_OK;
@ -12809,6 +12869,12 @@ nsresult nsCSSFrameConstructor::RemoveFixedItems(const nsFrameConstructorState&
nsIFrame *fixedChild = nsnull;
do {
fixedChild = mFixedContainingBlock->GetFirstChild(nsGkAtoms::fixedList);
if (fixedChild && fixedChild == aRootElementFrame) {
// Skip the root element frame, if it happens to be fixed-positioned
// It will be explicitly removed later in
// ReconstructDocElementHierarchyInternal
fixedChild = fixedChild->GetNextSibling();
}
if (fixedChild) {
// Remove the placeholder so it doesn't end up sitting about pointing
// to the removed fixed frame.

View File

@ -270,7 +270,7 @@ private:
nsIFrame* aParentFrame,
nsIFrame* aPrevPageFrame,
nsIFrame*& aPageFrame,
nsIFrame*& aPageContentFrame);
nsIFrame*& aCanvasFrame);
void DoContentStateChanged(nsIContent* aContent,
PRInt32 aStateMask);
@ -1049,7 +1049,8 @@ private:
nsIFrame* aPrevSibling,
nsFrameItems& aFrameItems);
nsresult RemoveFixedItems(const nsFrameConstructorState& aState);
nsresult RemoveFixedItems(const nsFrameConstructorState& aState,
nsIFrame* aRootElementFrame);
// Find the right frame to use for aContent when looking for sibling
// frames for aTargetContent. If aPrevSibling is true, this
@ -1164,6 +1165,9 @@ private:
nsIDocument* mDocument; // Weak ref
nsIPresShell* mPresShell; // Weak ref
// See the comment at the start of ConstructRootFrame for more details
// about the following frames.
// This is not the real CSS 2.1 "initial containing block"! It is just
// the outermost frame for the root element.
nsIFrame* mInitialContainingBlock;
@ -1181,9 +1185,10 @@ private:
PRUint16 mUpdateCount;
PRPackedBool mQuotesDirty : 1;
PRPackedBool mCountersDirty : 1;
PRPackedBool mInitialContainingBlockIsAbsPosContainer : 1;
PRPackedBool mIsDestroyingFrameTree : 1;
PRPackedBool mRebuildAllStyleData : 1;
// This is true if mDocElementContainingBlock supports absolute positioning
PRPackedBool mHasRootAbsPosContainingBlock : 1;
nsRevocableEventPtr<RestyleEvent> mRestyleEvent;

View File

@ -52,17 +52,6 @@
#include "nsBlockFrame.h"
#endif
nsresult
nsAbsoluteContainingBlock::FirstChild(const nsIFrame* aDelegatingFrame,
nsIAtom* aListName,
nsIFrame** aFirstChild) const
{
NS_PRECONDITION(GetChildListName() == aListName, "unexpected child list name");
*aFirstChild = mAbsoluteFrames.FirstChild();
return NS_OK;
}
nsresult
nsAbsoluteContainingBlock::SetInitialChildList(nsIFrame* aDelegatingFrame,
nsIAtom* aListName,

View File

@ -84,10 +84,7 @@ public:
nsIAtom* GetChildListName() const { return mChildListName; }
#endif
nsresult FirstChild(const nsIFrame* aDelegatingFrame,
nsIAtom* aListName,
nsIFrame** aFirstChild) const;
nsIFrame* GetFirstChild() { return mAbsoluteFrames.FirstChild(); }
nsIFrame* GetFirstChild() const { return mAbsoluteFrames.FirstChild(); }
nsresult SetInitialChildList(nsIFrame* aDelegatingFrame,
nsIAtom* aListName,

View File

@ -520,9 +520,7 @@ nsIFrame*
nsBlockFrame::GetFirstChild(nsIAtom* aListName) const
{
if (nsGkAtoms::absoluteList == aListName) {
nsIFrame* result = nsnull;
mAbsoluteContainer.FirstChild(this, aListName, &result);
return result;
return mAbsoluteContainer.GetFirstChild();
}
else if (nsnull == aListName) {
return (mLines.empty()) ? nsnull : mLines.front()->mFirstChild;
@ -803,9 +801,11 @@ CalculateContainingBlockSizeForAbsolutes(const nsHTMLReflowState& aReflowState,
cbSize.width -= border.LeftRight();
cbSize.height -= border.TopBottom();
if (frame->GetParent()->GetContent() == frame->GetContent()) {
// We are a wrapped frame for the content. Use the container's
// dimensions, if they have been precomputed.
if (frame->GetParent()->GetContent() == frame->GetContent() &&
frame->GetParent()->GetType() != nsGkAtoms::canvasFrame) {
// We are a wrapped frame for the content (and the wrapper is not the
// canvas frame, whose size is not meaningful here).
// Use the container's dimensions, if they have been precomputed.
// XXX This is a hack! We really should be waiting until the outermost
// frame is fully reflowed and using the resulting dimensions, even
// if they're intrinsic.
@ -816,14 +816,10 @@ CalculateContainingBlockSizeForAbsolutes(const nsHTMLReflowState& aReflowState,
// content.
const nsHTMLReflowState* aLastRS = &aReflowState;
const nsHTMLReflowState* lastButOneRS = &aReflowState;
PRBool isCanvasBlock = PR_FALSE;
while (aLastRS->parentReflowState &&
aLastRS->parentReflowState->frame->GetContent() == frame->GetContent()) {
lastButOneRS = aLastRS;
aLastRS = aLastRS->parentReflowState;
if (aLastRS->frame->GetType() == nsGkAtoms::canvasFrame) {
isCanvasBlock = PR_TRUE;
}
}
if (aLastRS != &aReflowState) {
// Scrollbars need to be specifically excluded, if present, because they are outside the
@ -844,23 +840,11 @@ CalculateContainingBlockSizeForAbsolutes(const nsHTMLReflowState& aReflowState,
}
// We found a reflow state for the outermost wrapping frame, so use
// its computed metrics if available
// XXX grotesque hack for Firefox 2 compatibility until we can
// properly fix abs-pos containers! If this is the block for
// the root element, don't adjust the width here, just use the block's
// width. We have to do this because the abs-pos frame will be
// positioned relative to the block, not the canvas frame, and the
// block might have borders and margin which will throw things off
// if we use the canvas frame width.
// Positioning abs-pos frames relative to the canvas is bug 425432.
if (aLastRS->ComputedWidth() != NS_UNCONSTRAINEDSIZE && !isCanvasBlock) {
if (aLastRS->ComputedWidth() != NS_UNCONSTRAINEDSIZE) {
cbSize.width = PR_MAX(0,
aLastRS->ComputedWidth() + aLastRS->mComputedPadding.LeftRight() - scrollbars.LeftRight());
}
if (aLastRS->ComputedHeight() != NS_UNCONSTRAINEDSIZE) {
// XXX This can be terribly wrong if we're the root element's block,
// because our margin and borders will be included in the height
// here but the abs-pos element(s) are positioned relative to
// our content rect...
cbSize.height = PR_MAX(0,
aLastRS->ComputedHeight() + aLastRS->mComputedPadding.TopBottom() - scrollbars.TopBottom());
}

View File

@ -1592,6 +1592,9 @@ nsContainerFrame::List(FILE* out, PRInt32 aIndent) const
PRInt32 listIndex = 0;
PRBool outputOneList = PR_FALSE;
do {
if (!outputOneList) {
fputs("\n", out);
}
nsIFrame* kid = GetFirstChild(listName);
if (nsnull != kid) {
if (outputOneList) {

View File

@ -5561,12 +5561,19 @@ nsFrame::CorrectStyleParentFrame(nsIFrame* aProspectiveParent,
parent = parent->GetParent();
} while (parent);
// We can get here if aProspectiveParent is the scrollframe for a viewport
// and the kids are the anonymous scrollbars.
NS_ASSERTION(aProspectiveParent->GetStyleContext()->GetPseudoType() ==
nsCSSAnonBoxes::viewportScroll,
if (aProspectiveParent->GetStyleContext()->GetPseudoType() ==
nsCSSAnonBoxes::viewportScroll) {
// aProspectiveParent is the scrollframe for a viewport
// and the kids are the anonymous scrollbars
return aProspectiveParent;
}
// We can get here if the root element is absolutely positioned.
// We can't test for this very accurately, but it can only happen
// when the prospective parent is a canvas frame.
NS_ASSERTION(aProspectiveParent->GetType() == nsGkAtoms::canvasFrame,
"Should have found a parent before this");
return aProspectiveParent;
return nsnull;
}
nsresult

View File

@ -54,6 +54,7 @@
#include "nsIPresShell.h"
#include "nsIScrollPositionListener.h"
#include "nsDisplayList.h"
#include "nsAbsoluteContainingBlock.h"
// for focus
#include "nsIDOMWindowInternal.h"
@ -67,6 +68,8 @@
//#define DEBUG_CANVAS_FOCUS
#endif
#define CANVAS_ABS_POS_CHILD_LIST NS_CONTAINER_LIST_COUNT_INCL_OC
// Interface IDs
/**
@ -81,7 +84,8 @@ class CanvasFrame : public nsHTMLContainerFrame,
public nsICanvasFrame {
public:
CanvasFrame(nsStyleContext* aContext)
: nsHTMLContainerFrame(aContext), mDoPaintFocus(PR_FALSE) {}
: nsHTMLContainerFrame(aContext), mDoPaintFocus(PR_FALSE),
mAbsoluteContainer(nsGkAtoms::absoluteList) {}
// nsISupports
NS_IMETHOD QueryInterface(const nsIID& aIID, void** aInstancePtr);
@ -91,6 +95,8 @@ public:
nsIFrame* aPrevInFlow);
virtual void Destroy();
NS_IMETHOD SetInitialChildList(nsIAtom* aListName,
nsIFrame* aChildList);
NS_IMETHOD AppendFrames(nsIAtom* aListName,
nsIFrame* aFrameList);
NS_IMETHOD InsertFrames(nsIAtom* aListName,
@ -99,6 +105,9 @@ public:
NS_IMETHOD RemoveFrame(nsIAtom* aListName,
nsIFrame* aOldFrame);
virtual nsIAtom* GetAdditionalChildListName(PRInt32 aIndex) const;
virtual nsIFrame* GetFirstChild(nsIAtom* aListName) const;
virtual nscoord GetMinWidth(nsIRenderingContext *aRenderingContext);
virtual nscoord GetPrefWidth(nsIRenderingContext *aRenderingContext);
NS_IMETHOD Reflow(nsPresContext* aPresContext,
@ -106,6 +115,11 @@ public:
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus);
virtual PRBool IsContainingBlock() const { return PR_TRUE; }
virtual PRBool IsFrameOfType(PRUint32 aFlags) const
{
return nsHTMLContainerFrame::IsFrameOfType(aFlags &
~(nsIFrame::eCanContainOverflowContainers));
}
NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
@ -128,6 +142,21 @@ public:
*/
virtual nsIAtom* GetType() const;
virtual nsresult StealFrame(nsPresContext* aPresContext,
nsIFrame* aChild,
PRBool aForceNormal)
{
NS_ASSERTION(!aForceNormal, "No-one should be passing this in here");
// CanvasFrame keeps overflow container continuations of its child
// frame in main child list
nsresult rv = nsContainerFrame::StealFrame(aPresContext, aChild, PR_TRUE);
if (NS_FAILED(rv)) {
rv = nsContainerFrame::StealFrame(aPresContext, aChild);
}
return rv;
}
#ifdef DEBUG
NS_IMETHOD GetFrameName(nsAString& aResult) const;
#endif
@ -141,8 +170,9 @@ protected:
virtual PRIntn GetSkipSides() const;
// Data members
PRPackedBool mDoPaintFocus;
nsCOMPtr<nsIViewManager> mViewManager;
PRPackedBool mDoPaintFocus;
nsCOMPtr<nsIViewManager> mViewManager;
nsAbsoluteContainingBlock mAbsoluteContainer;
private:
NS_IMETHOD_(nsrefcnt) AddRef() { return NS_OK; }
@ -198,6 +228,8 @@ CanvasFrame::Init(nsIContent* aContent,
void
CanvasFrame::Destroy()
{
mAbsoluteContainer.DestroyFrames(this);
nsIScrollableView* scrollingView = nsnull;
mViewManager->GetRootScrollableView(&scrollingView);
if (scrollingView) {
@ -246,20 +278,32 @@ CanvasFrame::SetHasFocus(PRBool aHasFocus)
{
if (mDoPaintFocus != aHasFocus) {
mDoPaintFocus = aHasFocus;
nsIViewManager* vm = PresContext()->PresShell()->GetViewManager();
if (vm) {
vm->UpdateAllViews(NS_VMREFRESH_NO_SYNC);
}
mViewManager->UpdateAllViews(NS_VMREFRESH_NO_SYNC);
}
return NS_OK;
}
NS_IMETHODIMP
CanvasFrame::SetInitialChildList(nsIAtom* aListName,
nsIFrame* aChildList)
{
if (nsGkAtoms::absoluteList == aListName)
return mAbsoluteContainer.SetInitialChildList(this, aListName, aChildList);
NS_ASSERTION(aListName || !aChildList || !aChildList->GetNextSibling(),
"Primary child list can have at most one frame in it");
return nsHTMLContainerFrame::SetInitialChildList(aListName, aChildList);
}
NS_IMETHODIMP
CanvasFrame::AppendFrames(nsIAtom* aListName,
nsIFrame* aFrameList)
{
nsresult rv;
if (nsGkAtoms::absoluteList == aListName)
return mAbsoluteContainer.AppendFrames(this, aListName, aFrameList);
NS_ASSERTION(!aListName, "unexpected child list name");
NS_PRECONDITION(mFrames.IsEmpty(), "already have a child frame");
if (aListName) {
@ -292,6 +336,9 @@ CanvasFrame::InsertFrames(nsIAtom* aListName,
{
nsresult rv;
if (nsGkAtoms::absoluteList == aListName)
return mAbsoluteContainer.InsertFrames(this, aListName, aPrevFrame, aFrameList);
// Because we only support a single child frame inserting is the same
// as appending
NS_PRECONDITION(!aPrevFrame, "unexpected previous sibling frame");
@ -310,6 +357,9 @@ CanvasFrame::RemoveFrame(nsIAtom* aListName,
{
nsresult rv;
if (nsGkAtoms::absoluteList == aListName)
return mAbsoluteContainer.RemoveFrame(this, aListName, aOldFrame);
NS_ASSERTION(!aListName, "unexpected child list name");
if (aListName) {
// We only support the unnamed principal child list
@ -335,6 +385,24 @@ CanvasFrame::RemoveFrame(nsIAtom* aListName,
return rv;
}
nsIAtom*
CanvasFrame::GetAdditionalChildListName(PRInt32 aIndex) const
{
if (CANVAS_ABS_POS_CHILD_LIST == aIndex)
return nsGkAtoms::absoluteList;
return nsHTMLContainerFrame::GetAdditionalChildListName(aIndex);
}
nsIFrame*
CanvasFrame::GetFirstChild(nsIAtom* aListName) const
{
if (nsGkAtoms::absoluteList == aListName)
return mAbsoluteContainer.GetFirstChild();
return nsHTMLContainerFrame::GetFirstChild(aListName);
}
nsRect CanvasFrame::CanvasArea() const
{
nsRect result(GetOverflowRect());
@ -419,6 +487,13 @@ CanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsDisplayListSet& aLists)
{
nsresult rv;
if (GetPrevInFlow()) {
DisplayOverflowContainers(aBuilder, aDirtyRect, aLists);
}
aBuilder->MarkFramesForDisplayList(this, mAbsoluteContainer.GetFirstChild(), aDirtyRect);
// Force a background to be shown. We may have a background propagated to us,
// in which case GetStyleBackground wouldn't have the right background
// and the code in nsFrame::DisplayBorderBackgroundOutline might not give us
@ -432,8 +507,8 @@ CanvasFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
NS_ENSURE_SUCCESS(rv, rv);
}
nsIFrame* kid = GetFirstChild(nsnull);
if (kid) {
nsIFrame* kid;
for (kid = GetFirstChild(nsnull); kid; kid = kid->GetNextSibling()) {
// Put our child into its own pseudo-stack.
rv = BuildDisplayListForChild(aBuilder, kid, aDirtyRect, aLists,
DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT);
@ -528,7 +603,7 @@ CanvasFrame::GetPrefWidth(nsIRenderingContext *aRenderingContext)
}
NS_IMETHODIMP
CanvasFrame::Reflow(nsPresContext* aPresContext,
CanvasFrame::Reflow(nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
const nsHTMLReflowState& aReflowState,
nsReflowStatus& aStatus)
@ -540,7 +615,28 @@ CanvasFrame::Reflow(nsPresContext* aPresContext,
// Initialize OUT parameter
aStatus = NS_FRAME_COMPLETE;
// Reflow our one and only child frame
CanvasFrame* prevCanvasFrame = static_cast<CanvasFrame*>
(GetPrevInFlow());
if (prevCanvasFrame) {
nsIFrame* overflow = prevCanvasFrame->GetOverflowFrames(aPresContext, PR_TRUE);
if (overflow) {
NS_ASSERTION(!overflow->GetNextSibling(),
"must have doc root as canvas frame's only child");
nsHTMLContainerFrame::ReparentFrameView(aPresContext, overflow, prevCanvasFrame, this);
// Prepend overflow to the our child list. There may already be
// children placeholders for fixed-pos elements, which don't get
// reflowed but must not be lost until the canvas frame is destroyed.
mFrames.InsertFrames(this, nsnull, overflow);
}
}
// Reflow our one and only normal child frame. It's either the root
// element's frame or a placeholder for that frame, if the root element
// is abs-pos or fixed-pos. We may have additional children which
// are placeholders for continuations of fixed-pos content, but those
// don't need to be reflowed. The normal child is always comes before
// the fixed-pos placeholders, because we insert it at the start
// of the child list, above.
nsHTMLReflowMetrics kidDesiredSize;
if (mFrames.IsEmpty()) {
// We have no child frame, so return an empty size
@ -549,11 +645,9 @@ CanvasFrame::Reflow(nsPresContext* aPresContext,
nsIFrame* kidFrame = mFrames.FirstChild();
PRBool kidDirty = (kidFrame->GetStateBits() & NS_FRAME_IS_DIRTY) != 0;
// We must specify an unconstrained available height, because constrained
// is only for when we're paginated...
nsHTMLReflowState kidReflowState(aPresContext, aReflowState, kidFrame,
nsSize(aReflowState.availableWidth,
NS_UNCONSTRAINEDSIZE));
aReflowState.availableHeight));
if (aReflowState.mFlags.mVResize &&
(kidFrame->GetStateBits() & NS_FRAME_CONTAINS_RELATIVE_HEIGHT)) {
@ -561,16 +655,44 @@ CanvasFrame::Reflow(nsPresContext* aPresContext,
// hack for framesets.
kidReflowState.mFlags.mVResize = PR_TRUE;
}
nsPoint kidPt(kidReflowState.mComputedMargin.left,
kidReflowState.mComputedMargin.top);
// Apply CSS relative positioning
const nsStyleDisplay* styleDisp = kidFrame->GetStyleDisplay();
if (NS_STYLE_POSITION_RELATIVE == styleDisp->mPosition) {
kidPt += nsPoint(kidReflowState.mComputedOffsets.left,
kidReflowState.mComputedOffsets.top);
}
// Reflow the frame
ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState,
kidReflowState.mComputedMargin.left, kidReflowState.mComputedMargin.top,
0, aStatus);
kidPt.x, kidPt.y, 0, aStatus);
// Complete the reflow and position and size the child frame
FinishReflowChild(kidFrame, aPresContext, &kidReflowState, kidDesiredSize,
kidReflowState.mComputedMargin.left,
kidReflowState.mComputedMargin.top, 0);
kidPt.x, kidPt.y, 0);
if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
nsIFrame* nextFrame = kidFrame->GetNextInFlow();
NS_ASSERTION(nextFrame || aStatus & NS_FRAME_REFLOW_NEXTINFLOW,
"If it's incomplete and has no nif yet, it must flag a nif reflow.");
if (!nextFrame) {
nsresult rv = nsHTMLContainerFrame::CreateNextInFlow(aPresContext,
this, kidFrame, nextFrame);
NS_ENSURE_SUCCESS(rv, rv);
kidFrame->SetNextSibling(nextFrame->GetNextSibling());
nextFrame->SetNextSibling(nsnull);
SetOverflowFrames(aPresContext, nextFrame);
// Root overflow containers will be normal children of
// the canvas frame, but that's ok because there
// aren't any other frames we need to isolate them from
// during reflow.
}
if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) {
nextFrame->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
}
}
// If the child frame was just inserted, then we're responsible for making sure
// it repaints
@ -586,20 +708,35 @@ CanvasFrame::Reflow(nsPresContext* aPresContext,
nsIFrame* viewport = PresContext()->GetPresShell()->GetRootFrame();
viewport->Invalidate(nsRect(nsPoint(0, 0), viewport->GetSize()));
}
// Return our desired size (which doesn't matter)
aDesiredSize.width = aReflowState.availableWidth;
aDesiredSize.height = kidDesiredSize.height +
kidReflowState.mComputedMargin.TopBottom();
aDesiredSize.width = aReflowState.ComputedWidth();
aDesiredSize.height = aReflowState.ComputedHeight();
aDesiredSize.mOverflowArea.UnionRect(
nsRect(0, 0, aDesiredSize.width, aDesiredSize.height),
kidDesiredSize.mOverflowArea +
nsPoint(kidReflowState.mComputedMargin.left,
kidReflowState.mComputedMargin.top));
FinishAndStoreOverflow(&aDesiredSize);
kidDesiredSize.mOverflowArea + kidPt);
if (mAbsoluteContainer.HasAbsoluteFrames()) {
PRBool widthChanged = aDesiredSize.width != mRect.width;
PRBool heightChanged = aDesiredSize.height != mRect.height;
nsRect absPosBounds;
mAbsoluteContainer.Reflow(this, aPresContext, aReflowState, aStatus,
aDesiredSize.width, aDesiredSize.height,
PR_TRUE, widthChanged, heightChanged,
&absPosBounds);
aDesiredSize.mOverflowArea.UnionRect(aDesiredSize.mOverflowArea, absPosBounds);
}
}
if (prevCanvasFrame) {
ReflowOverflowContainerChildren(aPresContext, aReflowState,
aDesiredSize.mOverflowArea, 0,
aStatus);
}
FinishAndStoreOverflow(&aDesiredSize);
NS_FRAME_TRACE_REFLOW_OUT("CanvasFrame::Reflow", aStatus);
NS_FRAME_SET_TRUNCATION(aStatus, aReflowState, aDesiredSize);
return NS_OK;

View File

@ -113,31 +113,24 @@ NS_NewTableCellInnerFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) {
return NS_NewBlockFrame(aPresShell, aContext);
}
// This type of AreaFrame is the document root, a margin root, and the
// initial containing block for absolutely positioned elements
inline nsIFrame*
NS_NewDocumentElementFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) {
return NS_NewAreaFrame(aPresShell, aContext, NS_BLOCK_SPACE_MGR|NS_BLOCK_MARGIN_ROOT);
}
// This type of AreaFrame is a margin root, but does not shrink wrap
// This type of BlockFrame is a margin root, but does not shrink wrap
inline nsIFrame*
NS_NewAbsoluteItemWrapperFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) {
return NS_NewAreaFrame(aPresShell, aContext, NS_BLOCK_SPACE_MGR|NS_BLOCK_MARGIN_ROOT);
return NS_NewBlockFrame(aPresShell, aContext, NS_BLOCK_SPACE_MGR|NS_BLOCK_MARGIN_ROOT);
}
// This type of AreaFrame shrink wraps
// This type of BlockFrame shrink wraps
inline nsIFrame*
NS_NewFloatingItemWrapperFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) {
return NS_NewAreaFrame(aPresShell, aContext,
return NS_NewBlockFrame(aPresShell, aContext,
NS_BLOCK_SPACE_MGR|NS_BLOCK_MARGIN_ROOT);
}
// This type of AreaFrame doesn't use its own space manager and
// This type of BlockFrame doesn't use its own space manager and
// doesn't shrink wrap.
inline nsIFrame*
NS_NewRelativeItemWrapperFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, PRUint32 aFlags) {
return NS_NewAreaFrame(aPresShell, aContext, aFlags);
return NS_NewBlockFrame(aPresShell, aContext, aFlags);
}
nsIFrame*

View File

@ -1531,25 +1531,7 @@ nsHTMLReflowState::ComputeContainingBlockRectangle(nsPresContext* aPres
// If the ancestor is block-level, the containing block is formed by the
// padding edge of the ancestor
aContainingBlockWidth += aContainingBlockRS->mComputedPadding.LeftRight();
// If the containing block is the initial containing block and it has a
// height that depends on its content, then use the viewport height instead.
// This gives us a reasonable value against which to compute percentage
// based heights and to do bottom relative positioning
if ((NS_AUTOHEIGHT == aContainingBlockHeight) &&
nsLayoutUtils::IsInitialContainingBlock(aContainingBlockRS->frame)) {
// Use the viewport height as the containing block height
const nsHTMLReflowState* rs = aContainingBlockRS->parentReflowState;
while (rs) {
aContainingBlockHeight = rs->mComputedHeight;
rs = rs->parentReflowState;
}
} else {
aContainingBlockHeight +=
aContainingBlockRS->mComputedPadding.TopBottom();
}
aContainingBlockHeight += aContainingBlockRS->mComputedPadding.TopBottom();
}
} else {
// an element in quirks mode gets a containing block based on looking for a

View File

@ -1073,11 +1073,8 @@ nsPositionedInlineFrame::GetAdditionalChildListName(PRInt32 aIndex) const
nsIFrame*
nsPositionedInlineFrame::GetFirstChild(nsIAtom* aListName) const
{
if (nsGkAtoms::absoluteList == aListName) {
nsIFrame* result = nsnull;
mAbsoluteContainer.FirstChild(this, aListName, &result);
return result;
}
if (nsGkAtoms::absoluteList == aListName)
return mAbsoluteContainer.GetFirstChild();
return nsInlineFrame::GetFirstChild(aListName);
}

View File

@ -69,55 +69,6 @@ nsPageContentFrame::ComputeSize(nsIRenderingContext *aRenderingContext,
return nsSize(aAvailableWidth, height);
}
/**
* Returns true if aFrame is a placeholder for one of our fixed frames.
*/
inline PRBool
nsPageContentFrame::IsFixedPlaceholder(nsIFrame* aFrame)
{
if (!aFrame || nsGkAtoms::placeholderFrame != aFrame->GetType())
return PR_FALSE;
return static_cast<nsPlaceholderFrame*>(aFrame)->GetOutOfFlowFrame()
->GetParent() == this;
}
/**
* Steals replicated fixed placeholder frames from aDocRoot so they don't
* get in the way of reflow.
*/
inline nsFrameList
nsPageContentFrame::StealFixedPlaceholders(nsIFrame* aDocRoot)
{
nsPresContext* presContext = PresContext();
nsFrameList list;
if (GetPrevInFlow()) {
for (nsIFrame* f = aDocRoot->GetFirstChild(nsnull);
IsFixedPlaceholder(f); f = aDocRoot->GetFirstChild(nsnull)) {
nsresult rv = static_cast<nsContainerFrame*>(aDocRoot)
->StealFrame(presContext, f);
NS_ENSURE_SUCCESS(rv, list);
list.AppendFrame(nsnull, f);
}
}
return list;
}
/**
* Restores stolen replicated fixed placeholder frames to aDocRoot.
*/
static inline nsresult
ReplaceFixedPlaceholders(nsIFrame* aDocRoot,
nsFrameList& aPlaceholderList)
{
nsresult rv = NS_OK;
if (aPlaceholderList.NotEmpty()) {
rv = static_cast<nsContainerFrame*>(aDocRoot)
->AddFrames(aPlaceholderList.FirstChild(), nsnull);
}
return rv;
}
NS_IMETHODIMP
nsPageContentFrame::Reflow(nsPresContext* aPresContext,
nsHTMLReflowMetrics& aDesiredSize,
@ -129,67 +80,27 @@ nsPageContentFrame::Reflow(nsPresContext* aPresContext,
aStatus = NS_FRAME_COMPLETE; // initialize out parameter
nsresult rv = NS_OK;
// A PageContentFrame must always have one child: the doc root element's frame.
// We only need to get overflow frames if we don't already have that child;
// Also we need to avoid repeating the call to ReplicateFixedFrames.
nsPageContentFrame* prevPageContentFrame = static_cast<nsPageContentFrame*>
(GetPrevInFlow());
if (mFrames.IsEmpty() && prevPageContentFrame) {
// Pull the doc root frame's continuation and copy fixed frames.
nsIFrame* overflow = prevPageContentFrame->GetOverflowFrames(aPresContext, PR_TRUE);
NS_ASSERTION(overflow && !overflow->GetNextSibling(),
"must have doc root as pageContentFrame's only child");
nsHTMLContainerFrame::ReparentFrameView(aPresContext, overflow, prevPageContentFrame, this);
// Prepend overflow to the page content frame. There may already be
// children placeholders which don't get reflowed but must not be
// lost until the page content frame is destroyed.
mFrames.InsertFrames(this, nsnull, overflow);
if (GetPrevInFlow() && (GetStateBits() & NS_FRAME_FIRST_REFLOW)) {
nsresult rv = aPresContext->PresShell()->FrameConstructor()
->ReplicateFixedFrames(this);
NS_ENSURE_SUCCESS(rv, rv);
}
// A PageContentFrame must always have one child: the canvas frame.
// Resize our frame allowing it only to be as big as we are
// XXX Pay attention to the page's border and padding...
if (mFrames.NotEmpty()) {
nsIFrame* frame = mFrames.FirstChild();
nsSize maxSize(aReflowState.availableWidth, aReflowState.availableHeight);
nsHTMLReflowState kidReflowState(aPresContext, aReflowState, frame, maxSize);
kidReflowState.SetComputedHeight(aReflowState.availableHeight);
mPD->mPageContentSize = aReflowState.availableWidth;
// Get replicated fixed frames' placeholders out of the way
nsFrameList stolenPlaceholders = StealFixedPlaceholders(frame);
// Reflow the page content area
rv = ReflowChild(frame, aPresContext, aDesiredSize, kidReflowState, 0, 0, 0, aStatus);
NS_ENSURE_SUCCESS(rv, rv);
// Put removed fixed placeholders back
rv = ReplaceFixedPlaceholders(frame, stolenPlaceholders);
NS_ENSURE_SUCCESS(rv, rv);
if (!NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
nsIFrame* nextFrame = frame->GetNextInFlow();
NS_ASSERTION(nextFrame || aStatus & NS_FRAME_REFLOW_NEXTINFLOW,
"If it's incomplete and has no nif yet, it must flag a nif reflow.");
if (!nextFrame) {
nsresult rv = nsHTMLContainerFrame::CreateNextInFlow(aPresContext,
this, frame, nextFrame);
NS_ENSURE_SUCCESS(rv, rv);
frame->SetNextSibling(nextFrame->GetNextSibling());
nextFrame->SetNextSibling(nsnull);
SetOverflowFrames(aPresContext, nextFrame);
// Root overflow containers will be normal children of
// the pageContentFrame, but that's ok because there
// aren't any other frames we need to isolate them from
// during reflow.
}
if (NS_FRAME_OVERFLOW_IS_INCOMPLETE(aStatus)) {
nextFrame->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
}
}
// The document element's background should cover the entire canvas, so
// take into account the combined area and any space taken up by
// absolutely positioned elements

View File

@ -83,10 +83,6 @@ protected:
nsPageContentFrame(nsStyleContext* aContext) : ViewportFrame(aContext) {}
nsSharedPageData* mPD;
private:
PRBool IsFixedPlaceholder(nsIFrame* aFrame);
nsFrameList StealFixedPlaceholders(nsIFrame* aDocRoot);
};
#endif /* nsPageContentFrame_h___ */

View File

@ -179,11 +179,8 @@ ViewportFrame::GetAdditionalChildListName(PRInt32 aIndex) const
nsIFrame*
ViewportFrame::GetFirstChild(nsIAtom* aListName) const
{
if (nsGkAtoms::fixedList == aListName) {
nsIFrame* result = nsnull;
mFixedContainer.FirstChild(this, aListName, &result);
return result;
}
if (nsGkAtoms::fixedList == aListName)
return mFixedContainer.GetFirstChild();
return nsContainerFrame::GetFirstChild(aListName);
}
@ -309,8 +306,7 @@ ViewportFrame::Reflow(nsPresContext* aPresContext,
nsPoint offset = AdjustReflowStateForScrollbars(&reflowState);
#ifdef DEBUG
nsIFrame* f;
mFixedContainer.FirstChild(this, nsGkAtoms::fixedList, &f);
nsIFrame* f = mFixedContainer.GetFirstChild();
NS_ASSERTION(!f || (offset.x == 0 && offset.y == 0),
"We don't handle correct positioning of fixed frames with "
"scrollbars in odd positions");

View File

@ -0,0 +1,5 @@
<!DOCTYPE HTML>
<html style="position:relative; height:50%;">
<body style="position:absolute; width:50%; top:50px; left:50px; height:100%; margin:0; border:10px solid black;">
</body>
</html>

View File

@ -125,6 +125,7 @@ fails == 25888-3r.html 25888-3r-ref.html # bug 25888
== 180085-1.html 180085-1-ref.html
== 180085-2.html 180085-2-ref.html
== 185388-1.html 185388-1-ref.html
!= 200774-1.html about:blank # really a crashtest
== 201215-1.html 201215-1-ref.html
== 201293-1a.html 201293-1-ref.html
== 201293-1b.html 201293-1-ref.html
@ -166,6 +167,28 @@ fails == 25888-3r.html 25888-3r-ref.html # bug 25888
== 240470-1.html 240470-1-ref.html
== 243266-1.html 243266-1-ref.html
== 243302-1.html 243302-1-ref.html
== 243519-1.html 243519-1-ref.html
== 243519-2.html 243519-2-ref.html
== 243519-3.html 243519-3-ref.html
== 243519-4a.html 243519-4-ref.html
== 243519-4b.html 243519-4-ref.html
== 243519-4c.html 243519-4-ref.html
== 243519-4d.html 243519-4-ref.html
== 243519-4e.html 243519-4-ref.html
== 243519-4f.html 243519-4-ref.html
== 243519-5a.html 243519-5-ref.html
== 243519-5b.html 243519-5-ref.html
== 243519-5c.html 243519-5-ref.html
== 243519-5d.html 243519-5-ref.html
== 243519-6.html 243519-6-ref.html
== 243519-7.html 243519-7-ref.html
== 243519-8.svg 243519-8-ref.svg
== 243519-9a.html 243519-9-ref.html
== 243519-9b.html 243519-9-ref.html
== 243519-9c.html 243519-9-ref.html
== 243519-9d.html 243519-9-ref.html
== 243519-9e.html 243519-9-ref.html
== 243519-9f.html 243519-9-ref.html
== 244135-1.html 244135-1-ref.html
== 244135-2.html 244135-2-ref.html
== 244932-1.html 244932-1-ref.html