From 48541412c120b39629abd7fbdcda42492dc0c4f2 Mon Sep 17 00:00:00 2001 From: "bzbarsky@mit.edu" Date: Fri, 5 Oct 2007 17:35:00 -0700 Subject: [PATCH] Fix a few issues in bfcache and XBL when javascript is being toggled on and off. Bug 398668, r+sr+a=jst --- content/xbl/src/nsXBLProtoImplMethod.cpp | 8 +++- docshell/base/nsDocShell.cpp | 48 +++++++++++++++++++++++- docshell/base/nsIContentViewer.idl | 8 +++- layout/base/nsDocumentViewer.cpp | 10 +++++ 4 files changed, 71 insertions(+), 3 deletions(-) diff --git a/content/xbl/src/nsXBLProtoImplMethod.cpp b/content/xbl/src/nsXBLProtoImplMethod.cpp index d18768118319..bc19852fc654 100644 --- a/content/xbl/src/nsXBLProtoImplMethod.cpp +++ b/content/xbl/src/nsXBLProtoImplMethod.cpp @@ -287,7 +287,13 @@ nsXBLProtoImplMethod::Traverse(nsCycleCollectionTraversalCallback &cb) const nsresult nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement) { - NS_PRECONDITION(mIsCompiled, "Can't execute uncompiled method"); + if (!mIsCompiled) { + // Someone might have enabled script between when the binding would have + // been compiled and now. If this is the constructor we shouldn't run it + // because our other scripted stuff is not set up, and if it's the + // destructor then the constructor never ran. In either case, bail out. + return NS_OK; + } if (!mJSMethodObject) { // Nothing to do here diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 0fafce2ba515..15822bb6e5c6 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -5706,9 +5706,33 @@ nsDocShell::RestoreFromHistory() // Now we simulate appending child docshells for subframes. for (i = 0; i < childShells.Count(); ++i) { nsIDocShellTreeItem *childItem = childShells.ObjectAt(i); + nsCOMPtr childShell = do_QueryInterface(childItem); + + // Make sure to not clobber the state of the child. Since AddChild + // always clobbers it, save it off first. + PRBool allowPlugins; + childShell->GetAllowPlugins(&allowPlugins); + + PRBool allowJavascript; + childShell->GetAllowJavascript(&allowJavascript); + + PRBool allowRedirects; + childShell->GetAllowMetaRedirects(&allowRedirects); + + PRBool allowSubframes; + childShell->GetAllowSubframes(&allowSubframes); + + PRBool allowImages; + childShell->GetAllowImages(&allowImages); + AddChild(childItem); - nsCOMPtr childShell = do_QueryInterface(childItem); + childShell->SetAllowPlugins(allowPlugins); + childShell->SetAllowJavascript(allowJavascript); + childShell->SetAllowMetaRedirects(allowRedirects); + childShell->SetAllowSubframes(allowSubframes); + childShell->SetAllowImages(allowImages); + rv = childShell->BeginRestore(nsnull, PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); } @@ -6861,6 +6885,28 @@ nsDocShell::InternalLoad(nsIURI * aURI, // If we have a saved content viewer in history, restore and show it now. if (aSHEntry && (mLoadType & LOAD_CMD_HISTORY)) { + // It's possible that the previous viewer of mContentViewer is the + // viewer that will end up in aSHEntry when it gets closed. If that's + // the case, we need to go ahead and force it into its shentry so we + // can restore it. + if (mContentViewer) { + nsCOMPtr prevViewer; + mContentViewer->GetPreviousViewer(getter_AddRefs(prevViewer)); + if (prevViewer) { +#ifdef DEBUG + nsCOMPtr prevPrevViewer; + prevViewer->GetPreviousViewer(getter_AddRefs(prevPrevViewer)); + NS_ASSERTION(!prevPrevViewer, "Should never have viewer chain here"); +#endif + nsCOMPtr viewerEntry; + prevViewer->GetHistoryEntry(getter_AddRefs(viewerEntry)); + if (viewerEntry == aSHEntry) { + // Make sure this viewer ends up in the right place + mContentViewer->SetPreviousViewer(nsnull); + prevViewer->Destroy(); + } + } + } nsCOMPtr oldEntry = mOSHE; PRBool restoring; rv = RestorePresentation(aSHEntry, &restoring); diff --git a/docshell/base/nsIContentViewer.idl b/docshell/base/nsIContentViewer.idl index 1fe455a31c8f..198e3438d069 100644 --- a/docshell/base/nsIContentViewer.idl +++ b/docshell/base/nsIContentViewer.idl @@ -15,7 +15,7 @@ struct nsRect; [ptr] native nsIDeviceContextPtr(nsIDeviceContext); [ref] native nsRectRef(nsRect); -[scriptable, uuid(1d587109-9df7-4614-9a96-309902269e9e)] +[scriptable, uuid(89653afe-182f-401f-9f3c-8858d91387cd)] interface nsIContentViewer : nsISupports { @@ -105,4 +105,10 @@ interface nsIContentViewer : nsISupports * dynamic and editable (like Galley layout). */ void setPageMode(in PRBool aPageMode, in nsIPrintSettings aPrintSettings); + + /** + * Get the history entry that this viewer will save itself into when + * destroyed. Can return null + */ + readonly attribute nsISHEntry historyEntry; }; diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index f5d57172f307..881d7ecbeb91 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -1727,6 +1727,9 @@ DocumentViewerImpl::SetPreviousViewer(nsIContentViewer* aViewer) // link from the chain. This ensures that at most only 2 documents are alive // and undestroyed at any given time (the one that is showing and the one that // is loading with painting suppressed). + // It's very important that if this ever gets changed the code + // before the RestorePresentation call in nsDocShell::InternalLoad + // be changed accordingly. nsCOMPtr prevViewer; aViewer->GetPreviousViewer(getter_AddRefs(prevViewer)); if (prevViewer) { @@ -4059,3 +4062,10 @@ NS_IMETHODIMP DocumentViewerImpl::SetPageMode(PRBool aPageMode, nsIPrintSettings Show(); return NS_OK; } + +NS_IMETHODIMP +DocumentViewerImpl::GetHistoryEntry(nsISHEntry **aHistoryEntry) +{ + NS_IF_ADDREF(*aHistoryEntry = mSHEntry); + return NS_OK; +}