From 674ac1362020fd6d236d4399b46239211bbe523d Mon Sep 17 00:00:00 2001 From: "mrbkap%gmail.com" Date: Sat, 13 Aug 2005 03:54:29 +0000 Subject: [PATCH] Backing out changes for bug 303267 until the perf hits on the Seamonkey tinderbox can be explained. git-svn-id: svn://10.0.0.236/trunk@177687 18797224-902f-48f8-a5cc-f745e15eee43 --- .../html/document/src/nsHTMLDocument.cpp | 4 +- mozilla/content/xbl/src/nsXBLDocumentInfo.cpp | 2 - .../document/src/nsXULPrototypeDocument.cpp | 2 - mozilla/docshell/base/nsDocShell.cpp | 13 +- mozilla/docshell/base/nsIContentViewer.idl | 6 +- mozilla/dom/public/nsIScriptGlobalObject.h | 6 +- mozilla/dom/src/base/nsGlobalWindow.cpp | 550 ++++++++++-------- mozilla/dom/src/base/nsGlobalWindow.h | 25 +- mozilla/layout/base/nsDocumentViewer.cpp | 15 +- mozilla/layout/base/nsIDocumentViewer.h | 2 +- 10 files changed, 342 insertions(+), 283 deletions(-) diff --git a/mozilla/content/html/document/src/nsHTMLDocument.cpp b/mozilla/content/html/document/src/nsHTMLDocument.cpp index 8594efafa60..75c67b7c1eb 100644 --- a/mozilla/content/html/document/src/nsHTMLDocument.cpp +++ b/mozilla/content/html/document/src/nsHTMLDocument.cpp @@ -1915,8 +1915,8 @@ nsHTMLDocument::OpenCommon(const nsACString& aContentType, PRBool aReplace) nsCOMPtr kungFuDeathGrip = do_QueryInterface((nsIHTMLDocument*)this); - rv = mScriptGlobalObject->SetNewDocument((nsDocument *)this, nsnull, - PR_FALSE, PR_FALSE); + rv = mScriptGlobalObject->SetNewDocument((nsDocument *)this, PR_FALSE, + PR_FALSE); if (NS_FAILED(rv)) { return rv; diff --git a/mozilla/content/xbl/src/nsXBLDocumentInfo.cpp b/mozilla/content/xbl/src/nsXBLDocumentInfo.cpp index c8b440f6cf3..43a8d43419c 100644 --- a/mozilla/content/xbl/src/nsXBLDocumentInfo.cpp +++ b/mozilla/content/xbl/src/nsXBLDocumentInfo.cpp @@ -67,7 +67,6 @@ public: virtual void SetContext(nsIScriptContext *aContext); virtual nsIScriptContext *GetContext(); virtual nsresult SetNewDocument(nsIDOMDocument *aDocument, - nsISupports *aState, PRBool aRemoveEventListeners, PRBool aClearScope); virtual void SetDocShell(nsIDocShell *aDocShell); @@ -221,7 +220,6 @@ nsXBLDocGlobalObject::GetContext() nsresult nsXBLDocGlobalObject::SetNewDocument(nsIDOMDocument *aDocument, - nsISupports *aState, PRBool aRemoveEventListeners, PRBool aClearScope) { diff --git a/mozilla/content/xul/document/src/nsXULPrototypeDocument.cpp b/mozilla/content/xul/document/src/nsXULPrototypeDocument.cpp index 2833c2148b3..cc6c27ba75f 100644 --- a/mozilla/content/xul/document/src/nsXULPrototypeDocument.cpp +++ b/mozilla/content/xul/document/src/nsXULPrototypeDocument.cpp @@ -89,7 +89,6 @@ public: virtual void SetContext(nsIScriptContext *aContext); virtual nsIScriptContext *GetContext(); virtual nsresult SetNewDocument(nsIDOMDocument *aDocument, - nsISupports *aState, PRBool aRemoveEventListeners, PRBool aClearScope); virtual void SetDocShell(nsIDocShell *aDocShell); @@ -847,7 +846,6 @@ nsXULPDGlobalObject::GetContext() nsresult nsXULPDGlobalObject::SetNewDocument(nsIDOMDocument *aDocument, - nsISupports *aState, PRBool aRemoveEventListeners, PRBool aClearScope) { diff --git a/mozilla/docshell/base/nsDocShell.cpp b/mozilla/docshell/base/nsDocShell.cpp index 6cbf9478e30..2850dba4fc8 100644 --- a/mozilla/docshell/base/nsDocShell.cpp +++ b/mozilla/docshell/base/nsDocShell.cpp @@ -5227,14 +5227,8 @@ nsDocShell::RestoreFromHistory() mContentViewer.swap(viewer); viewer = nsnull; // force a release to complete ownership transfer - // Grab the window state up here so we can pass it to Open. - nsCOMPtr windowState; - mLSHE->GetWindowState(getter_AddRefs(windowState)); - - mLSHE->SetWindowState(nsnull); - // Reattach to the window object. - rv = mContentViewer->Open(windowState); + rv = mContentViewer->Open(); // Now remove it from the cached presentation. mLSHE->SetContentViewer(nsnull); @@ -5281,9 +5275,14 @@ nsDocShell::RestoreFromHistory() do_GetInterface(NS_STATIC_CAST(nsIInterfaceRequestor*, this)); NS_ASSERTION(privWin, "could not get nsPIDOMWindow interface"); + nsCOMPtr windowState; + mLSHE->GetWindowState(getter_AddRefs(windowState)); + rv = privWin->RestoreWindowState(windowState); NS_ENSURE_SUCCESS(rv, rv); + mLSHE->SetWindowState(nsnull); + // Now, dispatch a title change event which would happed as the // is parsed. nsCOMPtr nsDoc = do_QueryInterface(document); diff --git a/mozilla/docshell/base/nsIContentViewer.idl b/mozilla/docshell/base/nsIContentViewer.idl index f5e92c72721..8ee4564d22c 100644 --- a/mozilla/docshell/base/nsIContentViewer.idl +++ b/mozilla/docshell/base/nsIContentViewer.idl @@ -14,7 +14,7 @@ struct nsRect; [ptr] native nsIDeviceContextPtr(nsIDeviceContext); [ref] native nsRectRef(nsRect); -[scriptable, uuid(6a7ddb40-8a9e-4576-8ad1-71c5641d8780)] +[scriptable, uuid(62d0e866-e608-4b1a-9ab0-467142b3e3bd)] interface nsIContentViewer : nsISupports { @@ -85,10 +85,8 @@ interface nsIContentViewer : nsISupports /** * Attach the content viewer to its DOM window and docshell. - * @param aState A state object that might be useful in attaching the DOM - * window. */ - void open(in nsISupports aState); + void open(); /** * Clears the current history entry. This is used if we need to clear out diff --git a/mozilla/dom/public/nsIScriptGlobalObject.h b/mozilla/dom/public/nsIScriptGlobalObject.h index 8a9a7aa399f..cc16c6997de 100644 --- a/mozilla/dom/public/nsIScriptGlobalObject.h +++ b/mozilla/dom/public/nsIScriptGlobalObject.h @@ -1,5 +1,4 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 sw=2 et tw=80: */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -52,8 +51,8 @@ class nsIScriptGlobalObjectOwner; struct JSObject; #define NS_ISCRIPTGLOBALOBJECT_IID \ -{ 0xd4ddb2f8, 0x385f, 0x4baa, \ - { 0xba, 0x69, 0x6c, 0x42, 0xb3, 0xc2, 0xd0, 0xd0 } } +{ 0x2b16fc80, 0xfa41, 0x11d1, \ +{ 0x9b, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3} } /** * The JavaScript specific global object. This often used to store @@ -68,7 +67,6 @@ public: virtual void SetContext(nsIScriptContext *aContext) = 0; virtual nsIScriptContext *GetContext() = 0; virtual nsresult SetNewDocument(nsIDOMDocument *aDocument, - nsISupports *aState, PRBool aRemoveEventListeners, PRBool aClearScope) = 0; virtual void SetDocShell(nsIDocShell *aDocShell) = 0; diff --git a/mozilla/dom/src/base/nsGlobalWindow.cpp b/mozilla/dom/src/base/nsGlobalWindow.cpp index 8e583624880..b540ecd4d9a 100644 --- a/mozilla/dom/src/base/nsGlobalWindow.cpp +++ b/mozilla/dom/src/base/nsGlobalWindow.cpp @@ -1,5 +1,4 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set sw=2 ts=2 et tw=80: */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -273,15 +272,14 @@ nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow) mInClose(PR_FALSE), mOpenerWasCleared(PR_FALSE), mIsPopupSpam(PR_FALSE), + mJSObject(nsnull), mArguments(nsnull), - mGlobalObjectOwner(nsnull), - mDocShell(nsnull), mTimeouts(nsnull), mTimeoutInsertionPoint(&mTimeouts), mTimeoutPublicIdCounter(1), mTimeoutFiringDepth(0), - mIsFrozen(PR_FALSE), - mJSObject(nsnull) + mGlobalObjectOwner(nsnull), + mDocShell(nsnull) { // Initialize the PRCList (this). PR_INIT_CLIST(this); @@ -539,111 +537,17 @@ nsGlobalWindow::GetPopupControlState() const return gPopupControlState; } -#define WINDOWSTATEHOLDER_IID \ -{0x2aa29291, 0x3ac9, 0x4d37, {0xa4, 0x3d, 0x45, 0x15, 0x2f, 0x16, 0x23, 0x04 }} - -class WindowStateHolder : public nsISupports -{ -public: - NS_DEFINE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID) - NS_DECL_ISUPPORTS - - WindowStateHolder(nsGlobalWindow *aWindow, - nsIXPConnectJSObjectHolder *aHolder, - nsNavigator *aNavigator); - - // Get the contents of focus memory when the state was saved - // (if the focus was inside of this window). - nsIDOMElement* GetFocusedElement() { return mFocusedElement; } - nsIDOMWindowInternal* GetFocusedWindow() { return mFocusedWindow; } - - nsGlobalWindow* GetInnerWindow() { return mInnerWindow; } - nsIXPConnectJSObjectHolder* GetInnerWindowHolder() - { return mInnerWindowHolder; } - - nsNavigator* GetNavigator() { return mNavigator; } - - void DidRestoreWindow() - { - mInnerWindow = nsnull; - mInnerWindowHolder = nsnull; - mNavigator = nsnull; - } - -protected: - ~WindowStateHolder(); - - nsGlobalWindow *mInnerWindow; - // We hold onto this to make sure the inner window doesn't go away. The outer - // window ends up recalculating it anyway. - nsCOMPtr mInnerWindowHolder; - nsRefPtr mNavigator; - nsCOMPtr mFocusedElement; - nsCOMPtr mFocusedWindow; -}; - -WindowStateHolder::WindowStateHolder(nsGlobalWindow *aWindow, - nsIXPConnectJSObjectHolder *aHolder, - nsNavigator *aNavigator) - : mInnerWindow(aWindow), - mInnerWindowHolder(aHolder), - mNavigator(aNavigator) -{ - NS_PRECONDITION(aWindow, "null window"); - NS_PRECONDITION(aWindow->IsInnerWindow(), "Saving an outer window"); - - nsIFocusController *fc = aWindow->GetRootFocusController(); - NS_ASSERTION(fc, "null focus controller"); - - // We want to save the focused element/window only if they are inside of - // this window. - - nsCOMPtr focusWinInternal; - fc->GetFocusedWindow(getter_AddRefs(focusWinInternal)); - - nsCOMPtr focusedWindow = do_QueryInterface(focusWinInternal); - - // The outer window is used for focus purposes, so make sure that's what - // we're looking for. - nsPIDOMWindow *targetWindow = aWindow->GetOuterWindow(); - - while (focusedWindow) { - if (focusedWindow == targetWindow) { - fc->GetFocusedWindow(getter_AddRefs(mFocusedWindow)); - fc->GetFocusedElement(getter_AddRefs(mFocusedElement)); - break; - } - - focusedWindow = - NS_STATIC_CAST(nsGlobalWindow*, - NS_STATIC_CAST(nsPIDOMWindow*, - focusedWindow))->GetPrivateParent(); - } - - aWindow->SuspendTimeouts(); -} - -WindowStateHolder::~WindowStateHolder() -{ - NS_ASSERTION(!mInnerWindow || !mInnerWindow->mContext, - "Potentially leaking the inner window's JS object and document"); -} - -NS_IMPL_ISUPPORTS1(WindowStateHolder, WindowStateHolder) - nsresult nsGlobalWindow::SetNewDocument(nsIDOMDocument* aDocument, - nsISupports* aState, PRBool aRemoveEventListeners, PRBool aClearScopeHint) { - return SetNewDocument(aDocument, aState, aRemoveEventListeners, - aClearScopeHint, PR_FALSE); + return SetNewDocument(aDocument, aRemoveEventListeners, aClearScopeHint, + PR_FALSE); } nsresult nsGlobalWindow::SetNewDocument(nsIDOMDocument* aDocument, - nsISupports* aState, PRBool aRemoveEventListeners, PRBool aClearScopeHint, PRBool aIsInternalCall) @@ -657,7 +561,6 @@ nsGlobalWindow::SetNewDocument(nsIDOMDocument* aDocument, } return GetOuterWindowInternal()->SetNewDocument(aDocument, - aState, aRemoveEventListeners, aClearScopeHint, PR_TRUE); } @@ -846,20 +749,11 @@ nsGlobalWindow::SetNewDocument(nsIDOMDocument* aDocument, // listener manager over to the new inner window. nsCOMPtr listenerManager; - if (currentInner && !currentInner->IsFrozen()) { + if (currentInner) { if (!reUseInnerWindow) { currentInner->ClearAllTimeouts(); currentInner->mChromeEventHandler = nsnull; - - if (currentInner->mLocation) { - // Invalidate the inner window's location object now that - // the inner window is being torn down. We need to do this - // to prevent people from holding on to an old inner - // window's location object somehow and tracking the - // location of the docshell... - currentInner->mLocation->SetDocShell(nsnull); - } } if (aRemoveEventListeners && currentInner->mListenerManager) { @@ -880,47 +774,35 @@ nsGlobalWindow::SetNewDocument(nsIDOMDocument* aDocument, PRUint32 flags = 0; - if (reUseInnerWindow && !currentInner->IsFrozen()) { + if (reUseInnerWindow) { // We're reusing the current inner window. newInnerWindow = currentInner; } else { - if (aState) { - nsCOMPtr wsh = do_QueryInterface(aState); - NS_ASSERTION(wsh, "What kind of weird state are you giving me here?"); + if (thisChrome) { + newInnerWindow = new nsGlobalChromeWindow(this); - newInnerWindow = wsh->GetInnerWindow(); - mInnerWindowHolder = wsh->GetInnerWindowHolder(); - mNavigator = wsh->GetNavigator(); // This assignment addrefs. + flags = nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT; } else { - if (thisChrome) { - newInnerWindow = new nsGlobalChromeWindow(this); - - flags = nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT; - } else { - newInnerWindow = new nsGlobalWindow(this); - } + newInnerWindow = new nsGlobalWindow(this); } if (!newInnerWindow) { return NS_ERROR_OUT_OF_MEMORY; } - if (!aState) { - // This is redundant if we're restoring from a previous inner window. - nsIScriptGlobalObject *sgo = - (nsIScriptGlobalObject *)newInnerWindow.get(); + nsIScriptGlobalObject *sgo = + (nsIScriptGlobalObject *)newInnerWindow.get(); - nsresult rv = xpc-> - InitClassesWithNewWrappedGlobal(cx, sgo, NS_GET_IID(nsISupports), - flags, - getter_AddRefs(mInnerWindowHolder)); - NS_ENSURE_SUCCESS(rv, rv); + nsresult rv = xpc-> + InitClassesWithNewWrappedGlobal(cx, sgo, NS_GET_IID(nsISupports), + flags, + getter_AddRefs(mInnerWindowHolder)); + NS_ENSURE_SUCCESS(rv, rv); - mInnerWindowHolder->GetJSObject(&newInnerWindow->mJSObject); - } + mInnerWindowHolder->GetJSObject(&newInnerWindow->mJSObject); if (currentInner && currentInner->mJSObject) { - if (mNavigator && !aState) { + if (mNavigator) { // 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 @@ -946,8 +828,7 @@ nsGlobalWindow::SetNewDocument(nsIDOMDocument* aDocument, } nsIScriptContext *callerScx; - if (cx && (callerScx = GetScriptContextFromJSContext(cx)) && - !currentInner->IsFrozen()) { + if (cx && (callerScx = GetScriptContextFromJSContext(cx))) { // 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 @@ -963,27 +844,21 @@ nsGlobalWindow::SetNewDocument(nsIDOMDocument* aDocument, // Clear scope on the outer window ::JS_ClearScope(cx, mJSObject); ::JS_ClearWatchPointsForObject(cx, mJSObject); - // Clear the regexp statics for the new page unconditionally. - // XXX They don't get restored on the inner window when we go back. - ::JS_ClearRegExpStatics(cx); // Re-initialize the outer window. scx->InitContext(this); - // Don't clear scope on our current inner window if it's going to be - // held in the bfcache. - if (!currentInner->IsFrozen()) { - if (!termFuncSet) { - ::JS_ClearScope(cx, currentInner->mJSObject); - ::JS_ClearWatchPointsForObject(cx, currentInner->mJSObject); - } - - // Make the current inner window release its strong references - // to the document to prevent it from keeping everything - // around. But remember the document's principal. - currentInner->mDocument = nsnull; - currentInner->mDocumentPrincipal = oldPrincipal; + if (!termFuncSet) { + ::JS_ClearScope(cx, currentInner->mJSObject); + ::JS_ClearWatchPointsForObject(cx, currentInner->mJSObject); + ::JS_ClearRegExpStatics(cx); } + + // Make the current inner window release its strong references + // to the document to prevent it from keeping everything + // around. But remember the document's principal. + currentInner->mDocument = nsnull; + currentInner->mDocumentPrincipal = oldPrincipal; } mInnerWindow = newInnerWindow; @@ -994,57 +869,54 @@ nsGlobalWindow::SetNewDocument(nsIDOMDocument* aDocument, ::JS_SetGlobalObject(cx, mJSObject); - if (newDoc != oldDoc && !aState) { + if (newDoc != oldDoc) { nsCOMPtr html_doc(do_QueryInterface(mDocument)); nsWindowSH::InstallGlobalScopePolluter(cx, newInnerWindow->mJSObject, html_doc); } - - newInnerWindow->mListenerManager = listenerManager; } if (newDoc) { newDoc->SetScriptGlobalObject(newInnerWindow); } - if (!aState) { - if (reUseInnerWindow) { - newInnerWindow->mDocument = aDocument; - } else { - rv = newInnerWindow->SetNewDocument(aDocument, nsnull, - aRemoveEventListeners, - aClearScopeHint, PR_TRUE); - NS_ENSURE_SUCCESS(rv, rv); + if (reUseInnerWindow) { + newInnerWindow->mDocument = aDocument; + } else { + rv = newInnerWindow->SetNewDocument(aDocument, aRemoveEventListeners, + aClearScopeHint, PR_TRUE); + NS_ENSURE_SUCCESS(rv, rv); - // Initialize DOM classes etc on the inner window. - rv = scx->InitClasses(newInnerWindow->mJSObject); - NS_ENSURE_SUCCESS(rv, rv); + // Initialize DOM classes etc on the inner window. + rv = scx->InitClasses(newInnerWindow->mJSObject); + NS_ENSURE_SUCCESS(rv, rv); - if (navigatorHolder) { - // Restore window.navigator onto the new inner window. - JSObject *nav; - navigatorHolder->GetJSObject(&nav); + if (navigatorHolder) { + // Restore window.navigator onto the new inner window. + JSObject *nav; + navigatorHolder->GetJSObject(&nav); - ::JS_DefineProperty(cx, newInnerWindow->mJSObject, "navigator", - OBJECT_TO_JSVAL(nav), nsnull, nsnull, - JSPROP_ENUMERATE); - } + ::JS_DefineProperty(cx, newInnerWindow->mJSObject, "navigator", + OBJECT_TO_JSVAL(nav), nsnull, nsnull, + JSPROP_ENUMERATE); } - if (mArguments) { - jsval args = OBJECT_TO_JSVAL(mArguments); - - ::JS_SetProperty(cx, newInnerWindow->mJSObject, "arguments", - &args); - - ::JS_UnlockGCThing(cx, mArguments); - mArguments = nsnull; - } - - // Give the new inner window our chrome event handler (since it - // doesn't have one). - newInnerWindow->mChromeEventHandler = mChromeEventHandler; + newInnerWindow->mListenerManager = listenerManager; } + + if (mArguments) { + jsval args = OBJECT_TO_JSVAL(mArguments); + + ::JS_SetProperty(cx, newInnerWindow->mJSObject, "arguments", + &args); + + ::JS_UnlockGCThing(cx, mArguments); + mArguments = nsnull; + } + + // Give the new inner window our chrome event handler (since it + // doesn't have one). + newInnerWindow->mChromeEventHandler = mChromeEventHandler; } if (scx && IsOuterWindow()) { @@ -1079,8 +951,8 @@ nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell) NS_ASSERTION(!mTimeouts, "Uh, outer window holds timeouts!"); JSContext *cx = (JSContext *)mContext->GetNativeContext(); - nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal(); + nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal(); if (currentInner) { currentInner->ClearAllTimeouts(); @@ -1089,6 +961,8 @@ nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell) currentInner->mListenerManager = nsnull; } + JSContext *cx = (JSContext *)mContext->GetNativeContext(); + // XXXjst: We shouldn't need to do this, but if we don't we leak // the world... actually, even with this we leak the // world... need to figure this out. @@ -1134,14 +1008,6 @@ nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell) ::JS_ClearRegExpStatics(cx); currentInner->mChromeEventHandler = nsnull; - - if (currentInner->mLocation) { - // Invalidate the inner window's location object now that the inner - // window is stored in the bfcache. We need to do this to prevent people - // from holding on to an old inner window's location object somehow and - // tracking the location of the docshell... - currentInner->mLocation->SetDocShell(nsnull); - } } // if we are closing the window while in full screen mode, be sure @@ -1185,8 +1051,8 @@ nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell) mDocShell = aDocShell; // Weak Reference - NS_ASSERTION(!mLocation, "Uh, outer window has location object!"); - + if (mLocation) + mLocation->SetDocShell(aDocShell); if (mNavigator) mNavigator->SetDocShell(aDocShell); if (mHistory) @@ -5052,12 +4918,12 @@ nsGlobalWindow::GetPrivateRoot() NS_IMETHODIMP nsGlobalWindow::GetLocation(nsIDOMLocation ** aLocation) { - FORWARD_TO_INNER(GetLocation, (aLocation), NS_ERROR_NOT_INITIALIZED); + FORWARD_TO_OUTER(GetLocation, (aLocation), NS_ERROR_NOT_INITIALIZED); *aLocation = nsnull; - if (!mLocation && GetDocShellInternal()) { - mLocation = new nsLocation(GetDocShellInternal()); + if (!mLocation && mDocShell) { + mLocation = new nsLocation(mDocShell); if (!mLocation) { return NS_ERROR_OUT_OF_MEMORY; } @@ -6575,35 +6441,247 @@ nsGlobalWindow::EnsureSizeUpToDate() } } +#define WINDOWSTATEHOLDER_IID \ +{0xae1c7401, 0xcdee, 0x404a, {0xbd, 0x63, 0x05, 0xc0, 0x35, 0x0d, 0xa7, 0x72}} + +class WindowStateHolder : public nsISupports +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID) + NS_DECL_ISUPPORTS + + WindowStateHolder(JSContext *cx, // The JSContext for the window + JSObject *aObject, // An object to save the properties onto + nsGlobalWindow *aWindow); // The window to operate on + + // This is the property store object that holds the window properties. + JSObject* GetObject() { return mJSObj; } + + // Get the listener manager, which holds all event handlers for the window. + nsIEventListenerManager* GetListenerManager() { return mListenerManager; } + + // Get the saved value of the mMutationBits field. + PRUint32 GetMutationBits() { return mMutationBits; } + + // Get the contents of focus memory when the state was saved + // (if the focus was inside of this window). + nsIDOMElement* GetFocusedElement() { return mFocusedElement; } + nsIDOMWindowInternal* GetFocusedWindow() { return mFocusedWindow; } + + // Manage the list of saved timeouts for the window. + nsTimeout* GetSavedTimeouts() { return mSavedTimeouts; } + nsTimeout** GetTimeoutInsertionPoint() { return mTimeoutInsertionPoint; } + void ClearSavedTimeouts() { mSavedTimeouts = nsnull; } + +protected: + ~WindowStateHolder(); + + JSRuntime *mRuntime; + JSObject *mJSObj; + nsCOMPtr mListenerManager; + nsCOMPtr mFocusedElement; + nsCOMPtr mFocusedWindow; + nsTimeout *mSavedTimeouts; + nsTimeout **mTimeoutInsertionPoint; + PRUint32 mMutationBits; +}; + +WindowStateHolder::WindowStateHolder(JSContext *cx, JSObject *aObject, + nsGlobalWindow *aWindow) + : mRuntime(::JS_GetRuntime(cx)), mJSObj(aObject) +{ + NS_ASSERTION(aWindow, "null window"); + + // Prevent mJSObj from being gc'd for the lifetime of this object. + ::JS_AddNamedRoot(cx, &mJSObj, "WindowStateHolder::mJSObj"); + + aWindow->GetListenerManager(getter_AddRefs(mListenerManager)); + mMutationBits = aWindow->mMutationBits; + + // Clear the window's EventListenerManager pointer so that it can't have + // listeners removed from it later. + aWindow->mListenerManager = nsnull; + + nsIFocusController *fc = aWindow->GetRootFocusController(); + NS_ASSERTION(fc, "null focus controller"); + + // We want to save the focused element/window only if they are inside of + // this window. + + nsCOMPtr focusWinInternal; + fc->GetFocusedWindow(getter_AddRefs(focusWinInternal)); + + nsCOMPtr focusedWindow = do_QueryInterface(focusWinInternal); + + // The outer window is used for focus purposes, so make sure that's what + // we're looking for. + nsPIDOMWindow *targetWindow = aWindow->GetOuterWindow(); + + while (focusedWindow) { + if (focusedWindow == targetWindow) { + fc->GetFocusedWindow(getter_AddRefs(mFocusedWindow)); + fc->GetFocusedElement(getter_AddRefs(mFocusedElement)); + break; + } + + focusedWindow = + NS_STATIC_CAST(nsGlobalWindow*, + NS_STATIC_CAST(nsPIDOMWindow*, + focusedWindow))->GetPrivateParent(); + } + + aWindow->SuspendTimeouts(); + + // Clear the timeout list for aWindow (but we don't need to for children) + mSavedTimeouts = aWindow->mTimeouts; + mTimeoutInsertionPoint = aWindow->mTimeoutInsertionPoint; + + aWindow->mTimeouts = nsnull; + aWindow->mTimeoutInsertionPoint = &aWindow->mTimeouts; +} + +WindowStateHolder::~WindowStateHolder() +{ + // Release the timeouts, if we still have any. + nsTimeout *timeout = mSavedTimeouts; + while (timeout) { + nsTimeout *next = timeout->mNext; + NS_ASSERTION(!timeout->mTimer, "live timer in a saved window state"); + timeout->Release(nsnull); + timeout = next; + } + + ::JS_RemoveRootRT(mRuntime, &mJSObj); +} + +NS_IMPL_ISUPPORTS1(WindowStateHolder, WindowStateHolder) + +static JSClass sWindowStateClass = { + "window state", 0, + JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, + JSCLASS_NO_OPTIONAL_MEMBERS +}; + +static nsresult +CopyJSPropertyArray(JSContext *cx, JSObject *aSource, JSObject *aDest, + JSIdArray *props) +{ + jsint length = props->length; + for (jsint i = 0; i < length; ++i) { + jsval propname_value; + + if (!::JS_IdToValue(cx, props->vector[i], &propname_value) || + !JSVAL_IS_STRING(propname_value)) { + NS_WARNING("Failed to copy non-string-named window property"); + return NS_ERROR_FAILURE; + } + + JSString *propname = JSVAL_TO_STRING(propname_value); + jschar *propname_str = ::JS_GetStringChars(propname); + NS_ENSURE_TRUE(propname_str, NS_ERROR_FAILURE); + + // We exclude the "location" property because restoring it this way is + // problematic. It will "just work" without us explicitly saving or + // restoring the value. + + if (!nsCRT::strcmp(NS_REINTERPRET_CAST(PRUnichar*, propname_str), + NS_LITERAL_STRING("location").get())) { + continue; + } + + size_t propname_len = ::JS_GetStringLength(propname); + + JSPropertyOp getter, setter; + uintN attrs; + JSBool found; + if (!::JS_GetUCPropertyAttrsGetterAndSetter(cx, aSource, propname_str, + propname_len, &attrs, &found, + &getter, &setter)) + return NS_ERROR_FAILURE; + + NS_ENSURE_TRUE(found, NS_ERROR_UNEXPECTED); + + jsval propvalue; + if (!::JS_LookupUCProperty(cx, aSource, propname_str, + propname_len, &propvalue)) + return NS_ERROR_FAILURE; + + PRBool res = ::JS_DefineUCProperty(cx, aDest, propname_str, propname_len, + propvalue, getter, setter, attrs); +#ifdef DEBUG_PAGE_CACHE + if (res) + printf("Copied window property: %s\n", + NS_ConvertUTF16toUTF8(NS_REINTERPRET_CAST(PRUnichar*, + propname_str)).get()); +#endif + + if (!res) { +#ifdef DEBUG + printf("failed to copy property: %s\n", + NS_ConvertUTF16toUTF8(NS_REINTERPRET_CAST(PRUnichar*, + propname_str)).get()); +#endif + return NS_ERROR_FAILURE; + } + } + + return NS_OK; +} + +static nsresult +CopyJSProperties(JSContext *cx, JSObject *aSource, JSObject *aDest) +{ + // Enumerate all of the properties on aSource and install them on aDest. + + JSIdArray *props = ::JS_Enumerate(cx, aSource); + if (props) { + props = ::JS_EnumerateResolvedStandardClasses(cx, aSource, props); + } + if (!props) { +#ifdef DEBUG_PAGE_CACHE + printf("failed to enumerate JS properties\n"); +#endif + return NS_ERROR_FAILURE; + } + +#ifdef DEBUG_PAGE_CACHE + printf("props length = %d\n", props->length); +#endif + + nsresult rv = CopyJSPropertyArray(cx, aSource, aDest, props); + ::JS_DestroyIdArray(cx, props); + return rv; +} + nsresult nsGlobalWindow::SaveWindowState(nsISupports **aState) { - NS_PRECONDITION(IsOuterWindow(), "Can't save the inner window's state"); - *aState = nsnull; - if (!mContext || !mJSObject) { + if (IsOuterWindow() && (!mContext || !mJSObject)) { // The window may be getting torn down; don't bother saving state. return NS_OK; } - nsGlobalWindow *inner = GetCurrentInnerWindowInternal(); - NS_ASSERTION(inner, "No inner window to save"); + FORWARD_TO_INNER(SaveWindowState, (aState), NS_ERROR_NOT_INITIALIZED); - nsCOMPtr state = new WindowStateHolder(inner, - mInnerWindowHolder, - mNavigator); + JSContext *cx = NS_STATIC_CAST(JSContext*, + GetContextInternal()->GetNativeContext()); + NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE); + + JSObject *stateObj = ::JS_NewObject(cx, &sWindowStateClass, NULL, NULL); + NS_ENSURE_TRUE(stateObj, NS_ERROR_OUT_OF_MEMORY); + + // The window state object will root the JSObject. + nsCOMPtr state = new WindowStateHolder(cx, stateObj, this); NS_ENSURE_TRUE(state, NS_ERROR_OUT_OF_MEMORY); #ifdef DEBUG_PAGE_CACHE printf("saving window state, stateObj = %p\n", (void*)stateObj); #endif - - if (inner->mLocation) - inner->mLocation->SetDocShell(nsnull); - - // Don't do anything else to this inner window! - inner->Freeze(); + nsresult rv = CopyJSProperties(cx, mJSObject, stateObj); + NS_ENSURE_SUCCESS(rv, rv); state.swap(*aState); return NS_OK; @@ -6612,21 +6690,35 @@ nsGlobalWindow::SaveWindowState(nsISupports **aState) nsresult nsGlobalWindow::RestoreWindowState(nsISupports *aState) { - NS_ASSERTION(IsOuterWindow(), "Cannot restore an inner window"); + // SetNewDocument() has already been called so we should have a + // new clean inner window to restore state into here. - if (!mContext || !mJSObject) { + if (IsOuterWindow() && (!mContext || !mJSObject)) { // The window may be getting torn down; don't bother restoring state. return NS_OK; } + FORWARD_TO_INNER(RestoreWindowState, (aState), NS_ERROR_NOT_INITIALIZED); + + JSContext *cx = NS_STATIC_CAST(JSContext*, + GetContextInternal()->GetNativeContext()); + NS_ENSURE_TRUE(cx, NS_ERROR_FAILURE); + + // Note that we don't need to call JS_ClearScope here. The scope is already + // cleared by SetNewDocument(), and calling it again here would remove the + // XPConnect properties. + nsCOMPtr holder = do_QueryInterface(aState); NS_ENSURE_TRUE(holder, NS_ERROR_FAILURE); #ifdef DEBUG_PAGE_CACHE printf("restoring window state, stateObj = %p\n", (void*)holder->GetObject()); #endif + nsresult rv = CopyJSProperties(cx, holder->GetObject(), mJSObject); + NS_ENSURE_SUCCESS(rv, rv); - nsGlobalWindow *inner = GetCurrentInnerWindowInternal(); + mListenerManager = holder->GetListenerManager(); + mMutationBits = holder->GetMutationBits(); nsIDOMElement *focusedElement = holder->GetFocusedElement(); nsIDOMWindowInternal *focusedWindow = holder->GetFocusedWindow(); @@ -6645,6 +6737,7 @@ nsGlobalWindow::RestoreWindowState(nsISupports *aState) // We don't bother checking whether the element or frame is focusable. // If it was focusable when we stored the presentation, it must be // focusable now. + PRBool didFocusContent = PR_FALSE; nsIDocument *doc = focusedContent->GetCurrentDoc(); if (doc) { nsIPresShell *shell = doc->GetShellAt(0); @@ -6667,15 +6760,16 @@ nsGlobalWindow::RestoreWindowState(nsISupports *aState) fc->SetFocusedElement(focusedElement); } - // And we're ready to go! - inner->Thaw(); + mTimeouts = holder->GetSavedTimeouts(); + mTimeoutInsertionPoint = holder->GetTimeoutInsertionPoint(); - if (inner->mLocation) - inner->mLocation->SetDocShell(mDocShell); + holder->ClearSavedTimeouts(); - holder->DidRestoreWindow(); + // If our state is being restored from history, we won't be getting an onload + // event. Make sure we're marked as being completely loaded. + mIsDocumentLoaded = PR_TRUE; - return inner->ResumeTimeouts(); + return ResumeTimeouts(); } void diff --git a/mozilla/dom/src/base/nsGlobalWindow.h b/mozilla/dom/src/base/nsGlobalWindow.h index 162cdbb3f41..01311da408c 100644 --- a/mozilla/dom/src/base/nsGlobalWindow.h +++ b/mozilla/dom/src/base/nsGlobalWindow.h @@ -1,5 +1,4 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 sw=2 et tw=80: */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -154,7 +153,6 @@ public: virtual void SetContext(nsIScriptContext *aContext); virtual nsIScriptContext *GetContext(); virtual nsresult SetNewDocument(nsIDOMDocument *aDocument, - nsISupports *aState, PRBool aRemoveEventListeners, PRBool aClearScopeHint); virtual void SetDocShell(nsIDocShell* aDocShell); @@ -280,7 +278,6 @@ protected: void ClearControllers(); nsresult SetNewDocument(nsIDOMDocument *aDocument, - nsISupports *aState, PRBool aRemoveEventListeners, PRBool aClearScopeHint, PRBool aIsInternalCall); @@ -385,25 +382,6 @@ protected: void SuspendTimeouts(); nsresult ResumeTimeouts(); - void Freeze() - { - NS_ASSERTION(IsInnerWindow(), "Freeze called on an outer window"); - mIsFrozen = PR_TRUE; - } - - void Thaw() - { - NS_ASSERTION(IsInnerWindow(), "Freeze called on an outer window"); - mIsFrozen = PR_FALSE; - } - - PRBool IsFrozen() const - { - NS_ASSERTION(IsInnerWindow(), - "Why do you care if an outer window is frozen?"); - return mIsFrozen; - } - // When adding new member variables, be careful not to create cycles // through JavaScript. If there is any chance that a member variable // could own objects that are implemented in JavaScript, then those @@ -427,6 +405,7 @@ protected: nsRefPtr mScreen; nsRefPtr mHistory; nsRefPtr mFrames; + nsRefPtr mLocation; nsRefPtr mMenubar; nsRefPtr mToolbar; nsRefPtr mLocationbar; @@ -450,8 +429,6 @@ protected: nsTimeout** mTimeoutInsertionPoint; PRUint32 mTimeoutPublicIdCounter; PRUint32 mTimeoutFiringDepth; - nsRefPtr mLocation; - PRPackedBool mIsFrozen; // These member variables are used on both inner and the outer windows. nsCOMPtr mDocumentPrincipal; diff --git a/mozilla/layout/base/nsDocumentViewer.cpp b/mozilla/layout/base/nsDocumentViewer.cpp index f2d2036df60..31021187a44 100644 --- a/mozilla/layout/base/nsDocumentViewer.cpp +++ b/mozilla/layout/base/nsDocumentViewer.cpp @@ -1,5 +1,4 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 sw=2 et tw=80: */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * @@ -355,7 +354,6 @@ private: nsresult MakeWindow(nsIWidget* aParentWidget, const nsRect& aBounds); nsresult InitInternal(nsIWidget* aParentWidget, - nsISupports *aState, nsIDeviceContext* aDeviceContext, const nsRect& aBounds, PRBool aDoCreation, @@ -629,7 +627,7 @@ DocumentViewerImpl::Init(nsIWidget* aParentWidget, nsIDeviceContext* aDeviceContext, const nsRect& aBounds) { - return InitInternal(aParentWidget, nsnull, aDeviceContext, aBounds, PR_TRUE, PR_FALSE); + return InitInternal(aParentWidget, aDeviceContext, aBounds, PR_TRUE, PR_FALSE); } nsresult @@ -767,7 +765,6 @@ DocumentViewerImpl::InitPresentationStuff(PRBool aDoInitialReflow) // all the new objects or just initialize the existing ones nsresult DocumentViewerImpl::InitInternal(nsIWidget* aParentWidget, - nsISupports *aState, nsIDeviceContext* aDeviceContext, const nsRect& aBounds, PRBool aDoCreation, @@ -846,7 +843,7 @@ DocumentViewerImpl::InitInternal(nsIWidget* aParentWidget, nsCOMPtr domdoc(do_QueryInterface(mDocument)); if (domdoc) { - global->SetNewDocument(domdoc, aState, PR_TRUE, PR_TRUE); + global->SetNewDocument(domdoc, PR_TRUE, PR_TRUE); } } } @@ -1206,7 +1203,7 @@ DocumentViewerImpl::PageHide(PRBool aIsUnload) } NS_IMETHODIMP -DocumentViewerImpl::Open(nsISupports *aState) +DocumentViewerImpl::Open() { NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED); @@ -1219,7 +1216,7 @@ DocumentViewerImpl::Open(nsISupports *aState) nsRect bounds; mWindow->GetBounds(bounds); - nsresult rv = InitInternal(mParentWidget, aState, mDeviceContext, bounds, + nsresult rv = InitInternal(mParentWidget, mDeviceContext, bounds, PR_FALSE, PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); @@ -1513,7 +1510,7 @@ DocumentViewerImpl::SetDOMDocument(nsIDOMDocument *aDocument) // Set the script global object on the new document nsCOMPtr global = do_GetInterface(container); if (global) { - global->SetNewDocument(aDocument, nsnull, PR_TRUE, PR_TRUE); + global->SetNewDocument(aDocument, PR_TRUE, PR_TRUE); } } @@ -3939,7 +3936,7 @@ DocumentViewerImpl::ReturnToGalleyPresentation() } } - InitInternal(mParentWidget, nsnull, mDeviceContext, bounds, !wasCached, PR_TRUE); + InitInternal(mParentWidget, mDeviceContext, bounds, !wasCached, PR_TRUE); if (mPrintEngine && !wasCached) { mPrintEngine->Destroy(); diff --git a/mozilla/layout/base/nsIDocumentViewer.h b/mozilla/layout/base/nsIDocumentViewer.h index 7fde76a533d..18b3c5c3c91 100644 --- a/mozilla/layout/base/nsIDocumentViewer.h +++ b/mozilla/layout/base/nsIDocumentViewer.h @@ -45,7 +45,7 @@ class nsIPresShell; class nsIStyleSheet; #define NS_IDOCUMENT_VIEWER_IID \ - { 0x42ecec88, 0x80d5, 0x48ac,{0x9a, 0xcd, 0x12, 0x51, 0xdc, 0x42, 0x60, 0x4a}} + { 0xbd4fde0c, 0x71fd, 0x4d77,{0xab, 0x66, 0x26, 0xce, 0x43, 0x93, 0x2e, 0x4e}} /** * A document viewer is a kind of content viewer that uses NGLayout