Bug 522352 - make nsSubDocumentFrame not assume as much about docshells: move all that into the frameloader, r=bz (preparation and merge reduction for Electrolysis, where not all frameloaders have docshells)

--HG--
extra : rebase_source : 7c51147603fccb93040fdb6e883b33dbab130040
This commit is contained in:
Benjamin Smedberg 2009-10-16 15:42:29 -04:00
parent bbc370f4a7
commit 4bb6d6c511
4 changed files with 196 additions and 183 deletions

View File

@ -49,6 +49,7 @@
#include "nsPresContext.h"
#include "nsIPresShell.h"
#include "nsIContent.h"
#include "nsIContentViewer.h"
#include "nsIDocument.h"
#include "nsIDOMDocument.h"
#include "nsIDOMWindow.h"
@ -64,6 +65,7 @@
#include "nsUnicharUtils.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptSecurityManager.h"
#include "nsIScrollable.h"
#include "nsFrameLoader.h"
#include "nsIDOMEventTarget.h"
#include "nsIFrame.h"
@ -74,6 +76,8 @@
#include "nsEventDispatcher.h"
#include "nsISHistory.h"
#include "nsISHistoryInternal.h"
#include "nsIDOMNSHTMLDocument.h"
#include "nsIView.h"
#include "nsIURI.h"
#include "nsIURL.h"
@ -465,6 +469,107 @@ AllDescendantsOfType(nsIDocShellTreeItem* aParentItem, PRInt32 aType)
return PR_TRUE;
}
bool
nsFrameLoader::Show(PRInt32 marginWidth, PRInt32 marginHeight,
PRInt32 scrollbarPrefX, PRInt32 scrollbarPrefY,
nsIFrameFrame* frame)
{
nsContentType contentType;
nsresult rv = EnsureDocShell();
if (NS_FAILED(rv)) {
return false;
}
if (!mDocShell)
return false;
nsCOMPtr<nsIPresShell> presShell;
mDocShell->GetPresShell(getter_AddRefs(presShell));
if (presShell)
return true;
mDocShell->SetMarginWidth(marginWidth);
mDocShell->SetMarginHeight(marginHeight);
nsCOMPtr<nsIScrollable> sc = do_QueryInterface(mDocShell);
if (sc) {
sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X,
scrollbarPrefX);
sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_Y,
scrollbarPrefY);
}
nsCOMPtr<nsIDocShellTreeItem> treeItem = do_QueryInterface(mDocShell);
NS_ASSERTION(treeItem,
"Found a nsIDocShell that isn't a nsIDocShellTreeItem.");
PRInt32 itemType;
treeItem->GetItemType(&itemType);
if (itemType == nsIDocShellTreeItem::typeChrome)
contentType = eContentTypeUI;
else {
nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
treeItem->GetSameTypeParent(getter_AddRefs(sameTypeParent));
contentType = sameTypeParent ? eContentTypeContentFrame : eContentTypeContent;
}
nsIView* view = frame->CreateViewAndWidget(contentType);
if (!view)
return false;
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(mDocShell);
NS_ASSERTION(baseWindow, "Found a nsIDocShell that isn't a nsIBaseWindow.");
baseWindow->InitWindow(nsnull, view->GetWidget(), 0, 0, 10, 10);
// This is kinda whacky, this "Create()" call doesn't really
// create anything, one starts to wonder why this was named
// "Create"...
baseWindow->Create();
baseWindow->SetVisibility(PR_TRUE);
// Trigger editor re-initialization if midas is turned on in the
// sub-document. This shouldn't be necessary, but given the way our
// editor works, it is. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=284245
mDocShell->GetPresShell(getter_AddRefs(presShell));
if (presShell) {
nsCOMPtr<nsIDOMNSHTMLDocument> doc =
do_QueryInterface(presShell->GetDocument());
if (doc) {
nsAutoString designMode;
doc->GetDesignMode(designMode);
if (designMode.EqualsLiteral("on")) {
doc->SetDesignMode(NS_LITERAL_STRING("off"));
doc->SetDesignMode(NS_LITERAL_STRING("on"));
}
}
}
return true;
}
void
nsFrameLoader::Hide()
{
if (!mDocShell)
return;
nsCOMPtr<nsIContentViewer> contentViewer;
mDocShell->GetContentViewer(getter_AddRefs(contentViewer));
if (contentViewer)
contentViewer->SetSticky(PR_FALSE);
nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mDocShell);
NS_ASSERTION(baseWin,
"Found an nsIDocShell which doesn't implement nsIBaseWindow.");
baseWin->SetVisibility(PR_FALSE);
baseWin->SetParentWidget(nsnull);
}
nsresult
nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
nsRefPtr<nsFrameLoader>& aFirstToSwap,

