зеркало из https://github.com/mozilla/gecko-dev.git
bug 303267: Store the entire inner window in the window state holder instead of copying properties and restoring them. This fixes going back and forth with the bfcache on when the page gone to has javascript in it. r=jst sr=bryner
This commit is contained in:
Родитель
981274f805
Коммит
2b7c7bca7a
|
@ -1915,8 +1915,8 @@ nsHTMLDocument::OpenCommon(const nsACString& aContentType, PRBool aReplace)
|
|||
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;
|
||||
|
|
|
@ -67,6 +67,7 @@ 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);
|
||||
|
@ -220,6 +221,7 @@ nsXBLDocGlobalObject::GetContext()
|
|||
|
||||
nsresult
|
||||
nsXBLDocGlobalObject::SetNewDocument(nsIDOMDocument *aDocument,
|
||||
nsISupports *aState,
|
||||
PRBool aRemoveEventListeners,
|
||||
PRBool aClearScope)
|
||||
{
|
||||
|
|
|
@ -89,6 +89,7 @@ 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);
|
||||
|
@ -846,6 +847,7 @@ nsXULPDGlobalObject::GetContext()
|
|||
|
||||
nsresult
|
||||
nsXULPDGlobalObject::SetNewDocument(nsIDOMDocument *aDocument,
|
||||
nsISupports *aState,
|
||||
PRBool aRemoveEventListeners,
|
||||
PRBool aClearScope)
|
||||
{
|
||||
|
|
|
@ -5233,8 +5233,14 @@ 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<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);
|
||||
|
@ -5285,14 +5291,9 @@ nsDocShell::RestoreFromHistory()
|
|||
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);
|
||||
|
|
|
@ -14,7 +14,7 @@ struct nsRect;
|
|||
[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
|
||||
{
|
||||
|
||||
|
@ -85,8 +85,10 @@ 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();
|
||||
void open(in nsISupports aState);
|
||||
|
||||
/**
|
||||
* Clears the current history entry. This is used if we need to clear out
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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
|
||||
*
|
||||
|
@ -51,8 +52,8 @@ 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
|
||||
|
@ -67,6 +68,7 @@ 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;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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
|
||||
*
|
||||
|
@ -272,14 +273,15 @@ 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),
|
||||
mGlobalObjectOwner(nsnull),
|
||||
mDocShell(nsnull)
|
||||
mIsFrozen(PR_FALSE),
|
||||
mJSObject(nsnull)
|
||||
{
|
||||
// Initialize the PRCList (this).
|
||||
PR_INIT_CLIST(this);
|
||||
|
@ -415,6 +417,48 @@ nsGlobalWindow::ClearControllers()
|
|||
}
|
||||
}
|
||||
|
||||
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
|
||||
//*****************************************************************************
|
||||
|
@ -537,17 +581,125 @@ 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)
|
||||
|
@ -561,6 +713,7 @@ nsGlobalWindow::SetNewDocument(nsIDOMDocument* aDocument,
|
|||
}
|
||||
|
||||
return GetOuterWindowInternal()->SetNewDocument(aDocument,
|
||||
aState,
|
||||
aRemoveEventListeners,
|
||||
aClearScopeHint, PR_TRUE);
|
||||
}
|
||||
|
@ -749,11 +902,20 @@ nsGlobalWindow::SetNewDocument(nsIDOMDocument* aDocument,
|
|||
// 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) {
|
||||
|
@ -774,35 +936,47 @@ nsGlobalWindow::SetNewDocument(nsIDOMDocument* aDocument,
|
|||
|
||||
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);
|
||||
if (aState) {
|
||||
nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
|
||||
NS_ASSERTION(wsh, "What kind of weird state are you giving me here?");
|
||||
|
||||
flags = nsIXPConnect::FLAG_SYSTEM_GLOBAL_OBJECT;
|
||||
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();
|
||||
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);
|
||||
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
|
||||
|
@ -828,7 +1002,8 @@ nsGlobalWindow::SetNewDocument(nsIDOMDocument* aDocument,
|
|||
}
|
||||
|
||||
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
|
||||
|
@ -844,21 +1019,27 @@ 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);
|
||||
|
||||
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;
|
||||
|
@ -869,54 +1050,57 @@ nsGlobalWindow::SetNewDocument(nsIDOMDocument* aDocument,
|
|||
|
||||
::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);
|
||||
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);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
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 (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()) {
|
||||
|
@ -951,40 +1135,10 @@ nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell)
|
|||
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;
|
||||
currentInner->FreeInnerObjects(cx);
|
||||
|
||||
nsCOMPtr<nsIDocument> doc =
|
||||
do_QueryInterface(mDocument);
|
||||
|
@ -1006,8 +1160,6 @@ nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell)
|
|||
}
|
||||
|
||||
::JS_ClearRegExpStatics(cx);
|
||||
|
||||
currentInner->mChromeEventHandler = nsnull;
|
||||
}
|
||||
|
||||
// if we are closing the window while in full screen mode, be sure
|
||||
|
@ -1051,8 +1203,8 @@ nsGlobalWindow::SetDocShell(nsIDocShell* aDocShell)
|
|||
|
||||
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)
|
||||
|
@ -4918,12 +5070,12 @@ nsGlobalWindow::GetPrivateRoot()
|
|||
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;
|
||||
}
|
||||
|
@ -6441,247 +6593,42 @@ 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<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);
|
||||
nsGlobalWindow *inner = GetCurrentInnerWindowInternal();
|
||||
NS_ASSERTION(inner, "No inner window to save");
|
||||
|
||||
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<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;
|
||||
|
@ -6690,35 +6637,21 @@ nsGlobalWindow::SaveWindowState(nsISupports **aState)
|
|||
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();
|
||||
|
@ -6737,7 +6670,6 @@ 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);
|
||||
|
@ -6760,16 +6692,15 @@ nsGlobalWindow::RestoreWindowState(nsISupports *aState)
|
|||
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
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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
|
||||
*
|
||||
|
@ -153,6 +154,7 @@ 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);
|
||||
|
@ -277,7 +279,10 @@ protected:
|
|||
void CleanUp();
|
||||
void ClearControllers();
|
||||
|
||||
void FreeInnerObjects(JSContext *cx);
|
||||
|
||||
nsresult SetNewDocument(nsIDOMDocument *aDocument,
|
||||
nsISupports *aState,
|
||||
PRBool aRemoveEventListeners,
|
||||
PRBool aClearScopeHint,
|
||||
PRBool aIsInternalCall);
|
||||
|
@ -382,6 +387,25 @@ 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
|
||||
|
@ -405,7 +429,6 @@ protected:
|
|||
nsRefPtr<nsScreen> mScreen;
|
||||
nsRefPtr<nsHistory> mHistory;
|
||||
nsRefPtr<nsDOMWindowList> mFrames;
|
||||
nsRefPtr<nsLocation> mLocation;
|
||||
nsRefPtr<nsBarProp> mMenubar;
|
||||
nsRefPtr<nsBarProp> mToolbar;
|
||||
nsRefPtr<nsBarProp> mLocationbar;
|
||||
|
@ -429,6 +452,8 @@ protected:
|
|||
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;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- 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
|
||||
*
|
||||
|
@ -354,6 +355,7 @@ private:
|
|||
nsresult MakeWindow(nsIWidget* aParentWidget,
|
||||
const nsRect& aBounds);
|
||||
nsresult InitInternal(nsIWidget* aParentWidget,
|
||||
nsISupports *aState,
|
||||
nsIDeviceContext* aDeviceContext,
|
||||
const nsRect& aBounds,
|
||||
PRBool aDoCreation,
|
||||
|
@ -627,7 +629,7 @@ 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
|
||||
|
@ -765,6 +767,7 @@ 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,
|
||||
|
@ -843,7 +846,7 @@ DocumentViewerImpl::InitInternal(nsIWidget* aParentWidget,
|
|||
nsCOMPtr<nsIDOMDocument> domdoc(do_QueryInterface(mDocument));
|
||||
|
||||
if (domdoc) {
|
||||
global->SetNewDocument(domdoc, PR_TRUE, PR_TRUE);
|
||||
global->SetNewDocument(domdoc, aState, PR_TRUE, PR_TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1203,7 +1206,7 @@ DocumentViewerImpl::PageHide(PRBool aIsUnload)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DocumentViewerImpl::Open()
|
||||
DocumentViewerImpl::Open(nsISupports *aState)
|
||||
{
|
||||
NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED);
|
||||
|
||||
|
@ -1216,7 +1219,7 @@ DocumentViewerImpl::Open()
|
|||
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);
|
||||
|
||||
|
@ -1510,7 +1513,7 @@ DocumentViewerImpl::SetDOMDocument(nsIDOMDocument *aDocument)
|
|||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3931,7 +3934,7 @@ DocumentViewerImpl::ReturnToGalleyPresentation()
|
|||
}
|
||||
}
|
||||
|
||||
InitInternal(mParentWidget, mDeviceContext, bounds, !wasCached, PR_TRUE);
|
||||
InitInternal(mParentWidget, nsnull, mDeviceContext, bounds, !wasCached, PR_TRUE);
|
||||
|
||||
if (mPrintEngine && !wasCached) {
|
||||
mPrintEngine->Destroy();
|
||||
|
|
|
@ -45,7 +45,7 @@ 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
|
||||
|
|
Загрузка…
Ссылка в новой задаче