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