View File

@ -51,6 +51,7 @@
class nsIContent;
class nsIURI;
class nsIFrameFrame;
class nsFrameLoader : public nsIFrameLoader
{
@ -80,6 +81,21 @@ public:
void Finalize();
nsIDocShell* GetExistingDocShell() { return mDocShell; }
/**
* Called from the layout frame associated with this frame loader;
* this notifies us to hook up with the widget and view.
*/
bool Show(PRInt32 marginWidth, PRInt32 marginHeight,
PRInt32 scrollbarPrefX, PRInt32 scrollbarPrefY,
nsIFrameFrame* frame);
/**
* Called from the layout frame associated with this frame loader, when
* the frame is being torn down; this notifies us that out widget and view
* are going away and we should unhook from them.
*/
void Hide();
// The guts of an nsIFrameLoaderOwner::SwapFrameLoader implementation. A
// frame loader owner needs to call this, and pass in the two references to
// nsRefPtrs for frame loaders that need to be swapped.

View File

@ -74,7 +74,7 @@
#include "nsIDOMHTMLFrameElement.h"
#include "nsIDOMHTMLIFrameElement.h"
#include "nsIDOMXULElement.h"
#include "nsIFrameLoader.h"
#include "nsFrameLoader.h"
#include "nsIScriptSecurityManager.h"
#include "nsXPIDLString.h"
#include "nsIScrollable.h"
@ -190,9 +190,10 @@ protected:
// Helper method to look up the HTML marginwidth & marginheight attributes
nsIntSize GetMarginAttributes();
nsFrameLoader* FrameLoader();
PRBool IsInline() { return mIsInline; }
nsresult ShowDocShell();
nsresult CreateViewAndWidget(nsContentType aContentType);
nsIView* CreateViewAndWidget(nsContentType aContentType);
virtual nscoord GetIntrinsicWidth();
virtual nscoord GetIntrinsicHeight();
@ -213,16 +214,18 @@ protected:
*/
nsIFrame* ObtainIntrinsicSizeFrame();
nsCOMPtr<nsIFrameLoader> mFrameLoader;
nsRefPtr<nsFrameLoader> mFrameLoader;
nsIView* mInnerView;
PRPackedBool mDidCreateDoc;
PRPackedBool mIsInline;
PRPackedBool mPostedReflowCallback;
bool mDidCreateDoc;
};
nsSubDocumentFrame::nsSubDocumentFrame(nsStyleContext* aContext)
: nsLeafFrame(aContext), mDidCreateDoc(PR_FALSE),
mIsInline(PR_FALSE), mPostedReflowCallback(PR_FALSE)
: nsLeafFrame(aContext)
, mIsInline(PR_FALSE)
, mPostedReflowCallback(PR_FALSE)
, mDidCreateDoc(false)
{
}
@ -287,22 +290,39 @@ nsSubDocumentFrame::Init(nsIContent* aContent,
return NS_OK;
}
inline PRInt32 ConvertOverflow(PRUint8 aOverflow)
{
switch (aOverflow) {
case NS_STYLE_OVERFLOW_VISIBLE:
case NS_STYLE_OVERFLOW_AUTO:
return nsIScrollable::Scrollbar_Auto;
case NS_STYLE_OVERFLOW_HIDDEN:
case NS_STYLE_OVERFLOW_CLIP:
return nsIScrollable::Scrollbar_Never;
case NS_STYLE_OVERFLOW_SCROLL:
return nsIScrollable::Scrollbar_Always;
}
NS_NOTREACHED("invalid overflow value passed to ConvertOverflow");
return nsIScrollable::Scrollbar_Auto;
}
void
nsSubDocumentFrame::ShowViewer()
{
if (!PresContext()->IsDynamic()) {
// We let the printing code take care of loading the document; just
// create a widget for it to use
nsresult rv = CreateViewAndWidget(eContentTypeContent);
if (NS_FAILED(rv)) {
return;
}
(void) CreateViewAndWidget(eContentTypeContent);
} else {
nsresult rv = ShowDocShell();
if (NS_FAILED(rv)) {
return;
nsFrameLoader* frameloader = FrameLoader();
if (frameloader) {
nsIntSize margin = GetMarginAttributes();
const nsStyleDisplay* disp = GetStyleDisplay();
mDidCreateDoc = frameloader->Show(margin.width, margin.height,
ConvertOverflow(disp->mOverflowX),
ConvertOverflow(disp->mOverflowY),
this);
}
mDidCreateDoc = PR_TRUE;
}
}
@ -777,39 +797,8 @@ nsSubDocumentFrame::Destroy()
void
nsSubDocumentFrame::HideViewer()
{
if (mFrameLoader && mDidCreateDoc) {
// Get the content viewer through the docshell, but don't call
// GetDocShell() since we don't want to create one if we don't
// have one.
nsCOMPtr<nsIDocShell> docShell;
mFrameLoader->GetDocShell(getter_AddRefs(docShell));
if (docShell) {
nsCOMPtr<nsIContentViewer> content_viewer;
docShell->GetContentViewer(getter_AddRefs(content_viewer));
if (content_viewer) {
// Mark the content viewer as non-sticky so that the presentation
// can safely go away when this frame is destroyed.
content_viewer->SetSticky(PR_FALSE);
}
nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(docShell);
NS_ASSERTION(baseWin, "Docshell must be an nsIBaseWindow");
// Now reverse the steps we took in ShowDocShell(). But don't call
// Destroy(); that will be handled by destroying our frame loader, if
// needed.
// Hide the content viewer now that the frame is going away...
baseWin->SetVisibility(PR_FALSE);
// Clear out the parentWidget, since it might be about to die with us
baseWin->SetParentWidget(nsnull);
}
}
if (mFrameLoader && mDidCreateDoc)
mFrameLoader->Hide();
}
nsIntSize
@ -828,6 +817,24 @@ nsSubDocumentFrame::GetMarginAttributes()
return result;
}
nsFrameLoader*
nsSubDocumentFrame::FrameLoader()
{
nsIContent* content = GetContent();
if (!content)
return nsnull;
if (!mFrameLoader) {
nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(content);
if (loaderOwner) {
nsCOMPtr<nsIFrameLoader> loader;
loaderOwner->GetFrameLoader(getter_AddRefs(loader));
mFrameLoader = static_cast<nsFrameLoader*>(loader.get());
}
}
return mFrameLoader;
}
// XXX this should be called ObtainDocShell or something like that,
// to indicate that it could have side effects
NS_IMETHODIMP
@ -835,23 +842,7 @@ nsSubDocumentFrame::GetDocShell(nsIDocShell **aDocShell)
{
*aDocShell = nsnull;
nsIContent* content = GetContent();
if (!content) {
// Hmm, no content in this frame
// that's odd, not much to be done here then.
return NS_OK;
}
if (!mFrameLoader) {
nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(content);
if (loaderOwner) {
loaderOwner->GetFrameLoader(getter_AddRefs(mFrameLoader));
}
NS_ENSURE_STATE(mFrameLoader);
}
NS_ENSURE_STATE(FrameLoader());
return mFrameLoader->GetDocShell(aDocShell);
}
@ -895,122 +886,14 @@ nsSubDocumentFrame::EndSwapDocShells(nsIFrame* aOther)
other->InvalidateOverflowRect();
}
inline PRInt32 ConvertOverflow(PRUint8 aOverflow)
{
switch (aOverflow) {
case NS_STYLE_OVERFLOW_VISIBLE:
case NS_STYLE_OVERFLOW_AUTO:
return nsIScrollable::Scrollbar_Auto;
case NS_STYLE_OVERFLOW_HIDDEN:
case NS_STYLE_OVERFLOW_CLIP:
return nsIScrollable::Scrollbar_Never;
case NS_STYLE_OVERFLOW_SCROLL:
return nsIScrollable::Scrollbar_Always;
}
NS_NOTREACHED("invalid overflow value passed to ConvertOverflow");
return nsIScrollable::Scrollbar_Auto;
}
nsresult
nsSubDocumentFrame::ShowDocShell()
{
nsCOMPtr<nsIDocShell> docShell;
nsresult rv = GetDocShell(getter_AddRefs(docShell));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIPresShell> presShell;
docShell->GetPresShell(getter_AddRefs(presShell));
if (presShell) {
// The docshell is already showing, nothing left to do...
NS_ASSERTION(mInnerView, "What's going on?");
return NS_OK;
}
// pass along marginwidth, marginheight, scrolling so sub document
// can use it
nsIntSize margin = GetMarginAttributes();
docShell->SetMarginWidth(margin.width);
docShell->SetMarginHeight(margin.height);
// Current and initial scrolling is set so that all succeeding docs
// will use the scrolling value set here, regardless if scrolling is
// set by viewing a particular document (e.g. XUL turns off scrolling)
nsCOMPtr<nsIScrollable> sc(do_QueryInterface(docShell));
if (sc) {
const nsStyleDisplay *disp = GetStyleDisplay();
sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_X,
ConvertOverflow(disp->mOverflowX));
sc->SetDefaultScrollbarPreferences(nsIScrollable::ScrollOrientation_Y,
ConvertOverflow(disp->mOverflowY));
}
PRInt32 itemType = nsIDocShellTreeItem::typeContent;
nsCOMPtr<nsIDocShellTreeItem> treeItem(do_QueryInterface(docShell));
if (treeItem) {
treeItem->GetItemType(&itemType);
}
nsContentType contentType;
if (itemType == nsIDocShellTreeItem::typeChrome) {
contentType = eContentTypeUI;
}
else {
nsCOMPtr<nsIDocShellTreeItem> sameTypeParent;
treeItem->GetSameTypeParent(getter_AddRefs(sameTypeParent));
contentType = sameTypeParent ? eContentTypeContentFrame : eContentTypeContent;
}
rv = CreateViewAndWidget(contentType);
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsIBaseWindow> baseWindow(do_QueryInterface(docShell));
if (baseWindow) {
baseWindow->InitWindow(nsnull, mInnerView->GetWidget(), 0, 0, 10, 10);
// This is kinda whacky, this "Create()" call doesn't really
// create anything, one starts to wonder why this was named
// "Create"...
baseWindow->Create();
baseWindow->SetVisibility(PR_TRUE);
}
// Trigger editor re-initialization if midas is turned on in the
// sub-document. This shouldn't be necessary, but given the way our
// editor works, it is. See
// https://bugzilla.mozilla.org/show_bug.cgi?id=284245
docShell->GetPresShell(getter_AddRefs(presShell));
if (presShell) {
nsCOMPtr<nsIDOMNSHTMLDocument> doc =
do_QueryInterface(presShell->GetDocument());
if (doc) {
nsAutoString designMode;
doc->GetDesignMode(designMode);
if (designMode.EqualsLiteral("on")) {
doc->SetDesignMode(NS_LITERAL_STRING("off"));
doc->SetDesignMode(NS_LITERAL_STRING("on"));
}
}
}
return NS_OK;
}
nsresult
nsIView*
nsSubDocumentFrame::CreateViewAndWidget(nsContentType aContentType)
{
if (mInnerView) {
// Nothing to do here
return NS_OK;
return mInnerView;
}
// create, init, set the parent of the view
nsIView* outerView = GetView();
NS_ASSERTION(outerView, "Must have an outer view already");
@ -1020,18 +903,21 @@ nsSubDocumentFrame::CreateViewAndWidget(nsContentType aContentType)
nsIView* innerView = viewMan->CreateView(viewBounds, outerView);
if (!innerView) {
NS_ERROR("Could not create inner view");
return NS_ERROR_OUT_OF_MEMORY;
return nsnull;
}
mInnerView = innerView;
viewMan->InsertChild(outerView, innerView, nsnull, PR_TRUE);
if (aContentType == eContentTypeContentFrame) {
// No widget needed.
return NS_OK;
if (aContentType != eContentTypeContentFrame) {
// widget needed.
nsresult rv = innerView->CreateWidget(kCChildCID, nsnull, nsnull,
PR_TRUE, PR_TRUE, aContentType);
if (NS_FAILED(rv)) {
NS_WARNING("Couldn't create widget for frame.");
mInnerView = nsnull;
}
}
return innerView->CreateWidget(kCChildCID, nsnull, nsnull, PR_TRUE, PR_TRUE,
aContentType);
return mInnerView;
}
nsIFrame*

View File

@ -44,6 +44,7 @@
#define nsIFrameFrame_h___
class nsIDocShell;
class nsIView;
class nsIFrameFrame
{
@ -59,6 +60,11 @@ public:
*/
NS_IMETHOD BeginSwapDocShells(nsIFrame* aOther) = 0;
virtual void EndSwapDocShells(nsIFrame* aOther) = 0;
/**
* The frameloader informs us what kind of widget to create during Show()
*/
virtual nsIView* CreateViewAndWidget(nsContentType aContentType) = 0;
};
#endif