diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp index b5947bc7150..8a9522982f4 100644 --- a/content/html/document/src/nsHTMLDocument.cpp +++ b/content/html/document/src/nsHTMLDocument.cpp @@ -1961,7 +1961,7 @@ nsHTMLDocument::OpenCommon(const nsACString& aContentType, PRBool aReplace) mWillReparent = PR_TRUE; #endif - rv = window->SetNewDocument(this, nsnull, PR_FALSE); + rv = window->SetNewDocument(this, nsnull); NS_ENSURE_SUCCESS(rv, rv); #ifdef DEBUG diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index 3cfe130ddbc..2e3817c7266 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -1568,39 +1568,18 @@ NS_IMPL_ISUPPORTS1(WindowStateHolder, WindowStateHolder) nsresult nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, - nsISupports* aState, - PRBool aClearScopeHint) + nsISupports* aState) { - return SetNewDocument(aDocument, aState, aClearScopeHint, PR_FALSE); -} + NS_PRECONDITION(mDocumentPrincipal == nsnull, + "mDocumentPrincipal prematurely set!"); -nsresult -nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, - nsISupports* aState, - PRBool aClearScopeHint, - PRBool aIsInternalCall) -{ - NS_ASSERTION(mDocumentPrincipal == nsnull, - "mDocumentPrincipal prematurely set!"); -#ifdef PR_LOGGING - if (IsInnerWindow() && aDocument && gDOMLeakPRLog && - PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) { - nsIURI *uri = aDocument->GetDocumentURI(); - nsCAutoString spec; - if (uri) - uri->GetSpec(spec); - PR_LogPrint("DOMWINDOW %p SetNewDocument %s", this, spec.get()); - } -#endif + if (!aDocument) { + NS_ERROR("SetNewDocument(null) called!"); - if (IsOuterWindow() && IsFrozen()) { - // This outer is now getting its first inner, thaw the outer now - // that it's ready and is getting an inner window. - - Thaw(); + return NS_ERROR_INVALID_ARG; } - if (!aIsInternalCall && IsInnerWindow()) { + if (IsInnerWindow()) { if (!mOuterWindow) { return NS_ERROR_NOT_INITIALIZED; } @@ -1611,15 +1590,15 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, return NS_ERROR_NOT_AVAILABLE; } - return GetOuterWindowInternal()->SetNewDocument(aDocument, - aState, - aClearScopeHint, PR_TRUE); + return GetOuterWindowInternal()->SetNewDocument(aDocument, aState); } - if (!aDocument) { - NS_ERROR("SetNewDocument(null) called!"); + NS_PRECONDITION(IsOuterWindow(), "Must only be called on outer windows"); - return NS_ERROR_INVALID_ARG; + if (IsFrozen()) { + // This outer is now getting its first inner, thaw the outer now + // that it's ready and is getting an inner window. + Thaw(); } NS_ASSERTION(!GetCurrentInnerWindow() || @@ -1667,16 +1646,10 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, SetStatus(EmptyString()); SetDefaultStatus(EmptyString()); - // This code should not be called during shutdown any more (now that - // we don't ever call SetNewDocument(nsnull), so no need to null - // check xpc here. - nsIXPConnect *xpc = nsContentUtils::XPConnect(); - PRBool reUseInnerWindow = WouldReuseInnerWindow(aDocument); // Remember the old document's principal. nsIPrincipal *oldPrincipal = nsnull; - if (oldDoc) { oldPrincipal = oldDoc->NodePrincipal(); } @@ -1707,11 +1680,405 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, mNavigator->LoadingNewDocument(); } - PRUint32 st_id, st_ndx; // we loop over all our context/globs lots! - // Set mDocument even if this is an outer window to avoid // having to *always* reach into the inner window to find the // document. + mDocument = do_QueryInterface(aDocument); + mDoc = aDocument; + +#ifdef DEBUG + mLastOpenedURI = aDocument->GetDocumentURI(); +#endif + + PRUint32 st_id; // we loop over all our context/globs lots! + NS_STID_FOR_ID(st_id) { + nsIScriptContext *langContext = GetScriptContextInternal(st_id); + if (langContext) + langContext->WillInitializeContext(); + } + + nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal(); + + nsRefPtr newInnerWindow; + + nsCOMPtr thisChrome = + do_QueryInterface(static_cast(this)); + nsCOMPtr navigatorHolder; + jsval nav; + + PRBool isChrome = PR_FALSE; + + nsCxPusher cxPusher; + if (!cxPusher.Push(cx)) { + return NS_ERROR_FAILURE; + } + + JSAutoRequest ar(cx); + + // Make sure to clear scope on the outer window *before* we + // initialize the new inner window. If we don't, things + // (Object.prototype etc) could leak from the old outer to the new + // inner scope. + NS_STID_FOR_ID(st_id) { + nsIScriptContext *langContext = GetScriptContextInternal(st_id); + if (langContext) + langContext->ClearScope(mScriptGlobals[NS_STID_INDEX(st_id)], + PR_FALSE); + } + + if (reUseInnerWindow) { + // We're reusing the current inner window. + NS_ASSERTION(!currentInner->IsFrozen(), + "We should never be reusing a shared inner window"); + newInnerWindow = currentInner; + + if (aDocument != oldDoc) { + nsWindowSH::InvalidateGlobalScopePolluter(cx, currentInner->mJSObject); + } + } else { + if (aState) { + nsCOMPtr wsh = do_QueryInterface(aState); + NS_ASSERTION(wsh, "What kind of weird state are you giving me here?"); + + newInnerWindow = wsh->GetInnerWindow(); + NS_STID_FOR_ID(st_id) { + mInnerWindowHolders[NS_STID_INDEX(st_id)] = wsh->GetInnerWindowHolder(st_id); + } + + // These assignments addref. + mNavigator = wsh->GetNavigator(); + mLocation = wsh->GetLocation(); + + if (mNavigator) { + // Update mNavigator's docshell pointer now. + mNavigator->SetDocShell(mDocShell); + mNavigator->LoadingNewDocument(); + } + } else { + if (thisChrome) { + newInnerWindow = new nsGlobalChromeWindow(this); + + isChrome = PR_TRUE; + } else { + if (mIsModalContentWindow) { + newInnerWindow = new nsGlobalModalWindow(this); + } else { + newInnerWindow = new nsGlobalWindow(this); + } + } + + mLocation = nsnull; + } + + if (!newInnerWindow) { + return NS_ERROR_OUT_OF_MEMORY; + } + + if (currentInner && currentInner->mJSObject) { + if (mNavigator && !aState) { + // Hold on to the navigator wrapper so that we can set + // window.navigator in the new window to point to the same + // object (assuming we didn't change origins etc). See bug + // 163645 for more on why we need this. + + nsIDOMNavigator* navigator = + static_cast(mNavigator.get()); + nsContentUtils::WrapNative(cx, currentInner->mJSObject, navigator, + &NS_GET_IID(nsIDOMNavigator), &nav, + getter_AddRefs(navigatorHolder)); + } + } + + if (!aState) { + // This is redundant if we're restoring from a previous inner window. + nsIScriptGlobalObject *sgo = + (nsIScriptGlobalObject *)newInnerWindow.get(); + + // Freeze the outer window and null out the inner window so + // that initializing classes on the new inner doesn't end up + // reaching into the old inner window for classes etc. + // + // [This happens with Object.prototype when XPConnect creates + // a temporary global while initializing classes; the reason + // being that xpconnect creates the temp global w/o a parent + // and proto, which makes the JS engine look up classes in + // cx->globalObject, i.e. this outer window]. + + mInnerWindow = nsnull; + + Freeze(); + mCreatingInnerWindow = PR_TRUE; + // Every script context we are initialized with must create a + // new global. + rv = NS_OK; + NS_STID_FOR_ID(st_id) { + PRUint32 st_ndx = NS_STID_INDEX(st_id); + nsIScriptContext *this_ctx = GetScriptContextInternal(st_id); + if (this_ctx) { + void *&newGlobal = newInnerWindow->mScriptGlobals[st_ndx]; + nsCOMPtr &holder = mInnerWindowHolders[st_ndx]; + rv |= this_ctx->CreateNativeGlobalForInner(sgo, isChrome, + &newGlobal, + getter_AddRefs(holder)); + NS_ASSERTION(NS_SUCCEEDED(rv) && newGlobal && holder, + "Failed to get script global and holder"); + if (st_id == nsIProgrammingLanguage::JAVASCRIPT) { + newInnerWindow->mJSObject = (JSObject *)newGlobal; + } + } + } + mCreatingInnerWindow = PR_FALSE; + Thaw(); + + NS_ENSURE_SUCCESS(rv, rv); + } + + if (currentInner && currentInner->mJSObject) { + PRBool termFuncSet = PR_FALSE; + + if (oldDoc == aDocument) { + // Suspend the current context's request before Pop() resumes the old + // context's request. + JSAutoSuspendRequest asr(cx); + + // Pop our context here so that we get the correct one for the + // termination function. + cxPusher.Pop(); + + JSContext *oldCx = nsContentUtils::GetCurrentJSContext(); + + nsIScriptContext *callerScx; + if (oldCx && (callerScx = GetScriptContextFromJSContext(oldCx))) { + // We're called from document.open() (and document.open() is + // called from JS), clear the scope etc in a termination + // function on the calling context to prevent clearing the + // calling scope. + NS_ASSERTION(!currentInner->IsFrozen(), + "How does this opened window get into session history"); + + JSAutoRequest ar(oldCx); + + callerScx->SetTerminationFunction(ClearWindowScope, + static_cast + (currentInner)); + + termFuncSet = PR_TRUE; + } + + // Re-push our context. + cxPusher.Push(cx); + } + + // Don't clear scope on our current inner window if it's going to be + // held in the bfcache. + if (!currentInner->IsFrozen()) { + // Skip the ClearScope if we set a termination function to do + // it ourselves, later. + currentInner->FreeInnerObjects(!termFuncSet); + } + } + + mInnerWindow = newInnerWindow; + } + + if (!aState && !reUseInnerWindow) { + // Loading a new page and creating a new inner window, *not* + // restoring from session history. + + // InitClassesWithNewWrappedGlobal() (via CreateNativeGlobalForInner) + // for the new inner window + // sets the global object in cx to be the new wrapped global. We + // don't want that, but re-initializing the outer window will + // fix that for us. And perhaps more importantly, this will + // ensure that the outer window gets a new prototype so we don't + // leak prototype properties from the old inner window to the + // new one. + NS_STID_FOR_ID(st_id) { + nsIScriptContext *this_ctx = GetScriptContextInternal(st_id); + if (st_id == nsIProgrammingLanguage::JAVASCRIPT) + JS_BeginRequest((JSContext *)this_ctx->GetNativeContext()); + if (this_ctx) { + this_ctx->InitContext(this); + // Now that both the the inner and outer windows are initialized + // let each script context do its magic to hook them together. + void *glob = mScriptGlobals[NS_STID_INDEX(st_id)]; + this_ctx->ConnectToInner(newInnerWindow, glob); + } + if (st_id == nsIProgrammingLanguage::JAVASCRIPT) + JS_EndRequest((JSContext *)this_ctx->GetNativeContext()); + } + + nsCOMPtr frame = do_QueryInterface(GetFrameElementInternal()); + if (frame && frame->GetOwnerDoc()) { + nsPIDOMWindow* parentWindow = frame->GetOwnerDoc()->GetWindow(); + if (parentWindow && parentWindow->TimeoutSuspendCount()) { + SuspendTimeouts(parentWindow->TimeoutSuspendCount()); + } + } + } + // Tell the contexts we have completed setting up the doc. + NS_STID_FOR_ID(st_id) { + // Add an extra ref in case we release mContext during GC. + nsCOMPtr this_ctx = + GetScriptContextInternal(st_id); + if (this_ctx) { + nsCOMPtr dd(do_QueryInterface(aDocument)); + this_ctx->DidSetDocument(dd, newInnerWindow->GetScriptGlobal(st_id)); + } + } + + // Now that the prototype is all set up, install the global scope + // polluter. This must happen after the above prototype fixup. If + // the GSP was to be installed on the inner window's real + // prototype (as it would be if this was done before the prototype + // fixup above) we would end up holding the GSP alive (through + // XPConnect's internal marking of wrapper prototypes) as long as + // the inner window was around, and if the GSP had properties on + // it that held an element alive we'd hold the document alive, + // which could hold event handlers alive, which hold the context + // alive etc. + + if ((!reUseInnerWindow || aDocument != oldDoc) && !aState) { + nsCOMPtr html_doc(do_QueryInterface(mDocument)); + nsWindowSH::InstallGlobalScopePolluter(cx, newInnerWindow->mJSObject, + html_doc); + } + + // This code should not be called during shutdown any more (now that + // we don't ever call SetNewDocument(nsnull), so no need to null + // check xpc here. + nsIXPConnect *xpc = nsContentUtils::XPConnect(); + + if (aState) { + // Restoring from session history. + + nsCOMPtr wsh = do_QueryInterface(aState); + NS_ASSERTION(wsh, "What kind of weird state are you giving me here?"); + + // Restore the prototype for the Window/ChromeWindow class in + // the outer window scope. + nsCOMPtr ci = + do_QueryInterface((nsIScriptGlobalObject *)this); + + rv = xpc->RestoreWrappedNativePrototype(cx, mJSObject, ci, + wsh->GetOuterProto()); + NS_ENSURE_SUCCESS(rv, rv); + + // Refresh the outer window's prototype to what it was when the + // window state was saved. This will make the outer window + // object (and wrapper) pick up the prototype it had when the + // window state was saved. This means Object.prototype etc from + // the old inner will again be on the outer window's prototype + // chain. + + nsCOMPtr wrapper; + rv = xpc->GetWrappedNativeOfJSObject(cx, mJSObject, + getter_AddRefs(wrapper)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = wrapper->RefreshPrototype(); + NS_ENSURE_SUCCESS(rv, rv); + } + + if (aDocument) { + aDocument->SetScriptGlobalObject(newInnerWindow); + } + + if (!aState) { + if (reUseInnerWindow) { + if (newInnerWindow->mDoc != aDocument) { + newInnerWindow->mDocument = do_QueryInterface(aDocument); + newInnerWindow->mDoc = aDocument; + + // We're reusing the inner window for a new document. In this + // case we don't clear the inner window's scope, but we must + // make sure the cached document property gets updated. + + // XXXmarkh - tell other languages about this? + JSAutoRequest ar(cx); + ::JS_DeleteProperty(cx, currentInner->mJSObject, "document"); + } + } else { + rv = newInnerWindow->InnerWindowSetNewDocument(aDocument); + NS_ENSURE_SUCCESS(rv, rv); + + NS_STID_FOR_ID(st_id) { + nsIScriptContext *this_ctx = GetScriptContextInternal(st_id); + if (this_ctx) { + // Initialize DOM classes etc on the inner window. + void *glob = newInnerWindow->mScriptGlobals[NS_STID_INDEX(st_id)]; + rv = this_ctx->InitClasses(glob); + NS_ENSURE_SUCCESS(rv, rv); + + if (navigatorHolder && + st_id == nsIProgrammingLanguage::JAVASCRIPT) { + // Restore window.navigator onto the new inner window. + JSAutoRequest ar(cx); + + ::JS_DefineProperty(cx, newInnerWindow->mJSObject, "navigator", + nav, nsnull, nsnull, + JSPROP_ENUMERATE | JSPROP_PERMANENT | + JSPROP_READONLY); + + // The Navigator's prototype object keeps a reference to the + // window in which it was first created and can thus cause that + // window to stay alive for too long. Reparenting it here allows + // the window to be collected sooner. + nsIDOMNavigator* navigator = + static_cast(mNavigator); + + xpc-> + ReparentWrappedNativeIfFound(cx, JSVAL_TO_OBJECT(nav), + newInnerWindow->mJSObject, + navigator, + getter_AddRefs(navigatorHolder)); + } + } + } + } + + if (mArguments) { + newInnerWindow->DefineArgumentsProperty(mArguments); + newInnerWindow->mArguments = mArguments; + newInnerWindow->mArgumentsOrigin = mArgumentsOrigin; + + mArguments = nsnull; + mArgumentsOrigin = nsnull; + } + + // Give the new inner window our chrome event handler (since it + // doesn't have one). + newInnerWindow->mChromeEventHandler = mChromeEventHandler; + } + + NS_STID_FOR_ID(st_id) { + // Add an extra ref in case we release mContext during GC. + nsCOMPtr this_ctx = + GetScriptContextInternal(st_id); + if (this_ctx) { + this_ctx->GC(); + this_ctx->DidInitializeContext(); + } + } + + return NS_OK; +} + +nsresult +nsGlobalWindow::InnerWindowSetNewDocument(nsIDocument* aDocument) +{ + NS_PRECONDITION(IsInnerWindow(), "Must only be called on inner windows"); + +#ifdef PR_LOGGING + if (aDocument && gDOMLeakPRLog && + PR_LOG_TEST(gDOMLeakPRLog, PR_LOG_DEBUG)) { + nsIURI *uri = aDocument->GetDocumentURI(); + nsCAutoString spec; + if (uri) + uri->GetSpec(spec); + PR_LogPrint("DOMWINDOW %p SetNewDocument %s", this, spec.get()); + } +#endif mDocument = do_QueryInterface(aDocument); mDoc = aDocument; @@ -1722,374 +2089,6 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, mLastOpenedURI = aDocument->GetDocumentURI(); #endif - if (IsOuterWindow()) { - NS_STID_FOR_ID(st_id) { - nsIScriptContext *langContext = GetScriptContextInternal(st_id); - if (langContext) - langContext->WillInitializeContext(); - } - - nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal(); - - nsRefPtr newInnerWindow; - - nsCOMPtr thisChrome = - do_QueryInterface(static_cast(this)); - nsCOMPtr navigatorHolder; - jsval nav; - - PRBool isChrome = PR_FALSE; - - nsCxPusher cxPusher; - if (!cxPusher.Push(cx)) { - return NS_ERROR_FAILURE; - } - - JSAutoRequest ar(cx); - - // Make sure to clear scope on the outer window *before* we - // initialize the new inner window. If we don't, things - // (Object.prototype etc) could leak from the old outer to the new - // inner scope. - NS_STID_FOR_ID(st_id) { - nsIScriptContext *langContext = GetScriptContextInternal(st_id); - if (langContext) - langContext->ClearScope(mScriptGlobals[NS_STID_INDEX(st_id)], - PR_FALSE); - } - - if (reUseInnerWindow) { - // We're reusing the current inner window. - NS_ASSERTION(!currentInner->IsFrozen(), - "We should never be reusing a shared inner window"); - newInnerWindow = currentInner; - - if (aDocument != oldDoc) { - nsWindowSH::InvalidateGlobalScopePolluter(cx, currentInner->mJSObject); - } - } else { - if (aState) { - nsCOMPtr wsh = do_QueryInterface(aState); - NS_ASSERTION(wsh, "What kind of weird state are you giving me here?"); - - newInnerWindow = wsh->GetInnerWindow(); - NS_STID_FOR_ID(st_id) { - mInnerWindowHolders[NS_STID_INDEX(st_id)] = wsh->GetInnerWindowHolder(st_id); - } - - // These assignments addref. - mNavigator = wsh->GetNavigator(); - mLocation = wsh->GetLocation(); - - if (mNavigator) { - // Update mNavigator's docshell pointer now. - mNavigator->SetDocShell(mDocShell); - mNavigator->LoadingNewDocument(); - } - } else { - if (thisChrome) { - newInnerWindow = new nsGlobalChromeWindow(this); - - isChrome = PR_TRUE; - } else { - if (mIsModalContentWindow) { - newInnerWindow = new nsGlobalModalWindow(this); - } else { - newInnerWindow = new nsGlobalWindow(this); - } - } - - mLocation = nsnull; - } - - if (!newInnerWindow) { - return NS_ERROR_OUT_OF_MEMORY; - } - - if (currentInner && currentInner->mJSObject) { - if (mNavigator && !aState) { - // Hold on to the navigator wrapper so that we can set - // window.navigator in the new window to point to the same - // object (assuming we didn't change origins etc). See bug - // 163645 for more on why we need this. - - nsIDOMNavigator* navigator = - static_cast(mNavigator.get()); - nsContentUtils::WrapNative(cx, currentInner->mJSObject, navigator, - &NS_GET_IID(nsIDOMNavigator), &nav, - getter_AddRefs(navigatorHolder)); - } - } - - if (!aState) { - // This is redundant if we're restoring from a previous inner window. - nsIScriptGlobalObject *sgo = - (nsIScriptGlobalObject *)newInnerWindow.get(); - - // Freeze the outer window and null out the inner window so - // that initializing classes on the new inner doesn't end up - // reaching into the old inner window for classes etc. - // - // [This happens with Object.prototype when XPConnect creates - // a temporary global while initializing classes; the reason - // being that xpconnect creates the temp global w/o a parent - // and proto, which makes the JS engine look up classes in - // cx->globalObject, i.e. this outer window]. - - mInnerWindow = nsnull; - - Freeze(); - mCreatingInnerWindow = PR_TRUE; - // Every script context we are initialized with must create a - // new global. - rv = NS_OK; - NS_STID_FOR_ID(st_id) { - st_ndx = NS_STID_INDEX(st_id); - nsIScriptContext *this_ctx = GetScriptContextInternal(st_id); - if (this_ctx) { - void *&newGlobal = newInnerWindow->mScriptGlobals[st_ndx]; - nsCOMPtr &holder = mInnerWindowHolders[st_ndx]; - rv |= this_ctx->CreateNativeGlobalForInner(sgo, isChrome, - &newGlobal, - getter_AddRefs(holder)); - NS_ASSERTION(NS_SUCCEEDED(rv) && newGlobal && holder, - "Failed to get script global and holder"); - if (st_id == nsIProgrammingLanguage::JAVASCRIPT) { - newInnerWindow->mJSObject = (JSObject *)newGlobal; - } - } - } - mCreatingInnerWindow = PR_FALSE; - Thaw(); - - NS_ENSURE_SUCCESS(rv, rv); - } - - if (currentInner && currentInner->mJSObject) { - PRBool termFuncSet = PR_FALSE; - - if (oldDoc == aDocument) { - // Suspend the current context's request before Pop() resumes the old - // context's request. - JSAutoSuspendRequest asr(cx); - - // Pop our context here so that we get the correct one for the - // termination function. - cxPusher.Pop(); - - JSContext *oldCx = nsContentUtils::GetCurrentJSContext(); - - nsIScriptContext *callerScx; - if (oldCx && (callerScx = GetScriptContextFromJSContext(oldCx))) { - // We're called from document.open() (and document.open() is - // called from JS), clear the scope etc in a termination - // function on the calling context to prevent clearing the - // calling scope. - NS_ASSERTION(!currentInner->IsFrozen(), - "How does this opened window get into session history"); - - JSAutoRequest ar(oldCx); - - callerScx->SetTerminationFunction(ClearWindowScope, - static_cast - (currentInner)); - - termFuncSet = PR_TRUE; - } - - // Re-push our context. - cxPusher.Push(cx); - } - - // Don't clear scope on our current inner window if it's going to be - // held in the bfcache. - if (!currentInner->IsFrozen()) { - // Skip the ClearScope if we set a termination function to do - // it ourselves, later. - currentInner->FreeInnerObjects(!termFuncSet); - } - } - - mInnerWindow = newInnerWindow; - } - - if (!aState && !reUseInnerWindow) { - // Loading a new page and creating a new inner window, *not* - // restoring from session history. - - // InitClassesWithNewWrappedGlobal() (via CreateNativeGlobalForInner) - // for the new inner window - // sets the global object in cx to be the new wrapped global. We - // don't want that, but re-initializing the outer window will - // fix that for us. And perhaps more importantly, this will - // ensure that the outer window gets a new prototype so we don't - // leak prototype properties from the old inner window to the - // new one. - NS_STID_FOR_ID(st_id) { - nsIScriptContext *this_ctx = GetScriptContextInternal(st_id); - if (st_id == nsIProgrammingLanguage::JAVASCRIPT) - JS_BeginRequest((JSContext *)this_ctx->GetNativeContext()); - if (this_ctx) { - this_ctx->InitContext(this); - // Now that both the the inner and outer windows are initialized - // let each script context do its magic to hook them together. - void *glob = mScriptGlobals[NS_STID_INDEX(st_id)]; - this_ctx->ConnectToInner(newInnerWindow, glob); - } - if (st_id == nsIProgrammingLanguage::JAVASCRIPT) - JS_EndRequest((JSContext *)this_ctx->GetNativeContext()); - } - - nsCOMPtr frame = do_QueryInterface(GetFrameElementInternal()); - if (frame && frame->GetOwnerDoc()) { - nsPIDOMWindow* parentWindow = frame->GetOwnerDoc()->GetWindow(); - if (parentWindow && parentWindow->TimeoutSuspendCount()) { - SuspendTimeouts(parentWindow->TimeoutSuspendCount()); - } - } - } - // Tell the contexts we have completed setting up the doc. - NS_STID_FOR_ID(st_id) { - // Add an extra ref in case we release mContext during GC. - nsCOMPtr this_ctx = - GetScriptContextInternal(st_id); - if (this_ctx) { - nsCOMPtr dd(do_QueryInterface(aDocument)); - this_ctx->DidSetDocument(dd, newInnerWindow->GetScriptGlobal(st_id)); - } - } - - // Now that the prototype is all set up, install the global scope - // polluter. This must happen after the above prototype fixup. If - // the GSP was to be installed on the inner window's real - // prototype (as it would be if this was done before the prototype - // fixup above) we would end up holding the GSP alive (through - // XPConnect's internal marking of wrapper prototypes) as long as - // the inner window was around, and if the GSP had properties on - // it that held an element alive we'd hold the document alive, - // which could hold event handlers alive, which hold the context - // alive etc. - - if ((!reUseInnerWindow || aDocument != oldDoc) && !aState) { - nsCOMPtr html_doc(do_QueryInterface(mDocument)); - nsWindowSH::InstallGlobalScopePolluter(cx, newInnerWindow->mJSObject, - html_doc); - } - - if (aState) { - // Restoring from session history. - - nsCOMPtr wsh = do_QueryInterface(aState); - NS_ASSERTION(wsh, "What kind of weird state are you giving me here?"); - - // Restore the prototype for the Window/ChromeWindow class in - // the outer window scope. - nsCOMPtr ci = - do_QueryInterface((nsIScriptGlobalObject *)this); - - rv = xpc->RestoreWrappedNativePrototype(cx, mJSObject, ci, - wsh->GetOuterProto()); - NS_ENSURE_SUCCESS(rv, rv); - - // Refresh the outer window's prototype to what it was when the - // window state was saved. This will make the outer window - // object (and wrapper) pick up the prototype it had when the - // window state was saved. This means Object.prototype etc from - // the old inner will again be on the outer window's prototype - // chain. - - nsCOMPtr wrapper; - rv = xpc->GetWrappedNativeOfJSObject(cx, mJSObject, - getter_AddRefs(wrapper)); - NS_ENSURE_SUCCESS(rv, rv); - - rv = wrapper->RefreshPrototype(); - NS_ENSURE_SUCCESS(rv, rv); - } - - if (aDocument) { - aDocument->SetScriptGlobalObject(newInnerWindow); - } - - if (!aState) { - if (reUseInnerWindow) { - if (newInnerWindow->mDoc != aDocument) { - newInnerWindow->mDocument = do_QueryInterface(aDocument); - newInnerWindow->mDoc = aDocument; - - // We're reusing the inner window for a new document. In this - // case we don't clear the inner window's scope, but we must - // make sure the cached document property gets updated. - - // XXXmarkh - tell other languages about this? - JSAutoRequest ar(cx); - ::JS_DeleteProperty(cx, currentInner->mJSObject, "document"); - } - } else { - rv = newInnerWindow->SetNewDocument(aDocument, nsnull, - aClearScopeHint, PR_TRUE); - NS_ENSURE_SUCCESS(rv, rv); - - NS_STID_FOR_ID(st_id) { - nsIScriptContext *this_ctx = GetScriptContextInternal(st_id); - if (this_ctx) { - // Initialize DOM classes etc on the inner window. - void *glob = newInnerWindow->mScriptGlobals[NS_STID_INDEX(st_id)]; - rv = this_ctx->InitClasses(glob); - NS_ENSURE_SUCCESS(rv, rv); - - if (navigatorHolder && - st_id == nsIProgrammingLanguage::JAVASCRIPT) { - // Restore window.navigator onto the new inner window. - JSAutoRequest ar(cx); - - ::JS_DefineProperty(cx, newInnerWindow->mJSObject, "navigator", - nav, nsnull, nsnull, - JSPROP_ENUMERATE | JSPROP_PERMANENT | - JSPROP_READONLY); - - // The Navigator's prototype object keeps a reference to the - // window in which it was first created and can thus cause that - // window to stay alive for too long. Reparenting it here allows - // the window to be collected sooner. - nsIDOMNavigator* navigator = - static_cast(mNavigator); - - xpc-> - ReparentWrappedNativeIfFound(cx, JSVAL_TO_OBJECT(nav), - newInnerWindow->mJSObject, - navigator, - getter_AddRefs(navigatorHolder)); - } - } - } - } - - if (mArguments) { - newInnerWindow->DefineArgumentsProperty(mArguments); - newInnerWindow->mArguments = mArguments; - newInnerWindow->mArgumentsOrigin = mArgumentsOrigin; - - mArguments = nsnull; - mArgumentsOrigin = nsnull; - } - - // Give the new inner window our chrome event handler (since it - // doesn't have one). - newInnerWindow->mChromeEventHandler = mChromeEventHandler; - } - - NS_STID_FOR_ID(st_id) { - // Add an extra ref in case we release mContext during GC. - nsCOMPtr this_ctx = - GetScriptContextInternal(st_id); - if (this_ctx) { - this_ctx->GC(); - this_ctx->DidInitializeContext(); - } - } - } - // Clear our mutation bitfield. mMutationBits = 0; @@ -9445,8 +9444,7 @@ nsGlobalModalWindow::SetReturnValue(nsIVariant *aRetVal) nsresult nsGlobalModalWindow::SetNewDocument(nsIDocument *aDocument, - nsISupports *aState, - PRBool aClearScopeHint) + nsISupports *aState) { // If we're loading a new document into a modal dialog, clear the // return value that was set, if any, by the current document. @@ -9454,7 +9452,7 @@ nsGlobalModalWindow::SetNewDocument(nsIDocument *aDocument, mReturnValue = nsnull; } - return nsGlobalWindow::SetNewDocument(aDocument, aState, aClearScopeHint); + return nsGlobalWindow::SetNewDocument(aDocument, aState); } //***************************************************************************** diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index 8d89e7aa3da..86c4873164c 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -335,8 +335,7 @@ public: virtual NS_HIDDEN_(void) SetDocShell(nsIDocShell* aDocShell); virtual NS_HIDDEN_(nsresult) SetNewDocument(nsIDocument *aDocument, - nsISupports *aState, - PRBool aClearScopeHint); + nsISupports *aState); virtual NS_HIDDEN_(void) SetOpenerWindow(nsIDOMWindowInternal *aOpener, PRBool aOriginalOpener); virtual NS_HIDDEN_(void) EnsureSizeUpToDate(); @@ -463,10 +462,8 @@ protected: void FreeInnerObjects(PRBool aClearScope); nsGlobalWindow *CallerInnerWindow(); - nsresult SetNewDocument(nsIDocument *aDocument, - nsISupports *aState, - PRBool aClearScopeHint, - PRBool aIsInternalCall); + nsresult InnerWindowSetNewDocument(nsIDocument* aDocument); + nsresult DefineArgumentsProperty(nsIArray *aArguments); // Get the parent, returns null if this is a toplevel window @@ -848,8 +845,7 @@ public: NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsGlobalModalWindow, nsGlobalWindow) virtual NS_HIDDEN_(nsresult) SetNewDocument(nsIDocument *aDocument, - nsISupports *aState, - PRBool aClearScopeHint); + nsISupports *aState); protected: nsCOMPtr mReturnValue; diff --git a/dom/base/nsPIDOMWindow.h b/dom/base/nsPIDOMWindow.h index 02d0f887dcc..faa28ee7fd5 100644 --- a/dom/base/nsPIDOMWindow.h +++ b/dom/base/nsPIDOMWindow.h @@ -78,8 +78,8 @@ class nsIArray; class nsPIWindowRoot; #define NS_PIDOMWINDOW_IID \ -{ 0x2962cfa4, 0x13f9, 0x4606, \ - { 0x84, 0x64, 0xef, 0x4c, 0xfa, 0x33, 0xcc, 0xce } } +{ 0x81cdf500, 0x2183, 0x4af6, \ + { 0xa4, 0x56, 0x35, 0x1f, 0x4a, 0x0d, 0x1a, 0x0b } } class nsPIDOMWindow : public nsIDOMWindowInternal { @@ -353,8 +353,7 @@ public: * created. */ virtual nsresult SetNewDocument(nsIDocument *aDocument, - nsISupports *aState, - PRBool aClearScope) = 0; + nsISupports *aState) = 0; /** * Set the opener window. aOriginalOpener is true if and only if this is the diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index f8a59e338b3..b0048b268df 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -946,7 +946,7 @@ DocumentViewerImpl::InitInternal(nsIWidget* aParentWidget, getter_AddRefs(window)); if (window) { - window->SetNewDocument(mDocument, aState, PR_TRUE); + window->SetNewDocument(mDocument, aState); nsJSContext::LoadStart(); } @@ -1695,7 +1695,7 @@ DocumentViewerImpl::SetDOMDocument(nsIDOMDocument *aDocument) // Set the script global object on the new document nsCOMPtr window = do_GetInterface(container); if (window) { - window->SetNewDocument(newDoc, nsnull, PR_TRUE); + window->SetNewDocument(newDoc, nsnull); } // Clear the list of old child docshells. CChild docshells for the new