diff --git a/mozilla/content/html/style/src/nsHTMLStyleSheet.cpp b/mozilla/content/html/style/src/nsHTMLStyleSheet.cpp index b994b7335d9..f5eecbd09d6 100644 --- a/mozilla/content/html/style/src/nsHTMLStyleSheet.cpp +++ b/mozilla/content/html/style/src/nsHTMLStyleSheet.cpp @@ -1575,34 +1575,15 @@ HTMLStyleSheetImpl::ConstructDocElementFrame(nsIPresContext* aPresContext, // Unless the 'overflow' policy forbids scrolling, wrap the frame in a // scroll frame. - nsIFrame* scrollFrame = nsnull; - nsStyleDisplay* display = (nsStyleDisplay*) - styleContext->GetMutableStyleData(eStyleStruct_Display); - - // XXX This needs to go away... Yes, but where. - // Check the webshell and see if scrolling is enabled there. - nsISupports* container; - if (nsnull != aPresContext) { - aPresContext->GetContainer(&container); - if (nsnull != container) { - nsIWebShell* webShell = nsnull; - container->QueryInterface(kIWebShellIID, (void**) &webShell); - if (nsnull != webShell) { - PRInt32 scrolling = -1; - webShell->GetScrolling(scrolling); - if (-1 != scrolling) { - display->mOverflow = scrolling; - } - NS_RELEASE(webShell); - } - NS_RELEASE(container); - } - } + nsIFrame* scrollFrame = nsnull; - if (NS_STYLE_OVERFLOW_HIDDEN != display->mOverflow) { + const nsStyleDisplay* display = (const nsStyleDisplay*) + styleContext->GetStyleData(eStyleStruct_Display); + + if (IsScrollable(aPresContext, display)) { NS_NewScrollFrame(scrollFrame); scrollFrame->Init(*aPresContext, aDocElement, aRootFrame, styleContext); - + // The scrolled frame gets a pseudo element style context nsIStyleContext* scrolledPseudoStyle = aPresContext->ResolvePseudoStyleContextFor(nsnull, @@ -1656,50 +1637,105 @@ HTMLStyleSheetImpl::ConstructRootFrame(nsIPresContext* aPresContext, nsIFrame*& aNewFrame) { #ifdef NS_DEBUG - nsIDocument* doc; - nsIContent* rootContent; + nsIDocument* doc; + nsIContent* rootContent; - // Verify that the content object is really the root content object - aDocElement->GetDocument(doc); - rootContent = doc->GetRootContent(); - NS_RELEASE(doc); - NS_ASSERTION(rootContent == aDocElement, "unexpected content"); - NS_RELEASE(rootContent); + // Verify that the content object is really the root content object + aDocElement->GetDocument(doc); + rootContent = doc->GetRootContent(); + NS_RELEASE(doc); + NS_ASSERTION(rootContent == aDocElement, "unexpected content"); + NS_RELEASE(rootContent); #endif - nsIFrame* rootFrame; + nsIFrame* viewportFrame; nsIStyleContext* rootPseudoStyle; - // Create the root frame - NS_NewRootFrame(rootFrame); - + // Create the viewport frame + NS_NewViewportFrame(viewportFrame); + // Create a pseudo element style context + // XXX Use a different pseudo style context... rootPseudoStyle = aPresContext->ResolvePseudoStyleContextFor(nsnull, nsHTMLAtoms::rootPseudo, nsnull); - // Initialize the root frame. It has a NULL content object - rootFrame->Init(*aPresContext, nsnull, nsnull, rootPseudoStyle); + // Initialize the viewport frame. It has a NULL content object + viewportFrame->Init(*aPresContext, nsnull, nsnull, rootPseudoStyle); - // Bind the root frame to the root view + // Bind the viewport frame to the root view nsIPresShell* presShell = aPresContext->GetShell(); nsIViewManager* viewManager = presShell->GetViewManager(); nsIView* rootView; - + NS_RELEASE(presShell); viewManager->GetRootView(rootView); - rootFrame->SetView(rootView); + viewportFrame->SetView(rootView); NS_RELEASE(viewManager); - + + // As long as the webshell doesn't prohibit it, create a scroll frame + // that will act as the scolling mechanism for the viewport + // XXX We should only do this when presenting to the screen, i.e., for galley + // mode and print-preview, but not when printing + PRBool isScrollable = PR_TRUE; + nsISupports* container; + if (nsnull != aPresContext) { + aPresContext->GetContainer(&container); + if (nsnull != container) { + nsIWebShell* webShell = nsnull; + container->QueryInterface(kIWebShellIID, (void**) &webShell); + if (nsnull != webShell) { + PRInt32 scrolling = -1; + webShell->GetScrolling(scrolling); + if (NS_STYLE_OVERFLOW_HIDDEN == scrolling) { + isScrollable = PR_FALSE; + } + NS_RELEASE(webShell); + } + NS_RELEASE(container); + } + } + + // If the viewport should offer a scrolling mechanism, then create a + // scroll frame + nsIFrame* scrollFrame; + if (isScrollable) { + NS_NewScrollFrame(scrollFrame); + scrollFrame->Init(*aPresContext, nsnull, viewportFrame, rootPseudoStyle); + } + + // Create the root frame. The document element's frame is a child of the + // root frame. + // + // Note: the major reason we need the root frame is to implement margins for + // the document element's frame. If we didn't need to support margins on the + // document element's frame, then we could eliminate the root frame and make + // the document element frame a child of the viewport (or its scroll frame) + nsIFrame* rootFrame; + NS_NewRootFrame(rootFrame); + + rootFrame->Init(*aPresContext, nsnull, isScrollable ? scrollFrame : + viewportFrame, rootPseudoStyle); + if (isScrollable) { + nsHTMLContainerFrame::CreateViewForFrame(*aPresContext, rootFrame, + rootPseudoStyle, PR_TRUE); + } + // Create frames for the document element and its child elements nsIFrame* docElementFrame; ConstructDocElementFrame(aPresContext, aDocElement, rootFrame, rootPseudoStyle, docElementFrame); NS_RELEASE(rootPseudoStyle); - // Set the root frame's initial child list + // Set the initial child lists rootFrame->SetInitialChildList(*aPresContext, nsnull, docElementFrame); + if (isScrollable) { + scrollFrame->SetInitialChildList(*aPresContext, nsnull, rootFrame); + viewportFrame->SetInitialChildList(*aPresContext, nsnull, scrollFrame); + } else { + viewportFrame->SetInitialChildList(*aPresContext, nsnull, rootFrame); + } - aNewFrame = rootFrame; + aNewFrame = viewportFrame; return NS_OK; } @@ -2977,40 +3013,35 @@ HTMLStyleSheetImpl::ReconstructFrames(nsIPresContext* aPresContext, return rv; } - // XXX Currently we only know how to do this for XML documents if (nsnull != document) { nsIPresShell* shell = aPresContext->GetShell(); -// nsIXMLDocument* xmlDocument; -// rv = document->QueryInterface(kIXMLDocumentIID, (void **)&xmlDocument); - if (NS_SUCCEEDED(rv)) { + // XXX This API needs changing, because it appears to be designed for + // an arbitrary content element, but yet it always constructs the document + // element's frame. Plus it has the problem noted above in the previous XXX rv = aParentFrame->RemoveFrame(*aPresContext, *shell, nsnull, aFrameSubTree); + if (NS_SUCCEEDED(rv)) { - nsIFrame *newChild; - // XXX See ConstructXMLContents for an explanation of why - // we create this pseudostyle + nsIFrame* newChild; nsIStyleContext* rootPseudoStyle; - rootPseudoStyle = aPresContext->ResolvePseudoStyleContextFor(nsnull, - nsHTMLAtoms::rootPseudo, nsnull); - + + aParentFrame->GetStyleContext(rootPseudoStyle); rv = ConstructDocElementFrame(aPresContext, aContent, aParentFrame, rootPseudoStyle, newChild); + NS_RELEASE(rootPseudoStyle); if (NS_SUCCEEDED(rv)) { rv = aParentFrame->InsertFrames(*aPresContext, *shell, nsnull, nsnull, newChild); } - NS_IF_RELEASE(rootPseudoStyle); } -// NS_RELEASE(xmlDocument); } NS_RELEASE(document); NS_RELEASE(shell); } return rv; - } nsIFrame* diff --git a/mozilla/layout/base/nsPresShell.cpp b/mozilla/layout/base/nsPresShell.cpp index e6c6cb0c334..1be209360ce 100644 --- a/mozilla/layout/base/nsPresShell.cpp +++ b/mozilla/layout/base/nsPresShell.cpp @@ -1170,18 +1170,23 @@ PresShell::ReconstructFrames(void) { nsresult rv = NS_OK; if (nsnull != mRootFrame) { - nsIFrame* childFrame; - rv = mRootFrame->FirstChild(nsnull, childFrame); - if (nsnull != mDocument) { - nsIContent* root = mDocument->GetRootContent(); - if (nsnull != root) { + nsIContent* rootContent = mDocument->GetRootContent(); + if (nsnull != rootContent) { + nsIFrame* docElementFrame; + nsIFrame* parentFrame; - EnterReflowLock(); - rv = mStyleSet->ReconstructFrames(mPresContext, root, - mRootFrame, childFrame); - ExitReflowLock(); - NS_RELEASE(root); + // Get the frame that corresponds to the document element + GetPrimaryFrameFor(rootContent, docElementFrame); + if (nsnull != docElementFrame) { + docElementFrame->GetParent(parentFrame); + + EnterReflowLock(); + rv = mStyleSet->ReconstructFrames(mPresContext, rootContent, + parentFrame, docElementFrame); + ExitReflowLock(); + NS_RELEASE(rootContent); + } } } } diff --git a/mozilla/layout/generic/nsHTMLFrame.cpp b/mozilla/layout/generic/nsHTMLFrame.cpp index 8a11793d8ea..9db67e9caf2 100644 --- a/mozilla/layout/generic/nsHTMLFrame.cpp +++ b/mozilla/layout/generic/nsHTMLFrame.cpp @@ -71,8 +71,14 @@ public: NS_IMETHOD GetFrameName(nsString& aResult) const; + // XXX Temporary hack... + NS_IMETHOD SetRect(const nsRect& aRect); + protected: virtual PRIntn GetSkipSides() const; + +private: + nscoord mNaturalHeight; }; //---------------------------------------------------------------------- @@ -97,6 +103,27 @@ RootFrame::SetInitialChildList(nsIPresContext& aPresContext, return NS_OK; } +// XXX Temporary hack until we support the CSS2 'min-width', 'max-width', +// 'min-height', and 'max-height' properties. Then we can do this in a top-down +// fashion +NS_IMETHODIMP +RootFrame::SetRect(const nsRect& aRect) +{ + nsresult rv = nsHTMLContainerFrame::SetRect(aRect); + + // Make sure our child's frame is adjusted as well + nsIFrame* kidFrame = mFrames.FirstChild(); + if (nsnull != kidFrame) { + nscoord yDelta = aRect.height - mNaturalHeight; + nsSize kidSize; + + kidFrame->GetSize(kidSize); + kidFrame->SizeTo(kidSize.width, kidSize.height + yDelta); + } + + return rv; +} + NS_IMETHODIMP RootFrame::Reflow(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aDesiredSize, @@ -162,23 +189,23 @@ RootFrame::Reflow(nsIPresContext& aPresContext, } // Reflow our one and only child frame + nsHTMLReflowMetrics kidDesiredSize(nsnull); if (mFrames.NotEmpty()) { - nsIFrame* myOnlyChild = mFrames.FirstChild(); + nsIFrame* kidFrame = mFrames.FirstChild(); - // Note: the root frame does not have border or padding... - nsHTMLReflowMetrics desiredSize(nsnull); // We must pass in that the available height is unconstrained, because // constrained is only for when we're paginated... - nsHTMLReflowState kidReflowState(aPresContext, myOnlyChild, - aReflowState, + nsHTMLReflowState kidReflowState(aPresContext, kidFrame, aReflowState, nsSize(aReflowState.availableWidth, NS_UNCONSTRAINEDSIZE)); if (isChildInitialReflow) { kidReflowState.reason = eReflowReason_Initial; kidReflowState.reflowCommand = nsnull; } + // XXX TROY +#if 0 // For a height that's 'auto', make the frame as big as the available space - // minus and top and bottom margins + // minus any top and bottom margins if (NS_AUTOHEIGHT == kidReflowState.computedHeight) { kidReflowState.computedHeight = aReflowState.availableHeight - kidReflowState.computedMargin.top - kidReflowState.computedMargin.bottom; @@ -189,20 +216,28 @@ RootFrame::Reflow(nsIPresContext& aPresContext, kidReflowState.ComputeBorderPaddingFor(myOnlyChild, &aReflowState, borderPadding); kidReflowState.computedHeight -= borderPadding.top + borderPadding.bottom; } +#endif // Reflow the frame nsIHTMLReflow* htmlReflow; - if (NS_OK == myOnlyChild->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) { - ReflowChild(myOnlyChild, aPresContext, desiredSize, kidReflowState, + if (NS_OK == kidFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) { + // XXX Temporary hack until the block/inline code changes. It expects + // the available width to be the space minus any margins... + kidReflowState.availableWidth -= kidReflowState.computedMargin.left + + kidReflowState.computedMargin.right; + ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState, aStatus); nsRect rect(kidReflowState.computedMargin.left, kidReflowState.computedMargin.top, - desiredSize.width, desiredSize.height); - myOnlyChild->SetRect(rect); + kidDesiredSize.width, kidDesiredSize.height); + kidFrame->SetRect(rect); + // XXX TROY +#if 0 // XXX We should resolve the details of who/when DidReflow() // notifications are sent... htmlReflow->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); +#endif } // If this is a resize reflow then do a repaint @@ -210,13 +245,18 @@ RootFrame::Reflow(nsIPresContext& aPresContext, nsRect damageRect(0, 0, aReflowState.availableWidth, aReflowState.availableHeight); Invalidate(damageRect, PR_FALSE); } - } - // Return the max size as our desired size - aDesiredSize.width = aReflowState.availableWidth; - aDesiredSize.height = aReflowState.availableHeight; - aDesiredSize.ascent = aDesiredSize.height; - aDesiredSize.descent = 0; + // Return our desired size + aDesiredSize.width = kidDesiredSize.width + kidReflowState.computedMargin.left + + kidReflowState.computedMargin.right; + aDesiredSize.height = kidDesiredSize.height + kidReflowState.computedMargin.top + + kidReflowState.computedMargin.bottom; + aDesiredSize.ascent = aDesiredSize.height; + aDesiredSize.descent = 0; + + // XXX Temporary hack. Remember this for later when our parent resizes us + mNaturalHeight = aDesiredSize.height; + } NS_FRAME_TRACE_REFLOW_OUT("RootFrame::Reflow", aStatus); return NS_OK; diff --git a/mozilla/layout/generic/nsHTMLParts.h b/mozilla/layout/generic/nsHTMLParts.h index 1a26e173d11..051012d9f91 100644 --- a/mozilla/layout/generic/nsHTMLParts.h +++ b/mozilla/layout/generic/nsHTMLParts.h @@ -254,6 +254,7 @@ extern nsresult NS_NewHTMLFrameOuterFrame(nsIFrame*& aNewFrame); // extern nsresult NS_NewHTMLFramesetFrame(nsIFrame*& aNewFrame); +extern nsresult NS_NewViewportFrame(nsIFrame*& aNewFrame); extern nsresult NS_NewRootFrame(nsIFrame*& aNewFrame); extern nsresult NS_NewImageFrame(nsIFrame*& aFrameResult); extern nsresult NS_NewInlineFrame(nsIFrame*& aNewFrame); diff --git a/mozilla/layout/generic/nsViewportFrame.cpp b/mozilla/layout/generic/nsViewportFrame.cpp index fa655ed5c3a..4e0b85af76d 100644 --- a/mozilla/layout/generic/nsViewportFrame.cpp +++ b/mozilla/layout/generic/nsViewportFrame.cpp @@ -1 +1,128 @@ -// Just a placeholder for the time being... +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#include "nsHTMLParts.h" +#include "nsContainerFrame.h" +#include "nsHTMLIIDs.h" + +static NS_DEFINE_IID(kIFrameIID, NS_IFRAME_IID); + +/** + * Viewport frame class. + * + * The viewport frame is the parent frame for the document element's frame. + * It only supports having a single child frame which must be one of the + * following: + * - scroll frame + * - root frame + * + * It has an additional named child list: + * - "Fixed-list" which contains the fixed positioned frames + */ +class ViewportFrame : public nsContainerFrame { +public: + NS_IMETHOD Reflow(nsIPresContext& aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); + + NS_IMETHOD GetFrameName(nsString& aResult) const; +}; + +//---------------------------------------------------------------------- + +nsresult +NS_NewViewportFrame(nsIFrame*& aResult) +{ + ViewportFrame* frame = new ViewportFrame; + if (nsnull == frame) { + return NS_ERROR_OUT_OF_MEMORY; + } + aResult = frame; + return NS_OK; +} + +NS_IMETHODIMP +ViewportFrame::Reflow(nsIPresContext& aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) +{ + NS_FRAME_TRACE_REFLOW_IN("ViewportFrame::Reflow"); + NS_PRECONDITION(nsnull == aDesiredSize.maxElementSize, "unexpected request"); + + // Initialize OUT parameter + aStatus = NS_FRAME_COMPLETE; + + // Check for an incremental reflow + if (eReflowReason_Incremental == aReflowState.reason) { + // See if we're the target frame + nsIFrame* targetFrame; + aReflowState.reflowCommand->GetTarget(targetFrame); + if (this == targetFrame) { + // The viewport does not support being the target of an incremental + // reflow command + NS_ASSERTION(PR_FALSE, "unexpected reflow command target"); + + } else { + nsIFrame* nextFrame; + // Get the next frame in the reflow chain + aReflowState.reflowCommand->GetNext(nextFrame); + NS_ASSERTION(nextFrame == mFrames.FirstChild(), "unexpected next reflow command frame"); + } + } + + // Reflow our one and only child frame + if (mFrames.NotEmpty()) { + nsIFrame* kidFrame = mFrames.FirstChild(); + nsHTMLReflowMetrics desiredSize(nsnull); + nsSize availableSpace(aReflowState.availableWidth, + aReflowState.availableHeight); + nsHTMLReflowState kidReflowState(aPresContext, kidFrame, + aReflowState, availableSpace); + + // Reflow the frame + nsIHTMLReflow* htmlReflow; + if (NS_OK == kidFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) { + kidReflowState.computedHeight = aReflowState.availableHeight; + ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, + aStatus); + + nsRect rect(0, 0, desiredSize.width, desiredSize.height); + kidFrame->SetRect(rect); + + // XXX We should resolve the details of who/when DidReflow() + // notifications are sent... + htmlReflow->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); + } + } + + // Return the max size as our desired size + aDesiredSize.width = aReflowState.availableWidth; + aDesiredSize.height = aReflowState.availableHeight; + aDesiredSize.ascent = aReflowState.availableHeight; + aDesiredSize.descent = 0; + + NS_FRAME_TRACE_REFLOW_OUT("ViewportFrame::Reflow", aStatus); + return NS_OK; +} + +NS_IMETHODIMP +ViewportFrame::GetFrameName(nsString& aResult) const +{ + return MakeFrameName("Viewport", aResult); +} diff --git a/mozilla/layout/html/base/src/Makefile.in b/mozilla/layout/html/base/src/Makefile.in index 8514244b089..78b9fa6c388 100644 --- a/mozilla/layout/html/base/src/Makefile.in +++ b/mozilla/layout/html/base/src/Makefile.in @@ -60,6 +60,7 @@ CPPSRCS= \ nsSplittableFrame.cpp \ nsTextFrame.cpp \ nsTextTransformer.cpp \ + nsViewportFrame.cpp \ nsWBRFrame.cpp \ $(NULL) diff --git a/mozilla/layout/html/base/src/makefile.win b/mozilla/layout/html/base/src/makefile.win index 55003553a1a..b30a8844cb2 100644 --- a/mozilla/layout/html/base/src/makefile.win +++ b/mozilla/layout/html/base/src/makefile.win @@ -60,6 +60,7 @@ CPPSRCS= \ nsSplittableFrame.cpp \ nsTextFrame.cpp \ nsTextTransformer.cpp \ + nsViewportFrame.cpp \ nsWBRFrame.cpp \ $(NULL) @@ -98,6 +99,7 @@ CPP_OBJS= \ .\$(OBJDIR)\nsSplittableFrame.obj \ .\$(OBJDIR)\nsTextFrame.obj \ .\$(OBJDIR)\nsTextTransformer.obj \ + .\$(OBJDIR)\nsViewportFrame.obj \ .\$(OBJDIR)\nsWBRFrame.obj \ $(NULL) diff --git a/mozilla/layout/html/base/src/nsHTMLFrame.cpp b/mozilla/layout/html/base/src/nsHTMLFrame.cpp index 8a11793d8ea..9db67e9caf2 100644 --- a/mozilla/layout/html/base/src/nsHTMLFrame.cpp +++ b/mozilla/layout/html/base/src/nsHTMLFrame.cpp @@ -71,8 +71,14 @@ public: NS_IMETHOD GetFrameName(nsString& aResult) const; + // XXX Temporary hack... + NS_IMETHOD SetRect(const nsRect& aRect); + protected: virtual PRIntn GetSkipSides() const; + +private: + nscoord mNaturalHeight; }; //---------------------------------------------------------------------- @@ -97,6 +103,27 @@ RootFrame::SetInitialChildList(nsIPresContext& aPresContext, return NS_OK; } +// XXX Temporary hack until we support the CSS2 'min-width', 'max-width', +// 'min-height', and 'max-height' properties. Then we can do this in a top-down +// fashion +NS_IMETHODIMP +RootFrame::SetRect(const nsRect& aRect) +{ + nsresult rv = nsHTMLContainerFrame::SetRect(aRect); + + // Make sure our child's frame is adjusted as well + nsIFrame* kidFrame = mFrames.FirstChild(); + if (nsnull != kidFrame) { + nscoord yDelta = aRect.height - mNaturalHeight; + nsSize kidSize; + + kidFrame->GetSize(kidSize); + kidFrame->SizeTo(kidSize.width, kidSize.height + yDelta); + } + + return rv; +} + NS_IMETHODIMP RootFrame::Reflow(nsIPresContext& aPresContext, nsHTMLReflowMetrics& aDesiredSize, @@ -162,23 +189,23 @@ RootFrame::Reflow(nsIPresContext& aPresContext, } // Reflow our one and only child frame + nsHTMLReflowMetrics kidDesiredSize(nsnull); if (mFrames.NotEmpty()) { - nsIFrame* myOnlyChild = mFrames.FirstChild(); + nsIFrame* kidFrame = mFrames.FirstChild(); - // Note: the root frame does not have border or padding... - nsHTMLReflowMetrics desiredSize(nsnull); // We must pass in that the available height is unconstrained, because // constrained is only for when we're paginated... - nsHTMLReflowState kidReflowState(aPresContext, myOnlyChild, - aReflowState, + nsHTMLReflowState kidReflowState(aPresContext, kidFrame, aReflowState, nsSize(aReflowState.availableWidth, NS_UNCONSTRAINEDSIZE)); if (isChildInitialReflow) { kidReflowState.reason = eReflowReason_Initial; kidReflowState.reflowCommand = nsnull; } + // XXX TROY +#if 0 // For a height that's 'auto', make the frame as big as the available space - // minus and top and bottom margins + // minus any top and bottom margins if (NS_AUTOHEIGHT == kidReflowState.computedHeight) { kidReflowState.computedHeight = aReflowState.availableHeight - kidReflowState.computedMargin.top - kidReflowState.computedMargin.bottom; @@ -189,20 +216,28 @@ RootFrame::Reflow(nsIPresContext& aPresContext, kidReflowState.ComputeBorderPaddingFor(myOnlyChild, &aReflowState, borderPadding); kidReflowState.computedHeight -= borderPadding.top + borderPadding.bottom; } +#endif // Reflow the frame nsIHTMLReflow* htmlReflow; - if (NS_OK == myOnlyChild->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) { - ReflowChild(myOnlyChild, aPresContext, desiredSize, kidReflowState, + if (NS_OK == kidFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) { + // XXX Temporary hack until the block/inline code changes. It expects + // the available width to be the space minus any margins... + kidReflowState.availableWidth -= kidReflowState.computedMargin.left + + kidReflowState.computedMargin.right; + ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState, aStatus); nsRect rect(kidReflowState.computedMargin.left, kidReflowState.computedMargin.top, - desiredSize.width, desiredSize.height); - myOnlyChild->SetRect(rect); + kidDesiredSize.width, kidDesiredSize.height); + kidFrame->SetRect(rect); + // XXX TROY +#if 0 // XXX We should resolve the details of who/when DidReflow() // notifications are sent... htmlReflow->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); +#endif } // If this is a resize reflow then do a repaint @@ -210,13 +245,18 @@ RootFrame::Reflow(nsIPresContext& aPresContext, nsRect damageRect(0, 0, aReflowState.availableWidth, aReflowState.availableHeight); Invalidate(damageRect, PR_FALSE); } - } - // Return the max size as our desired size - aDesiredSize.width = aReflowState.availableWidth; - aDesiredSize.height = aReflowState.availableHeight; - aDesiredSize.ascent = aDesiredSize.height; - aDesiredSize.descent = 0; + // Return our desired size + aDesiredSize.width = kidDesiredSize.width + kidReflowState.computedMargin.left + + kidReflowState.computedMargin.right; + aDesiredSize.height = kidDesiredSize.height + kidReflowState.computedMargin.top + + kidReflowState.computedMargin.bottom; + aDesiredSize.ascent = aDesiredSize.height; + aDesiredSize.descent = 0; + + // XXX Temporary hack. Remember this for later when our parent resizes us + mNaturalHeight = aDesiredSize.height; + } NS_FRAME_TRACE_REFLOW_OUT("RootFrame::Reflow", aStatus); return NS_OK; diff --git a/mozilla/layout/html/base/src/nsHTMLParts.h b/mozilla/layout/html/base/src/nsHTMLParts.h index 1a26e173d11..051012d9f91 100644 --- a/mozilla/layout/html/base/src/nsHTMLParts.h +++ b/mozilla/layout/html/base/src/nsHTMLParts.h @@ -254,6 +254,7 @@ extern nsresult NS_NewHTMLFrameOuterFrame(nsIFrame*& aNewFrame); // extern nsresult NS_NewHTMLFramesetFrame(nsIFrame*& aNewFrame); +extern nsresult NS_NewViewportFrame(nsIFrame*& aNewFrame); extern nsresult NS_NewRootFrame(nsIFrame*& aNewFrame); extern nsresult NS_NewImageFrame(nsIFrame*& aFrameResult); extern nsresult NS_NewInlineFrame(nsIFrame*& aNewFrame); diff --git a/mozilla/layout/html/base/src/nsPresShell.cpp b/mozilla/layout/html/base/src/nsPresShell.cpp index e6c6cb0c334..1be209360ce 100644 --- a/mozilla/layout/html/base/src/nsPresShell.cpp +++ b/mozilla/layout/html/base/src/nsPresShell.cpp @@ -1170,18 +1170,23 @@ PresShell::ReconstructFrames(void) { nsresult rv = NS_OK; if (nsnull != mRootFrame) { - nsIFrame* childFrame; - rv = mRootFrame->FirstChild(nsnull, childFrame); - if (nsnull != mDocument) { - nsIContent* root = mDocument->GetRootContent(); - if (nsnull != root) { + nsIContent* rootContent = mDocument->GetRootContent(); + if (nsnull != rootContent) { + nsIFrame* docElementFrame; + nsIFrame* parentFrame; - EnterReflowLock(); - rv = mStyleSet->ReconstructFrames(mPresContext, root, - mRootFrame, childFrame); - ExitReflowLock(); - NS_RELEASE(root); + // Get the frame that corresponds to the document element + GetPrimaryFrameFor(rootContent, docElementFrame); + if (nsnull != docElementFrame) { + docElementFrame->GetParent(parentFrame); + + EnterReflowLock(); + rv = mStyleSet->ReconstructFrames(mPresContext, rootContent, + parentFrame, docElementFrame); + ExitReflowLock(); + NS_RELEASE(rootContent); + } } } } diff --git a/mozilla/layout/html/base/src/nsScrollFrame.cpp b/mozilla/layout/html/base/src/nsScrollFrame.cpp index a3197b2914b..02501409f1f 100644 --- a/mozilla/layout/html/base/src/nsScrollFrame.cpp +++ b/mozilla/layout/html/base/src/nsScrollFrame.cpp @@ -296,9 +296,10 @@ nsScrollFrame::Reflow(nsIPresContext& aPresContext, kidReflowSize); nsHTMLReflowMetrics kidDesiredSize(aDesiredSize.maxElementSize); - // Recompute the computed width based on the scroll area size - kidReflowState.computedWidth = scrollAreaSize.width - padding.left - - padding.right; + // Reset the computed width based on the scroll area size + // XXX We should have a nsScrollReflowState which overrides the + // InitConstraints() function... + kidReflowState.computedWidth = scrollAreaSize.width - padding.left - padding.right; kidReflowState.computedHeight = NS_AUTOHEIGHT; ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState, @@ -319,6 +320,41 @@ nsScrollFrame::Reflow(nsIPresContext& aPresContext, kidDesiredSize.height = yMost; } } + + // XXX Speculative code... + // Now if we're 'auto' scrolling and we don't need the vertical scrollbar + // then reflow the child frame again, this time letting it reflow to the space + // where the vertical scrollbar would be... + if ((display->mOverflow != NS_STYLE_OVERFLOW_SCROLL) && + (NS_AUTOHEIGHT != aReflowState.computedHeight)) { + if (kidDesiredSize.height < scrollAreaSize.height) { + // No vertical scrollbar needed so reflow the document with a larger + // computed width + // XXX We need to be checking for horizontal scrolling... + kidReflowState.availableWidth += NSToCoordRound(sbWidth); + kidReflowState.computedWidth += NSToCoordRound(sbWidth); + scrollAreaSize.width += NSToCoordRound(sbWidth); + kidReflowState.reason = eReflowReason_Resize; + ReflowChild(kidFrame, aPresContext, kidDesiredSize, kidReflowState, + aStatus); + NS_ASSERTION(NS_FRAME_IS_COMPLETE(aStatus), "bad status"); + } + + // If it's an area frame then get the total size, which includes the + // space taken up by absolutely positioned child elements + nsIAreaFrame* areaFrame; + if (NS_SUCCEEDED(kidFrame->QueryInterface(kAreaFrameIID, (void**)&areaFrame))) { + nscoord xMost, yMost; + + areaFrame->GetPositionedInfo(xMost, yMost); + if (xMost > kidDesiredSize.width) { + kidDesiredSize.width = xMost; + } + if (yMost > kidDesiredSize.height) { + kidDesiredSize.height = yMost; + } + } + } // Make sure the height of the scrolled frame fills the entire scroll area, // unless we're shrink wrapping @@ -336,6 +372,7 @@ nsScrollFrame::Reflow(nsIPresContext& aPresContext, } } +#if 0 if (kidDesiredSize.height <= scrollAreaSize.height) { // If the scrollbars are auto and the scrolled frame is fully visible // vertically then the vertical scrollbar will be hidden so increase the @@ -344,6 +381,7 @@ nsScrollFrame::Reflow(nsIPresContext& aPresContext, kidDesiredSize.width += NSToCoordRound(sbWidth); } } +#endif } // Make sure the width of the scrolled frame fills the entire scroll area if (kidDesiredSize.width < scrollAreaSize.width) { @@ -351,7 +389,9 @@ nsScrollFrame::Reflow(nsIPresContext& aPresContext, } // Place and size the child. - nsRect rect(border.left, border.top, kidDesiredSize.width, kidDesiredSize.height); + nscoord x = border.left; + nscoord y = border.top; + nsRect rect(x, y, kidDesiredSize.width, kidDesiredSize.height); kidFrame->SetRect(rect); // XXX Moved to root frame @@ -371,12 +411,20 @@ nsScrollFrame::Reflow(nsIPresContext& aPresContext, // Compute our desired size aDesiredSize.width = scrollAreaSize.width; +#if 0 aDesiredSize.width += border.left + border.right + NSToCoordRound(sbWidth); +#else + aDesiredSize.width += border.left + border.right; + if (kidDesiredSize.height > scrollAreaSize.height) { + aDesiredSize.width += NSToCoordRound(sbWidth); + } +#endif - // For the height if we're shrink wrapping then use the child's desired size; - // otherwise, use the scroll area size + // For the height if we're shrink wrapping then use whatever is smaller between + // the available height and the child's desired size; otherwise, use the scroll + // area size if (NS_AUTOHEIGHT == aReflowState.computedHeight) { - aDesiredSize.height = kidDesiredSize.height; + aDesiredSize.height = PR_MIN(aReflowState.availableHeight, kidDesiredSize.height); } else { aDesiredSize.height = scrollAreaSize.height; } diff --git a/mozilla/layout/html/base/src/nsViewportFrame.cpp b/mozilla/layout/html/base/src/nsViewportFrame.cpp index fa655ed5c3a..4e0b85af76d 100644 --- a/mozilla/layout/html/base/src/nsViewportFrame.cpp +++ b/mozilla/layout/html/base/src/nsViewportFrame.cpp @@ -1 +1,128 @@ -// Just a placeholder for the time being... +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public License + * Version 1.0 (the "NPL"); you may not use this file except in + * compliance with the NPL. You may obtain a copy of the NPL at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the NPL is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL + * for the specific language governing rights and limitations under the + * NPL. + * + * The Initial Developer of this code under the NPL is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All Rights + * Reserved. + */ +#include "nsHTMLParts.h" +#include "nsContainerFrame.h" +#include "nsHTMLIIDs.h" + +static NS_DEFINE_IID(kIFrameIID, NS_IFRAME_IID); + +/** + * Viewport frame class. + * + * The viewport frame is the parent frame for the document element's frame. + * It only supports having a single child frame which must be one of the + * following: + * - scroll frame + * - root frame + * + * It has an additional named child list: + * - "Fixed-list" which contains the fixed positioned frames + */ +class ViewportFrame : public nsContainerFrame { +public: + NS_IMETHOD Reflow(nsIPresContext& aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus); + + NS_IMETHOD GetFrameName(nsString& aResult) const; +}; + +//---------------------------------------------------------------------- + +nsresult +NS_NewViewportFrame(nsIFrame*& aResult) +{ + ViewportFrame* frame = new ViewportFrame; + if (nsnull == frame) { + return NS_ERROR_OUT_OF_MEMORY; + } + aResult = frame; + return NS_OK; +} + +NS_IMETHODIMP +ViewportFrame::Reflow(nsIPresContext& aPresContext, + nsHTMLReflowMetrics& aDesiredSize, + const nsHTMLReflowState& aReflowState, + nsReflowStatus& aStatus) +{ + NS_FRAME_TRACE_REFLOW_IN("ViewportFrame::Reflow"); + NS_PRECONDITION(nsnull == aDesiredSize.maxElementSize, "unexpected request"); + + // Initialize OUT parameter + aStatus = NS_FRAME_COMPLETE; + + // Check for an incremental reflow + if (eReflowReason_Incremental == aReflowState.reason) { + // See if we're the target frame + nsIFrame* targetFrame; + aReflowState.reflowCommand->GetTarget(targetFrame); + if (this == targetFrame) { + // The viewport does not support being the target of an incremental + // reflow command + NS_ASSERTION(PR_FALSE, "unexpected reflow command target"); + + } else { + nsIFrame* nextFrame; + // Get the next frame in the reflow chain + aReflowState.reflowCommand->GetNext(nextFrame); + NS_ASSERTION(nextFrame == mFrames.FirstChild(), "unexpected next reflow command frame"); + } + } + + // Reflow our one and only child frame + if (mFrames.NotEmpty()) { + nsIFrame* kidFrame = mFrames.FirstChild(); + nsHTMLReflowMetrics desiredSize(nsnull); + nsSize availableSpace(aReflowState.availableWidth, + aReflowState.availableHeight); + nsHTMLReflowState kidReflowState(aPresContext, kidFrame, + aReflowState, availableSpace); + + // Reflow the frame + nsIHTMLReflow* htmlReflow; + if (NS_OK == kidFrame->QueryInterface(kIHTMLReflowIID, (void**)&htmlReflow)) { + kidReflowState.computedHeight = aReflowState.availableHeight; + ReflowChild(kidFrame, aPresContext, desiredSize, kidReflowState, + aStatus); + + nsRect rect(0, 0, desiredSize.width, desiredSize.height); + kidFrame->SetRect(rect); + + // XXX We should resolve the details of who/when DidReflow() + // notifications are sent... + htmlReflow->DidReflow(aPresContext, NS_FRAME_REFLOW_FINISHED); + } + } + + // Return the max size as our desired size + aDesiredSize.width = aReflowState.availableWidth; + aDesiredSize.height = aReflowState.availableHeight; + aDesiredSize.ascent = aReflowState.availableHeight; + aDesiredSize.descent = 0; + + NS_FRAME_TRACE_REFLOW_OUT("ViewportFrame::Reflow", aStatus); + return NS_OK; +} + +NS_IMETHODIMP +ViewportFrame::GetFrameName(nsString& aResult) const +{ + return MakeFrameName("Viewport", aResult); +} diff --git a/mozilla/layout/html/style/src/nsHTMLStyleSheet.cpp b/mozilla/layout/html/style/src/nsHTMLStyleSheet.cpp index b994b7335d9..f5eecbd09d6 100644 --- a/mozilla/layout/html/style/src/nsHTMLStyleSheet.cpp +++ b/mozilla/layout/html/style/src/nsHTMLStyleSheet.cpp @@ -1575,34 +1575,15 @@ HTMLStyleSheetImpl::ConstructDocElementFrame(nsIPresContext* aPresContext, // Unless the 'overflow' policy forbids scrolling, wrap the frame in a // scroll frame. - nsIFrame* scrollFrame = nsnull; - nsStyleDisplay* display = (nsStyleDisplay*) - styleContext->GetMutableStyleData(eStyleStruct_Display); - - // XXX This needs to go away... Yes, but where. - // Check the webshell and see if scrolling is enabled there. - nsISupports* container; - if (nsnull != aPresContext) { - aPresContext->GetContainer(&container); - if (nsnull != container) { - nsIWebShell* webShell = nsnull; - container->QueryInterface(kIWebShellIID, (void**) &webShell); - if (nsnull != webShell) { - PRInt32 scrolling = -1; - webShell->GetScrolling(scrolling); - if (-1 != scrolling) { - display->mOverflow = scrolling; - } - NS_RELEASE(webShell); - } - NS_RELEASE(container); - } - } + nsIFrame* scrollFrame = nsnull; - if (NS_STYLE_OVERFLOW_HIDDEN != display->mOverflow) { + const nsStyleDisplay* display = (const nsStyleDisplay*) + styleContext->GetStyleData(eStyleStruct_Display); + + if (IsScrollable(aPresContext, display)) { NS_NewScrollFrame(scrollFrame); scrollFrame->Init(*aPresContext, aDocElement, aRootFrame, styleContext); - + // The scrolled frame gets a pseudo element style context nsIStyleContext* scrolledPseudoStyle = aPresContext->ResolvePseudoStyleContextFor(nsnull, @@ -1656,50 +1637,105 @@ HTMLStyleSheetImpl::ConstructRootFrame(nsIPresContext* aPresContext, nsIFrame*& aNewFrame) { #ifdef NS_DEBUG - nsIDocument* doc; - nsIContent* rootContent; + nsIDocument* doc; + nsIContent* rootContent; - // Verify that the content object is really the root content object - aDocElement->GetDocument(doc); - rootContent = doc->GetRootContent(); - NS_RELEASE(doc); - NS_ASSERTION(rootContent == aDocElement, "unexpected content"); - NS_RELEASE(rootContent); + // Verify that the content object is really the root content object + aDocElement->GetDocument(doc); + rootContent = doc->GetRootContent(); + NS_RELEASE(doc); + NS_ASSERTION(rootContent == aDocElement, "unexpected content"); + NS_RELEASE(rootContent); #endif - nsIFrame* rootFrame; + nsIFrame* viewportFrame; nsIStyleContext* rootPseudoStyle; - // Create the root frame - NS_NewRootFrame(rootFrame); - + // Create the viewport frame + NS_NewViewportFrame(viewportFrame); + // Create a pseudo element style context + // XXX Use a different pseudo style context... rootPseudoStyle = aPresContext->ResolvePseudoStyleContextFor(nsnull, nsHTMLAtoms::rootPseudo, nsnull); - // Initialize the root frame. It has a NULL content object - rootFrame->Init(*aPresContext, nsnull, nsnull, rootPseudoStyle); + // Initialize the viewport frame. It has a NULL content object + viewportFrame->Init(*aPresContext, nsnull, nsnull, rootPseudoStyle); - // Bind the root frame to the root view + // Bind the viewport frame to the root view nsIPresShell* presShell = aPresContext->GetShell(); nsIViewManager* viewManager = presShell->GetViewManager(); nsIView* rootView; - + NS_RELEASE(presShell); viewManager->GetRootView(rootView); - rootFrame->SetView(rootView); + viewportFrame->SetView(rootView); NS_RELEASE(viewManager); - + + // As long as the webshell doesn't prohibit it, create a scroll frame + // that will act as the scolling mechanism for the viewport + // XXX We should only do this when presenting to the screen, i.e., for galley + // mode and print-preview, but not when printing + PRBool isScrollable = PR_TRUE; + nsISupports* container; + if (nsnull != aPresContext) { + aPresContext->GetContainer(&container); + if (nsnull != container) { + nsIWebShell* webShell = nsnull; + container->QueryInterface(kIWebShellIID, (void**) &webShell); + if (nsnull != webShell) { + PRInt32 scrolling = -1; + webShell->GetScrolling(scrolling); + if (NS_STYLE_OVERFLOW_HIDDEN == scrolling) { + isScrollable = PR_FALSE; + } + NS_RELEASE(webShell); + } + NS_RELEASE(container); + } + } + + // If the viewport should offer a scrolling mechanism, then create a + // scroll frame + nsIFrame* scrollFrame; + if (isScrollable) { + NS_NewScrollFrame(scrollFrame); + scrollFrame->Init(*aPresContext, nsnull, viewportFrame, rootPseudoStyle); + } + + // Create the root frame. The document element's frame is a child of the + // root frame. + // + // Note: the major reason we need the root frame is to implement margins for + // the document element's frame. If we didn't need to support margins on the + // document element's frame, then we could eliminate the root frame and make + // the document element frame a child of the viewport (or its scroll frame) + nsIFrame* rootFrame; + NS_NewRootFrame(rootFrame); + + rootFrame->Init(*aPresContext, nsnull, isScrollable ? scrollFrame : + viewportFrame, rootPseudoStyle); + if (isScrollable) { + nsHTMLContainerFrame::CreateViewForFrame(*aPresContext, rootFrame, + rootPseudoStyle, PR_TRUE); + } + // Create frames for the document element and its child elements nsIFrame* docElementFrame; ConstructDocElementFrame(aPresContext, aDocElement, rootFrame, rootPseudoStyle, docElementFrame); NS_RELEASE(rootPseudoStyle); - // Set the root frame's initial child list + // Set the initial child lists rootFrame->SetInitialChildList(*aPresContext, nsnull, docElementFrame); + if (isScrollable) { + scrollFrame->SetInitialChildList(*aPresContext, nsnull, rootFrame); + viewportFrame->SetInitialChildList(*aPresContext, nsnull, scrollFrame); + } else { + viewportFrame->SetInitialChildList(*aPresContext, nsnull, rootFrame); + } - aNewFrame = rootFrame; + aNewFrame = viewportFrame; return NS_OK; } @@ -2977,40 +3013,35 @@ HTMLStyleSheetImpl::ReconstructFrames(nsIPresContext* aPresContext, return rv; } - // XXX Currently we only know how to do this for XML documents if (nsnull != document) { nsIPresShell* shell = aPresContext->GetShell(); -// nsIXMLDocument* xmlDocument; -// rv = document->QueryInterface(kIXMLDocumentIID, (void **)&xmlDocument); - if (NS_SUCCEEDED(rv)) { + // XXX This API needs changing, because it appears to be designed for + // an arbitrary content element, but yet it always constructs the document + // element's frame. Plus it has the problem noted above in the previous XXX rv = aParentFrame->RemoveFrame(*aPresContext, *shell, nsnull, aFrameSubTree); + if (NS_SUCCEEDED(rv)) { - nsIFrame *newChild; - // XXX See ConstructXMLContents for an explanation of why - // we create this pseudostyle + nsIFrame* newChild; nsIStyleContext* rootPseudoStyle; - rootPseudoStyle = aPresContext->ResolvePseudoStyleContextFor(nsnull, - nsHTMLAtoms::rootPseudo, nsnull); - + + aParentFrame->GetStyleContext(rootPseudoStyle); rv = ConstructDocElementFrame(aPresContext, aContent, aParentFrame, rootPseudoStyle, newChild); + NS_RELEASE(rootPseudoStyle); if (NS_SUCCEEDED(rv)) { rv = aParentFrame->InsertFrames(*aPresContext, *shell, nsnull, nsnull, newChild); } - NS_IF_RELEASE(rootPseudoStyle); } -// NS_RELEASE(xmlDocument); } NS_RELEASE(document); NS_RELEASE(shell); } return rv; - } nsIFrame* diff --git a/mozilla/layout/style/nsHTMLStyleSheet.cpp b/mozilla/layout/style/nsHTMLStyleSheet.cpp index b994b7335d9..f5eecbd09d6 100644 --- a/mozilla/layout/style/nsHTMLStyleSheet.cpp +++ b/mozilla/layout/style/nsHTMLStyleSheet.cpp @@ -1575,34 +1575,15 @@ HTMLStyleSheetImpl::ConstructDocElementFrame(nsIPresContext* aPresContext, // Unless the 'overflow' policy forbids scrolling, wrap the frame in a // scroll frame. - nsIFrame* scrollFrame = nsnull; - nsStyleDisplay* display = (nsStyleDisplay*) - styleContext->GetMutableStyleData(eStyleStruct_Display); - - // XXX This needs to go away... Yes, but where. - // Check the webshell and see if scrolling is enabled there. - nsISupports* container; - if (nsnull != aPresContext) { - aPresContext->GetContainer(&container); - if (nsnull != container) { - nsIWebShell* webShell = nsnull; - container->QueryInterface(kIWebShellIID, (void**) &webShell); - if (nsnull != webShell) { - PRInt32 scrolling = -1; - webShell->GetScrolling(scrolling); - if (-1 != scrolling) { - display->mOverflow = scrolling; - } - NS_RELEASE(webShell); - } - NS_RELEASE(container); - } - } + nsIFrame* scrollFrame = nsnull; - if (NS_STYLE_OVERFLOW_HIDDEN != display->mOverflow) { + const nsStyleDisplay* display = (const nsStyleDisplay*) + styleContext->GetStyleData(eStyleStruct_Display); + + if (IsScrollable(aPresContext, display)) { NS_NewScrollFrame(scrollFrame); scrollFrame->Init(*aPresContext, aDocElement, aRootFrame, styleContext); - + // The scrolled frame gets a pseudo element style context nsIStyleContext* scrolledPseudoStyle = aPresContext->ResolvePseudoStyleContextFor(nsnull, @@ -1656,50 +1637,105 @@ HTMLStyleSheetImpl::ConstructRootFrame(nsIPresContext* aPresContext, nsIFrame*& aNewFrame) { #ifdef NS_DEBUG - nsIDocument* doc; - nsIContent* rootContent; + nsIDocument* doc; + nsIContent* rootContent; - // Verify that the content object is really the root content object - aDocElement->GetDocument(doc); - rootContent = doc->GetRootContent(); - NS_RELEASE(doc); - NS_ASSERTION(rootContent == aDocElement, "unexpected content"); - NS_RELEASE(rootContent); + // Verify that the content object is really the root content object + aDocElement->GetDocument(doc); + rootContent = doc->GetRootContent(); + NS_RELEASE(doc); + NS_ASSERTION(rootContent == aDocElement, "unexpected content"); + NS_RELEASE(rootContent); #endif - nsIFrame* rootFrame; + nsIFrame* viewportFrame; nsIStyleContext* rootPseudoStyle; - // Create the root frame - NS_NewRootFrame(rootFrame); - + // Create the viewport frame + NS_NewViewportFrame(viewportFrame); + // Create a pseudo element style context + // XXX Use a different pseudo style context... rootPseudoStyle = aPresContext->ResolvePseudoStyleContextFor(nsnull, nsHTMLAtoms::rootPseudo, nsnull); - // Initialize the root frame. It has a NULL content object - rootFrame->Init(*aPresContext, nsnull, nsnull, rootPseudoStyle); + // Initialize the viewport frame. It has a NULL content object + viewportFrame->Init(*aPresContext, nsnull, nsnull, rootPseudoStyle); - // Bind the root frame to the root view + // Bind the viewport frame to the root view nsIPresShell* presShell = aPresContext->GetShell(); nsIViewManager* viewManager = presShell->GetViewManager(); nsIView* rootView; - + NS_RELEASE(presShell); viewManager->GetRootView(rootView); - rootFrame->SetView(rootView); + viewportFrame->SetView(rootView); NS_RELEASE(viewManager); - + + // As long as the webshell doesn't prohibit it, create a scroll frame + // that will act as the scolling mechanism for the viewport + // XXX We should only do this when presenting to the screen, i.e., for galley + // mode and print-preview, but not when printing + PRBool isScrollable = PR_TRUE; + nsISupports* container; + if (nsnull != aPresContext) { + aPresContext->GetContainer(&container); + if (nsnull != container) { + nsIWebShell* webShell = nsnull; + container->QueryInterface(kIWebShellIID, (void**) &webShell); + if (nsnull != webShell) { + PRInt32 scrolling = -1; + webShell->GetScrolling(scrolling); + if (NS_STYLE_OVERFLOW_HIDDEN == scrolling) { + isScrollable = PR_FALSE; + } + NS_RELEASE(webShell); + } + NS_RELEASE(container); + } + } + + // If the viewport should offer a scrolling mechanism, then create a + // scroll frame + nsIFrame* scrollFrame; + if (isScrollable) { + NS_NewScrollFrame(scrollFrame); + scrollFrame->Init(*aPresContext, nsnull, viewportFrame, rootPseudoStyle); + } + + // Create the root frame. The document element's frame is a child of the + // root frame. + // + // Note: the major reason we need the root frame is to implement margins for + // the document element's frame. If we didn't need to support margins on the + // document element's frame, then we could eliminate the root frame and make + // the document element frame a child of the viewport (or its scroll frame) + nsIFrame* rootFrame; + NS_NewRootFrame(rootFrame); + + rootFrame->Init(*aPresContext, nsnull, isScrollable ? scrollFrame : + viewportFrame, rootPseudoStyle); + if (isScrollable) { + nsHTMLContainerFrame::CreateViewForFrame(*aPresContext, rootFrame, + rootPseudoStyle, PR_TRUE); + } + // Create frames for the document element and its child elements nsIFrame* docElementFrame; ConstructDocElementFrame(aPresContext, aDocElement, rootFrame, rootPseudoStyle, docElementFrame); NS_RELEASE(rootPseudoStyle); - // Set the root frame's initial child list + // Set the initial child lists rootFrame->SetInitialChildList(*aPresContext, nsnull, docElementFrame); + if (isScrollable) { + scrollFrame->SetInitialChildList(*aPresContext, nsnull, rootFrame); + viewportFrame->SetInitialChildList(*aPresContext, nsnull, scrollFrame); + } else { + viewportFrame->SetInitialChildList(*aPresContext, nsnull, rootFrame); + } - aNewFrame = rootFrame; + aNewFrame = viewportFrame; return NS_OK; } @@ -2977,40 +3013,35 @@ HTMLStyleSheetImpl::ReconstructFrames(nsIPresContext* aPresContext, return rv; } - // XXX Currently we only know how to do this for XML documents if (nsnull != document) { nsIPresShell* shell = aPresContext->GetShell(); -// nsIXMLDocument* xmlDocument; -// rv = document->QueryInterface(kIXMLDocumentIID, (void **)&xmlDocument); - if (NS_SUCCEEDED(rv)) { + // XXX This API needs changing, because it appears to be designed for + // an arbitrary content element, but yet it always constructs the document + // element's frame. Plus it has the problem noted above in the previous XXX rv = aParentFrame->RemoveFrame(*aPresContext, *shell, nsnull, aFrameSubTree); + if (NS_SUCCEEDED(rv)) { - nsIFrame *newChild; - // XXX See ConstructXMLContents for an explanation of why - // we create this pseudostyle + nsIFrame* newChild; nsIStyleContext* rootPseudoStyle; - rootPseudoStyle = aPresContext->ResolvePseudoStyleContextFor(nsnull, - nsHTMLAtoms::rootPseudo, nsnull); - + + aParentFrame->GetStyleContext(rootPseudoStyle); rv = ConstructDocElementFrame(aPresContext, aContent, aParentFrame, rootPseudoStyle, newChild); + NS_RELEASE(rootPseudoStyle); if (NS_SUCCEEDED(rv)) { rv = aParentFrame->InsertFrames(*aPresContext, *shell, nsnull, nsnull, newChild); } - NS_IF_RELEASE(rootPseudoStyle); } -// NS_RELEASE(xmlDocument); } NS_RELEASE(document); NS_RELEASE(shell); } return rv; - } nsIFrame*