Mozilla Home
Privacy
Cookies
Legal
Bugzilla
Browse
Advanced Search
New Bug
Reports
Documentation
Log In
Log In with GitHub
or
Remember me
Browse
Advanced Search
New Bug
Reports
Documentation
Attachment 192640 Details for
Bug 303267
[patch]
this time, without the leaks=
temp.diff (text/plain), 61.04 KB, created by
Blake Kaplan (:mrbkap) (inactive)
(
hide
)
Description:
this time, without the leaks=
Filename:
MIME Type:
Creator:
Blake Kaplan (:mrbkap) (inactive)
Size:
61.04 KB
patch
obsolete
>? patch303642.txt >? temp.diff >? dom/src/base/.nsGlobalWindow.cpp.swp >? js/src/gc-debug >Index: content/html/document/src/nsHTMLDocument.cpp >=================================================================== >RCS file: /cvsroot/mozilla/content/html/document/src/nsHTMLDocument.cpp,v >retrieving revision 3.617 >diff -p -U10 -r3.617 nsHTMLDocument.cpp >--- content/html/document/src/nsHTMLDocument.cpp 13 Aug 2005 03:54:28 -0000 3.617 >+++ content/html/document/src/nsHTMLDocument.cpp 13 Aug 2005 23:14:43 -0000 >@@ -1908,22 +1908,22 @@ nsHTMLDocument::OpenCommon(const nsACStr > } > > // Before we reset the doc notify the globalwindow of the change. > > if (mScriptGlobalObject) { > // Hold onto ourselves on the offchance that we're down to one ref > > nsCOMPtr<nsIDOMDocument> kungFuDeathGrip = > do_QueryInterface((nsIHTMLDocument*)this); > >- rv = mScriptGlobalObject->SetNewDocument((nsDocument *)this, PR_FALSE, >- PR_FALSE); >+ rv = mScriptGlobalObject->SetNewDocument((nsDocument *)this, nsnull, >+ PR_FALSE, PR_FALSE); > > if (NS_FAILED(rv)) { > return rv; > } > } > > // XXX This is a nasty workaround for a scrollbar code bug > // (http://bugzilla.mozilla.org/show_bug.cgi?id=55334). > > // Hold on to our root element >Index: content/xbl/src/nsXBLDocumentInfo.cpp >=================================================================== >RCS file: /cvsroot/mozilla/content/xbl/src/nsXBLDocumentInfo.cpp,v >retrieving revision 1.31 >diff -p -U10 -r1.31 nsXBLDocumentInfo.cpp >--- content/xbl/src/nsXBLDocumentInfo.cpp 13 Aug 2005 03:54:28 -0000 1.31 >+++ content/xbl/src/nsXBLDocumentInfo.cpp 13 Aug 2005 23:14:44 -0000 >@@ -60,20 +60,21 @@ class nsXBLDocGlobalObject : public nsIS > public: > nsXBLDocGlobalObject(); > > // nsISupports interface > NS_DECL_ISUPPORTS > > // nsIScriptGlobalObject methods > virtual void SetContext(nsIScriptContext *aContext); > virtual nsIScriptContext *GetContext(); > virtual nsresult SetNewDocument(nsIDOMDocument *aDocument, >+ nsISupports *aState, > PRBool aRemoveEventListeners, > PRBool aClearScope); > virtual void SetDocShell(nsIDocShell *aDocShell); > virtual nsIDocShell *GetDocShell(); > virtual void SetOpenerWindow(nsIDOMWindowInternal *aOpener); > virtual void SetGlobalObjectOwner(nsIScriptGlobalObjectOwner* aOwner); > virtual nsIScriptGlobalObjectOwner *GetGlobalObjectOwner(); > virtual nsresult HandleDOMEvent(nsPresContext* aPresContext, > nsEvent* aEvent, > nsIDOMEvent** aDOMEvent, >@@ -213,20 +214,21 @@ nsXBLDocGlobalObject::GetContext() > ::JS_SetPrivate(cx, mJSObject, this); > NS_ADDREF(this); > } > > return mScriptContext; > } > > > nsresult > nsXBLDocGlobalObject::SetNewDocument(nsIDOMDocument *aDocument, >+ nsISupports *aState, > PRBool aRemoveEventListeners, > PRBool aClearScope) > { > NS_NOTREACHED("waaah!"); > return NS_ERROR_UNEXPECTED; > } > > > void > nsXBLDocGlobalObject::SetDocShell(nsIDocShell *aDocShell) >Index: content/xul/document/src/nsXULPrototypeDocument.cpp >=================================================================== >RCS file: /cvsroot/mozilla/content/xul/document/src/nsXULPrototypeDocument.cpp,v >retrieving revision 1.66 >diff -p -U10 -r1.66 nsXULPrototypeDocument.cpp >--- content/xul/document/src/nsXULPrototypeDocument.cpp 13 Aug 2005 03:54:29 -0000 1.66 >+++ content/xul/document/src/nsXULPrototypeDocument.cpp 13 Aug 2005 23:14:44 -0000 >@@ -82,20 +82,21 @@ class nsXULPDGlobalObject : public nsISc > public: > nsXULPDGlobalObject(); > > // nsISupports interface > NS_DECL_ISUPPORTS > > // nsIScriptGlobalObject methods > virtual void SetContext(nsIScriptContext *aContext); > virtual nsIScriptContext *GetContext(); > virtual nsresult SetNewDocument(nsIDOMDocument *aDocument, >+ nsISupports *aState, > PRBool aRemoveEventListeners, > PRBool aClearScope); > virtual void SetDocShell(nsIDocShell *aDocShell); > virtual nsIDocShell *GetDocShell(); > virtual void SetOpenerWindow(nsIDOMWindowInternal *aOpener); > virtual void SetGlobalObjectOwner(nsIScriptGlobalObjectOwner* aOwner); > virtual nsIScriptGlobalObjectOwner *GetGlobalObjectOwner(); > virtual nsresult HandleDOMEvent(nsPresContext* aPresContext, > nsEvent* aEvent, > nsIDOMEvent** aDOMEvent, >@@ -839,20 +840,21 @@ nsXULPDGlobalObject::GetContext() > ::JS_SetPrivate(cx, mJSObject, this); > NS_ADDREF(this); > } > > return mScriptContext; > } > > > nsresult > nsXULPDGlobalObject::SetNewDocument(nsIDOMDocument *aDocument, >+ nsISupports *aState, > PRBool aRemoveEventListeners, > PRBool aClearScope) > { > NS_NOTREACHED("waaah!"); > return NS_ERROR_UNEXPECTED; > } > > > void > nsXULPDGlobalObject::SetDocShell(nsIDocShell *aDocShell) >Index: docshell/base/nsDocShell.cpp >=================================================================== >RCS file: /cvsroot/mozilla/docshell/base/nsDocShell.cpp,v >retrieving revision 1.721 >diff -p -U10 -r1.721 nsDocShell.cpp >--- docshell/base/nsDocShell.cpp 13 Aug 2005 03:54:29 -0000 1.721 >+++ docshell/base/nsDocShell.cpp 13 Aug 2005 23:14:47 -0000 >@@ -5220,22 +5220,28 @@ nsDocShell::RestoreFromHistory() > // Destroy() is called. > > if (mContentViewer) { > mContentViewer->Close(mSavingOldViewer ? mOSHE.get() : nsnull); > mContentViewer->Destroy(); > } > > 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<nsISupports> windowState; >+ mLSHE->GetWindowState(getter_AddRefs(windowState)); >+ >+ mLSHE->SetWindowState(nsnull); >+ > // Reattach to the window object. >- rv = mContentViewer->Open(); >+ rv = mContentViewer->Open(windowState); > > // Now remove it from the cached presentation. > mLSHE->SetContentViewer(nsnull); > mEODForCurrentDocument = PR_FALSE; > > // Restore the sticky state of the viewer. The viewer has set this state > // on the history entry in Destroy() just before marking itself non-sticky, > // to avoid teardown of the presentation. > PRBool sticky; > mLSHE->GetSticky(&sticky); >@@ -5268,28 +5274,23 @@ nsDocShell::RestoreFromHistory() > document->GetChannel(), PR_TRUE); > } > > // This is the end of our CreateContentViewer() replacement. > // Now we simulate a load. First, we restore the state of the javascript > // window object. > nsCOMPtr<nsPIDOMWindow> privWin = > do_GetInterface(NS_STATIC_CAST(nsIInterfaceRequestor*, this)); > NS_ASSERTION(privWin, "could not get nsPIDOMWindow interface"); > >- nsCOMPtr<nsISupports> 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 > // <head> is parsed. > nsCOMPtr<nsIDOMNSDocument> nsDoc = do_QueryInterface(document); > if (nsDoc) { > const nsAFlatString &title = document->GetDocumentTitle(); > nsDoc->SetTitle(title); > } > > // Now we simulate appending child docshells for subframes. > PRInt32 i = 0; >Index: docshell/base/nsIContentViewer.idl >=================================================================== >RCS file: /cvsroot/mozilla/docshell/base/nsIContentViewer.idl,v >retrieving revision 1.19 >diff -p -U10 -r1.19 nsIContentViewer.idl >--- docshell/base/nsIContentViewer.idl 13 Aug 2005 03:54:29 -0000 1.19 >+++ docshell/base/nsIContentViewer.idl 13 Aug 2005 23:14:47 -0000 >@@ -7,21 +7,21 @@ interface nsISHEntry; > %{ C++ > class nsIWidget; > class nsIDeviceContext; > struct nsRect; > %} > > [ptr] native nsIWidgetPtr(nsIWidget); > [ptr] native nsIDeviceContextPtr(nsIDeviceContext); > [ref] native nsRectRef(nsRect); > >-[scriptable, uuid(62d0e866-e608-4b1a-9ab0-467142b3e3bd)] >+[scriptable, uuid(6a7ddb40-8a9e-4576-8ad1-71c5641d8780)] > interface nsIContentViewer : nsISupports > { > > [noscript] void init(in nsIWidgetPtr aParentWidget, > in nsIDeviceContextPtr aDeviceContext, > [const] in nsRectRef aBounds); > > attribute nsISupports container; > > void loadStart(in nsISupports aDoc); >@@ -78,19 +78,21 @@ interface nsIContentViewer : nsISupports > /* > * This is called when the DOM window wants to be closed. Returns true > * if the window can close immediately. Otherwise, returns false and will > * close the DOM window as soon as practical. > */ > > boolean requestWindowClose(); > > /** > * 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(); >+ void open(in nsISupports aState); > > /** > * Clears the current history entry. This is used if we need to clear out > * the saved presentation state. > */ > void clearHistoryEntry(); > }; >Index: dom/public/nsIScriptGlobalObject.h >=================================================================== >RCS file: /cvsroot/mozilla/dom/public/nsIScriptGlobalObject.h,v >retrieving revision 3.28 >diff -p -U10 -r3.28 nsIScriptGlobalObject.h >--- dom/public/nsIScriptGlobalObject.h 13 Aug 2005 03:54:29 -0000 3.28 >+++ dom/public/nsIScriptGlobalObject.h 13 Aug 2005 23:14:47 -0000 >@@ -1,11 +1,12 @@ > /* -*- 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 > * > * The contents of this file are subject to the Mozilla Public License Version > * 1.1 (the "License"); you may not use this file except in compliance with > * the License. You may obtain a copy of the License at > * http://www.mozilla.org/MPL/ > * > * Software distributed under the License is distributed on an "AS IS" basis, > * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License >@@ -44,36 +45,37 @@ > class nsIScriptContext; > class nsIDOMDocument; > class nsIDOMEvent; > class nsPresContext; > class nsIDocShell; > class nsIDOMWindowInternal; > class nsIScriptGlobalObjectOwner; > struct JSObject; > > #define NS_ISCRIPTGLOBALOBJECT_IID \ >-{ 0x2b16fc80, 0xfa41, 0x11d1, \ >-{ 0x9b, 0xc3, 0x00, 0x60, 0x08, 0x8c, 0xa6, 0xb3} } >+{ 0xd4ddb2f8, 0x385f, 0x4baa, \ >+ { 0xba, 0x69, 0x6c, 0x42, 0xb3, 0xc2, 0xd0, 0xd0 } } > > /** > * The JavaScript specific global object. This often used to store > * per-window global state. > */ > > class nsIScriptGlobalObject : public nsISupports > { > public: > NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISCRIPTGLOBALOBJECT_IID) > > 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; > virtual nsIDocShell *GetDocShell() = 0; > virtual void SetOpenerWindow(nsIDOMWindowInternal *aOpener)=0; > > /** > * Let the script global object know who its owner is. > * The script global object should not addref the owner. It > * will be told when the owner goes away. >Index: dom/src/base/nsGlobalWindow.cpp >=================================================================== >RCS file: /cvsroot/mozilla/dom/src/base/nsGlobalWindow.cpp,v >retrieving revision 1.763 >diff -p -U10 -r1.763 nsGlobalWindow.cpp >--- dom/src/base/nsGlobalWindow.cpp 13 Aug 2005 03:54:29 -0000 1.763 >+++ dom/src/base/nsGlobalWindow.cpp 13 Aug 2005 23:14:50 -0000 >@@ -1,11 +1,12 @@ > /* -*- 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 > * > * The contents of this file are subject to the Mozilla Public License Version > * 1.1 (the "License"); you may not use this file except in compliance with > * the License. You may obtain a copy of the License at > * http://www.mozilla.org/MPL/ > * > * Software distributed under the License is distributed on an "AS IS" basis, > * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License >@@ -265,28 +266,29 @@ static const char kPkcs11ContractID[] = > //*** nsGlobalWindow: Object Management > //***************************************************************************** > > nsGlobalWindow::nsGlobalWindow(nsGlobalWindow *aOuterWindow) > : nsPIDOMWindow(aOuterWindow), > mFullScreen(PR_FALSE), > mIsClosed(PR_FALSE), > 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), >- mGlobalObjectOwner(nsnull), >- mDocShell(nsnull) >+ mIsFrozen(PR_FALSE), >+ mJSObject(nsnull) > { > // Initialize the PRCList (this). > PR_INIT_CLIST(this); > > if (aOuterWindow) { > // |this| is an inner window, add this inner window to the outer > // |window list of inners. > PR_INSERT_AFTER(this, aOuterWindow); > } > >@@ -408,20 +410,62 @@ nsGlobalWindow::ClearControllers() > > nsCOMPtr<nsIControllerContext> context = do_QueryInterface(controller); > if (context) > context->SetCommandContext(nsnull); > } > > mControllers = nsnull; > } > } > >+void >+nsGlobalWindow::FreeInnerObjects(JSContext *cx) >+{ >+ NS_ASSERTION(IsInnerWindow(), "Don't free inner objects on an outer window"); >+ >+ ClearAllTimeouts(); >+ >+ mChromeEventHandler = nsnull; >+ >+ if (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... >+ mLocation->SetDocShell(nsnull); >+ } >+ >+ if (mListenerManager) { >+ mListenerManager->RemoveAllListeners(PR_FALSE); >+ mListenerManager = nsnull; >+ } >+ >+ if (mDocument) { >+ nsCOMPtr<nsIDocument> doc = >+ do_QueryInterface(mDocument); >+ >+ // Remember the document's principal. >+ mDocumentPrincipal = doc->GetPrincipal(); >+ } >+ >+ // Remove our reference to the document and the document principal. >+ mDocument = nsnull; >+ >+ if (mJSObject && cx) { >+ ::JS_ClearScope(cx, mJSObject); >+ ::JS_ClearWatchPointsForObject(cx, mJSObject); >+ >+ nsWindowSH::InvalidateGlobalScopePolluter(cx, mJSObject); >+ } >+} >+ > //***************************************************************************** > // nsGlobalWindow::nsISupports > //***************************************************************************** > > > // QueryInterface implementation for nsGlobalWindow > NS_INTERFACE_MAP_BEGIN(nsGlobalWindow) > // Make sure this matches the cast in nsGlobalWindow::FromWrapper() > NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIScriptGlobalObject) > NS_INTERFACE_MAP_ENTRY(nsIDOMWindowInternal) >@@ -530,44 +574,153 @@ nsGlobalWindow::PopPopupControlState(Pop > { > ::PopPopupControlState(aState); > } > > PopupControlState > 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<nsIXPConnectJSObjectHolder> mInnerWindowHolder; >+ nsRefPtr<nsNavigator> mNavigator; >+ nsCOMPtr<nsIDOMElement> mFocusedElement; >+ nsCOMPtr<nsIDOMWindowInternal> 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<nsIDOMWindowInternal> focusWinInternal; >+ fc->GetFocusedWindow(getter_AddRefs(focusWinInternal)); >+ >+ nsCOMPtr<nsPIDOMWindow> 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() >+{ >+ if (mInnerWindow) { >+ // This window was left in the bfcache and is now going away. We need to >+ // free it up. >+ nsCOMPtr<nsIThreadJSContextStack> stack(do_GetService(sJSStackContractID)); >+ JSContext *cx = nsnull; >+ >+ if (stack) >+ stack->GetSafeJSContext(&cx); >+ >+ if (!cx) { >+ NS_WARNING("Trusting GC to finish cleaning up this inner window"); >+ return; >+ } >+ >+ mInnerWindow->FreeInnerObjects(cx); >+ } >+} >+ >+NS_IMPL_ISUPPORTS1(WindowStateHolder, WindowStateHolder) >+ > nsresult > nsGlobalWindow::SetNewDocument(nsIDOMDocument* aDocument, >+ nsISupports* aState, > PRBool aRemoveEventListeners, > PRBool aClearScopeHint) > { >- return SetNewDocument(aDocument, aRemoveEventListeners, aClearScopeHint, >- PR_FALSE); >+ return SetNewDocument(aDocument, aState, aRemoveEventListeners, >+ aClearScopeHint, PR_FALSE); > } > > nsresult > nsGlobalWindow::SetNewDocument(nsIDOMDocument* aDocument, >+ nsISupports* aState, > PRBool aRemoveEventListeners, > PRBool aClearScopeHint, > PRBool aIsInternalCall) > { > NS_WARN_IF_FALSE(mDocumentPrincipal == nsnull, > "mDocumentPrincipal prematurely set!"); > > if (!aIsInternalCall && IsInnerWindow()) { > if (!mOuterWindow) { > return NS_ERROR_NOT_INITIALIZED; > } > > return GetOuterWindowInternal()->SetNewDocument(aDocument, >+ aState, > aRemoveEventListeners, > aClearScopeHint, PR_TRUE); > } > > if (!aDocument) { > NS_ERROR("SetNewDocument(null) called!"); > > return NS_ERROR_INVALID_ARG; > } > >@@ -742,74 +895,95 @@ nsGlobalWindow::SetNewDocument(nsIDOMDoc > scx->WillInitializeContext(); > } > > if (IsOuterWindow()) { > nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal(); > > // In case we're not removing event listeners, move the event > // listener manager over to the new inner window. > nsCOMPtr<nsIEventListenerManager> listenerManager; > >- if (currentInner) { >+ if (currentInner && !currentInner->IsFrozen()) { > 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) { > currentInner->mListenerManager->RemoveAllListeners(PR_FALSE); > currentInner->mListenerManager = nsnull; > } else { > listenerManager = currentInner->mListenerManager; > } > > nsWindowSH::InvalidateGlobalScopePolluter(cx, currentInner->mJSObject); > } > > nsRefPtr<nsGlobalWindow> newInnerWindow; > > nsCOMPtr<nsIDOMChromeWindow> thisChrome = > do_QueryInterface(NS_STATIC_CAST(nsIDOMWindow *, this)); > nsCOMPtr<nsIXPConnectJSObjectHolder> navigatorHolder; > > PRUint32 flags = 0; > >- if (reUseInnerWindow) { >+ if (reUseInnerWindow && !currentInner->IsFrozen()) { > // We're reusing the current inner window. > newInnerWindow = currentInner; > } else { >- if (thisChrome) { >- newInnerWindow = new nsGlobalChromeWindow(this); >- >- flags = nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT; >+ if (aState) { >+ nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState); >+ NS_ASSERTION(wsh, "What kind of weird state are you giving me here?"); >+ >+ newInnerWindow = wsh->GetInnerWindow(); >+ mInnerWindowHolder = wsh->GetInnerWindowHolder(); >+ mNavigator = wsh->GetNavigator(); // This assignment addrefs. > } else { >- newInnerWindow = new nsGlobalWindow(this); >+ if (thisChrome) { >+ newInnerWindow = new nsGlobalChromeWindow(this); >+ >+ flags = nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT; >+ } else { >+ newInnerWindow = new nsGlobalWindow(this); >+ } > } > > if (!newInnerWindow) { > return NS_ERROR_OUT_OF_MEMORY; > } > >- nsIScriptGlobalObject *sgo = >- (nsIScriptGlobalObject *)newInnerWindow.get(); >- >- nsresult rv = xpc-> >- InitClassesWithNewWrappedGlobal(cx, sgo, NS_GET_IID(nsISupports), >- flags, >- getter_AddRefs(mInnerWindowHolder)); >- NS_ENSURE_SUCCESS(rv, rv); >+ if (!aState) { >+ // This is redundant if we're restoring from a previous inner window. >+ nsIScriptGlobalObject *sgo = >+ (nsIScriptGlobalObject *)newInnerWindow.get(); >+ >+ 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) { >+ 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 = > NS_STATIC_CAST(nsIDOMNavigator*, mNavigator.get()); > xpc->WrapNative(cx, currentInner->mJSObject, navigator, > NS_GET_IID(nsIDOMNavigator), > getter_AddRefs(navigatorHolder)); >@@ -821,109 +995,119 @@ nsGlobalWindow::SetNewDocument(nsIDOMDoc > nsCOMPtr<nsIJSContextStack> stack = > do_GetService(sJSStackContractID); > > JSContext *cx = nsnull; > > if (stack) { > stack->Peek(&cx); > } > > nsIScriptContext *callerScx; >- if (cx && (callerScx = GetScriptContextFromJSContext(cx))) { >+ if (cx && (callerScx = GetScriptContextFromJSContext(cx)) && >+ !currentInner->IsFrozen()) { > // 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. > callerScx->SetTerminationFunction(ClearWindowScope, > NS_STATIC_CAST(nsIDOMWindow *, > currentInner)); > > termFuncSet = PR_TRUE; > } > } > > // 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); > >- if (!termFuncSet) { >- ::JS_ClearScope(cx, currentInner->mJSObject); >- ::JS_ClearWatchPointsForObject(cx, currentInner->mJSObject); >- ::JS_ClearRegExpStatics(cx); >- } >+ // 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; >+ // 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; > > // InitClassesWithNewWrappedGlobal() sets the global object in > // cx to be the new wrapped global. We don't want that, so set > // it back to our own JS object. > > ::JS_SetGlobalObject(cx, mJSObject); > >- if (newDoc != oldDoc) { >+ if (newDoc != oldDoc && !aState) { > nsCOMPtr<nsIHTMLDocument> html_doc(do_QueryInterface(mDocument)); > nsWindowSH::InstallGlobalScopePolluter(cx, newInnerWindow->mJSObject, > html_doc); > } >+ >+ newInnerWindow->mListenerManager = listenerManager; > } > > if (newDoc) { > newDoc->SetScriptGlobalObject(newInnerWindow); > } > >- 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); >- >- 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); >+ if (!aState) { >+ if (reUseInnerWindow) { >+ newInnerWindow->mDocument = aDocument; >+ } else { >+ rv = newInnerWindow->SetNewDocument(aDocument, nsnull, >+ 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); >+ >+ 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); >+ } > } > >- newInnerWindow->mListenerManager = listenerManager; >- } >+ if (mArguments) { >+ jsval args = OBJECT_TO_JSVAL(mArguments); > >- if (mArguments) { >- jsval args = OBJECT_TO_JSVAL(mArguments); >+ ::JS_SetProperty(cx, newInnerWindow->mJSObject, "arguments", >+ &args); > >- ::JS_SetProperty(cx, newInnerWindow->mJSObject, "arguments", >- &args); >+ ::JS_UnlockGCThing(cx, mArguments); >+ mArguments = nsnull; >+ } > >- ::JS_UnlockGCThing(cx, mArguments); >- mArguments = nsnull; >+ // Give the new inner window our chrome event handler (since it >+ // doesn't have one). >+ newInnerWindow->mChromeEventHandler = mChromeEventHandler; > } >- >- // Give the new inner window our chrome event handler (since it >- // doesn't have one). >- newInnerWindow->mChromeEventHandler = mChromeEventHandler; > } > > if (scx && IsOuterWindow()) { > // Add an extra ref in case we release mContext during GC. > nsCOMPtr<nsIScriptContext> kungFuDeathGrip = scx; > scx->GC(); > > scx->DidInitializeContext(); > } > >@@ -944,54 +1128,24 @@ nsGlobalWindow::SetDocShell(nsIDocShell* > // SetDocShell(nsnull) means the window is being torn down. Drop our > // reference to the script context, allowing it to be deleted > // later. Meanwhile, keep our weak reference to the script object > // (mJSObject) so that it can be retrieved later (until it is > // finalized by the JS GC). > > if (!aDocShell && mContext) { > NS_ASSERTION(!mTimeouts, "Uh, outer window holds timeouts!"); > > JSContext *cx = (JSContext *)mContext->GetNativeContext(); >- > nsGlobalWindow *currentInner = GetCurrentInnerWindowInternal(); >- if (currentInner) { >- currentInner->ClearAllTimeouts(); >- >- if (currentInner->mListenerManager) { >- currentInner->mListenerManager->RemoveAllListeners(PR_FALSE); >- 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. >- if (currentInner->mJSObject) { >- ::JS_ClearScope(cx, currentInner->mJSObject); >- ::JS_ClearWatchPointsForObject(cx, currentInner->mJSObject); >- >- if (currentInner->mDocument) { >- nsCOMPtr<nsIDocument> doc = >- do_QueryInterface(currentInner->mDocument); > >- // Remember the document's principal. >- currentInner->mDocumentPrincipal = doc->GetPrincipal(); >- } >- >- // Release the current inner window's document reference >- // through the global scope polluter. >- nsWindowSH::InvalidateGlobalScopePolluter(cx, currentInner->mJSObject); >- } >- >- // Release the current inner window's document references. >- currentInner->mDocument = nsnull; >+ if (currentInner) { >+ currentInner->FreeInnerObjects(cx); > > nsCOMPtr<nsIDocument> doc = > do_QueryInterface(mDocument); > > // Remember the document's principal. > mDocumentPrincipal = doc->GetPrincipal(); > > // Release our document reference > mDocument = nsnull; > >@@ -999,22 +1153,20 @@ nsGlobalWindow::SetDocShell(nsIDocShell* > ::JS_ClearScope(cx, mJSObject); > ::JS_ClearWatchPointsForObject(cx, mJSObject); > > // An outer window shouldn't have a global scope polluter, but > // in case code on a webpage took one and put it in an outer > // object's prototype, we need to invalidate it nonetheless. > nsWindowSH::InvalidateGlobalScopePolluter(cx, mJSObject); > } > > ::JS_ClearRegExpStatics(cx); >- >- currentInner->mChromeEventHandler = nsnull; > } > > // if we are closing the window while in full screen mode, be sure > // to restore os chrome > if (mFullScreen) { > nsIFocusController *focusController = > nsGlobalWindow::GetRootFocusController(); > PRBool isActive = PR_FALSE; > focusController->GetActive(&isActive); > // only restore OS chrome if the closing window was active >@@ -1044,22 +1196,22 @@ nsGlobalWindow::SetDocShell(nsIDocShell* > mContext->GC(); > > if (mContext) { > mContext->SetOwner(nsnull); > mContext = nsnull; // force release now > } > } > > mDocShell = aDocShell; // Weak Reference > >- if (mLocation) >- mLocation->SetDocShell(aDocShell); >+ NS_ASSERTION(!mLocation, "Uh, outer window has location object!"); >+ > if (mNavigator) > mNavigator->SetDocShell(aDocShell); > if (mHistory) > mHistory->SetDocShell(aDocShell); > if (mFrames) > mFrames->SetDocShell(aDocShell); > if (mScreen) > mScreen->SetDocShell(aDocShell); > > if (mDocShell) { >@@ -4911,26 +5063,26 @@ nsGlobalWindow::GetPrivateRoot() > } > > return NS_STATIC_CAST(nsGlobalWindow *, > NS_STATIC_CAST(nsIDOMWindow *, parent)); > } > > > NS_IMETHODIMP > nsGlobalWindow::GetLocation(nsIDOMLocation ** aLocation) > { >- FORWARD_TO_OUTER(GetLocation, (aLocation), NS_ERROR_NOT_INITIALIZED); >+ FORWARD_TO_INNER(GetLocation, (aLocation), NS_ERROR_NOT_INITIALIZED); > > *aLocation = nsnull; > >- if (!mLocation && mDocShell) { >- mLocation = new nsLocation(mDocShell); >+ if (!mLocation && GetDocShellInternal()) { >+ mLocation = new nsLocation(GetDocShellInternal()); > if (!mLocation) { > return NS_ERROR_OUT_OF_MEMORY; > } > } > > NS_IF_ADDREF(*aLocation = mLocation); > > return NS_OK; > } > >@@ -6434,317 +6586,97 @@ nsGlobalWindow::EnsureSizeUpToDate() > // If we're a subframe, make sure our size is up to date. It's OK that this > // crosses the content/chrome boundary, since chrome can have pending reflows > // too. > nsGlobalWindow *parent = > NS_STATIC_CAST(nsGlobalWindow *, GetPrivateParent()); > if (parent) { > parent->FlushPendingNotifications(Flush_Layout); > } > } > >-#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<nsIEventListenerManager> mListenerManager; >- nsCOMPtr<nsIDOMElement> mFocusedElement; >- nsCOMPtr<nsIDOMWindowInternal> 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<nsIDOMWindowInternal> focusWinInternal; >- fc->GetFocusedWindow(getter_AddRefs(focusWinInternal)); >- >- nsCOMPtr<nsPIDOMWindow> 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 (IsOuterWindow() && (!mContext || !mJSObject)) { >+ if (!mContext || !mJSObject) { > // The window may be getting torn down; don't bother saving state. > return NS_OK; > } > >- FORWARD_TO_INNER(SaveWindowState, (aState), NS_ERROR_NOT_INITIALIZED); >- >- 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); >+ nsGlobalWindow *inner = GetCurrentInnerWindowInternal(); >+ NS_ASSERTION(inner, "No inner window to save"); > >- // The window state object will root the JSObject. >- nsCOMPtr<nsISupports> state = new WindowStateHolder(cx, stateObj, this); >+ nsCOMPtr<nsISupports> state = new WindowStateHolder(inner, >+ mInnerWindowHolder, >+ mNavigator); > NS_ENSURE_TRUE(state, NS_ERROR_OUT_OF_MEMORY); > > #ifdef DEBUG_PAGE_CACHE > printf("saving window state, stateObj = %p\n", (void*)stateObj); > #endif >- nsresult rv = CopyJSProperties(cx, mJSObject, stateObj); >- NS_ENSURE_SUCCESS(rv, rv); >+ >+ if (inner->mLocation) { >+ // Invalidate the inner window's location object now that the inner window >+ // is being put into 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. The docshell is restored when the window is >+ // taken out of the bfcache (meaning that any stale references to it will >+ // only see that particular document). >+ inner->mLocation->SetDocShell(nsnull); >+ } >+ >+ // Don't do anything else to this inner window! >+ inner->Freeze(); > > state.swap(*aState); > return NS_OK; > } > > nsresult > nsGlobalWindow::RestoreWindowState(nsISupports *aState) > { >- // SetNewDocument() has already been called so we should have a >- // new clean inner window to restore state into here. >+ NS_ASSERTION(IsOuterWindow(), "Cannot restore an inner window"); > >- if (IsOuterWindow() && (!mContext || !mJSObject)) { >+ if (!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<WindowStateHolder> 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); > >- mListenerManager = holder->GetListenerManager(); >- mMutationBits = holder->GetMutationBits(); >+ nsGlobalWindow *inner = GetCurrentInnerWindowInternal(); > > nsIDOMElement *focusedElement = holder->GetFocusedElement(); > nsIDOMWindowInternal *focusedWindow = holder->GetFocusedWindow(); > > // If the toplevel window isn't focused, just update the focus controller. > nsIFocusController *fc = nsGlobalWindow::GetRootFocusController(); > NS_ENSURE_TRUE(fc, NS_ERROR_UNEXPECTED); > > PRBool active; > fc->GetActive(&active); > if (active) { > PRBool didFocusContent = PR_FALSE; > nsCOMPtr<nsIContent> focusedContent = do_QueryInterface(focusedElement); > > if (focusedContent) { > // 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); > if (shell) { > nsPresContext *pc = shell->GetPresContext(); > if (pc) { > pc->EventStateManager()->SetContentState(focusedContent, > NS_EVENT_STATE_FOCUS); > didFocusContent = PR_TRUE; > } >@@ -6753,30 +6685,29 @@ nsGlobalWindow::RestoreWindowState(nsISu > } > > if (!didFocusContent && focusedWindow) > focusedWindow->Focus(); > } else if (focusedWindow) { > // Just update the saved focus memory. > fc->SetFocusedWindow(focusedWindow); > fc->SetFocusedElement(focusedElement); > } > >- mTimeouts = holder->GetSavedTimeouts(); >- mTimeoutInsertionPoint = holder->GetTimeoutInsertionPoint(); >+ // And we're ready to go! >+ inner->Thaw(); > >- holder->ClearSavedTimeouts(); >+ if (inner->mLocation) >+ inner->mLocation->SetDocShell(mDocShell); > >- // 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; >+ holder->DidRestoreWindow(); > >- return ResumeTimeouts(); >+ return inner->ResumeTimeouts(); > } > > void > nsGlobalWindow::SuspendTimeouts() > { > FORWARD_TO_INNER_VOID(SuspendTimeouts, ()); > > nsInt64 now = PR_IntervalNow(); > for (nsTimeout *t = mTimeouts; t; t = t->mNext) { > // Change mWhen to be the time remaining for this timer. >Index: dom/src/base/nsGlobalWindow.h >=================================================================== >RCS file: /cvsroot/mozilla/dom/src/base/nsGlobalWindow.h,v >retrieving revision 1.252 >diff -p -U10 -r1.252 nsGlobalWindow.h >--- dom/src/base/nsGlobalWindow.h 13 Aug 2005 03:54:29 -0000 1.252 >+++ dom/src/base/nsGlobalWindow.h 13 Aug 2005 23:14:50 -0000 >@@ -1,11 +1,12 @@ > /* -*- 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 > * > * The contents of this file are subject to the Mozilla Public License Version > * 1.1 (the "License"); you may not use this file except in compliance with > * the License. You may obtain a copy of the License at > * http://www.mozilla.org/MPL/ > * > * Software distributed under the License is distributed on an "AS IS" basis, > * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License >@@ -146,20 +147,21 @@ public: > // callback for close event > void ReallyCloseWindow(); > > // nsISupports > NS_DECL_ISUPPORTS > > // nsIScriptGlobalObject > virtual void SetContext(nsIScriptContext *aContext); > virtual nsIScriptContext *GetContext(); > virtual nsresult SetNewDocument(nsIDOMDocument *aDocument, >+ nsISupports *aState, > PRBool aRemoveEventListeners, > PRBool aClearScopeHint); > virtual void SetDocShell(nsIDocShell* aDocShell); > virtual nsIDocShell *GetDocShell(); > virtual void SetOpenerWindow(nsIDOMWindowInternal *aOpener); > virtual void SetGlobalObjectOwner(nsIScriptGlobalObjectOwner* aOwner); > virtual nsIScriptGlobalObjectOwner *GetGlobalObjectOwner(); > virtual nsresult HandleDOMEvent(nsPresContext* aPresContext, > nsEvent* aEvent, nsIDOMEvent** aDOMEvent, > PRUint32 aFlags, >@@ -270,21 +272,24 @@ public: > static PRBool IsCallerChrome(); > > friend class WindowStateHolder; > > protected: > // Object Management > virtual ~nsGlobalWindow(); > void CleanUp(); > void ClearControllers(); > >+ void FreeInnerObjects(JSContext *cx); >+ > nsresult SetNewDocument(nsIDOMDocument *aDocument, >+ nsISupports *aState, > PRBool aRemoveEventListeners, > PRBool aClearScopeHint, > PRBool aIsInternalCall); > > // Get the parent, returns null if this is a toplevel window > nsIDOMWindowInternal *GetParentInternal(); > > // popup tracking > PRBool IsPopupSpamWindow() > { >@@ -375,20 +380,39 @@ protected: > > PRBool DispatchCustomEvent(const char *aEventName); > > PRBool WindowExists(const nsAString& aName); > > already_AddRefed<nsIWidget> GetMainWidget(); > > 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 > // objects will keep the global object (this object) alive. To prevent > // these cycles, ownership of such members must be released in > // |CleanUp| and |SetDocShell|. > > // These members are only used on outer window objects. Make sure > // you never set any of these on an inner object! > PRPackedBool mFullScreen; >@@ -398,21 +422,20 @@ protected: > PRPackedBool mIsPopupSpam; > > nsCOMPtr<nsIScriptContext> mContext; > nsCOMPtr<nsIDOMWindowInternal> mOpener; > nsCOMPtr<nsIControllers> mControllers; > JSObject* mArguments; > nsRefPtr<nsNavigator> mNavigator; > nsRefPtr<nsScreen> mScreen; > nsRefPtr<nsHistory> mHistory; > nsRefPtr<nsDOMWindowList> mFrames; >- nsRefPtr<nsLocation> mLocation; > nsRefPtr<nsBarProp> mMenubar; > nsRefPtr<nsBarProp> mToolbar; > nsRefPtr<nsBarProp> mLocationbar; > nsRefPtr<nsBarProp> mPersonalbar; > nsRefPtr<nsBarProp> mStatusbar; > nsRefPtr<nsBarProp> mScrollbars; > nsCOMPtr<nsIWeakReference> mWindowUtils; > nsString mStatus; > nsString mDefaultStatus; > >@@ -422,20 +445,22 @@ protected: > nsCOMPtr<nsIDOMPkcs11> mPkcs11; > > nsCOMPtr<nsIXPConnectJSObjectHolder> mInnerWindowHolder; > > // These member variable are used only on inner windows. > nsCOMPtr<nsIEventListenerManager> mListenerManager; > nsTimeout* mTimeouts; > nsTimeout** mTimeoutInsertionPoint; > PRUint32 mTimeoutPublicIdCounter; > PRUint32 mTimeoutFiringDepth; >+ nsRefPtr<nsLocation> mLocation; >+ PRPackedBool mIsFrozen; > > // These member variables are used on both inner and the outer windows. > nsCOMPtr<nsIPrincipal> mDocumentPrincipal; > JSObject* mJSObject; > > friend class nsDOMScriptableHelper; > friend class nsDOMWindowUtils; > static nsIScriptSecurityManager *sSecMan; > static nsIFactory *sComputedDOMStyleFactory; > }; >Index: layout/base/nsDocumentViewer.cpp >=================================================================== >RCS file: /cvsroot/mozilla/layout/base/nsDocumentViewer.cpp,v >retrieving revision 1.444 >diff -p -U10 -r1.444 nsDocumentViewer.cpp >--- layout/base/nsDocumentViewer.cpp 13 Aug 2005 03:54:29 -0000 1.444 >+++ layout/base/nsDocumentViewer.cpp 13 Aug 2005 23:14:57 -0000 >@@ -1,11 +1,12 @@ > /* -*- 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 > * > * The contents of this file are subject to the Mozilla Public License Version > * 1.1 (the "License"); you may not use this file except in compliance with > * the License. You may obtain a copy of the License at > * http://www.mozilla.org/MPL/ > * > * Software distributed under the License is distributed on an "AS IS" basis, > * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License >@@ -347,20 +348,21 @@ public: > // nsIDocumentViewerPrint Printing Methods > NS_DECL_NSIDOCUMENTVIEWERPRINT > > protected: > virtual ~DocumentViewerImpl(); > > private: > nsresult MakeWindow(nsIWidget* aParentWidget, > const nsRect& aBounds); > nsresult InitInternal(nsIWidget* aParentWidget, >+ nsISupports *aState, > nsIDeviceContext* aDeviceContext, > const nsRect& aBounds, > PRBool aDoCreation, > PRBool aInPrintPreview); > nsresult InitPresentationStuff(PRBool aDoInitialReflow); > > nsresult GetPopupNode(nsIDOMNode** aNode); > nsresult GetPopupLinkNode(nsIDOMNode** aNode); > nsresult GetPopupImageNode(nsIImageLoadingContent** aNode); > >@@ -620,21 +622,21 @@ DocumentViewerImpl::GetContainer(nsISupp > nsCOMPtr<nsISupports> container = do_QueryReferent(mContainer); > container.swap(*aResult); > return NS_OK; > } > > NS_IMETHODIMP > DocumentViewerImpl::Init(nsIWidget* aParentWidget, > nsIDeviceContext* aDeviceContext, > const nsRect& aBounds) > { >- return InitInternal(aParentWidget, aDeviceContext, aBounds, PR_TRUE, PR_FALSE); >+ return InitInternal(aParentWidget, nsnull, aDeviceContext, aBounds, PR_TRUE, PR_FALSE); > } > > nsresult > DocumentViewerImpl::InitPresentationStuff(PRBool aDoInitialReflow) > { > // Create the style set... > nsStyleSet *styleSet; > nsresult rv = CreateStyleSet(mDocument, &styleSet); > NS_ENSURE_SUCCESS(rv, rv); > >@@ -758,20 +760,21 @@ DocumentViewerImpl::InitPresentationStuf > > return NS_OK; > } > > //----------------------------------------------- > // This method can be used to initial the "presentation" > // The aDoCreation indicates whether it should create > // all the new objects or just initialize the existing ones > nsresult > DocumentViewerImpl::InitInternal(nsIWidget* aParentWidget, >+ nsISupports *aState, > nsIDeviceContext* aDeviceContext, > const nsRect& aBounds, > PRBool aDoCreation, > PRBool aInPrintPreview) > { > mParentWidget = aParentWidget; // not ref counted > > nsresult rv = NS_OK; > NS_ENSURE_TRUE(mDocument, NS_ERROR_NULL_POINTER); > >@@ -836,21 +839,21 @@ DocumentViewerImpl::InitInternal(nsIWidg > // Set script-context-owner in the document > > nsCOMPtr<nsIScriptGlobalObject> global; > requestor->GetInterface(NS_GET_IID(nsIScriptGlobalObject), > getter_AddRefs(global)); > > if (global) { > nsCOMPtr<nsIDOMDocument> domdoc(do_QueryInterface(mDocument)); > > if (domdoc) { >- global->SetNewDocument(domdoc, PR_TRUE, PR_TRUE); >+ global->SetNewDocument(domdoc, aState, PR_TRUE, PR_TRUE); > } > } > } > } > > if (aDoCreation && mPresContext) { > // The ViewManager and Root View was created above (in > // MakeWindow())... > > rv = InitPresentationStuff(!makeCX); >@@ -1196,34 +1199,34 @@ DocumentViewerImpl::PageHide(PRBool aIsU > > // Never permit popups from the unload handler, no matter how we get > // here. > nsAutoPopupStatePusher popupStatePusher(openAbused, PR_TRUE); > > return global->HandleDOMEvent(mPresContext, &event, nsnull, > NS_EVENT_FLAG_INIT, &status); > } > > NS_IMETHODIMP >-DocumentViewerImpl::Open() >+DocumentViewerImpl::Open(nsISupports *aState) > { > NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED); > > // Our container might have gone away while we were closed. > // If this is the case, we must fail to open so we don't crash. > nsCOMPtr<nsISupports> container = do_QueryReferent(mContainer); > if (!container) > return NS_ERROR_NOT_AVAILABLE; > > nsRect bounds; > mWindow->GetBounds(bounds); > >- nsresult rv = InitInternal(mParentWidget, mDeviceContext, bounds, >+ nsresult rv = InitInternal(mParentWidget, aState, mDeviceContext, bounds, > PR_FALSE, PR_FALSE); > NS_ENSURE_SUCCESS(rv, rv); > > if (mDocument) > mDocument->SetContainer(nsCOMPtr<nsISupports>(do_QueryReferent(mContainer))); > > SyncParentSubDocMap(); > > // XXX re-enable image animations once that works correctly > >@@ -1503,21 +1506,21 @@ DocumentViewerImpl::SetDOMDocument(nsIDO > newDoc->SetContainer(container); > > if (mDocument != newDoc) { > // Replace the old document with the new one. Do this only when > // the new document really is a new document. > mDocument = newDoc; > > // Set the script global object on the new document > nsCOMPtr<nsIScriptGlobalObject> global = do_GetInterface(container); > if (global) { >- global->SetNewDocument(aDocument, PR_TRUE, PR_TRUE); >+ global->SetNewDocument(aDocument, nsnull, PR_TRUE, PR_TRUE); > } > } > > rv = SyncParentSubDocMap(); > NS_ENSURE_SUCCESS(rv, rv); > > // Replace the current pres shell with a new shell for the new document > > nsCOMPtr<nsILinkHandler> linkHandler; > if (mPresShell) { >@@ -3929,21 +3932,21 @@ DocumentViewerImpl::ReturnToGalleyPresen > if (mPrintEngine) { > // Very important! Turn On scripting > mPrintEngine->TurnScriptingOn(PR_TRUE); > > if (wasCached) { > mPrintEngine->Destroy(); > NS_RELEASE(mPrintEngine); > } > } > >- InitInternal(mParentWidget, mDeviceContext, bounds, !wasCached, PR_TRUE); >+ InitInternal(mParentWidget, nsnull, mDeviceContext, bounds, !wasCached, PR_TRUE); > > if (mPrintEngine && !wasCached) { > mPrintEngine->Destroy(); > NS_RELEASE(mPrintEngine); > } > > // this needs to be set here not earlier, > // because it is needing when re-constructing the Galley Mode) > SetIsPrintPreview(PR_FALSE); > >Index: layout/base/nsIDocumentViewer.h >=================================================================== >RCS file: /cvsroot/mozilla/layout/base/nsIDocumentViewer.h,v >retrieving revision 1.16 >diff -p -U10 -r1.16 nsIDocumentViewer.h >--- layout/base/nsIDocumentViewer.h 13 Aug 2005 03:54:29 -0000 1.16 >+++ layout/base/nsIDocumentViewer.h 13 Aug 2005 23:14:57 -0000 >@@ -38,21 +38,21 @@ > #define nsIDocumentViewer_h___ > > #include "nsIContentViewer.h" > > class nsIDocument; > class nsPresContext; > class nsIPresShell; > class nsIStyleSheet; > > #define NS_IDOCUMENT_VIEWER_IID \ >- { 0xbd4fde0c, 0x71fd, 0x4d77,{0xab, 0x66, 0x26, 0xce, 0x43, 0x93, 0x2e, 0x4e}} >+ { 0x42ecec88, 0x80d5, 0x48ac,{0x9a, 0xcd, 0x12, 0x51, 0xdc, 0x42, 0x60, 0x4a}} > > /** > * A document viewer is a kind of content viewer that uses NGLayout > * to manage the presentation of the content. > */ > class nsIDocumentViewer : public nsIContentViewer > { > public: > NS_DEFINE_STATIC_IID_ACCESSOR(NS_IDOCUMENT_VIEWER_IID) >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
Flags:
bryner
: review+
jst
: superreview+
asa
: approval1.8b4+
Actions:
View
|
Diff
|
Review
Attachments on
bug 303267
:
191925
|
191999
|
192450
|
192553
| 192640 |
387025
|
387212
|
387671