Bug 751999: Split SetDocShell apart to make this code easier to read. r=jst

This commit is contained in:
Kyle Huey 2012-05-25 12:00:32 -07:00
Родитель b41b0e9390
Коммит ec7b0d3b86
4 изменённых файлов: 126 добавлений и 93 удалений

Просмотреть файл

@ -4676,7 +4676,7 @@ nsDocShell::Destroy()
if (mScriptGlobal) {
nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(mScriptGlobal));
win->SetDocShell(nsnull);
win->DetachFromDocShell();
mScriptGlobal = nsnull;
}

Просмотреть файл

@ -2141,109 +2141,135 @@ void
nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell)
{
NS_ASSERTION(IsOuterWindow(), "Uh, SetDocShell() called on inner window!");
MOZ_ASSERT(aDocShell);
if (aDocShell == mDocShell)
if (aDocShell == mDocShell) {
return;
}
// SetDocShell(nsnull) means the window is being torn down. Drop our
mDocShell = aDocShell; // Weak Reference
NS_ASSERTION(!mNavigator, "Non-null mNavigator in outer window!");
if (mFrames) {
mFrames->SetDocShell(aDocShell);
}
// Get our enclosing chrome shell and retrieve its global window impl, so
// that we can do some forwarding to the chrome document.
nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
mDocShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
mChromeEventHandler = do_QueryInterface(chromeEventHandler);
if (!mChromeEventHandler) {
// We have no chrome event handler. If we have a parent,
// get our chrome event handler from the parent. If
// we don't have a parent, then we need to make a new
// window root object that will function as a chrome event
// handler and receive all events that occur anywhere inside
// our window.
nsCOMPtr<nsIDOMWindow> parentWindow;
GetParent(getter_AddRefs(parentWindow));
if (parentWindow.get() != static_cast<nsIDOMWindow*>(this)) {
nsCOMPtr<nsPIDOMWindow> piWindow(do_QueryInterface(parentWindow));
mChromeEventHandler = piWindow->GetChromeEventHandler();
}
else {
NS_NewWindowRoot(this, getter_AddRefs(mChromeEventHandler));
}
}
bool docShellActive;
mDocShell->GetIsActive(&docShellActive);
mIsBackground = !docShellActive;
}
void
nsGlobalWindow::DetachFromDocShell()
{
NS_ASSERTION(IsOuterWindow(), "Uh, DetachFromDocShell() called on inner window!");
// DetachFromDocShell means the window is being torn down. Drop our
// reference to the script context, allowing it to be deleted
// later. Meanwhile, keep our weak reference to the script object
// (mJSObject) so that it can be retrieved later (until it is
// finalized by the JS GC).
if (!aDocShell) {
NS_ASSERTION(PR_CLIST_IS_EMPTY(&mTimeouts),
"Uh, outer window holds timeouts!");
NS_ASSERTION(PR_CLIST_IS_EMPTY(&mTimeouts),
"Uh, outer window holds timeouts!");
// Call FreeInnerObjects on all inner windows, not just the current
// one, since some could be held by WindowStateHolder objects that
// are GC-owned.
for (nsRefPtr<nsGlobalWindow> inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
inner != this;
inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
NS_ASSERTION(!inner->mOuterWindow || inner->mOuterWindow == this,
"bad outer window pointer");
inner->FreeInnerObjects();
}
// Make sure that this is called before we null out the document.
NotifyDOMWindowDestroyed(this);
NotifyWindowIDDestroyed("outer-window-destroyed");
nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
if (currentInner) {
NS_ASSERTION(mDoc, "Must have doc!");
// Remember the document's principal.
mDocumentPrincipal = mDoc->NodePrincipal();
// Release our document reference
mDocument = nsnull;
mDoc = nsnull;
mFocusedNode = nsnull;
}
ClearControllers();
mChromeEventHandler = nsnull; // force release now
if (mArguments) {
// We got no new document after someone called
// SetArguments(), drop our reference to the arguments.
mArguments = nsnull;
mArgumentsLast = nsnull;
mArgumentsOrigin = nsnull;
}
if (mContext) {
mContext->GC(js::gcreason::SET_DOC_SHELL);
mContext = nsnull;
}
#ifdef DEBUG
nsCycleCollector_DEBUG_shouldBeFreed(mContext);
nsCycleCollector_DEBUG_shouldBeFreed(static_cast<nsIScriptGlobalObject*>(this));
#endif
// Call FreeInnerObjects on all inner windows, not just the current
// one, since some could be held by WindowStateHolder objects that
// are GC-owned.
for (nsRefPtr<nsGlobalWindow> inner = (nsGlobalWindow *)PR_LIST_HEAD(this);
inner != this;
inner = (nsGlobalWindow*)PR_NEXT_LINK(inner)) {
NS_ASSERTION(!inner->mOuterWindow || inner->mOuterWindow == this,
"bad outer window pointer");
inner->FreeInnerObjects();
}
mDocShell = aDocShell; // Weak Reference
// Make sure that this is called before we null out the document.
NotifyDOMWindowDestroyed(this);
NotifyWindowIDDestroyed("outer-window-destroyed");
nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal();
if (currentInner) {
JSObject* obj = currentInner->FastGetGlobalJSObject();
if (obj) {
JSContext* cx;
nsContentUtils::ThreadJSContextStack()->GetSafeJSContext(&cx);
JSAutoRequest ar(cx);
js::NukeChromeCrossCompartmentWrappersForGlobal(cx, obj,
js::NukeForGlobalObject);
}
NS_ASSERTION(mDoc, "Must have doc!");
// Remember the document's principal.
mDocumentPrincipal = mDoc->NodePrincipal();
// Release our document reference
mDocument = nsnull;
mDoc = nsnull;
mFocusedNode = nsnull;
}
ClearControllers();
mChromeEventHandler = nsnull; // force release now
if (mArguments) {
// We got no new document after someone called
// SetArguments(), drop our reference to the arguments.
mArguments = nsnull;
mArgumentsLast = nsnull;
mArgumentsOrigin = nsnull;
}
if (mContext) {
mContext->GC(js::gcreason::SET_DOC_SHELL);
mContext = nsnull;
}
#ifdef DEBUG
nsCycleCollector_DEBUG_shouldBeFreed(mContext);
nsCycleCollector_DEBUG_shouldBeFreed(static_cast<nsIScriptGlobalObject*>(this));
#endif
mDocShell = nsnull; // Weak Reference
NS_ASSERTION(!mNavigator, "Non-null mNavigator in outer window!");
if (mFrames)
mFrames->SetDocShell(aDocShell);
if (!mDocShell) {
MaybeForgiveSpamCount();
CleanUp(false);
} else {
// Get our enclosing chrome shell and retrieve its global window impl, so
// that we can do some forwarding to the chrome document.
nsCOMPtr<nsIDOMEventTarget> chromeEventHandler;
mDocShell->GetChromeEventHandler(getter_AddRefs(chromeEventHandler));
mChromeEventHandler = do_QueryInterface(chromeEventHandler);
if (!mChromeEventHandler) {
// We have no chrome event handler. If we have a parent,
// get our chrome event handler from the parent. If
// we don't have a parent, then we need to make a new
// window root object that will function as a chrome event
// handler and receive all events that occur anywhere inside
// our window.
nsCOMPtr<nsIDOMWindow> parentWindow;
GetParent(getter_AddRefs(parentWindow));
if (parentWindow.get() != static_cast<nsIDOMWindow*>(this)) {
nsCOMPtr<nsPIDOMWindow> piWindow(do_QueryInterface(parentWindow));
mChromeEventHandler = piWindow->GetChromeEventHandler();
}
else NS_NewWindowRoot(this, getter_AddRefs(mChromeEventHandler));
}
bool docShellActive;
mDocShell->GetIsActive(&docShellActive);
mIsBackground = !docShellActive;
if (mFrames) {
mFrames->SetDocShell(nsnull);
}
MaybeForgiveSpamCount();
CleanUp(false);
}
void

Просмотреть файл

@ -320,6 +320,7 @@ public:
virtual NS_HIDDEN_(bool) WouldReuseInnerWindow(nsIDocument *aNewDocument);
virtual NS_HIDDEN_(void) SetDocShell(nsIDocShell* aDocShell);
virtual void DetachFromDocShell();
virtual NS_HIDDEN_(nsresult) SetNewDocument(nsIDocument *aDocument,
nsISupports *aState,
bool aForceReuseInnerWindow);
@ -810,7 +811,7 @@ protected:
// could own objects that are implemented in JavaScript, then those
// objects will keep the global object (this object) alive. To prevent
// these cycles, ownership of such members must be released in
// |CleanUp| and |SetDocShell|.
// |CleanUp| and |DetachFromDocShell|.
// This member is also used on both inner and outer windows, but
// for slightly different purposes. On inner windows it means the

Просмотреть файл

@ -48,8 +48,8 @@ class nsIArray;
class nsPIWindowRoot;
#define NS_PIDOMWINDOW_IID \
{ 0xf0bafbe6, 0xe45c, 0x490e, \
{ 0xa2, 0x1c, 0xfe, 0x14, 0x2f, 0xb6, 0x34, 0xba } }
{ 0xfcc2db29, 0x03ba, 0x4eb3, \
{ 0x96, 0xb8, 0xea, 0x0f, 0x6f, 0x1f, 0x61, 0x55 } }
class nsPIDOMWindow : public nsIDOMWindowInternal
{
@ -351,10 +351,16 @@ public:
}
/**
* Set or unset the docshell in the window.
* Set the docshell in the window. Must not be called with a null docshell
* (use DetachFromDocShell for that).
*/
virtual void SetDocShell(nsIDocShell *aDocShell) = 0;
/**
* Detach an outer window from its docshell.
*/
virtual void DetachFromDocShell() = 0;
/**
* Set a new document in the window. Calling this method will in
* most cases create a new inner window. If this method is called on