mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 78070. When the root element is removed, remove all frames except the viewport; when it's reinserted, recreate them as needed. r=roc,dbaron sr=roc
This commit is contained in:
parent
15a540ba45
commit
e6259a26ac
14
layout/base/crashtests/481806-1.html
Normal file
14
layout/base/crashtests/481806-1.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
function boom()
|
||||
{
|
||||
var hbox = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "hbox");
|
||||
document.removeChild(document.documentElement);
|
||||
document.appendChild(hbox);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload="boom();"></body>
|
||||
</html>
|
@ -227,6 +227,7 @@ load 468645-3.xhtml
|
||||
load 471594-1.xhtml
|
||||
load 479114-1.html
|
||||
load 477333-1.xhtml
|
||||
load 481806-1.html
|
||||
load 488390-1.xhtml
|
||||
load 489691.html
|
||||
load 490376-1.xhtml
|
||||
|
@ -2474,43 +2474,28 @@ nsCSSFrameConstructor::PropagateScrollToViewport()
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
/**
|
||||
* New one
|
||||
*/
|
||||
nsresult
|
||||
nsCSSFrameConstructor::ConstructDocElementFrame(nsFrameConstructorState& aState,
|
||||
nsIContent* aDocElement,
|
||||
nsIFrame* aParentFrame,
|
||||
nsCSSFrameConstructor::ConstructDocElementFrame(nsIContent* aDocElement,
|
||||
nsILayoutHistoryState* aFrameState,
|
||||
nsIFrame** aNewFrame)
|
||||
{
|
||||
NS_PRECONDITION(mFixedContainingBlock,
|
||||
"No viewport? Someone forgot to call ConstructRootFrame!");
|
||||
NS_PRECONDITION(mFixedContainingBlock == mPresShell->FrameManager()->GetRootFrame(),
|
||||
"Unexpected mFixedContainingBlock");
|
||||
|
||||
*aNewFrame = nsnull;
|
||||
|
||||
SetUpDocElementContainingBlock(aDocElement);
|
||||
|
||||
NS_ASSERTION(mDocElementContainingBlock, "Should have parent by now");
|
||||
|
||||
nsFrameConstructorState state(mPresShell, mFixedContainingBlock, nsnull,
|
||||
nsnull, aFrameState);
|
||||
|
||||
// XXXbz why, exactly?
|
||||
if (!mTempFrameTreeState)
|
||||
aState.mPresShell->CaptureHistoryState(getter_AddRefs(mTempFrameTreeState));
|
||||
|
||||
// ----- reattach gfx scrollbars ------
|
||||
// Gfx scrollframes were created in the root frame but the primary frame map may have been destroyed if a
|
||||
// new style sheet was loaded so lets reattach the frames to their content.
|
||||
// XXX this seems truly bogus, we wipe out mGfxScrollFrame below
|
||||
if (mGfxScrollFrame) {
|
||||
nsIFrame* gfxScrollbarFrame1 = mGfxScrollFrame->GetFirstChild(nsnull);
|
||||
// Check the frame type because when there aren't scrollbars, we'll
|
||||
// get the canvas.
|
||||
if (gfxScrollbarFrame1 &&
|
||||
gfxScrollbarFrame1->GetType() == nsGkAtoms::scrollbarFrame) {
|
||||
// XXX This works, but why?
|
||||
aState.mFrameManager->
|
||||
SetPrimaryFrameFor(gfxScrollbarFrame1->GetContent(), gfxScrollbarFrame1);
|
||||
|
||||
nsIFrame* gfxScrollbarFrame2 = gfxScrollbarFrame1->GetNextSibling();
|
||||
if (gfxScrollbarFrame2 &&
|
||||
gfxScrollbarFrame2->GetType() == nsGkAtoms::scrollbarFrame) {
|
||||
// XXX This works, but why?
|
||||
aState.mFrameManager->
|
||||
SetPrimaryFrameFor(gfxScrollbarFrame2->GetContent(), gfxScrollbarFrame2);
|
||||
}
|
||||
}
|
||||
}
|
||||
state.mPresShell->CaptureHistoryState(getter_AddRefs(mTempFrameTreeState));
|
||||
|
||||
// --------- CREATE AREA OR BOX FRAME -------
|
||||
nsRefPtr<nsStyleContext> styleContext;
|
||||
@ -2555,15 +2540,13 @@ nsCSSFrameConstructor::ConstructDocElementFrame(nsFrameConstructorState& aState,
|
||||
PropagateScrollToViewport() == aDocElement;
|
||||
|
||||
NS_ASSERTION(!display->IsScrollableOverflow() ||
|
||||
aState.mPresContext->IsPaginated() ||
|
||||
state.mPresContext->IsPaginated() ||
|
||||
propagatedScrollToViewport,
|
||||
"Scrollbars should have been propagated to the viewport");
|
||||
#endif
|
||||
|
||||
if (NS_UNLIKELY(display->mDisplay == NS_STYLE_DISPLAY_NONE)) {
|
||||
aState.mFrameManager->SetUndisplayedContent(aDocElement, styleContext);
|
||||
mRootElementFrame = nsnull;
|
||||
mRootElementStyleFrame = nsnull;
|
||||
state.mFrameManager->SetUndisplayedContent(aDocElement, styleContext);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -2571,7 +2554,8 @@ nsCSSFrameConstructor::ConstructDocElementFrame(nsFrameConstructorState& aState,
|
||||
if (mHasRootAbsPosContainingBlock) {
|
||||
// Push the absolute containing block now so we can absolutely position
|
||||
// the root element
|
||||
aState.PushAbsoluteContainingBlock(mDocElementContainingBlock, absoluteSaveState);
|
||||
state.PushAbsoluteContainingBlock(mDocElementContainingBlock,
|
||||
absoluteSaveState);
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
@ -2596,7 +2580,8 @@ nsCSSFrameConstructor::ConstructDocElementFrame(nsFrameConstructorState& aState,
|
||||
if (NS_UNLIKELY(!contentFrame)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
InitAndRestoreFrame(aState, aDocElement, aParentFrame, nsnull, contentFrame);
|
||||
InitAndRestoreFrame(state, aDocElement, mDocElementContainingBlock, nsnull,
|
||||
contentFrame);
|
||||
*aNewFrame = contentFrame;
|
||||
processChildren = PR_TRUE;
|
||||
}
|
||||
@ -2609,15 +2594,16 @@ nsCSSFrameConstructor::ConstructDocElementFrame(nsFrameConstructorState& aState,
|
||||
if (NS_UNLIKELY(!contentFrame)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
InitAndRestoreFrame(aState, aDocElement,
|
||||
aState.GetGeometricParent(display, aParentFrame),
|
||||
InitAndRestoreFrame(state, aDocElement,
|
||||
state.GetGeometricParent(display,
|
||||
mDocElementContainingBlock),
|
||||
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);
|
||||
rv = state.AddChild(contentFrame, frameItems, aDocElement,
|
||||
styleContext, mDocElementContainingBlock);
|
||||
if (NS_FAILED(rv) || !frameItems.childList) {
|
||||
return rv;
|
||||
}
|
||||
@ -2650,7 +2636,7 @@ nsCSSFrameConstructor::ConstructDocElementFrame(nsFrameConstructorState& aState,
|
||||
|
||||
nsFrameItems frameItems;
|
||||
// if the document is a table then just populate it.
|
||||
rv = ConstructTable(aState, item, aParentFrame,
|
||||
rv = ConstructTable(state, item, mDocElementContainingBlock,
|
||||
styleContext->GetStyleDisplay(),
|
||||
frameItems, &contentFrame);
|
||||
if (NS_FAILED(rv))
|
||||
@ -2666,10 +2652,11 @@ nsCSSFrameConstructor::ConstructDocElementFrame(nsFrameConstructorState& aState,
|
||||
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());
|
||||
rv = ConstructBlock(state, display, aDocElement,
|
||||
state.GetGeometricParent(display,
|
||||
mDocElementContainingBlock),
|
||||
mDocElementContainingBlock, styleContext,
|
||||
&contentFrame, frameItems, display->IsPositioned());
|
||||
if (NS_FAILED(rv) || !frameItems.childList)
|
||||
return rv;
|
||||
*aNewFrame = frameItems.childList;
|
||||
@ -2679,7 +2666,7 @@ nsCSSFrameConstructor::ConstructDocElementFrame(nsFrameConstructorState& aState,
|
||||
}
|
||||
|
||||
// set the primary frame
|
||||
aState.mFrameManager->SetPrimaryFrameFor(aDocElement, contentFrame);
|
||||
state.mFrameManager->SetPrimaryFrameFor(aDocElement, contentFrame);
|
||||
|
||||
NS_ASSERTION(processChildren ? !mRootElementFrame :
|
||||
mRootElementFrame == contentFrame,
|
||||
@ -2690,7 +2677,7 @@ nsCSSFrameConstructor::ConstructDocElementFrame(nsFrameConstructorState& aState,
|
||||
// assigning it to mRootElementStyleFrame.
|
||||
// Backgrounds should be propagated from that frame to the viewport.
|
||||
PRBool isChild;
|
||||
contentFrame->GetParentStyleContextFrame(aState.mPresContext,
|
||||
contentFrame->GetParentStyleContextFrame(state.mPresContext,
|
||||
&mRootElementStyleFrame, &isChild);
|
||||
if (!isChild) {
|
||||
mRootElementStyleFrame = mRootElementFrame;
|
||||
@ -2702,26 +2689,74 @@ nsCSSFrameConstructor::ConstructDocElementFrame(nsFrameConstructorState& aState,
|
||||
|
||||
NS_ASSERTION(!nsLayoutUtils::GetAsBlock(contentFrame),
|
||||
"Only XUL and SVG frames should reach here");
|
||||
ProcessChildren(aState, aDocElement, styleContext, contentFrame, PR_TRUE,
|
||||
ProcessChildren(state, aDocElement, styleContext, contentFrame, PR_TRUE,
|
||||
childItems, PR_FALSE);
|
||||
|
||||
// Set the initial child lists
|
||||
contentFrame->SetInitialChildList(nsnull, childItems.childList);
|
||||
}
|
||||
|
||||
mDocElementContainingBlock->AppendFrames(nsnull, *aNewFrame);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsCSSFrameConstructor::ConstructRootFrame(nsIContent* aDocElement,
|
||||
nsIFrame** aNewFrame)
|
||||
nsCSSFrameConstructor::ConstructRootFrame(nsIFrame** aNewFrame)
|
||||
{
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
|
||||
NS_PRECONDITION(aNewFrame, "null out param");
|
||||
|
||||
/*
|
||||
how the root frame hierarchy should look
|
||||
nsStyleSet *styleSet = mPresShell->StyleSet();
|
||||
|
||||
// Set up our style rule observer.
|
||||
// XXXbz wouldn't this make more sense as part of presshell init?
|
||||
{
|
||||
styleSet->SetBindingManager(mDocument->BindingManager());
|
||||
}
|
||||
|
||||
// --------- BUILD VIEWPORT -----------
|
||||
nsIFrame* viewportFrame = nsnull;
|
||||
nsRefPtr<nsStyleContext> viewportPseudoStyle;
|
||||
|
||||
viewportPseudoStyle = styleSet->ResolvePseudoStyleFor(nsnull,
|
||||
nsCSSAnonBoxes::viewport,
|
||||
nsnull);
|
||||
|
||||
viewportFrame = NS_NewViewportFrame(mPresShell, viewportPseudoStyle);
|
||||
|
||||
// XXXbz do we _have_ to pass a null content pointer to that frame?
|
||||
// Would it really kill us to pass in the root element or something?
|
||||
// What would that break?
|
||||
viewportFrame->Init(nsnull, nsnull, nsnull);
|
||||
|
||||
// Bind the viewport frame to the root view
|
||||
nsIView* rootView;
|
||||
mPresShell->GetViewManager()->GetRootView(rootView);
|
||||
viewportFrame->SetView(rootView);
|
||||
|
||||
nsContainerFrame::SyncFrameViewProperties(mPresShell->GetPresContext(), viewportFrame,
|
||||
viewportPseudoStyle, rootView);
|
||||
|
||||
// The viewport is the containing block for 'fixed' elements
|
||||
mFixedContainingBlock = viewportFrame;
|
||||
|
||||
*aNewFrame = viewportFrame;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCSSFrameConstructor::SetUpDocElementContainingBlock(nsIContent* aDocElement)
|
||||
{
|
||||
NS_PRECONDITION(aDocElement, "No element?");
|
||||
NS_PRECONDITION(!aDocElement->GetParent(), "Not root content?");
|
||||
NS_PRECONDITION(aDocElement->GetCurrentDoc(), "Not in a document?");
|
||||
NS_PRECONDITION(aDocElement->GetCurrentDoc()->GetRootContent() ==
|
||||
aDocElement, "Not the root of the document?");
|
||||
|
||||
/*
|
||||
how the root frame hierarchy should look
|
||||
|
||||
Galley presentation, non-XUL, with scrolling (i.e. not a frameset):
|
||||
|
||||
@ -2769,49 +2804,14 @@ nsCSSFrameConstructor::ConstructRootFrame(nsIContent* aDocElement,
|
||||
[abs-cb]: the default containing block for abs-pos content
|
||||
|
||||
Meaning of nsCSSFrameConstructor fields:
|
||||
mRootElementFrame is "root element frame".
|
||||
mRootElementFrame is "root element frame". This is the primary frame for
|
||||
the root element.
|
||||
mDocElementContainingBlock is the parent of mRootElementFrame
|
||||
(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.
|
||||
{
|
||||
mPresShell->StyleSet()->SetBindingManager(mDocument->BindingManager());
|
||||
}
|
||||
|
||||
// --------- BUILD VIEWPORT -----------
|
||||
nsIFrame* viewportFrame = nsnull;
|
||||
nsRefPtr<nsStyleContext> viewportPseudoStyle;
|
||||
nsStyleSet *styleSet = mPresShell->StyleSet();
|
||||
|
||||
viewportPseudoStyle = styleSet->ResolvePseudoStyleFor(nsnull,
|
||||
nsCSSAnonBoxes::viewport,
|
||||
nsnull);
|
||||
|
||||
viewportFrame = NS_NewViewportFrame(mPresShell, viewportPseudoStyle);
|
||||
|
||||
nsPresContext* presContext = mPresShell->GetPresContext();
|
||||
|
||||
// XXXbz do we _have_ to pass a null content pointer to that frame?
|
||||
// Would it really kill us to pass in the root element or something?
|
||||
// What would that break?
|
||||
viewportFrame->Init(nsnull, nsnull, nsnull);
|
||||
|
||||
// Bind the viewport frame to the root view
|
||||
nsIViewManager* viewManager = mPresShell->GetViewManager();
|
||||
nsIView* rootView;
|
||||
|
||||
viewManager->GetRootView(rootView);
|
||||
viewportFrame->SetView(rootView);
|
||||
|
||||
nsContainerFrame::SyncFrameViewProperties(presContext, viewportFrame,
|
||||
viewportPseudoStyle, rootView);
|
||||
|
||||
// The viewport is the containing block for 'fixed' elements
|
||||
mFixedContainingBlock = viewportFrame;
|
||||
*/
|
||||
|
||||
// --------- CREATE ROOT FRAME -------
|
||||
|
||||
@ -2824,7 +2824,10 @@ nsCSSFrameConstructor::ConstructRootFrame(nsIContent* aDocElement,
|
||||
// - renders the document element's background. This ensures the background covers
|
||||
// the entire canvas as specified by the CSS2 spec
|
||||
|
||||
nsPresContext* presContext = mPresShell->GetPresContext();
|
||||
PRBool isPaginated = presContext->IsRootPaginatedDocument();
|
||||
nsIFrame* viewportFrame = mFixedContainingBlock;
|
||||
nsStyleContext* viewportPseudoStyle = viewportFrame->GetStyleContext();
|
||||
|
||||
nsIFrame* rootFrame = nsnull;
|
||||
nsIAtom* rootPseudo;
|
||||
@ -2903,8 +2906,10 @@ nsCSSFrameConstructor::ConstructRootFrame(nsIContent* aDocElement,
|
||||
// state to build the scrollbar frames.
|
||||
nsFrameConstructorState state(mPresShell, nsnull, nsnull, nsnull);
|
||||
|
||||
// Start off with the viewport as parent; we'll adjust it as needed.
|
||||
nsIFrame* parentFrame = viewportFrame;
|
||||
|
||||
nsStyleSet* styleSet = mPresShell->StyleSet();
|
||||
// If paginated, make sure we don't put scrollbars in
|
||||
if (!isScrollable) {
|
||||
rootPseudoStyle = styleSet->ResolvePseudoStyleFor(nsnull,
|
||||
@ -2919,9 +2924,10 @@ nsCSSFrameConstructor::ConstructRootFrame(nsIContent* aDocElement,
|
||||
rootPseudo = nsCSSAnonBoxes::scrolledPageSequence;
|
||||
}
|
||||
|
||||
// Build the frame. We give it the content we are wrapping which is the document,
|
||||
// the root frame, the parent view port frame, and we should get back the new
|
||||
// frame and the scrollable view if one was created.
|
||||
// Build the frame. We give it the content we are wrapping which is the
|
||||
// document element, the root frame, the parent view port frame, and we
|
||||
// should get back the new frame and the scrollable view if one was
|
||||
// created.
|
||||
|
||||
// resolve a context for the scrollframe
|
||||
nsRefPtr<nsStyleContext> styleContext;
|
||||
@ -2951,7 +2957,7 @@ nsCSSFrameConstructor::ConstructRootFrame(nsIContent* aDocElement,
|
||||
nsIScrollableView* scrollableView = scrollable->GetScrollableView();
|
||||
NS_ENSURE_TRUE(scrollableView, NS_ERROR_FAILURE);
|
||||
|
||||
viewManager->SetRootScrollableView(scrollableView);
|
||||
mPresShell->GetViewManager()->SetRootScrollableView(scrollableView);
|
||||
parentFrame = newFrame;
|
||||
|
||||
mGfxScrollFrame = newFrame;
|
||||
@ -2978,9 +2984,11 @@ nsCSSFrameConstructor::ConstructRootFrame(nsIContent* aDocElement,
|
||||
mHasRootAbsPosContainingBlock = PR_TRUE;
|
||||
}
|
||||
|
||||
viewportFrame->SetInitialChildList(nsnull, newFrame);
|
||||
|
||||
*aNewFrame = viewportFrame;
|
||||
if (viewportFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
|
||||
viewportFrame->SetInitialChildList(nsnull, newFrame);
|
||||
} else {
|
||||
viewportFrame->AppendFrames(nsnull, newFrame);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -4715,23 +4723,20 @@ nsCSSFrameConstructor::ResolveStyleContext(nsIFrame* aParentFrame,
|
||||
nsIContent* aContent)
|
||||
{
|
||||
nsStyleContext* parentStyleContext = nsnull;
|
||||
if (aContent->GetParent()) {
|
||||
aParentFrame = nsFrame::CorrectStyleParentFrame(aParentFrame, nsnull);
|
||||
NS_ASSERTION(aContent->GetParent(), "Must have parent here");
|
||||
|
||||
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?
|
||||
}
|
||||
aParentFrame = nsFrame::CorrectStyleParentFrame(aParentFrame, nsnull);
|
||||
|
||||
if (aParentFrame) {
|
||||
// Resolve the style context based on the content object and the parent
|
||||
// style context
|
||||
parentStyleContext = aParentFrame->GetStyleContext();
|
||||
} else {
|
||||
// This has got to be a call from ConstructDocElementTableFrame.
|
||||
// Not sure how best to assert that here.
|
||||
// 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?
|
||||
}
|
||||
|
||||
return ResolveStyleContext(parentStyleContext, aContent);
|
||||
@ -5479,127 +5484,9 @@ nsresult
|
||||
nsCSSFrameConstructor::ReconstructDocElementHierarchy()
|
||||
{
|
||||
AUTO_LAYOUT_PHASE_ENTRY_POINT(mPresShell->GetPresContext(), FrameC);
|
||||
return ReconstructDocElementHierarchyInternal();
|
||||
return RecreateFramesForContent(mPresShell->GetDocument()->GetRootContent());
|
||||
}
|
||||
|
||||
static void
|
||||
InvalidateCanvasIfNeeded(nsIPresShell* presShell, nsIContent* node);
|
||||
|
||||
nsresult
|
||||
nsCSSFrameConstructor::ReconstructDocElementHierarchyInternal()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (gNoisyContentUpdates) {
|
||||
printf("nsCSSFrameConstructor::ReconstructDocElementHierarchy\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
// XXXbz is that null-check needed? Why?
|
||||
if (mDocument && mPresShell) {
|
||||
nsIContent *rootContent = mDocument->GetRootContent();
|
||||
|
||||
if (rootContent) {
|
||||
// Invalidate the canvas, just to be safe
|
||||
InvalidateCanvasIfNeeded(mPresShell, rootContent);
|
||||
|
||||
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);
|
||||
} else {
|
||||
state.mFrameManager->ClearUndisplayedContentIn(rootContent, nsnull);
|
||||
}
|
||||
|
||||
// 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, 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();
|
||||
state.mFrameManager->ClearPlaceholderFrameMap();
|
||||
state.mFrameManager->ClearUndisplayedContentMap();
|
||||
|
||||
if (docElementFrame) {
|
||||
// Take the docElementFrame, and remove it from its parent.
|
||||
// XXXbz So why can't we reuse ContentRemoved?
|
||||
|
||||
// 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();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rootContent && NS_SUCCEEDED(rv)) {
|
||||
mRootElementFrame = nsnull;
|
||||
mRootElementStyleFrame = nsnull;
|
||||
|
||||
// We don't reuse the old frame constructor state because,
|
||||
// for example, its mPopupItems may be stale
|
||||
nsFrameConstructorState state(mPresShell, mFixedContainingBlock,
|
||||
nsnull, nsnull, mTempFrameTreeState);
|
||||
|
||||
// Create the new document element hierarchy
|
||||
nsIFrame* newChild;
|
||||
rv = ConstructDocElementFrame(state, rootContent,
|
||||
mDocElementContainingBlock, &newChild);
|
||||
|
||||
// newChild could be null even if |rv| is success, thanks to XBL.
|
||||
if (NS_SUCCEEDED(rv) && newChild) {
|
||||
rv = state.mFrameManager->InsertFrames(mDocElementContainingBlock,
|
||||
nsnull, nsnull, newChild);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsIFrame*
|
||||
nsCSSFrameConstructor::GetFrameFor(nsIContent* aContent)
|
||||
{
|
||||
@ -5677,8 +5564,6 @@ nsCSSFrameConstructor::GetAbsoluteContainingBlock(nsIFrame* aFrame)
|
||||
nsIFrame*
|
||||
nsCSSFrameConstructor::GetFloatContainingBlock(nsIFrame* aFrame)
|
||||
{
|
||||
NS_PRECONDITION(mRootElementFrame, "no root element frame");
|
||||
|
||||
// Starting with aFrame, look for a frame that is a float containing block.
|
||||
// IF we hit a mathml frame, bail out; we don't allow floating out of mathml
|
||||
// frames, because they don't seem to be able to deal.
|
||||
@ -6115,6 +6000,9 @@ IsSpecialFramesetChild(nsIContent* aContent)
|
||||
aContent->Tag() == nsGkAtoms::frame);
|
||||
}
|
||||
|
||||
static void
|
||||
InvalidateCanvasIfNeeded(nsIPresShell* presShell, nsIContent* node);
|
||||
|
||||
nsresult
|
||||
nsCSSFrameConstructor::ContentAppended(nsIContent* aContainer,
|
||||
PRInt32 aNewIndexInContainer)
|
||||
@ -6486,66 +6374,45 @@ nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer,
|
||||
return NS_OK;
|
||||
#endif // MOZ_XUL
|
||||
|
||||
// If we have a null parent, then this must be the document element
|
||||
// being inserted
|
||||
// If we have a null parent, then this must be the document element being
|
||||
// inserted, or some other child of the document in the DOM (might be a PI,
|
||||
// say).
|
||||
if (! aContainer) {
|
||||
nsIContent *docElement = mDocument->GetRootContent();
|
||||
|
||||
if (aChild == docElement) {
|
||||
NS_PRECONDITION(nsnull == mRootElementFrame, "root element frame already created");
|
||||
|
||||
if (!mDocElementContainingBlock)
|
||||
return NS_OK; // We get into this situation when an XBL binding is asynchronously
|
||||
// applied to the root tag (e.g., <window> in XUL). It's ok. We can
|
||||
// just bail here because the root will really be built later during
|
||||
// InitialReflow.
|
||||
|
||||
// Create frames for the document element and its child elements
|
||||
nsIFrame* docElementFrame;
|
||||
nsFrameConstructorState state(mPresShell, mFixedContainingBlock, nsnull,
|
||||
nsnull, aFrameState);
|
||||
rv = ConstructDocElementFrame(state,
|
||||
docElement,
|
||||
mDocElementContainingBlock,
|
||||
&docElementFrame);
|
||||
|
||||
if (NS_SUCCEEDED(rv) && docElementFrame) {
|
||||
if (mDocElementContainingBlock->GetStateBits() & NS_FRAME_FIRST_REFLOW) {
|
||||
// Set the initial child list for the parent and wait on the initial
|
||||
// reflow.
|
||||
mDocElementContainingBlock->SetInitialChildList(nsnull,
|
||||
docElementFrame);
|
||||
} else {
|
||||
// Whoops, we've already received our initial reflow! Insert the doc.
|
||||
// element as a child so it reflows (note that containing block is
|
||||
// empty, so we can simply append).
|
||||
NS_ASSERTION(mDocElementContainingBlock->GetFirstChild(nsnull) == nsnull,
|
||||
"Unexpected child of document element containing block");
|
||||
mDocElementContainingBlock->AppendFrames(nsnull, docElementFrame);
|
||||
}
|
||||
InvalidateCanvasIfNeeded(mPresShell, aChild);
|
||||
#ifdef DEBUG
|
||||
if (gReallyNoisyContentUpdates) {
|
||||
nsIFrameDebug* fdbg = do_QueryFrame(docElementFrame);
|
||||
if (fdbg) {
|
||||
printf("nsCSSFrameConstructor::ContentInserted: resulting frame model:\n");
|
||||
fdbg->List(stdout, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (aChild != docElement) {
|
||||
// Not the root element; just bail out
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_PRECONDITION(nsnull == mRootElementFrame,
|
||||
"root element frame already created");
|
||||
|
||||
// Create frames for the document element and its child elements
|
||||
nsIFrame* docElementFrame;
|
||||
rv = ConstructDocElementFrame(docElement, aFrameState, &docElementFrame);
|
||||
|
||||
if (NS_SUCCEEDED(rv) && docElementFrame) {
|
||||
InvalidateCanvasIfNeeded(mPresShell, aChild);
|
||||
#ifdef DEBUG
|
||||
if (gReallyNoisyContentUpdates) {
|
||||
nsIFrameDebug* fdbg = do_QueryFrame(mFixedContainingBlock);
|
||||
if (fdbg) {
|
||||
printf("nsCSSFrameConstructor::ContentInserted: resulting frame "
|
||||
"model:\n");
|
||||
fdbg->List(stdout, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// otherwise this is not a child of the root element, and we
|
||||
// won't let it have a frame.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Otherwise, we've got parent content. Find its frame.
|
||||
nsIFrame* parentFrame = GetFrameFor(aContainer);
|
||||
if (! parentFrame)
|
||||
return NS_OK; // XXXwaterson will this break selects? (See ``Here
|
||||
// we have been notified...'' below.)
|
||||
return NS_OK;
|
||||
|
||||
// See if we have an XBL insertion point. If so, then that's our
|
||||
// real parent frame; if not, then the frame hasn't been built yet
|
||||
@ -6808,27 +6675,6 @@ nsCSSFrameConstructor::ContentInserted(nsIContent* aContainer,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCSSFrameConstructor::ReinsertContent(nsIContent* aContainer,
|
||||
nsIContent* aChild)
|
||||
{
|
||||
PRInt32 ix = aContainer->IndexOf(aChild);
|
||||
// XXX For now, do a brute force remove and insert.
|
||||
// XXXbz this probably doesn't work so well with anonymous content
|
||||
// XXXbz doesn't this need to do the state-saving stuff that
|
||||
// RecreateFramesForContent does?
|
||||
PRBool didReconstruct;
|
||||
nsresult res = ContentRemoved(aContainer, aChild, ix, &didReconstruct);
|
||||
|
||||
if (NS_SUCCEEDED(res) && !didReconstruct) {
|
||||
// If ContentRemoved just reconstructed everything, there is no need to
|
||||
// reinsert the content here
|
||||
res = ContentInserted(aContainer, aChild, ix, nsnull);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
DoDeletingFrameSubtree(nsFrameManager* aFrameManager,
|
||||
nsTArray<nsIFrame*>& aDestroyQueue,
|
||||
@ -7085,7 +6931,7 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
|
||||
|
||||
// Find the child frame that maps the content
|
||||
nsIFrame* childFrame =
|
||||
mPresShell->FrameManager()->GetPrimaryFrameFor(aChild, aIndexInContainer);
|
||||
frameManager->GetPrimaryFrameFor(aChild, aIndexInContainer);
|
||||
|
||||
if (!childFrame || childFrame->GetContent() != aChild) {
|
||||
// XXXbz the GetContent() != aChild check is needed due to bug 135040.
|
||||
@ -7100,6 +6946,29 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
|
||||
|
||||
#endif // MOZ_XUL
|
||||
|
||||
// If we're removing the root, then make sure to remove things starting at
|
||||
// the viewport's child instead of the primary frame (which might even be
|
||||
// null if the root had an XBL binding or display:none, even though the
|
||||
// frames above it got created). We do the adjustment after the childFrame
|
||||
// check above, because we do want to clear any undisplayed content we might
|
||||
// have for the root. Detecting removal of a root is a little exciting; in
|
||||
// particular, having a null aContainer is necessary but NOT sufficient. Due
|
||||
// to how we process reframes, the content node might not even be in our
|
||||
// document by now. So explicitly check whether the viewport's first kid's
|
||||
// content node is aChild.
|
||||
PRBool isRoot = PR_FALSE;
|
||||
if (!aContainer) {
|
||||
nsIFrame* viewport = frameManager->GetRootFrame();
|
||||
if (viewport) {
|
||||
nsIFrame* firstChild = viewport->GetFirstChild(nsnull);
|
||||
if (firstChild && firstChild->GetContent() == aChild) {
|
||||
isRoot = PR_TRUE;
|
||||
childFrame = firstChild;
|
||||
NS_ASSERTION(!childFrame->GetNextSibling(), "How did that happen?");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (childFrame) {
|
||||
InvalidateCanvasIfNeeded(mPresShell, aChild);
|
||||
|
||||
@ -7241,9 +7110,14 @@ nsCSSFrameConstructor::ContentRemoved(nsIContent* aContainer,
|
||||
}
|
||||
}
|
||||
|
||||
if (mRootElementFrame == childFrame) {
|
||||
if (isRoot) {
|
||||
mRootElementFrame = nsnull;
|
||||
mRootElementStyleFrame = nsnull;
|
||||
mDocElementContainingBlock = nsnull;
|
||||
mPageSequenceFrame = nsnull;
|
||||
mGfxScrollFrame = nsnull;
|
||||
mHasRootAbsPosContainingBlock = PR_FALSE;
|
||||
mFixedContainingBlock = frameManager->GetRootFrame();
|
||||
}
|
||||
|
||||
if (haveFLS && mRootElementFrame) {
|
||||
@ -7524,12 +7398,12 @@ nsCSSFrameConstructor::CharacterDataChanged(nsIContent* aContent,
|
||||
// Special check for text content that is a child of a letter frame. If
|
||||
// this happens, we should remove the letter frame, do whatever we're
|
||||
// planning to do with this notification, then put the letter frame back.
|
||||
// Note that this is basically what ReinsertContent ends up doing; the
|
||||
// reason we dont' want to call that here is that our text content could be
|
||||
// native anonymous, in which case ReinsertContent would completely barf on
|
||||
// it. And reinserting the non-anonymous ancestor would just lead us to
|
||||
// come back into this notification (e.g. if quotes or counters are
|
||||
// involved), leading to a loop.
|
||||
// Note that this is basically what RecreateFramesForContent ends up doing;
|
||||
// the reason we dont' want to call that here is that our text content
|
||||
// could be native anonymous, in which case RecreateFramesForContent would
|
||||
// completely barf on it. And recreating the non-anonymous ancestor would
|
||||
// just lead us to come back into this notification (e.g. if quotes or
|
||||
// counters are involved), leading to a loop.
|
||||
nsIFrame* block = GetFloatContainingBlock(frame);
|
||||
PRBool haveFirstLetterStyle = PR_FALSE;
|
||||
if (block) {
|
||||
@ -8724,6 +8598,9 @@ nsCSSFrameConstructor::CaptureStateForFramesOf(nsIContent* aContent,
|
||||
nsILayoutHistoryState* aHistoryState)
|
||||
{
|
||||
nsIFrame* frame = mPresShell->GetPrimaryFrameFor(aContent);
|
||||
if (frame == mRootElementFrame) {
|
||||
frame = mFixedContainingBlock;
|
||||
}
|
||||
if (frame) {
|
||||
CaptureStateFor(frame, aHistoryState);
|
||||
}
|
||||
@ -8934,14 +8811,18 @@ nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent)
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIContent> container = aContent->GetParent();
|
||||
if (container) {
|
||||
nsINode* containerNode = aContent->GetNodeParent();
|
||||
if (containerNode) {
|
||||
// XXXbz what if this is anonymous content?
|
||||
PRInt32 indexInContainer = container->IndexOf(aContent);
|
||||
PRInt32 indexInContainer = containerNode->IndexOf(aContent);
|
||||
// Before removing the frames associated with the content object,
|
||||
// ask them to save their state onto a temporary state object.
|
||||
CaptureStateForFramesOf(aContent, mTempFrameTreeState);
|
||||
|
||||
// Need both parents, since we need to pass null to ContentInserted and
|
||||
// ContentRemoved but want to use our real parent node for IndexOf.
|
||||
nsCOMPtr<nsIContent> container = aContent->GetParent();
|
||||
|
||||
// Remove the frames associated with the content object on which
|
||||
// the attribute change occurred.
|
||||
PRBool didReconstruct;
|
||||
@ -8954,9 +8835,6 @@ nsCSSFrameConstructor::RecreateFramesForContent(nsIContent* aContent)
|
||||
rv = ContentInserted(container, aContent,
|
||||
indexInContainer, mTempFrameTreeState);
|
||||
}
|
||||
} else {
|
||||
// The content is the root node, so just rebuild the world.
|
||||
ReconstructDocElementHierarchy();
|
||||
}
|
||||
|
||||
#ifdef ACCESSIBILITY
|
||||
@ -11073,20 +10951,13 @@ nsCSSFrameConstructor::WipeContainingBlock(nsFrameConstructorState& aState,
|
||||
// but it will *always* get the right answer.
|
||||
|
||||
nsIContent *blockContent = aContainingBlock->GetContent();
|
||||
nsCOMPtr<nsIContent> parentContainer = blockContent->GetParent();
|
||||
#ifdef DEBUG
|
||||
if (gNoisyContentUpdates) {
|
||||
printf("nsCSSFrameConstructor::WipeContainingBlock: blockContent=%p parentContainer=%p\n",
|
||||
static_cast<void*>(blockContent),
|
||||
static_cast<void*>(parentContainer));
|
||||
printf("nsCSSFrameConstructor::WipeContainingBlock: blockContent=%p\n",
|
||||
static_cast<void*>(blockContent));
|
||||
}
|
||||
#endif
|
||||
if (parentContainer) {
|
||||
ReinsertContent(parentContainer, blockContent);
|
||||
}
|
||||
else if (blockContent->GetCurrentDoc() == mDocument) {
|
||||
ReconstructDocElementHierarchyInternal();
|
||||
}
|
||||
RecreateFramesForContent(blockContent);
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
@ -11105,6 +10976,8 @@ nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame)
|
||||
}
|
||||
#endif
|
||||
|
||||
// XXXbz how exactly would we get here while isReflowing anyway? Should this
|
||||
// whole test be ifdef DEBUG?
|
||||
PRBool isReflowing;
|
||||
mPresShell->IsReflowLocked(&isReflowing);
|
||||
if(isReflowing) {
|
||||
@ -11129,74 +11002,17 @@ nsCSSFrameConstructor::ReframeContainingBlock(nsIFrame* aFrame)
|
||||
// And get the containingBlock's content
|
||||
nsCOMPtr<nsIContent> blockContent = containingBlock->GetContent();
|
||||
if (blockContent) {
|
||||
// Now find the containingBlock's content's parent
|
||||
nsCOMPtr<nsIContent> parentContainer = blockContent->GetParent();
|
||||
if (parentContainer) {
|
||||
#ifdef DEBUG
|
||||
if (gNoisyContentUpdates) {
|
||||
printf(" ==> blockContent=%p, parentContainer=%p\n",
|
||||
static_cast<void*>(blockContent),
|
||||
static_cast<void*>(parentContainer));
|
||||
}
|
||||
#endif
|
||||
return ReinsertContent(parentContainer, blockContent);
|
||||
if (gNoisyContentUpdates) {
|
||||
printf(" ==> blockContent=%p\n", static_cast<void*>(blockContent));
|
||||
}
|
||||
#endif
|
||||
return RecreateFramesForContent(blockContent);
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here, we're screwed!
|
||||
return ReconstructDocElementHierarchyInternal();
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsCSSFrameConstructor::RemoveFixedItems(const nsFrameConstructorState& aState,
|
||||
nsIFrame *aRootElementFrame)
|
||||
{
|
||||
nsresult rv=NS_OK;
|
||||
|
||||
if (mFixedContainingBlock) {
|
||||
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.
|
||||
nsPlaceholderFrame *placeholderFrame =
|
||||
aState.mFrameManager->GetPlaceholderFrameFor(fixedChild);
|
||||
NS_ASSERTION(placeholderFrame, "no placeholder for fixed-pos frame");
|
||||
NS_ASSERTION(placeholderFrame->GetType() ==
|
||||
nsGkAtoms::placeholderFrame,
|
||||
"Wrong type");
|
||||
UnregisterPlaceholderChain(aState.mFrameManager, placeholderFrame);
|
||||
nsIFrame* placeholderParent = placeholderFrame->GetParent();
|
||||
::DeletingFrameSubtree(aState.mFrameManager, placeholderFrame);
|
||||
rv = aState.mFrameManager->RemoveFrame(placeholderParent, nsnull,
|
||||
placeholderFrame);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Error removing placeholder for fixed frame in RemoveFixedItems");
|
||||
break;
|
||||
}
|
||||
|
||||
::DeletingFrameSubtree(aState.mFrameManager, fixedChild);
|
||||
rv = aState.mFrameManager->RemoveFrame(mFixedContainingBlock,
|
||||
nsGkAtoms::fixedList,
|
||||
fixedChild);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("Error removing frame from fixed containing block in RemoveFixedItems");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while(fixedChild);
|
||||
} else {
|
||||
NS_WARNING( "RemoveFixedItems called with no FixedContainingBlock data member set");
|
||||
}
|
||||
return rv;
|
||||
return RecreateFramesForContent(mPresShell->GetDocument()->GetRootContent());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -106,8 +106,7 @@ private:
|
||||
|
||||
public:
|
||||
// XXXbz this method needs to actually return errors!
|
||||
nsresult ConstructRootFrame(nsIContent* aDocElement,
|
||||
nsIFrame** aNewFrame);
|
||||
nsresult ConstructRootFrame(nsIFrame** aNewFrame);
|
||||
|
||||
nsresult ReconstructDocElementHierarchy();
|
||||
|
||||
@ -282,11 +281,6 @@ private:
|
||||
struct FrameConstructionItem;
|
||||
class FrameConstructionItemList;
|
||||
|
||||
nsresult ReconstructDocElementHierarchyInternal();
|
||||
|
||||
nsresult ReinsertContent(nsIContent* aContainer,
|
||||
nsIContent* aChild);
|
||||
|
||||
nsresult ConstructPageFrame(nsIPresShell* aPresShell,
|
||||
nsPresContext* aPresContext,
|
||||
nsIFrame* aParentFrame,
|
||||
@ -333,15 +327,16 @@ private:
|
||||
nsIFrame* aParentFrame,
|
||||
FrameConstructionItemList& aItems);
|
||||
|
||||
nsresult ConstructDocElementFrame(nsFrameConstructorState& aState,
|
||||
nsIContent* aDocElement,
|
||||
nsIFrame* aParentFrame,
|
||||
// Construct the frames for the document element. This must always return a
|
||||
// singe new frame (which may, of course, have a bunch of kids).
|
||||
// XXXbz no need to return a frame here, imo.
|
||||
nsresult ConstructDocElementFrame(nsIContent* aDocElement,
|
||||
nsILayoutHistoryState* aFrameState,
|
||||
nsIFrame** aNewFrame);
|
||||
|
||||
nsresult ConstructDocElementTableFrame(nsIContent* aDocElement,
|
||||
nsIFrame* aParentFrame,
|
||||
nsIFrame** aNewTableFrame,
|
||||
nsFrameConstructorState& aState);
|
||||
// Set up our mDocElementContainingBlock correctly for the given root
|
||||
// content.
|
||||
nsresult SetUpDocElementContainingBlock(nsIContent* aDocElement);
|
||||
|
||||
/**
|
||||
* CreateAttributeContent creates a single content/frame combination for an
|
||||
@ -1482,9 +1477,6 @@ private:
|
||||
nsIFrame* aPrevSibling,
|
||||
nsFrameItems& aFrameItems);
|
||||
|
||||
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
|
||||
// will look for last continuations, etc, as necessary. This calls
|
||||
@ -1601,7 +1593,8 @@ private:
|
||||
nsIFrame* mRootElementFrame;
|
||||
// This is the frame for the root element that has no pseudo-element style.
|
||||
nsIFrame* mRootElementStyleFrame;
|
||||
// This is the containing block for fixed-pos frames --- the viewport
|
||||
// This is the containing block for fixed-pos frames --- the
|
||||
// viewport or page frame
|
||||
nsIFrame* mFixedContainingBlock;
|
||||
// This is the containing block that contains the root element ---
|
||||
// the real "initial containing block" according to CSS 2.1.
|
||||
|
@ -2537,6 +2537,11 @@ PresShell::InitialReflow(nscoord aWidth, nscoord aHeight)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!mDocument) {
|
||||
// Nothing to do
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_ASSERTION(!mDidInitialReflow, "Why are we being called?");
|
||||
|
||||
nsCOMPtr<nsIPresShell> kungFuDeathGrip(this);
|
||||
@ -2563,10 +2568,27 @@ PresShell::InitialReflow(nscoord aWidth, nscoord aHeight)
|
||||
|
||||
mPresContext->SetVisibleArea(nsRect(0, 0, aWidth, aHeight));
|
||||
|
||||
nsIContent *root = mDocument ? mDocument->GetRootContent() : nsnull;
|
||||
|
||||
// Get the root frame from the frame manager
|
||||
// XXXbz it would be nice to move this somewhere else... like frame manager
|
||||
// Init(), say. But we need to make sure our views are all set up by the
|
||||
// time we do this!
|
||||
nsIFrame* rootFrame = FrameManager()->GetRootFrame();
|
||||
NS_ASSERTION(!rootFrame, "How did that happen, exactly?");
|
||||
if (!rootFrame) {
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
mFrameConstructor->BeginUpdate();
|
||||
mFrameConstructor->ConstructRootFrame(&rootFrame);
|
||||
FrameManager()->SetRootFrame(rootFrame);
|
||||
mFrameConstructor->EndUpdate();
|
||||
}
|
||||
|
||||
NS_ENSURE_STATE(!mHaveShutDown);
|
||||
|
||||
if (!rootFrame) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsIContent *root = mDocument->GetRootContent();
|
||||
|
||||
if (root) {
|
||||
MOZ_TIMER_DEBUGLOG(("Reset and start: Frame Creation: PresShell::InitialReflow(), this=%p\n",
|
||||
@ -2578,13 +2600,6 @@ PresShell::InitialReflow(nscoord aWidth, nscoord aHeight)
|
||||
nsAutoScriptBlocker scriptBlocker;
|
||||
mFrameConstructor->BeginUpdate();
|
||||
|
||||
if (!rootFrame) {
|
||||
// Have style sheet processor construct a frame for the
|
||||
// precursors to the root content object's frame
|
||||
mFrameConstructor->ConstructRootFrame(root, &rootFrame);
|
||||
FrameManager()->SetRootFrame(rootFrame);
|
||||
}
|
||||
|
||||
// Have the style sheet processor construct frame for the root
|
||||
// content object down
|
||||
mFrameConstructor->ContentInserted(nsnull, root, 0, nsnull);
|
||||
@ -2600,7 +2615,7 @@ PresShell::InitialReflow(nscoord aWidth, nscoord aHeight)
|
||||
mFrameConstructor->EndUpdate();
|
||||
}
|
||||
|
||||
// DidCauseReflow may have killed us too
|
||||
// nsAutoScriptBlocker going out of scope may have killed us too
|
||||
NS_ENSURE_STATE(!mHaveShutDown);
|
||||
|
||||
// Run the XBL binding constructors for any new frames we've constructed
|
||||
@ -2618,27 +2633,22 @@ PresShell::InitialReflow(nscoord aWidth, nscoord aHeight)
|
||||
|
||||
// And that might have run _more_ XBL constructors
|
||||
NS_ENSURE_STATE(!mHaveShutDown);
|
||||
|
||||
// Now reget the root frame, since all that script might have affected it
|
||||
// somehow. Currently that can't happen, as long as mHaveShutDown is
|
||||
// false, but let's not rely on that.
|
||||
rootFrame = FrameManager()->GetRootFrame();
|
||||
}
|
||||
|
||||
if (rootFrame) {
|
||||
// Note: Because the frame just got created, it has the NS_FRAME_IS_DIRTY
|
||||
// bit set. Unset it so that FrameNeedsReflow() will work right.
|
||||
NS_ASSERTION(!mDirtyRoots.Contains(rootFrame),
|
||||
"Why is the root in mDirtyRoots already?");
|
||||
NS_ASSERTION(rootFrame, "How did that happen?");
|
||||
|
||||
rootFrame->RemoveStateBits(NS_FRAME_IS_DIRTY |
|
||||
NS_FRAME_HAS_DIRTY_CHILDREN);
|
||||
FrameNeedsReflow(rootFrame, eResize, NS_FRAME_IS_DIRTY);
|
||||
// Note: Because the frame just got created, it has the NS_FRAME_IS_DIRTY
|
||||
// bit set. Unset it so that FrameNeedsReflow() will work right.
|
||||
NS_ASSERTION(!mDirtyRoots.Contains(rootFrame),
|
||||
"Why is the root in mDirtyRoots already?");
|
||||
|
||||
NS_ASSERTION(mDirtyRoots.Contains(rootFrame),
|
||||
"Should be in mDirtyRoots now");
|
||||
NS_ASSERTION(mReflowEvent.IsPending(), "Why no reflow event pending?");
|
||||
}
|
||||
rootFrame->RemoveStateBits(NS_FRAME_IS_DIRTY |
|
||||
NS_FRAME_HAS_DIRTY_CHILDREN);
|
||||
FrameNeedsReflow(rootFrame, eResize, NS_FRAME_IS_DIRTY);
|
||||
|
||||
NS_ASSERTION(mDirtyRoots.Contains(rootFrame),
|
||||
"Should be in mDirtyRoots now");
|
||||
NS_ASSERTION(mReflowEvent.IsPending(), "Why no reflow event pending?");
|
||||
|
||||
// Restore our root scroll position now if we're getting here after EndLoad
|
||||
// got called, since this is our one chance to do it. Note that we need not
|
||||
|
@ -50,6 +50,8 @@ DEFINES += -D_IMPL_NS_LAYOUT
|
||||
_TEST_FILES = \
|
||||
test_bug66619.html \
|
||||
test_bug114649.html \
|
||||
test_bug369950.html \
|
||||
bug369950-subframe.xml \
|
||||
test_bug386575.xhtml \
|
||||
test_bug388019.html \
|
||||
test_bug394057.html \
|
||||
|
11
layout/base/tests/bug369950-subframe.xml
Normal file
11
layout/base/tests/bug369950-subframe.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
|
||||
<head>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<p>foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo <x></y></p>
|
||||
|
||||
</body>
|
||||
</html>
|
74
layout/base/tests/test_bug369950.html
Normal file
74
layout/base/tests/test_bug369950.html
Normal file
@ -0,0 +1,74 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=369950
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 369950</title>
|
||||
<script type="application/javascript" src="/MochiKit/MochiKit.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=369950">Mozilla Bug 369950</a>
|
||||
<p id="display">
|
||||
<iframe id="i" src="bug369950-subframe.xml"></iframe>
|
||||
</p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 369950 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
addLoadEvent(function() {
|
||||
// Can't just run our code here, because we might not have painting
|
||||
// unsuppressed yet. Do it async.
|
||||
SimpleTest.executeSoon(doTheTest);
|
||||
});
|
||||
|
||||
function doTheTest() {
|
||||
var rect = $("i").getBoundingClientRect();
|
||||
var rect2 = $("i").contentDocument.documentElement.getBoundingClientRect();
|
||||
// We want coords relative to the iframe, so subtract off rect2.left/top.
|
||||
// 7px is a guess to get us from the bottom of the iframe into the scrollbar
|
||||
// groove for the horizontal scrollbar on the bottom.
|
||||
synthesizeMouse($("i").contentDocument.documentElement,
|
||||
-rect2.left + rect.width / 2, rect.height - rect2.top - 7,
|
||||
{}, $("i").contentWindow);
|
||||
// Scroll is async, so give it time
|
||||
SimpleTest.executeSoon(checkScroll);
|
||||
};
|
||||
|
||||
function checkScroll() {
|
||||
var rect = $("i").getBoundingClientRect();
|
||||
var rect2 = $("i").contentDocument.documentElement.getBoundingClientRect();
|
||||
isnot($("i").contentWindow.scrollX, 0, "Clicking scrollbar should scroll");
|
||||
|
||||
// Not doing things below here, since avoiding the scroll arrows
|
||||
// cross-platform is a huge pain.
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
|
||||
// 8px horizontal offset is a guess to get us into the scr
|
||||
synthesizeMouse($("i").contentDocument.documentElement, -rect2.left + 8,
|
||||
rect.height - rect2.top - 7, {}, $("i").contentWindow);
|
||||
// Scroll is async, so give it time
|
||||
SimpleTest.executeSoon(finishUp);
|
||||
}
|
||||
|
||||
function finishUp() {
|
||||
is($("i").contentWindow.scrollX, 0, "Clicking scrollbar should scroll back");
|
||||
SimpleTest.finish();
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -119,9 +119,9 @@ ViewportFrame::AppendFrames(nsIAtom* aListName,
|
||||
rv = mFixedContainer.AppendFrames(this, aListName, aFrameList);
|
||||
}
|
||||
else {
|
||||
// We only expect incremental changes for our fixed frames
|
||||
NS_ERROR("unexpected child list");
|
||||
rv = NS_ERROR_INVALID_ARG;
|
||||
NS_ASSERTION(!aListName, "unexpected child list");
|
||||
NS_ASSERTION(!GetFirstChild(nsnull), "Shouldn't have any kids!");
|
||||
rv = nsContainerFrame::AppendFrames(aListName, aFrameList);
|
||||
}
|
||||
|
||||
return rv;
|
||||
@ -138,9 +138,9 @@ ViewportFrame::InsertFrames(nsIAtom* aListName,
|
||||
rv = mFixedContainer.InsertFrames(this, aListName, aPrevFrame, aFrameList);
|
||||
}
|
||||
else {
|
||||
// We only expect incremental changes for our fixed frames
|
||||
NS_ERROR("unexpected child list");
|
||||
rv = NS_ERROR_INVALID_ARG;
|
||||
NS_ASSERTION(!aListName, "unexpected child list");
|
||||
NS_ASSERTION(!GetFirstChild(nsnull), "Shouldn't have any kids!");
|
||||
rv = nsContainerFrame::InsertFrames(aListName, aPrevFrame, aFrameList);
|
||||
}
|
||||
|
||||
return rv;
|
||||
@ -156,9 +156,8 @@ ViewportFrame::RemoveFrame(nsIAtom* aListName,
|
||||
rv = mFixedContainer.RemoveFrame(this, aListName, aOldFrame);
|
||||
}
|
||||
else {
|
||||
// We only expect incremental changes for our fixed frames
|
||||
NS_ERROR("unexpected child list");
|
||||
rv = NS_ERROR_INVALID_ARG;
|
||||
NS_ASSERTION(!aListName, "unexpected child list");
|
||||
rv = nsContainerFrame::RemoveFrame(aListName, aOldFrame);
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
Loading…
Reference in New Issue
Block a user