Index: accessible/src/base/nsAccessNode.cpp =================================================================== RCS file: /cvsroot/mozilla/accessible/src/base/nsAccessNode.cpp,v retrieving revision 1.23 diff -u -p -r1.23 nsAccessNode.cpp --- accessible/src/base/nsAccessNode.cpp 15 Apr 2005 21:22:25 -0000 1.23 +++ accessible/src/base/nsAccessNode.cpp 26 Apr 2005 18:31:39 -0000 @@ -498,7 +498,9 @@ nsAccessNode::GetDocShellTreeItemFor(nsI NS_ASSERTION(doc, "No document for node passed in"); nsCOMPtr container = doc->GetContainer(); nsIDocShellTreeItem *docShellTreeItem = nsnull; - CallQueryInterface(container, &docShellTreeItem); + if (container) { + CallQueryInterface(container, &docShellTreeItem); + } return docShellTreeItem; } Index: browser/app/profile/firefox.js =================================================================== RCS file: /cvsroot/mozilla/browser/app/profile/firefox.js,v retrieving revision 1.43 diff -u -p -r1.43 firefox.js --- browser/app/profile/firefox.js 23 Apr 2005 01:37:00 -0000 1.43 +++ browser/app/profile/firefox.js 26 Apr 2005 18:31:39 -0000 @@ -199,6 +199,7 @@ pref("browser.search.basic.min_ver", "0. pref("browser.history.grouping", "day"); pref("browser.sessionhistory.max_entries", 50); +pref("browser.sessionhistory.max_viewers", 5); // handle external links // 0=default window, 1=current window/tab, 2=new window, 3=new tab in most recent window Index: content/base/public/nsIDocument.h =================================================================== RCS file: /cvsroot/mozilla/content/base/public/nsIDocument.h,v retrieving revision 3.199 diff -u -p -r3.199 nsIDocument.h --- content/base/public/nsIDocument.h 19 Apr 2005 01:27:08 -0000 3.199 +++ content/base/public/nsIDocument.h 26 Apr 2005 18:31:39 -0000 @@ -52,6 +52,7 @@ #include "nsCRT.h" #include "mozFlushType.h" #include "nsPropertyTable.h" +#include "pldhash.h" class nsIAtom; class nsIContent; @@ -88,10 +89,9 @@ class nsHTMLStyleSheet; class nsIHTMLCSSStyleSheet; // IID for the nsIDocument interface -// f01b47c6-6271-4c0d-b786-eb5eee222b45 #define NS_IDOCUMENT_IID \ -{ 0xf01b47c6, 0x6271, 0x4c0d, \ - { 0xb7, 0x86, 0xeb, 0x5e, 0xee, 0x22, 0x2b, 0x45 } } +{ 0x8bc6ae5f, 0xb396, 0x11d9, \ + { 0xb1, 0x4f, 0x00, 0x11, 0x24, 0x78, 0xd6, 0x26 } } // The base value for the content ID counter. // This counter is used by the document to @@ -665,6 +665,26 @@ public: return mPartID; } + /** + * Sanitize the document by resetting all input elements and forms that have + * autocomplete=off to their default values. + */ + virtual nsresult Sanitize() = 0; + + /** + * Enumerate all subdocuments. + */ + typedef PRBool (*nsSubDocEnumFunc)(nsIDocument *aDocument, void *aData); + virtual void EnumerateSubDocuments(nsSubDocEnumFunc aCallback, + void *aData) = 0; + + /** + * Check whether there are any requests in our loadgroup or the loadgroups + * of any child documents, recursively. aIgnoreRequest may be set to a + * specific request to ignore (it can be null). + */ + virtual PRBool HasRequests(nsIRequest *aIgnoreRequest) = 0; + protected: ~nsIDocument() { Index: content/base/src/nsDocument.cpp =================================================================== RCS file: /cvsroot/mozilla/content/base/src/nsDocument.cpp,v retrieving revision 3.546 diff -u -p -r3.546 nsDocument.cpp --- content/base/src/nsDocument.cpp 19 Apr 2005 01:27:09 -0000 3.546 +++ content/base/src/nsDocument.cpp 26 Apr 2005 18:31:41 -0000 @@ -126,6 +126,8 @@ static NS_DEFINE_CID(kDOMEventGroupCID, #include "nsIScriptContext.h" #include "nsBindingManager.h" +#include "nsIDOMHTMLFormElement.h" +#include "nsIRequest.h" #include "nsICharsetAlias.h" static NS_DEFINE_CID(kCharsetAliasCID, NS_CHARSETALIAS_CID); @@ -1616,7 +1618,12 @@ nsDocument::RemoveStyleSheet(nsIStyleShe return; } - if (!mIsGoingAway) { + // If there is no script global object, we assume that either: + // 1) Document teardown is in progress + // 2) The document is in session history not being shown; it should not be + // possible for RemoveStyleSheet to be called in this case. + + if (mScriptGlobalObject) { PRBool applicable = PR_TRUE; aSheet->GetApplicable(applicable); if (applicable) { @@ -1832,7 +1839,7 @@ nsDocument::GetScriptGlobalObject() cons // ScriptGlobalObject. We can, however, try to obtain it for the // caller through our docshell. - if (mIsGoingAway) { + if (!mScriptGlobalObject) { nsCOMPtr requestor = do_QueryReferent(mDocumentContainer); if (requestor) { @@ -1847,37 +1854,6 @@ nsDocument::GetScriptGlobalObject() cons void nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject) { - // XXX HACK ALERT! If the script context owner is null, the document - // will soon be going away. So tell our content that to lose its - // reference to the document. This has to be done before we actually - // set the script context owner to null so that the content elements - // can remove references to their script objects. - if (!aScriptGlobalObject) { - PRInt32 count, indx; - - count = mChildren.Count(); - - mIsGoingAway = PR_TRUE; - - for (indx = 0; indx < count; ++indx) { - mChildren[indx]->UnbindFromTree(); - } - - // Propagate the out-of-band notification to each PresShell's - // anonymous content as well. This ensures that there aren't any - // accidental script references left in anonymous content keeping - // the document alive. (While not strictly necessary -- the - // PresShell owns us -- it's tidy.) - for (count = mPresShells.Count() - 1; count >= 0; --count) { - nsCOMPtr shell = - NS_STATIC_CAST(nsIPresShell*, mPresShells[count]); - if (!shell) - continue; - - shell->ReleaseAnonymousContent(); - } - } - mScriptGlobalObject = aScriptGlobalObject; } @@ -4574,3 +4550,170 @@ nsDocument::UnsetProperty(nsIAtom *aProp { return mPropertyTable.UnsetProperty(this, aPropertyName, aStatus); } + +nsresult +nsDocument::Sanitize() +{ + // Sanitize the document by resetting all password fields and any form + // fields with autocomplete=off to their default values. We do this now, + // instead of when the presentation is restored, to offer some protection + // in case there is ever an exploit that allows a cached document to be + // accessed from a different document. + + // First locate all input elements, regardless of whether they are + // in a form, and reset the password and autocomplete=off elements. + + nsCOMPtr nodes; + nsresult rv = GetElementsByTagName(NS_LITERAL_STRING("input"), + getter_AddRefs(nodes)); + NS_ENSURE_SUCCESS(rv, rv); + + PRUint32 length = 0; + if (nodes) + nodes->GetLength(&length); + + nsCOMPtr item; + nsAutoString value; + PRUint32 i; + + for (i = 0; i < length; ++i) { + nodes->Item(i, getter_AddRefs(item)); + NS_ASSERTION(item, "null item in node list!"); + + nsCOMPtr input = do_QueryInterface(item); + if (!input) + continue; + + PRBool resetValue = PR_FALSE; + + input->GetAttribute(NS_LITERAL_STRING("autocomplete"), value); + if (value.LowerCaseEqualsLiteral("off")) { + resetValue = PR_TRUE; + } else { + input->GetType(value); + if (value.LowerCaseEqualsLiteral("password")) + resetValue = PR_TRUE; + } + + if (resetValue) { + nsCOMPtr fc = do_QueryInterface(input); + fc->Reset(); + } + } + + // Now locate all _form_ elements that have autocomplete=off and reset them + rv = GetElementsByTagName(NS_LITERAL_STRING("form"), getter_AddRefs(nodes)); + NS_ENSURE_SUCCESS(rv, rv); + + length = 0; + if (nodes) + nodes->GetLength(&length); + + for (i = 0; i < length; ++i) { + nodes->Item(i, getter_AddRefs(item)); + NS_ASSERTION(item, "null item in nodelist"); + + nsCOMPtr form = do_QueryInterface(item); + if (!form) + continue; + + form->GetAttribute(NS_LITERAL_STRING("autocomplete"), value); + if (value.LowerCaseEqualsLiteral("off")) + form->Reset(); + } + + return NS_OK; +} + +struct SubDocEnumArgs +{ + nsIDocument::nsSubDocEnumFunc callback; + void *data; +}; + +PR_STATIC_CALLBACK(PLDHashOperator) +SubDocHashEnum(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + SubDocMapEntry *entry = NS_STATIC_CAST(SubDocMapEntry*, hdr); + SubDocEnumArgs *args = NS_STATIC_CAST(SubDocEnumArgs*, arg); + + nsIDocument *subdoc = entry->mSubDocument; + PRBool next = PR_TRUE; + + if (subdoc) + next = args->callback(subdoc, args->data); + + return next ? PL_DHASH_NEXT : PL_DHASH_STOP; +} + +void +nsDocument::EnumerateSubDocuments(nsSubDocEnumFunc aCallback, void *aData) +{ + if (mSubDocuments) { + SubDocEnumArgs args = { aCallback, aData }; + PL_DHashTableEnumerate(mSubDocuments, SubDocHashEnum, &args); + } +} + +PR_STATIC_CALLBACK(PLDHashOperator) +SubDocHasRequests(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + SubDocMapEntry *entry = NS_STATIC_CAST(SubDocMapEntry*, hdr); + PRBool *hasRequests = NS_STATIC_CAST(PRBool*, arg); + + nsIDocument *subdoc = entry->mSubDocument; + + // The aIgnoreRequest we were passed is only for us, so don't pass it on. + PRBool hasRequest = subdoc ? PR_FALSE : subdoc->HasRequests(nsnull); + if (hasRequest) { + *hasRequests = PR_TRUE; + return PL_DHASH_STOP; + } + + return PL_DHASH_NEXT; +} + +#ifdef DEBUG_bryner +#define DEBUG_PAGE_CACHE +#endif + +PRBool +nsDocument::HasRequests(nsIRequest *aIgnoreRequest) +{ + nsCOMPtr loadGroup = GetDocumentLoadGroup(); + if (loadGroup) { + nsCOMPtr requests; + loadGroup->GetRequests(getter_AddRefs(requests)); + + PRBool hasMore = PR_FALSE; + nsCOMPtr elem; + nsCOMPtr request; + + while (NS_SUCCEEDED(requests->HasMoreElements(&hasMore)) && hasMore) { + requests->GetNext(getter_AddRefs(elem)); + request = do_QueryInterface(elem); + if (request && request != aIgnoreRequest) { +#ifdef DEBUG_PAGE_CACHE + nsCAutoString requestName, docSpec; + request->GetName(requestName); + if (mDocumentURI) + mDocumentURI->GetSpec(docSpec); + + printf("document %s has request %s\n", + docSpec.get(), requestName.get()); +#endif + return PR_TRUE; + } + } + } + + PRBool subDocsHaveRequests = PR_FALSE; + if (mSubDocuments) { + PL_DHashTableEnumerate(mSubDocuments, SubDocHasRequests, + &subDocsHaveRequests); + } + + return subDocsHaveRequests; +} Index: content/base/src/nsDocument.h =================================================================== RCS file: /cvsroot/mozilla/content/base/src/nsDocument.h,v retrieving revision 3.251 diff -u -p -r3.251 nsDocument.h --- content/base/src/nsDocument.h 19 Apr 2005 01:27:09 -0000 3.251 +++ content/base/src/nsDocument.h 26 Apr 2005 18:31:41 -0000 @@ -524,6 +524,13 @@ public: virtual NS_HIDDEN_(void*) UnsetProperty(nsIAtom *aPropertyName, nsresult *aStatus = nsnull); + virtual NS_HIDDEN_(nsresult) Sanitize(); + + virtual NS_HIDDEN_(void) EnumerateSubDocuments(nsSubDocEnumFunc aCallback, + void *aData); + + virtual NS_HIDDEN_(PRBool) HasRequests(nsIRequest *aIgnoreRequest); + protected: void RetrieveRelevantHeaders(nsIChannel *aChannel); @@ -583,9 +590,6 @@ protected: nsHashtable mRadioGroups; // True if the document is being destroyed. - PRPackedBool mIsGoingAway; - - // True if the document is being destroyed. PRPackedBool mInDestructor; PRUint8 mXMLDeclarationBits; Index: content/base/src/nsSyncLoadService.cpp =================================================================== RCS file: /cvsroot/mozilla/content/base/src/nsSyncLoadService.cpp,v retrieving revision 1.44 diff -u -p -r1.44 nsSyncLoadService.cpp --- content/base/src/nsSyncLoadService.cpp 7 Mar 2005 19:46:02 -0000 1.44 +++ content/base/src/nsSyncLoadService.cpp 26 Apr 2005 18:31:41 -0000 @@ -120,6 +120,7 @@ public: NS_IMETHOD Unload(nsIDOMEvent* aEvent); NS_IMETHOD Abort(nsIDOMEvent* aEvent); NS_IMETHOD Error(nsIDOMEvent* aEvent); + NS_IMETHOD PageRestore(nsIDOMEvent* aEvent); NS_DECL_NSICHANNELEVENTSINK @@ -161,6 +162,7 @@ public: NS_IMETHOD Unload(nsIDOMEvent* aEvent); NS_IMETHOD Abort(nsIDOMEvent* aEvent); NS_IMETHOD Error(nsIDOMEvent* aEvent); + NS_IMETHOD PageRestore(nsIDOMEvent* aEvent); protected: nsWeakPtr mParent; @@ -249,6 +251,18 @@ txLoadListenerProxy::Error(nsIDOMEvent* return NS_OK; } +NS_IMETHODIMP +txLoadListenerProxy::PageRestore(nsIDOMEvent* aEvent) +{ + nsCOMPtr listener = do_QueryReferent(mParent); + + if (listener) { + return listener->PageRestore(aEvent); + } + + return NS_OK; +} + class nsForceXMLListener : public nsIStreamListener { public: @@ -513,6 +527,12 @@ nsSyncLoader::Error(nsIDOMEvent* aEvent) } NS_IMETHODIMP +nsSyncLoader::PageRestore(nsIDOMEvent* aEvent) +{ + return NS_OK; +} + +NS_IMETHODIMP nsSyncLoader::OnChannelRedirect(nsIChannel *aOldChannel, nsIChannel *aNewChannel, PRUint32 aFlags) Index: content/events/public/nsIEventListenerManager.h =================================================================== RCS file: /cvsroot/mozilla/content/events/public/nsIEventListenerManager.h,v retrieving revision 1.36 diff -u -p -r1.36 nsIEventListenerManager.h --- content/events/public/nsIEventListenerManager.h 31 Jul 2004 23:14:57 -0000 1.36 +++ content/events/public/nsIEventListenerManager.h 26 Apr 2005 18:31:41 -0000 @@ -53,9 +53,8 @@ class nsIAtom; * Event listener manager interface. */ #define NS_IEVENTLISTENERMANAGER_IID \ -{ /* cd91bcf0-ded9-11d1-bd85-00805f8ae3f4 */ \ -0xcd91bcf0, 0xded9, 0x11d1, \ -{0xbd, 0x85, 0x00, 0x80, 0x5f, 0x8a, 0xe3, 0xf4} } +{0xc23b877c, 0xb396, 0x11d9, \ +{0x86, 0xbd, 0x00, 0x11, 0x24, 0x78, 0xd6, 0x26} } class nsIEventListenerManager : public nsISupports { @@ -182,6 +181,12 @@ public: * Loop pass for evaluation of system event listeners. */ NS_IMETHOD GetSystemEventGroupLM(nsIDOMEventGroup** aGroup) = 0; + + /** + * Allows us to quickly determine if we have unload or beforeunload + * listeners registered. + */ + virtual PRBool HasUnloadListeners() = 0; }; nsresult Index: content/events/src/nsDOMEvent.cpp =================================================================== RCS file: /cvsroot/mozilla/content/events/src/nsDOMEvent.cpp,v retrieving revision 1.186 diff -u -p -r1.186 nsDOMEvent.cpp --- content/events/src/nsDOMEvent.cpp 5 Mar 2005 08:19:03 -0000 1.186 +++ content/events/src/nsDOMEvent.cpp 26 Apr 2005 18:31:41 -0000 @@ -58,8 +58,8 @@ static const char* const sEventNames[] = "mousedown", "mouseup", "click", "dblclick", "mouseover", "mouseout", "mousemove", "contextmenu", "keydown", "keyup", "keypress", "focus", "blur", "load", "beforeunload", "unload", "abort", "error", - "submit", "reset", "change", "select", "input", "paint" ,"text", - "compositionstart", "compositionend", "popupshowing", "popupshown", + "DOMPageRestore", "submit", "reset", "change", "select", "input", "paint", + "text", "compositionstart", "compositionend", "popupshowing", "popupshown", "popuphiding", "popuphidden", "close", "command", "broadcast", "commandupdate", "dragenter", "dragover", "dragexit", "dragdrop", "draggesture", "resize", "scroll","overflow", "underflow", "overflowchanged", @@ -434,6 +434,8 @@ nsDOMEvent::SetEventType(const nsAString mEvent->message = NS_IMAGE_ABORT; else if (atom == nsLayoutAtoms::onerror) mEvent->message = NS_IMAGE_ERROR; + else if (atom == nsLayoutAtoms::onDOMPageRestore) + mEvent->message = NS_PAGE_RESTORE; } else if (mEvent->eventStructType == NS_MUTATION_EVENT) { if (atom == nsLayoutAtoms::onDOMAttrModified) mEvent->message = NS_MUTATION_ATTRMODIFIED; @@ -794,6 +796,8 @@ const char* nsDOMEvent::GetEventName(PRU case NS_IMAGE_ERROR: case NS_SCRIPT_ERROR: return sEventNames[eDOMEvents_error]; + case NS_PAGE_RESTORE: + return sEventNames[eDOMEvents_DOMPageRestore]; case NS_FORM_SUBMIT: return sEventNames[eDOMEvents_submit]; case NS_FORM_RESET: Index: content/events/src/nsDOMEvent.h =================================================================== RCS file: /cvsroot/mozilla/content/events/src/nsDOMEvent.h,v retrieving revision 1.83 diff -u -p -r1.83 nsDOMEvent.h --- content/events/src/nsDOMEvent.h 5 Mar 2005 08:19:03 -0000 1.83 +++ content/events/src/nsDOMEvent.h 26 Apr 2005 18:31:41 -0000 @@ -85,6 +85,7 @@ public: eDOMEvents_unload, eDOMEvents_abort, eDOMEvents_error, + eDOMEvents_DOMPageRestore, eDOMEvents_submit, eDOMEvents_reset, eDOMEvents_change, Index: content/events/src/nsEventListenerManager.cpp =================================================================== RCS file: /cvsroot/mozilla/content/events/src/nsEventListenerManager.cpp,v retrieving revision 1.198 diff -u -p -r1.198 nsEventListenerManager.cpp --- content/events/src/nsEventListenerManager.cpp 22 Apr 2005 02:01:34 -0000 1.198 +++ content/events/src/nsEventListenerManager.cpp 26 Apr 2005 18:31:41 -0000 @@ -241,7 +241,8 @@ static const EventDispatchData sLoadEven {NS_PAGE_UNLOAD, HANDLER(&nsIDOMLoadListener::Unload),NS_EVENT_BITS_LOAD_UNLOAD}, {NS_IMAGE_ERROR, HANDLER(&nsIDOMLoadListener::Error), NS_EVENT_BITS_LOAD_ERROR}, {NS_SCRIPT_ERROR,HANDLER(&nsIDOMLoadListener::Error), NS_EVENT_BITS_LOAD_ERROR}, - {NS_BEFORE_PAGE_UNLOAD,HANDLER(&nsIDOMLoadListener::BeforeUnload), NS_EVENT_BITS_LOAD_BEFORE_UNLOAD} + {NS_BEFORE_PAGE_UNLOAD,HANDLER(&nsIDOMLoadListener::BeforeUnload), NS_EVENT_BITS_LOAD_BEFORE_UNLOAD}, + {NS_PAGE_RESTORE,HANDLER(&nsIDOMLoadListener::PageRestore), NS_EVENT_BITS_LOAD_PAGE_RESTORE} }; static const EventDispatchData sPaintEvents[] = { @@ -885,6 +886,10 @@ nsEventListenerManager::GetIdentifiersFo *aArrayType = eEventArrayType_Load; *aFlags = NS_EVENT_BITS_LOAD_ERROR; } + else if (aType == nsLayoutAtoms::onDOMPageRestore) { + *aArrayType = eEventArrayType_Load; + *aFlags = NS_EVENT_BITS_LOAD_PAGE_RESTORE; + } else if (aType == nsLayoutAtoms::onpaint) { *aArrayType = eEventArrayType_Paint; *aFlags = NS_EVENT_BITS_PAINT_PAINT; @@ -2208,6 +2213,26 @@ void nsEventListenerManager::GetCoordina } } +PRBool +nsEventListenerManager::HasUnloadListeners() +{ + nsVoidArray *listeners = GetListenersByType(eEventArrayType_Load, nsnull, + PR_FALSE); + if (listeners) { + PRInt32 count = listeners->Count(); + for (PRInt32 i = 0; i < count; ++i) { + PRUint32 subtype = NS_STATIC_CAST(nsListenerStruct*, + listeners->FastElementAt(i))->mSubType; + if (subtype == NS_EVENT_BITS_NONE || + subtype & (NS_EVENT_BITS_LOAD_UNLOAD | + NS_EVENT_BITS_LOAD_BEFORE_UNLOAD)) + return PR_TRUE; + } + } + + return PR_FALSE; +} + nsresult NS_NewEventListenerManager(nsIEventListenerManager** aInstancePtrResult) { Index: content/events/src/nsEventListenerManager.h =================================================================== RCS file: /cvsroot/mozilla/content/events/src/nsEventListenerManager.h,v retrieving revision 1.73 diff -u -p -r1.73 nsEventListenerManager.h --- content/events/src/nsEventListenerManager.h 1 Feb 2005 19:24:57 -0000 1.73 +++ content/events/src/nsEventListenerManager.h 26 Apr 2005 18:31:41 -0000 @@ -163,6 +163,8 @@ public: NS_IMETHOD GetSystemEventGroupLM(nsIDOMEventGroup** aGroup); + virtual PRBool HasUnloadListeners(); + static nsresult GetIdentifiersForType(nsIAtom* aType, EventArrayType* aArrayType, PRInt32* aSubType); @@ -300,6 +302,7 @@ protected: #define NS_EVENT_BITS_LOAD_ABORT 0x04 #define NS_EVENT_BITS_LOAD_ERROR 0x08 #define NS_EVENT_BITS_LOAD_BEFORE_UNLOAD 0x10 +#define NS_EVENT_BITS_LOAD_PAGE_RESTORE 0x20 //nsIDOMXULListener #define NS_EVENT_BITS_XUL_NONE 0x00 Index: content/html/content/src/nsGenericHTMLElement.cpp =================================================================== RCS file: /cvsroot/mozilla/content/html/content/src/nsGenericHTMLElement.cpp,v retrieving revision 1.582 diff -u -p -r1.582 nsGenericHTMLElement.cpp --- content/html/content/src/nsGenericHTMLElement.cpp 19 Apr 2005 01:27:10 -0000 1.582 +++ content/html/content/src/nsGenericHTMLElement.cpp 26 Apr 2005 18:31:41 -0000 @@ -1525,15 +1525,17 @@ nsGenericHTMLElement::HandleDOMEventForA // nothing else. nsCOMPtr win = do_QueryInterface(document->GetScriptGlobalObject()); - nsIFocusController *focusController = - win->GetRootFocusController(); - PRBool isActive = PR_FALSE; - focusController->GetActive(&isActive); - if (!isActive) { - nsCOMPtr domElement = do_QueryInterface(this); - if(domElement) - focusController->SetFocusedElement(domElement); - break; + if (win) { + nsIFocusController *focusController = + win->GetRootFocusController(); + PRBool isActive = PR_FALSE; + focusController->GetActive(&isActive); + if (!isActive) { + nsCOMPtr domElement = do_QueryInterface(this); + if(domElement) + focusController->SetFocusedElement(domElement); + break; + } } aPresContext->EventStateManager()-> Index: content/html/content/src/nsHTMLInputElement.cpp =================================================================== RCS file: /cvsroot/mozilla/content/html/content/src/nsHTMLInputElement.cpp,v retrieving revision 1.385 diff -u -p -r1.385 nsHTMLInputElement.cpp --- content/html/content/src/nsHTMLInputElement.cpp 7 Apr 2005 14:08:12 -0000 1.385 +++ content/html/content/src/nsHTMLInputElement.cpp 26 Apr 2005 18:31:42 -0000 @@ -1069,14 +1069,16 @@ nsHTMLInputElement::SetFocus(nsPresConte // nothing else. nsCOMPtr win = do_QueryInterface(doc->GetScriptGlobalObject()); - nsIFocusController *focusController = win->GetRootFocusController(); - PRBool isActive = PR_FALSE; - focusController->GetActive(&isActive); - if (!isActive) { - focusController->SetFocusedWindow(win); - focusController->SetFocusedElement(this); + if (win) { + nsIFocusController *focusController = win->GetRootFocusController(); + PRBool isActive = PR_FALSE; + focusController->GetActive(&isActive); + if (!isActive) { + focusController->SetFocusedWindow(win); + focusController->SetFocusedElement(this); - return; + return; + } } aPresContext->EventStateManager()->SetContentState(this, @@ -1119,14 +1121,16 @@ nsHTMLInputElement::Select() // nothing else. nsCOMPtr win = do_QueryInterface(doc->GetScriptGlobalObject()); - nsIFocusController *focusController = win->GetRootFocusController(); - PRBool isActive = PR_FALSE; - focusController->GetActive(&isActive); - if (!isActive) { - focusController->SetFocusedWindow(win); - focusController->SetFocusedElement(this); - SelectAll(presContext); - return NS_OK; + if (win) { + nsIFocusController *focusController = win->GetRootFocusController(); + PRBool isActive = PR_FALSE; + focusController->GetActive(&isActive); + if (!isActive) { + focusController->SetFocusedWindow(win); + focusController->SetFocusedElement(this); + SelectAll(presContext); + return NS_OK; + } } // Just like SetFocus() but without the ScrollIntoView()! Index: content/html/document/src/nsPluginDocument.cpp =================================================================== RCS file: /cvsroot/mozilla/content/html/document/src/nsPluginDocument.cpp,v retrieving revision 1.18 diff -u -p -r1.18 nsPluginDocument.cpp --- content/html/document/src/nsPluginDocument.cpp 18 Apr 2005 22:58:31 -0000 1.18 +++ content/html/document/src/nsPluginDocument.cpp 26 Apr 2005 18:31:42 -0000 @@ -97,6 +97,9 @@ nsPluginDocument::SetScriptGlobalObject( { if (!aScriptGlobalObject) { mStreamListener = nsnull; + } else if (!mStreamListener) { + mStreamListener = new nsMediaDocumentStreamListener(this); + // XXX no way to indicate OOM } nsMediaDocument::SetScriptGlobalObject(aScriptGlobalObject); Index: content/xbl/src/nsXBLPrototypeHandler.cpp =================================================================== RCS file: /cvsroot/mozilla/content/xbl/src/nsXBLPrototypeHandler.cpp,v retrieving revision 1.89 diff -u -p -r1.89 nsXBLPrototypeHandler.cpp --- content/xbl/src/nsXBLPrototypeHandler.cpp 30 Mar 2005 12:27:28 -0000 1.89 +++ content/xbl/src/nsXBLPrototypeHandler.cpp 26 Apr 2005 18:31:42 -0000 @@ -291,7 +291,8 @@ nsXBLPrototypeHandler::ExecuteHandler(ns privateWindow = do_QueryInterface(doc->GetScriptGlobalObject()); } - focusController = privateWindow->GetRootFocusController(); + if (privateWindow) + focusController = privateWindow->GetRootFocusController(); } NS_LossyConvertUCS2toASCII command(mHandlerText); Index: content/xbl/src/nsXBLService.cpp =================================================================== RCS file: /cvsroot/mozilla/content/xbl/src/nsXBLService.cpp,v retrieving revision 1.198 diff -u -p -r1.198 nsXBLService.cpp --- content/xbl/src/nsXBLService.cpp 25 Feb 2005 22:06:58 -0000 1.198 +++ content/xbl/src/nsXBLService.cpp 26 Apr 2005 18:31:43 -0000 @@ -229,11 +229,12 @@ public: NS_DECL_NSIREQUESTOBSERVER NS_IMETHOD Load(nsIDOMEvent* aEvent); - NS_IMETHOD BeforeUnload(nsIDOMEvent* aEvent) { return NS_OK; }; - NS_IMETHOD Unload(nsIDOMEvent* aEvent) { return NS_OK; }; - NS_IMETHOD Abort(nsIDOMEvent* aEvent) { return NS_OK; }; - NS_IMETHOD Error(nsIDOMEvent* aEvent) { return NS_OK; }; - NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; }; + NS_IMETHOD BeforeUnload(nsIDOMEvent* aEvent) { return NS_OK; } + NS_IMETHOD Unload(nsIDOMEvent* aEvent) { return NS_OK; } + NS_IMETHOD Abort(nsIDOMEvent* aEvent) { return NS_OK; } + NS_IMETHOD Error(nsIDOMEvent* aEvent) { return NS_OK; } + NS_IMETHOD PageRestore(nsIDOMEvent* aEvent) { return NS_OK; } + NS_IMETHOD HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; } #ifdef MOZ_XUL static nsIXULPrototypeCache* gXULCache; Index: docshell/base/nsDocShell.cpp =================================================================== RCS file: /cvsroot/mozilla/docshell/base/nsDocShell.cpp,v retrieving revision 1.674 diff -u -p -r1.674 nsDocShell.cpp --- docshell/base/nsDocShell.cpp 20 Apr 2005 04:41:48 -0000 1.674 +++ docshell/base/nsDocShell.cpp 26 Apr 2005 18:31:45 -0000 @@ -166,9 +166,15 @@ static NS_DEFINE_CID(kDOMScriptObjectFac #if defined(DEBUG_bryner) //#define DEBUG_DOCSHELL_FOCUS +#define DEBUG_PAGE_CACHE #endif #include "plevent.h" +#include "nsGUIEvent.h" +#include "nsIPrivateDOMEvent.h" +#include "nsIDOMEventReceiver.h" +#include "nsIEventListenerManager.h" +#include "nsICaret.h" // Number of documents currently loading static PRInt32 gNumberOfDocumentsLoading = 0; @@ -199,6 +205,9 @@ static PRBool gValidateOrigin = (PRBool) static PRLogModuleInfo* gDocShellLog; #endif +// Used to let SetupNewViewer() know that the previous viewer can be saved. +static PRBool gSavingOldViewer = PR_FALSE; + //***************************************************************************** //*** nsDocShellFocusController //***************************************************************************** @@ -1355,12 +1364,7 @@ nsDocShell::SetCurrentURI(nsIURI *aURI, isRoot = PR_TRUE; } if (mLSHE) { - nsCOMPtr historyEntry(do_QueryInterface(mLSHE)); - - // Check if this is a subframe navigation - if (historyEntry) { - historyEntry->GetIsSubFrame(&isSubFrame); - } + mLSHE->GetIsSubFrame(&isSubFrame); } if (!isSubFrame && !isRoot) { @@ -1681,6 +1685,20 @@ nsDocShell::TabToTreeOwner(PRBool aForwa return NS_OK; } +NS_IMETHODIMP +nsDocShell::GetSecurityUI(nsISecureBrowserUI **aSecurityUI) +{ + NS_IF_ADDREF(*aSecurityUI = mSecurityUI); + return NS_OK; +} + +NS_IMETHODIMP +nsDocShell::SetSecurityUI(nsISecureBrowserUI *aSecurityUI) +{ + mSecurityUI = aSecurityUI; + return NS_OK; +} + //***************************************************************************** // nsDocShell::nsIDocShellTreeItem //***************************************************************************** @@ -3261,12 +3279,11 @@ nsDocShell::LoadPage(nsISupports *aPageD // load the page as view-source // if (nsIWebPageDescriptor::DISPLAY_AS_SOURCE == aDisplayType) { - nsCOMPtr srcHE(do_QueryInterface(shEntry)); nsCOMPtr oldUri, newUri; nsCString spec, newSpec; // Create a new view-source URI and replace the original. - rv = srcHE->GetURI(getter_AddRefs(oldUri)); + rv = shEntry->GetURI(getter_AddRefs(oldUri)); if (NS_FAILED(rv)) return rv; @@ -3720,7 +3737,7 @@ nsDocShell::SetTitle(const PRUnichar * a // would suffice. if (mOSHE && (mLoadType != LOAD_BYPASS_HISTORY) && (mLoadType != LOAD_HISTORY) && (mLoadType != LOAD_ERROR_PAGE)) { - mOSHE->SetTitle(mTitle.get()); + mOSHE->SetTitle(mTitle); } @@ -4315,7 +4332,37 @@ nsDocShell::CancelRefreshURITimers() return NS_OK; } -NS_IMETHODIMP +void +nsDocShell::SuspendRefreshURIs() +{ + if (!mRefreshURIList) + return; + PRUint32 n = 0; + mRefreshURIList->Count(&n); + + nsCOMPtr timer; + nsCOMPtr callback; + nsCOMPtr rt; + + for (PRUint32 i = 0; i < n; ++i) { + timer = do_QueryElementAt(mRefreshURIList, --n); + if (!timer) + continue; // this must be a nsRefreshURI already + + // Replace this timer object with a nsRefreshTimer object. + nsCOMPtr callback; + timer->GetCallback(getter_AddRefs(callback)); + + timer->Cancel(); + + nsCOMPtr rt = do_QueryInterface(callback); + NS_ASSERTION(rt, "RefreshURIList timer callbacks should only be RefreshTimer objects"); + + mRefreshURIList->ReplaceElementAt(rt, i); + } +} + +nsresult nsDocShell::RefreshURIFromQueue() { if (!mRefreshURIList) @@ -4701,6 +4748,440 @@ nsDocShell::CreateAboutBlankContentViewe return rv; } +PRBool +nsDocShell::CanSavePresentation(nsIRequest *aNewRequest) +{ + // If the document is not done loading, don't cache it. + nsCOMPtr pWin = do_QueryInterface(mScriptGlobal); + if (pWin && pWin->IsLoading()) + return PR_FALSE; + + // If there are any active requests in the document load group, don't cache + // the document. Ideally we would instead suspend these requests and + // resume them when restoring the presentation, but that is potentially + // difficult (e.g. XMLHttpRequest). + + nsCOMPtr doc = do_QueryInterface(pWin->GetExtantDocument()); + if (doc && doc->HasRequests(aNewRequest)) + return PR_FALSE; + + // Only save presentation for "normal" loads and link loads. Anything else + // probably wants to refetch the page, so caching the old presentation + // would be incorrect. + if (mLoadType != LOAD_NORMAL && + mLoadType != LOAD_HISTORY && + mLoadType != LOAD_LINK) + return PR_FALSE; + + // If there is an unload or beforeunload listener on the window, then we do + // not save the presentation into the session history cache. + nsCOMPtr er = do_QueryInterface(mScriptGlobal); + if (er) { + nsCOMPtr eventManager; + er->GetListenerManager(getter_AddRefs(eventManager)); + + if (eventManager && eventManager->HasUnloadListeners()) + return PR_FALSE; + } + + // If the session history entry has the saveLayoutState flag set to false, + // then we should not cache the presentation. + + if (!mOSHE) + return PR_FALSE; // no entry to save into + + PRBool canSaveState; + mOSHE->GetSaveLayoutStateFlag(&canSaveState); + return canSaveState; +} + +nsresult +nsDocShell::CaptureState() +{ + nsCOMPtr privWin = do_QueryInterface(mScriptGlobal); + if (!privWin || !mOSHE) + return NS_ERROR_FAILURE; + + nsCOMPtr windowState; + nsresult rv = privWin->SaveWindowState(getter_AddRefs(windowState)); + NS_ENSURE_SUCCESS(rv, rv); + +#ifdef DEBUG_PAGE_CACHE + nsCOMPtr uri; + mOSHE->GetURI(getter_AddRefs(uri)); + nsCAutoString spec; + if (uri) + uri->GetSpec(spec); + printf("Saving presentation into session history\n"); + printf(" SH URI: %s\n", spec.get()); +#endif + + rv = mOSHE->SetWindowState(windowState); + NS_ENSURE_SUCCESS(rv, rv); + + // Suspend refresh URIs and save off the timer queue + SuspendRefreshURIs(); + rv = mOSHE->SetRefreshURIList(mRefreshURIList); + NS_ENSURE_SUCCESS(rv, rv); + + mRefreshURIList = nsnull; + + // Capture the current content viewer bounds. + nsCOMPtr shell; + nsDocShell::GetPresShell(getter_AddRefs(shell)); + if (shell) { + nsIViewManager *vm = shell->GetViewManager(); + if (vm) { + nsIView *rootView = nsnull; + vm->GetRootView(rootView); + if (rootView) { + nsIWidget *widget = rootView->GetWidget(); + if (widget) { + nsRect bounds(0, 0, 0, 0); + widget->GetBounds(bounds); + rv = mOSHE->SetViewerBounds(bounds); + } + } + } + } + + // Disable the caret for this shell and all of its children. + DisableCaret(this); + + // Capture the docshell hierarchy. + + PRInt32 childCount = mChildList.Count(); + nsCOMPtr childShell; + + mOSHE->ClearChildShells(); + + for (PRInt32 i = 0; i < childCount; ++i) { + childShell = do_QueryInterface(ChildAt(i)); + NS_ASSERTION(childShell, "null child shell"); + + mOSHE->AddChildShell(childShell); + } + + // Capture the security state. + nsCOMPtr securityState; + if (mSecurityUI) + mSecurityUI->CaptureState(getter_AddRefs(securityState)); + + return mOSHE->SetSecurityState(securityState); +} + +nsresult +nsDocShell::RestorePresentation(nsISHEntry *aSHEntry) +{ + nsCOMPtr uri; + aSHEntry->GetURI(getter_AddRefs(uri)); + + nsCOMPtr viewer; + aSHEntry->GetContentViewer(getter_AddRefs(viewer)); + +#ifdef DEBUG_PAGE_CACHE + nsCAutoString spec; + if (uri) + uri->GetSpec(spec); +#endif + + if (!viewer) { +#ifdef DEBUG_PAGE_CACHE + printf("no saved presentation for uri: %s\n", spec.get()); +#endif + return NS_ERROR_FAILURE; + } + + NS_ASSERTION(mContentViewer != viewer, "Restoring existing presentation"); + +#ifdef DEBUG_PAGE_CACHE + printf("restoring presentation from session history: %s\n", spec.get()); +#endif + + // Save off the root view's parent and sibling so that we can insert the + // new content viewer's root view at the same position. Also save the + // bounds of the root view's widget. + + nsIView *rootViewSibling = nsnull, *rootViewParent = nsnull; + nsRect newBounds(0, 0, 0, 0); + + nsCOMPtr oldPresShell; + nsDocShell::GetPresShell(getter_AddRefs(oldPresShell)); + if (oldPresShell) { + nsIViewManager *vm = oldPresShell->GetViewManager(); + if (vm) { + nsIView *oldRootView = nsnull; + vm->GetRootView(oldRootView); + + if (oldRootView) { + rootViewSibling = oldRootView->GetNextSibling(); + rootViewParent = oldRootView->GetParent(); + + nsIWidget *widget = oldRootView->GetWidget(); + if (widget) { + widget->GetBounds(newBounds); + } + } + } + } + + // Transfer ownership to mContentViewer. By ensuring that either the + // docshell or the session history, but not both, have references to the + // content viewer, we prevent the viewer from being torn down after + // Destroy() is called. + + PRBool savePresentation = CanSavePresentation(nsnull); + if (!savePresentation) + FireUnloadNotification(); + + mFiredUnloadEvent = PR_FALSE; + + if (mContentViewer) { + mContentViewer->Close(); + + if (savePresentation) + mContentViewer->SetHistoryEntry(mOSHE); + + mContentViewer->Destroy(); + } + + mContentViewer.swap(viewer); + viewer = nsnull; // force a release to complete ownership transfer + + // Reattach to the window object. + nsresult rv = mContentViewer->Open(); + NS_ENSURE_SUCCESS(rv, rv); + + // Now remove it from the cached presentation. + aSHEntry->SetContentViewer(nsnull); + + // Restore our child docshell hierarchy. + DestroyChildren(); + + PRInt32 i = 0; + nsCOMPtr childShell; + while (NS_SUCCEEDED(aSHEntry->ChildShellAt(i++, + getter_AddRefs(childShell))) && + childShell) { + AddChild(childShell); + } + + // And release the references in the history entry. + aSHEntry->ClearChildShells(); + + // restore the sticky state of the viewer + PRBool sticky; + aSHEntry->GetSticky(&sticky); + mContentViewer->SetSticky(sticky); + + // save the previous content viewer size + nsRect oldBounds(0, 0, 0, 0); + aSHEntry->GetViewerBounds(oldBounds); + + // Insert the new root view at the correct location in the view tree. + if (rootViewParent) { + nsIViewManager *parentVM = rootViewParent->GetViewManager(); + + nsCOMPtr shell; + nsDocShell::GetPresShell(getter_AddRefs(shell)); + + if (parentVM && shell) { + nsIViewManager *newVM = shell->GetViewManager(); + if (newVM) { + nsIView *newRootView = nsnull; + newVM->GetRootView(newRootView); + if (newRootView) { + parentVM->InsertChild(rootViewParent, newRootView, + rootViewSibling, PR_TRUE); + + NS_ASSERTION(newRootView->GetNextSibling() == + rootViewSibling, + "error in InsertChild"); + + if (oldPresShell) + oldPresShell->InvalidateViewManagers(); + } + } + } + } + + // restore the state of the window object + nsCOMPtr privWin = + do_GetInterface(NS_STATIC_CAST(nsIInterfaceRequestor*, this)); + NS_ASSERTION(privWin, "could not get nsPIDOMWindow interface"); + + nsCOMPtr windowState; + aSHEntry->GetWindowState(getter_AddRefs(windowState)); + + rv = privWin->RestoreWindowState(windowState); + NS_ENSURE_SUCCESS(rv, rv); + + aSHEntry->SetWindowState(nsnull); + + // Restore the refresh URI list. + aSHEntry->GetRefreshURIList(getter_AddRefs(mRefreshURIList)); + aSHEntry->SetRefreshURIList(nsnull); + + RefreshURIFromQueue(); + + mOSHE = aSHEntry; + EndPageLoad(nsnull, nsnull, NS_OK); + + nsCOMPtr rootSH; + GetRootSessionHistory(getter_AddRefs(rootSH)); + if (rootSH && (mLoadType & LOAD_CMD_HISTORY)) { + nsCOMPtr hist = do_QueryInterface(rootSH); + hist->UpdateIndex(); + } + + // Make sure this presentation is the same size as the previous + // presentation. If this is not the same size we showed it at last time, + // then we need to resize the widget. + + // XXXbryner This interacts poorly with Firefox's infobar. If the old + // presentation had the infobar visible, then we will resize the new + // presentation to that smaller size. However, firing the locationchanged + // event will hide the infobar, which will immediately resize the window + // back to the larger size. A future optimization might be to restore + // the presentation at the "wrong" size, then fire the locationchanged + // event and check whether the docshell's new size is the same as the + // cached viewer size (skipping the resize if they are equal). + + nsCOMPtr shell; + nsDocShell::GetPresShell(getter_AddRefs(shell)); + + if (shell) { + nsIViewManager *vm = shell->GetViewManager(); + if (vm) { + nsIView *rootView = nsnull; + vm->GetRootView(rootView); + + if (rootView) { + nsIWidget *widget = rootView->GetWidget(); + if (widget && !newBounds.IsEmpty()) { +#ifdef DEBUG_PAGE_CACHE + printf("resize widget(%d, %d, %d, %d)\n", newBounds.x, + newBounds.y, newBounds.width, newBounds.height); +#endif + + widget->Resize(newBounds.x, newBounds.y, newBounds.width, + newBounds.height, PR_FALSE); + } + } + } + } + + // Reset the security state + if (mSecurityUI) { + nsCOMPtr securityState; + aSHEntry->GetSecurityState(getter_AddRefs(securityState)); + if (securityState) + mSecurityUI->TransitionToState(securityState); + } + + SetCurrentURI(uri); + + // Dispatch events. This is a little messy. We need to avoid firing + // onload so that it is visible from the content DOM window, but we _do_ + // want the chrome to see it for chrome/extensions that look for page load. + // In addition, we need to fire DOMPageRestore on the content window. + + nsEvent event(NS_PAGE_LOAD); + nsEventStatus status = nsEventStatus_eIgnore; + + nsCOMPtr handler = privWin->GetChromeEventHandler(); + + nsCOMPtr presContext; + GetPresContext(getter_AddRefs(presContext)); + + PRUint32 flags = NS_EVENT_FLAG_INIT; + event.flags |= flags; + flags &= ~(NS_EVENT_FLAG_CANT_BUBBLE | NS_EVENT_FLAG_CANT_CANCEL); + flags |= NS_EVENT_FLAG_BUBBLE | NS_EVENT_FLAG_CAPTURE; + + nsIDOMEvent *domEvt = nsnull; + + rv = handler->HandleChromeEvent(presContext, &event, &domEvt, + flags & NS_EVENT_CAPTURE_MASK, &status); + NS_ENSURE_SUCCESS(rv, rv); + + if (domEvt) { + nsrefcnt rc; + NS_RELEASE2(domEvt, rc); + if (0 != rc) { + // Okay, so someone in the DOM loop (a listener, JS object) + // still has a ref to the DOM Event but the internal data + // hasn't been malloc'd. Force a copy of the data here so the + // DOM Event is still valid. + + nsCOMPtr privateEvent = + do_QueryInterface(domEvt); + + if (privateEvent) { + privateEvent->DuplicatePrivateData(); + } + } + } + + if (mScriptGlobal) { + nsEventStatus status = nsEventStatus_eIgnore; + nsEvent restoreEvent(NS_PAGE_RESTORE); + + nsCOMPtr presContext; + nsDocShell::GetPresContext(getter_AddRefs(presContext)); + + if (presContext) { + mScriptGlobal->HandleDOMEvent(presContext, &restoreEvent, nsnull, + NS_EVENT_FLAG_INIT, &status); + } + } + + rv = mContentViewer->Show(); + NS_ENSURE_SUCCESS(rv, rv); + + // Restart plugins + if (shell) + shell->StartPlugins(); + + // XXXbryner Making this invalidate synchronous causes unpainted areas + // (on Mac, at least) if the above locationchanged event hides Firefox's + // infobar. Doing it asynchronously seems to work around the problem, but + // shouldn't the style change that hides the infobar handle all necessary + // invalidation, including the newly-exposed area? + + return mParentWidget->Invalidate(PR_FALSE); +} + +/* static */ void +nsDocShell::DisableCaret(nsIDocShellTreeItem *aRoot) +{ + nsCOMPtr ds = do_QueryInterface(aRoot); + if (ds) { + nsCOMPtr presShell; + ds->GetPresShell(getter_AddRefs(presShell)); + if (presShell) { + nsCOMPtr caret; + presShell->GetCaret(getter_AddRefs(caret)); + + if (caret) { + caret->SetCaretVisible(PR_FALSE); + } + } + } + + nsCOMPtr node = do_QueryInterface(aRoot); + if (node) { + PRInt32 childCount = 0; + node->GetChildCount(&childCount); + + nsCOMPtr child; + for (PRInt32 i = 0; i < childCount; ++i) { + node->GetChildAt(i, getter_AddRefs(child)); + DisableCaret(child); + } + } +} + NS_IMETHODIMP nsDocShell::CreateContentViewer(const char *aContentType, nsIRequest * request, @@ -4727,7 +5208,10 @@ nsDocShell::CreateContentViewer(const ch // is changed within the DocShell - otherwise, javascript will get the // wrong information :-( // - (void) FireUnloadNotification(); + + PRBool savePresentation = CanSavePresentation(request); + if (!savePresentation) + FireUnloadNotification(); // Set mFiredUnloadEvent = PR_FALSE so that the unload handler for the // *new* document will fire. @@ -4742,6 +5226,14 @@ nsDocShell::CreateContentViewer(const ch PRBool onLocationChangeNeeded = OnLoadingSite(aOpenedChannel, PR_FALSE); + if (savePresentation) { + // The old content viewer will be saved during the call to Embed(). + rv = CaptureState(); + gSavingOldViewer = PR_TRUE; + // XXX this isn't really fatal, necessarily... + // should we try to fire unload if NS_FAILED(rv) ? + } + // let's try resetting the load group if we need to... nsCOMPtr currentLoadGroup; NS_ENSURE_SUCCESS(aOpenedChannel-> @@ -4783,6 +5275,7 @@ nsDocShell::CreateContentViewer(const ch NS_ENSURE_SUCCESS(Embed(viewer, "", (nsISupports *) nsnull), NS_ERROR_FAILURE); + gSavingOldViewer = PR_FALSE; mEODForCurrentDocument = PR_FALSE; // if this document is part of a multipart document, @@ -5005,6 +5498,7 @@ nsDocShell::SetupNewViewer(nsIContentVie // Ensure that the content viewer is destroyed *after* the GC - bug 71515 nsCOMPtr kungfuDeathGrip = mContentViewer; + nsCOMPtr oldDocument; if (mContentViewer) { // Stop any activity that may be happening in the old document before // releasing it... @@ -5030,8 +5524,17 @@ nsDocShell::SetupNewViewer(nsIContentVie } } + mContentViewer->GetDOMDocument(getter_AddRefs(oldDocument)); + mContentViewer->Close(); aNewViewer->SetPreviousViewer(mContentViewer); + + if (gSavingOldViewer) { + // Tell the old content viewer to hibernate in session history when + // it is destroyed. + mContentViewer->SetHistoryEntry(mOSHE); + } + mContentViewer = nsnull; } @@ -5572,7 +6075,7 @@ nsDocShell::InternalLoad(nsIURI * aURI, NS_ENSURE_TRUE(hEntry, NS_ERROR_FAILURE); nsCOMPtr shEntry(do_QueryInterface(hEntry)); if (shEntry) - shEntry->SetTitle(mTitle.get()); + shEntry->SetTitle(mTitle); } return NS_OK; @@ -5627,6 +6130,20 @@ nsDocShell::InternalLoad(nsIURI * aURI, // been called. mLSHE = aSHEntry; + // If we have a saved content viewer in history, restore and show it now. + if (aSHEntry) { + if (!CanSavePresentation(nsnull)) + FireUnloadNotification(); + + mFiredUnloadEvent = PR_FALSE; + + CaptureState(); + + rv = RestorePresentation(aSHEntry); + if (NS_SUCCEEDED(rv)) + return rv; + } + nsCOMPtr req; rv = DoURILoad(aURI, aReferrer, !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER), @@ -6524,12 +7041,11 @@ nsDocShell::AddToSessionHistory(nsIURI * } //Title is set in nsDocShell::SetTitle() - entry->Create(aURI, // uri - nsnull, // Title - nsnull, // DOMDocument - inputStream, // Post data stream - nsnull, // LayoutHistory state - cacheKey, // CacheKey + entry->Create(aURI, // uri + EmptyString(), // Title + inputStream, // Post data stream + nsnull, // LayoutHistory state + cacheKey, // CacheKey mContentTypeHint); // Content-type entry->SetReferrerURI(referrerURI); /* If cache got a 'no-store', ask SH not to store @@ -6560,7 +7076,6 @@ nsDocShell::AddToSessionHistory(nsIURI * if (LOAD_TYPE_HAS_FLAGS(mLoadType, LOAD_FLAGS_REPLACE_HISTORY)) { // Replace current entry in session history. PRInt32 index = 0; - nsCOMPtr hEntry; mSessionHistory->GetIndex(&index); nsCOMPtr shPrivate(do_QueryInterface(mSessionHistory)); // Replace the current entry with the new entry @@ -6605,10 +7120,8 @@ nsDocShell::LoadHistoryEntry(nsISHEntry nsCAutoString contentType; NS_ENSURE_TRUE(aEntry, NS_ERROR_FAILURE); - nsCOMPtr hEntry(do_QueryInterface(aEntry)); - NS_ENSURE_TRUE(hEntry, NS_ERROR_FAILURE); - NS_ENSURE_SUCCESS(hEntry->GetURI(getter_AddRefs(uri)), NS_ERROR_FAILURE); + NS_ENSURE_SUCCESS(aEntry->GetURI(getter_AddRefs(uri)), NS_ERROR_FAILURE); NS_ENSURE_SUCCESS(aEntry->GetReferrerURI(getter_AddRefs(referrerURI)), NS_ERROR_FAILURE); NS_ENSURE_SUCCESS(aEntry->GetPostData(getter_AddRefs(postData)), @@ -6703,9 +7216,8 @@ nsDocShell::CloneAndReplace(nsISHEntry * nsISHEntry *dest = (nsISHEntry *) nsnull; PRUint32 srcID; src->GetID(&srcID); - nsCOMPtr srcHE(do_QueryInterface(src)); - if (!src || !replaceEntry || !srcHE) + if (!src || !replaceEntry) return NS_ERROR_FAILURE; if (srcID == aCloneID) { Index: docshell/base/nsDocShell.h =================================================================== RCS file: /cvsroot/mozilla/docshell/base/nsDocShell.h,v retrieving revision 1.178 diff -u -p -r1.178 nsDocShell.h --- docshell/base/nsDocShell.h 5 Apr 2005 03:28:54 -0000 1.178 +++ docshell/base/nsDocShell.h 26 Apr 2005 18:31:45 -0000 @@ -100,6 +100,7 @@ #include "nsIHttpChannel.h" #include "nsDocShellTransferableHooks.h" #include "nsIAuthPromptProvider.h" +#include "nsISecureBrowserUI.h" /** * Load flag for error pages. This should be bigger than all flags on @@ -340,7 +341,8 @@ protected: NS_IMETHOD EnsureEditorData(); nsresult EnsureTransferableHookData(); NS_IMETHOD EnsureFind(); - NS_IMETHOD RefreshURIFromQueue(); + nsresult RefreshURIFromQueue(); + void SuspendRefreshURIs(); NS_IMETHOD DisplayLoadError(nsresult aError, nsIURI *aURI, const PRUnichar *aURL, nsIChannel* aFailedChannel = nsnull); @@ -395,6 +397,49 @@ protected: PRBool SetCurrentURI(nsIURI *aURI, nsIRequest *aRequest, PRBool aFireOnLocationChange); + // The following methods deal with saving and restoring content viewers + // in session history. + + // mContentViewer points to the current content viewer associated with + // this docshell. When loading a new document, the content viewer is + // either destroyed or stored into a session history entry. To make sure + // that destruction happens in a controlled fashion, a given content viewer + // is always owned in exactly one of these ways: + // 1) The content viewer is active and owned by a docshell's + // mContentViewer. + // 2) The content viewer is still being displayed while we begin loading + // a new document. The content viewer is owned by the _new_ + // content viewer's mPreviousViewer, and has a pointer to the + // nsISHEntry where it will eventually be stored. The content viewer + // has been close()d by the docshell, which detaches the document from + // the window object. + // 3) The content viewer is cached in session history. The nsISHEntry + // has the only owning reference to the content viewer. The viewer + // has released its nsISHEntry pointer to prevent circular ownership. + // + // When restoring a content viewer from session history, open() is called + // to reattach the document to the window object. The content viewer is + // then placed into mContentViewer and removed from the history entry. + // (mContentViewer is put into session history as described above, if + // applicable). + + // Determines whether we can safely cache the current mContentViewer in + // session history. This checks a number of factors such as cache policy, + // pending requests, and unload handlers. |aNewRequest| should be the + // request for the document to be loaded in place of the current document. + PRBool CanSavePresentation(nsIRequest *aNewRequest); + + // Captures the state of the supporting elements of the presentation + // (the "window" object, docshell tree, meta-refresh loads, and security + // state) and stores them on |mOSHE|. + nsresult CaptureState(); + + // Restores the presentation stored in |aSHEntry|. + nsresult RestorePresentation(nsISHEntry *aSHEntry); + + // Disable the caret in |aRoot| and all children. + static void DisableCaret(nsIDocShellTreeItem *aRoot); + protected: // Override the parent setter from nsDocLoader virtual nsresult SetDocLoaderParent(nsDocLoader * aLoader); @@ -474,6 +519,9 @@ protected: // Transferable hooks/callbacks nsCOMPtr mTransferableHookData; + // Secure browser UI object + nsCOMPtr mSecurityUI; + // WEAK REFERENCES BELOW HERE. // Note these are intentionally not addrefd. Doing so will create a cycle. // For that reasons don't use nsCOMPtr. Index: docshell/base/nsIContentViewer.idl =================================================================== RCS file: /cvsroot/mozilla/docshell/base/nsIContentViewer.idl,v retrieving revision 1.14 diff -u -p -r1.14 nsIContentViewer.idl --- docshell/base/nsIContentViewer.idl 15 Apr 2004 23:30:03 -0000 1.14 +++ docshell/base/nsIContentViewer.idl 26 Apr 2005 18:31:45 -0000 @@ -1,6 +1,7 @@ #include "nsISupports.idl" interface nsIDOMDocument; +interface nsISHEntry; %{ C++ @@ -13,7 +14,7 @@ struct nsRect; [ptr] native nsIDeviceContextPtr(nsIDeviceContext); [ref] native nsRectRef(nsRect); -[scriptable, uuid(70b8f22d-135c-4c94-8044-1bd3238d0990)] +[scriptable, uuid(e2c68a4d-b396-11d9-a3d1-00112478d626)] interface nsIContentViewer : nsISupports { @@ -68,4 +69,21 @@ interface nsIContentViewer : nsISupports */ boolean requestWindowClose(); + + /** + * Attach the content viewer to its DOM window and docshell. + */ + void open(); + + /** + * Set the session history entry for the content viewer. If this is set, + * then the following actions will happen when destroy() is called (*): + * - Sanitize() will be called on the viewer's document + * - The content viewer will set the contentViewer property on the + * history entry, and release its reference (ownership reversal). + * - hide() will be called, and no further destruction will happen. + * + * (*) unless the document is currently being printed + */ + void setHistoryEntry(in nsISHEntry entry); }; Index: docshell/base/nsIDocShell.idl =================================================================== RCS file: /cvsroot/mozilla/docshell/base/nsIDocShell.idl,v retrieving revision 1.77 diff -u -p -r1.77 nsIDocShell.idl --- docshell/base/nsIDocShell.idl 22 Feb 2005 19:56:10 -0000 1.77 +++ docshell/base/nsIDocShell.idl 26 Apr 2005 18:31:45 -0000 @@ -64,6 +64,7 @@ interface nsIInputStream; interface nsIRequest; interface nsISHEntry; interface nsILayoutHistoryState; +interface nsISecureBrowserUI; [scriptable, uuid(BBFDF99E-D675-42FD-B3EA-EA341C2331A6)] interface nsIDocShell : nsISupports @@ -340,5 +341,11 @@ interface nsIDocShell : nsISupports attribute nsILayoutHistoryState layoutHistoryState; readonly attribute boolean shouldSaveLayoutState; + + /** + * The SecureBrowserUI object for this docshell. This is set by XUL + * or nsWebBrowser for their root docshell. + */ + attribute nsISecureBrowserUI securityUI; }; Index: dom/public/base/nsPIDOMWindow.h =================================================================== RCS file: /cvsroot/mozilla/dom/public/base/nsPIDOMWindow.h,v retrieving revision 1.44 diff -u -p -r1.44 nsPIDOMWindow.h --- dom/public/base/nsPIDOMWindow.h 31 Jan 2005 22:49:41 -0000 1.44 +++ dom/public/base/nsPIDOMWindow.h 26 Apr 2005 18:31:45 -0000 @@ -124,6 +124,12 @@ public: return !mIsDocumentLoaded || mRunningTimeout; } + // Check whether a document is currently loading + PRBool IsLoading() const + { + return !mIsDocumentLoaded; + } + PRBool IsHandlingResizeEvent() const { return mIsHandlingResizeEvent; @@ -139,6 +145,12 @@ public: // Clear all pending timeouts and intervals. virtual void ClearAllTimeouts() = 0; + // Returns an object containing the window's state. + virtual nsresult SaveWindowState(nsISupports **aState) = 0; + + // Restore the window state from aState. + virtual nsresult RestoreWindowState(nsISupports *aState) = 0; + protected: nsPIDOMWindow() : mRunningTimeout(nsnull), mMutationBits(0), mIsDocumentLoaded(PR_FALSE), Index: dom/public/coreEvents/nsIDOMLoadListener.h =================================================================== RCS file: /cvsroot/mozilla/dom/public/coreEvents/nsIDOMLoadListener.h,v retrieving revision 1.10 diff -u -p -r1.10 nsIDOMLoadListener.h --- dom/public/coreEvents/nsIDOMLoadListener.h 17 Apr 2004 21:50:08 -0000 1.10 +++ dom/public/coreEvents/nsIDOMLoadListener.h 26 Apr 2005 18:31:45 -0000 @@ -47,9 +47,8 @@ * */ #define NS_IDOMLOADLISTENER_IID \ -{ /* d1810238-14f8-4cab-9b96-96bedb9de7be */ \ -0xd1810238, 0x14f8, 0x4cab, \ -{0x9b, 0x96, 0x96, 0xbe, 0xdb, 0x9d, 0xe7, 0xbe} } +{0x0f7fa587, 0xaac5, 0x11d9, \ +{0xba, 0x4e, 0x00, 0x11, 0x24, 0x78, 0xd6, 0x26} } class nsIDOMLoadListener : public nsIDOMEventListener { @@ -91,6 +90,13 @@ public: */ NS_IMETHOD Error(nsIDOMEvent* aEvent) = 0; + /** + * Processes a DOMPageRestore event. This is dispatched when a page's + * presentation is restored from session history (onload does not fire + * in this case). + * @param aEvent The event object + */ + NS_IMETHOD PageRestore(nsIDOMEvent* aEvent) = 0; }; #endif // nsIDOMLoadListener_h__ Index: dom/src/base/nsGlobalWindow.cpp =================================================================== RCS file: /cvsroot/mozilla/dom/src/base/nsGlobalWindow.cpp,v retrieving revision 1.731 diff -u -p -r1.731 nsGlobalWindow.cpp --- dom/src/base/nsGlobalWindow.cpp 21 Apr 2005 20:22:57 -0000 1.731 +++ dom/src/base/nsGlobalWindow.cpp 26 Apr 2005 18:31:46 -0000 @@ -153,6 +153,8 @@ #include "nsIBindingManager.h" #include "nsIXBLService.h" +#include "nsIDOMNSHTMLElement.h" +#include "nsIDOMXULElement.h" // used for popup blocking, needs to be converted to something // belonging to the back-end like nsIContentPolicy @@ -171,6 +173,10 @@ static PRInt32 gRunningTime PRInt32 gTimeoutCnt = 0; #endif +#ifdef DEBUG_bryner +#define DEBUG_PAGE_CACHE +#endif + #define DOM_MIN_TIMEOUT_VALUE 10 // 10ms // CIDs @@ -4272,10 +4278,12 @@ nsGlobalWindow::GetPrivateRoot() nsIDocument* doc = chromeElement->GetDocument(); if (doc) { parent = do_QueryInterface(doc->GetScriptGlobalObject()); - nsCOMPtr tempParent; - parent->GetTop(getter_AddRefs(tempParent)); - return NS_STATIC_CAST(nsGlobalWindow *, - NS_STATIC_CAST(nsIDOMWindow*, tempParent)); + if (parent) { + nsCOMPtr tempParent; + parent->GetTop(getter_AddRefs(tempParent)); + return NS_STATIC_CAST(nsGlobalWindow *, + NS_STATIC_CAST(nsIDOMWindow*, tempParent)); + } } } @@ -5768,6 +5776,345 @@ 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, JSObject *aObject, nsGlobalWindow *aWindow); + + JSObject* GetObject() { return mJSObj; } + nsIEventListenerManager* GetListenerManager() { return mListenerManager; } + nsIDOMElement* GetFocusedElement() { return mFocusedElement; } + nsIDOMWindowInternal* GetFocusedWindow() { return mFocusedWindow; } + nsTimeout* GetSavedTimeouts() { return mSavedTimeouts; } + nsTimeout** GetTimeoutInsertionPoint() { return mTimeoutInsertionPoint; } + void ClearSavedTimeouts() { mSavedTimeouts = nsnull; } + +private: + ~WindowStateHolder(); + + JSRuntime *mRuntime; + JSObject *mJSObj; + nsCOMPtr mListenerManager; + nsCOMPtr mFocusedElement; + nsCOMPtr mFocusedWindow; + nsTimeout *mSavedTimeouts; + nsTimeout **mTimeoutInsertionPoint; +}; + +WindowStateHolder::WindowStateHolder(JSContext *cx, JSObject *aObject, + nsGlobalWindow *aWindow) + : mRuntime(::JS_GetRuntime(cx)), mJSObj(aObject), mSavedTimeouts(nsnull) +{ + NS_ASSERTION(aWindow, "null window"); + + aWindow->GetListenerManager(getter_AddRefs(mListenerManager)); + + nsIFocusController *fc = aWindow->GetRootFocusController(); + NS_ASSERTION(fc, "null focus controller"); + + // We want to save the focused element/window only if they are inside of + // this window. + + nsCOMPtr focusWinInternal; + fc->GetFocusedWindow(getter_AddRefs(focusWinInternal)); + + nsPIDOMWindow *focusedWindow = + NS_STATIC_CAST(nsPIDOMWindow*, + NS_STATIC_CAST(nsGlobalWindow*, + NS_STATIC_CAST(nsIDOMWindowInternal*, + focusWinInternal))); + + while (focusedWindow) { + if (focusedWindow == aWindow) { + fc->GetFocusedWindow(getter_AddRefs(mFocusedWindow)); + fc->GetFocusedElement(getter_AddRefs(mFocusedElement)); + break; + } + + focusedWindow = + NS_STATIC_CAST(nsGlobalWindow*, 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; + + ::JS_AddNamedRoot(cx, &mJSObj, "WindowStateHolder::mJSObj"); +} + +WindowStateHolder::~WindowStateHolder() +{ + ::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; + jsint i; + for (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 window property\n"); + continue; + } + + JSString *propname = JSVAL_TO_STRING(propname_value); + jschar *propname_str = ::JS_GetStringChars(propname); + NS_ENSURE_TRUE(propname_str, NS_ERROR_FAILURE); + + 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; + + if (!found) + continue; + + jsval propvalue; + if (!::JS_GetUCProperty(cx, aSource, propname_str, + propname_len, &propvalue)) { + NS_ERROR("property was found, but get failed"); + 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", propname_str); +#endif + + if (!res) { +#ifdef DEBUG + printf("failed to copy property: %s\n", propname_str); +#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) { +#ifdef DEBUG_PAGE_CACHE + printf("[no properties]\n"); +#endif + return NS_OK; + } + +#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) +{ + *aState = nsnull; + + if (!mContext || !mJSObject) { + // The window may be getting torn down; don't bother saving state. + return NS_OK; + } + + JSContext *cx = NS_STATIC_CAST(JSContext*, mContext->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); + +#ifdef DEBUG_PAGE_CACHE + printf("saving window state, stateObj = %p\n", stateObj); +#endif + nsresult rv = CopyJSProperties(cx, mJSObject, stateObj); + NS_ENSURE_SUCCESS(rv, rv); + + *aState = new WindowStateHolder(cx, stateObj, this); + NS_ENSURE_TRUE(*aState, NS_ERROR_OUT_OF_MEMORY); + + NS_ADDREF(*aState); + return NS_OK; +} + +nsresult +nsGlobalWindow::RestoreWindowState(nsISupports *aState) +{ + if (!mContext || !mJSObject) { + // The window may be getting torn down; don't bother restoring state. + return NS_OK; + } + + JSContext *cx = NS_STATIC_CAST(JSContext*, mContext->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 will remove the + // XPConnect properties. + + nsCOMPtr holder = do_QueryInterface(aState); + if (holder) { +#ifdef DEBUG_PAGE_CACHE + printf("restoring window state, stateObj = %p\n", holder->GetObject()); +#endif + nsresult rv = CopyJSProperties(cx, holder->GetObject(), mJSObject); + NS_ENSURE_SUCCESS(rv, rv); + + mListenerManager = holder->GetListenerManager(); + + nsIDOMElement *focusedElement = holder->GetFocusedElement(); + if (focusedElement) { + nsCOMPtr htmlElement = + do_QueryInterface(focusedElement); + if (htmlElement) { + htmlElement->Focus(); + } else { + nsCOMPtr xulElement = + do_QueryInterface(focusedElement); + if (xulElement) { + xulElement->Focus(); + } + } + } else { + nsIDOMWindowInternal *focusedWindow = holder->GetFocusedWindow(); + if (focusedWindow) { + focusedWindow->Focus(); + } + } + } + + mTimeouts = holder->GetSavedTimeouts(); + mTimeoutInsertionPoint = holder->GetTimeoutInsertionPoint(); + + holder->ClearSavedTimeouts(); + + return ResumeTimeouts(); +} + +void +nsGlobalWindow::SuspendTimeouts() +{ + PRInt64 now = PR_IntervalNow(); + for (nsTimeout *t = mTimeouts; t; t = t->mNext) { + // Change mWhen to be the time remaining for this timer. + t->mWhen = PR_MAX(0, t->mWhen - now); + + // Drop the XPCOM timer; we'll reschedule when restoring the state. + if (t->mTimer) { + t->mTimer->Cancel(); + t->mTimer = nsnull; + } + + // We don't Release() the timeout because we still need it. + } + + // Suspend our children as well. + nsCOMPtr node = do_QueryInterface(mDocShell); + if (node) { + PRInt32 childCount = 0; + node->GetChildCount(&childCount); + + nsCOMPtr childShell; + for (PRInt32 i = 0; i < childCount; ++i) { + node->GetChildAt(i, getter_AddRefs(childShell)); + NS_ASSERTION(childShell, "null child shell"); + + nsCOMPtr pWin = do_GetInterface(childShell); + if (pWin) { + nsGlobalWindow *win = + NS_STATIC_CAST(nsGlobalWindow*, + NS_STATIC_CAST(nsPIDOMWindow*, pWin)); + + win->SuspendTimeouts(); + } + } + } +} + +nsresult +nsGlobalWindow::ResumeTimeouts() +{ + // Restore all of the timeouts, using the stored time remaining. + + PRInt64 now = PR_IntervalNow(); + nsresult rv; + + for (nsTimeout *t = mTimeouts; t; t = t->mNext) { + PRInt32 interval = PR_MAX(t->mWhen, DOM_MIN_TIMEOUT_VALUE); + t->mWhen += now; + + t->mTimer = do_CreateInstance("@mozilla.org/timer;1"); + NS_ENSURE_TRUE(t->mTimer, NS_ERROR_OUT_OF_MEMORY); + + rv = t->mTimer->InitWithFuncCallback(TimerCallback, t, interval, + nsITimer::TYPE_ONE_SHOT); + NS_ENSURE_SUCCESS(rv, rv); + } + + // Resume our children as well. + nsCOMPtr node = do_QueryInterface(mDocShell); + if (node) { + PRInt32 childCount = 0; + node->GetChildCount(&childCount); + + nsCOMPtr childShell; + for (PRInt32 i = 0; i < childCount; ++i) { + node->GetChildAt(i, getter_AddRefs(childShell)); + NS_ASSERTION(childShell, "null child shell"); + + nsCOMPtr pWin = do_GetInterface(childShell); + if (pWin) { + nsGlobalWindow *win = + NS_STATIC_CAST(nsGlobalWindow*, + NS_STATIC_CAST(nsPIDOMWindow*, pWin)); + + rv = win->ResumeTimeouts(); + NS_ENSURE_SUCCESS(rv, rv); + } + } + } + + return NS_OK; +} + // QueryInterface implementation for nsGlobalChromeWindow NS_INTERFACE_MAP_BEGIN(nsGlobalChromeWindow) NS_INTERFACE_MAP_ENTRY(nsIDOMChromeWindow) Index: dom/src/base/nsGlobalWindow.h =================================================================== RCS file: /cvsroot/mozilla/dom/src/base/nsGlobalWindow.h,v retrieving revision 1.242 diff -u -p -r1.242 nsGlobalWindow.h --- dom/src/base/nsGlobalWindow.h 6 Mar 2005 18:43:07 -0000 1.242 +++ dom/src/base/nsGlobalWindow.h 26 Apr 2005 18:31:47 -0000 @@ -199,7 +199,11 @@ public: virtual NS_HIDDEN_(OpenAllowValue) GetOpenAllow(const nsAString &aName); virtual NS_HIDDEN_(void) ClearAllTimeouts(); - + virtual NS_HIDDEN_(nsresult) SaveWindowState(nsISupports **aState); + virtual NS_HIDDEN_(nsresult) RestoreWindowState(nsISupports *aState); + virtual NS_HIDDEN_(void) SuspendTimeouts(); + virtual NS_HIDDEN_(nsresult) ResumeTimeouts(); + // nsIDOMViewCSS NS_DECL_NSIDOMVIEWCSS @@ -215,6 +219,8 @@ public: static void ShutDown(); static PRBool IsCallerChrome(); + friend class WindowStateHolder; + protected: // Object Management virtual ~nsGlobalWindow(); Index: embedding/browser/cocoa/src/CHClickListener.mm =================================================================== RCS file: /cvsroot/mozilla/embedding/browser/cocoa/src/CHClickListener.mm,v retrieving revision 1.9 diff -u -p -r1.9 CHClickListener.mm --- embedding/browser/cocoa/src/CHClickListener.mm 4 Mar 2005 02:01:52 -0000 1.9 +++ embedding/browser/cocoa/src/CHClickListener.mm 26 Apr 2005 18:31:47 -0000 @@ -203,28 +203,30 @@ CHClickListener::MouseDown(nsIDOMEvent* nsCOMPtr sgo; doc->GetScriptGlobalObject(getter_AddRefs(sgo)); nsCOMPtr window = do_QueryInterface(sgo); - PRInt32 scrollX, scrollY; - window->GetScrollX(&scrollX); - window->GetScrollY(&scrollY); - xDelta += scrollX; // Normal direction. - yDelta -= scrollY; // Remember, y is flipped. + if (window) { + PRInt32 scrollX, scrollY; + window->GetScrollX(&scrollX); + window->GetScrollY(&scrollY); + xDelta += scrollX; // Normal direction. + yDelta -= scrollY; // Remember, y is flipped. #define XMENUOFFSET 20 #define MENUHEIGHT 20 - xDelta += XMENUOFFSET; - yDelta -= MENUHEIGHT*(selIndex+1); + xDelta += XMENUOFFSET; + yDelta -= MENUHEIGHT*(selIndex+1); - NSEvent* event = [NSApp currentEvent]; - NSPoint point = [event locationInWindow]; - point.x -= xDelta; - point.y -= yDelta; + NSEvent* event = [NSApp currentEvent]; + NSPoint point = [event locationInWindow]; + point.x -= xDelta; + point.y -= yDelta; - NSEvent* mouseEvent = [NSEvent mouseEventWithType: NSLeftMouseDown location: point - modifierFlags: 0 timestamp: [event timestamp] - windowNumber: [event windowNumber] context: [event context] - eventNumber: [event eventNumber] clickCount: [event clickCount] pressure: [event pressure]]; - [NSMenu popUpContextMenu: menu withEvent: mouseEvent forView: [[event window] contentView]]; + NSEvent* mouseEvent = [NSEvent mouseEventWithType: NSLeftMouseDown location: point + modifierFlags: 0 timestamp: [event timestamp] + windowNumber: [event windowNumber] context: [event context] + eventNumber: [event eventNumber] clickCount: [event clickCount] pressure: [event pressure]]; + [NSMenu popUpContextMenu: menu withEvent: mouseEvent forView: [[event window] contentView]]; + } } return NS_OK; } Index: embedding/browser/webBrowser/nsWebBrowser.cpp =================================================================== RCS file: /cvsroot/mozilla/embedding/browser/webBrowser/nsWebBrowser.cpp,v retrieving revision 1.151 diff -u -p -r1.151 nsWebBrowser.cpp --- embedding/browser/webBrowser/nsWebBrowser.cpp 10 Apr 2005 12:37:35 -0000 1.151 +++ embedding/browser/webBrowser/nsWebBrowser.cpp 26 Apr 2005 18:31:48 -0000 @@ -1215,8 +1215,9 @@ NS_IMETHODIMP nsWebBrowser::Create() rv = GetContentDOMWindow(getter_AddRefs(domWindow)); if (NS_SUCCEEDED(rv)) { - mSecurityUI = do_CreateInstance(NS_SECURE_BROWSER_UI_CONTRACTID, &rv); - if (NS_SUCCEEDED(rv))mSecurityUI->Init(domWindow); + nsCOMPtr securityUI = + do_CreateInstance(NS_SECURE_BROWSER_UI_CONTRACTID, &rv); + if (NS_SUCCEEDED(rv)) securityUI->Init(domWindow); } mDocShellTreeOwner->AddToWatcher(); // evil twin of Remove in SetDocShell(0) Index: embedding/browser/webBrowser/nsWebBrowser.h =================================================================== RCS file: /cvsroot/mozilla/embedding/browser/webBrowser/nsWebBrowser.h,v retrieving revision 1.48 diff -u -p -r1.48 nsWebBrowser.h --- embedding/browser/webBrowser/nsWebBrowser.h 10 Apr 2005 12:37:35 -0000 1.48 +++ embedding/browser/webBrowser/nsWebBrowser.h 26 Apr 2005 18:31:48 -0000 @@ -168,7 +168,6 @@ protected: nativeWindow mParentNativeWindow; nsIWebProgressListener *mProgressListener; nsCOMPtr mWebProgress; - nsCOMPtr mSecurityUI; nsCOMPtr mPrintSettings; Index: embedding/tests/mfcembed/StdAfx.h =================================================================== RCS file: /cvsroot/mozilla/embedding/tests/mfcembed/StdAfx.h,v retrieving revision 1.27 diff -u -p -r1.27 StdAfx.h --- embedding/tests/mfcembed/StdAfx.h 25 Oct 2004 19:34:42 -0000 1.27 +++ embedding/tests/mfcembed/StdAfx.h 26 Apr 2005 18:31:53 -0000 @@ -115,6 +115,7 @@ #include "nsIEmbeddingSiteWindow2.h" #include "nsIWebBrowserFind.h" #include "nsIWebBrowserFocus.h" +#include "nsIURI.h" // Printer Includes #include "nsIWebBrowserPrint.h" Index: extensions/xmlextras/base/src/nsDOMParser.cpp =================================================================== RCS file: /cvsroot/mozilla/extensions/xmlextras/base/src/nsDOMParser.cpp,v retrieving revision 1.41 diff -u -p -r1.41 nsDOMParser.cpp --- extensions/xmlextras/base/src/nsDOMParser.cpp 30 Mar 2005 04:18:08 -0000 1.41 +++ extensions/xmlextras/base/src/nsDOMParser.cpp 26 Apr 2005 18:31:54 -0000 @@ -333,6 +333,12 @@ nsDOMParser::Error(nsIDOMEvent* aEvent) return NS_OK; } +NS_IMETHODIMP +nsDOMParser::PageRestore(nsIDOMEvent* aEvent) +{ + return NS_OK; +} + nsDOMParser::nsDOMParser() : mLoopingForSyncLoad(PR_FALSE) { Index: extensions/xmlextras/base/src/nsDOMParser.h =================================================================== RCS file: /cvsroot/mozilla/extensions/xmlextras/base/src/nsDOMParser.h,v retrieving revision 1.11 diff -u -p -r1.11 nsDOMParser.h --- extensions/xmlextras/base/src/nsDOMParser.h 18 Apr 2004 22:14:13 -0000 1.11 +++ extensions/xmlextras/base/src/nsDOMParser.h 26 Apr 2005 18:31:54 -0000 @@ -67,6 +67,7 @@ public: NS_IMETHOD Unload(nsIDOMEvent* aEvent); NS_IMETHOD Abort(nsIDOMEvent* aEvent); NS_IMETHOD Error(nsIDOMEvent* aEvent); + NS_IMETHOD PageRestore(nsIDOMEvent* aEvent); private: nsCOMPtr mBaseURI; Index: extensions/xmlextras/base/src/nsLoadListenerProxy.cpp =================================================================== RCS file: /cvsroot/mozilla/extensions/xmlextras/base/src/nsLoadListenerProxy.cpp,v retrieving revision 1.8 diff -u -p -r1.8 nsLoadListenerProxy.cpp --- extensions/xmlextras/base/src/nsLoadListenerProxy.cpp 18 Apr 2004 22:14:13 -0000 1.8 +++ extensions/xmlextras/base/src/nsLoadListenerProxy.cpp 26 Apr 2005 18:31:54 -0000 @@ -121,3 +121,15 @@ nsLoadListenerProxy::Error(nsIDOMEvent* return NS_OK; } + +NS_IMETHODIMP +nsLoadListenerProxy::PageRestore(nsIDOMEvent* aEvent) +{ + nsCOMPtr listener(do_QueryReferent(mParent)); + + if (listener) { + return listener->PageRestore(aEvent); + } + + return NS_OK; +} Index: extensions/xmlextras/base/src/nsLoadListenerProxy.h =================================================================== RCS file: /cvsroot/mozilla/extensions/xmlextras/base/src/nsLoadListenerProxy.h,v retrieving revision 1.6 diff -u -p -r1.6 nsLoadListenerProxy.h --- extensions/xmlextras/base/src/nsLoadListenerProxy.h 18 Apr 2004 22:14:13 -0000 1.6 +++ extensions/xmlextras/base/src/nsLoadListenerProxy.h 26 Apr 2005 18:31:54 -0000 @@ -69,6 +69,7 @@ public: NS_IMETHOD Unload(nsIDOMEvent* aEvent); NS_IMETHOD Abort(nsIDOMEvent* aEvent); NS_IMETHOD Error(nsIDOMEvent* aEvent); + NS_IMETHOD PageRestore(nsIDOMEvent* aEvent); protected: nsWeakPtr mParent; Index: extensions/xmlextras/base/src/nsXMLHttpRequest.cpp =================================================================== RCS file: /cvsroot/mozilla/extensions/xmlextras/base/src/nsXMLHttpRequest.cpp,v retrieving revision 1.125 diff -u -p -r1.125 nsXMLHttpRequest.cpp --- extensions/xmlextras/base/src/nsXMLHttpRequest.cpp 14 Mar 2005 22:15:05 -0000 1.125 +++ extensions/xmlextras/base/src/nsXMLHttpRequest.cpp 26 Apr 2005 18:31:54 -0000 @@ -1731,6 +1731,12 @@ nsXMLHttpRequest::Error(nsIDOMEvent* aEv return NS_OK; } +NS_IMETHODIMP +nsXMLHttpRequest::PageRestore(nsIDOMEvent* aEvent) +{ + return NS_OK; +} + nsresult nsXMLHttpRequest::ChangeState(PRUint32 aState, PRBool aBroadcast, PRBool aClearEventListeners) Index: extensions/xmlextras/base/src/nsXMLHttpRequest.h =================================================================== RCS file: /cvsroot/mozilla/extensions/xmlextras/base/src/nsXMLHttpRequest.h,v retrieving revision 1.48 diff -u -p -r1.48 nsXMLHttpRequest.h --- extensions/xmlextras/base/src/nsXMLHttpRequest.h 7 Mar 2005 19:46:03 -0000 1.48 +++ extensions/xmlextras/base/src/nsXMLHttpRequest.h 26 Apr 2005 18:31:54 -0000 @@ -97,6 +97,7 @@ public: NS_IMETHOD Unload(nsIDOMEvent* aEvent); NS_IMETHOD Abort(nsIDOMEvent* aEvent); NS_IMETHOD Error(nsIDOMEvent* aEvent); + NS_IMETHOD PageRestore(nsIDOMEvent* aEvent); // nsIStreamListener NS_DECL_NSISTREAMLISTENER Index: extensions/xmlextras/tests/TestXMLExtras.cpp =================================================================== RCS file: /cvsroot/mozilla/extensions/xmlextras/tests/TestXMLExtras.cpp,v retrieving revision 1.21 diff -u -p -r1.21 TestXMLExtras.cpp --- extensions/xmlextras/tests/TestXMLExtras.cpp 27 Feb 2005 19:34:10 -0000 1.21 +++ extensions/xmlextras/tests/TestXMLExtras.cpp 26 Apr 2005 18:31:54 -0000 @@ -78,6 +78,7 @@ public: virtual nsresult Unload(nsIDOMEvent* aEvent) {printf("Unload\n"); return NS_OK;} virtual nsresult Abort(nsIDOMEvent* aEvent) {printf("Abort\n"); return NS_OK;} virtual nsresult Error(nsIDOMEvent* aEvent) {printf("Error\n"); return NS_OK;} + NS_IMETHOD PageRestore(nsIDOMEvent* aEvent) {printf("PageRestore\n"); return NS_OK;} }; NS_IMPL_ADDREF(nsMyListener) Index: layout/base/Makefile.in =================================================================== RCS file: /cvsroot/mozilla/layout/base/Makefile.in,v retrieving revision 1.20 diff -u -p -r1.20 Makefile.in --- layout/base/Makefile.in 1 Apr 2005 23:06:59 -0000 1.20 +++ layout/base/Makefile.in 26 Apr 2005 18:31:56 -0000 @@ -73,6 +73,7 @@ REQUIRES = xpcom \ util \ windowwatcher \ accessibility \ + shistory \ $(NULL) XPIDLSRCS = \ Index: layout/base/nsDocumentViewer.cpp =================================================================== RCS file: /cvsroot/mozilla/layout/base/nsDocumentViewer.cpp,v retrieving revision 1.420 diff -u -p -r1.420 nsDocumentViewer.cpp --- layout/base/nsDocumentViewer.cpp 7 Apr 2005 04:04:05 -0000 1.420 +++ layout/base/nsDocumentViewer.cpp 26 Apr 2005 18:31:57 -0000 @@ -148,7 +148,6 @@ #include "nsISupportsPrimitives.h" // PrintOptions is now implemented by PrintSettingsService -static const char sPrintSettingsServiceContractID[] = "@mozilla.org/gfx/printsettings-service;1"; static const char sPrintOptionsContractID[] = "@mozilla.org/gfx/printsettings-service;1"; // Printing Events @@ -189,6 +188,7 @@ static const char sPrintOptionsContractI #include "nsISelectionController.h" #include "nsBidiUtils.h" +#include "nsISHEntry.h" //paint forcing #include "prenv.h" @@ -346,7 +346,6 @@ protected: virtual ~DocumentViewerImpl(); private: - void ForceRefresh(void); nsresult MakeWindow(nsIWidget* aParentWidget, const nsRect& aBounds); nsresult InitInternal(nsIWidget* aParentWidget, @@ -398,30 +397,37 @@ protected: nsCOMPtr mFocusListener; nsCOMPtr mPreviousViewer; - - PRPackedBool mEnableRendering; - PRPackedBool mStopped; - PRPackedBool mLoaded; - PRPackedBool mDeferredWindowClose; - PRInt16 mNumURLStarts; - PRInt16 mDestroyRefCount; // a second "refcount" for the document viewer's "destroy" + nsCOMPtr mSHEntry; nsIWidget* mParentWidget; // purposely won't be ref counted - PRPackedBool mInPermitUnload; + PRInt16 mNumURLStarts; + PRInt16 mDestroyRefCount; // a second "refcount" for the document viewer's "destroy" + + unsigned mEnableRendering : 1; + unsigned mStopped : 1; + unsigned mLoaded : 1; + unsigned mDeferredWindowClose : 1; + // document management data + // these items are specific to markup documents (html and xml) + // may consider splitting these out into a subclass + unsigned mIsSticky : 1; + unsigned mInPermitUnload : 1; #ifdef NS_PRINTING - PRPackedBool mClosingWhilePrinting; - nsPrintEngine* mPrintEngine; - nsCOMPtr mDialogParentWin; + unsigned mClosingWhilePrinting : 1; + #if NS_PRINT_PREVIEW - // These data member support delayed printing when the document is loading + // These data members support delayed printing when the document is loading + unsigned mPrintIsPending : 1; + unsigned mPrintDocIsFullyLoaded : 1; nsCOMPtr mCachedPrintSettings; nsCOMPtr mCachedPrintWebProgressListner; - PRPackedBool mPrintIsPending; - PRPackedBool mPrintDocIsFullyLoaded; #endif // NS_PRINT_PREVIEW + nsPrintEngine* mPrintEngine; + nsCOMPtr mDialogParentWin; + #ifdef NS_DEBUG FILE* mDebugFile; #endif // NS_DEBUG @@ -434,10 +440,6 @@ protected: nsCString mForceCharacterSet; nsCString mPrevDocCharacterSet; - // document management data - // these items are specific to markup documents (html and xml) - // may consider splitting these out into a subclass - PRPackedBool mIsSticky; }; @@ -494,8 +496,8 @@ void DocumentViewerImpl::PrepareToStartL // Note: operator new zeros our memory, so no need to init things to null. DocumentViewerImpl::DocumentViewerImpl(nsPresContext* aPresContext) : mPresContext(aPresContext), - mHintCharsetSource(kCharsetUninitialized), - mIsSticky(PR_TRUE) + mIsSticky(PR_TRUE), + mHintCharsetSource(kCharsetUninitialized) { PrepareToStartLoad(); } @@ -795,19 +797,19 @@ DocumentViewerImpl::InitInternal(nsIWidg makeCX = PR_TRUE; #endif } - } - if (aDoCreation && mPresContext) { - // Create the ViewManager and Root View... + if (mPresContext) { + // Create the ViewManager and Root View... - // We must do this before we tell the script global object about - // this new document since doing that will cause us to re-enter - // into nsSubDocumentFrame code through reflows caused by - // FlushPendingNotifications() calls down the road... + // We must do this before we tell the script global object about + // this new document since doing that will cause us to re-enter + // into nsSubDocumentFrame code through reflows caused by + // FlushPendingNotifications() calls down the road... - rv = MakeWindow(aParentWidget, aBounds); - NS_ENSURE_SUCCESS(rv, rv); - Hide(); + rv = MakeWindow(aParentWidget, aBounds); + NS_ENSURE_SUCCESS(rv, rv); + Hide(); + } } nsCOMPtr requestor(do_QueryInterface(mContainer)); @@ -1171,6 +1173,25 @@ DocumentViewerImpl::Unload() } NS_IMETHODIMP +DocumentViewerImpl::Open() +{ + NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED); + + nsRect bounds; + mWindow->GetBounds(bounds); + + nsresult rv = InitInternal(mParentWidget, mDeviceContext, bounds, + PR_FALSE, PR_FALSE); + NS_ENSURE_SUCCESS(rv, rv); + + SyncParentSubDocMap(); + + // XXX re-enable image animations once that works correctly + + return NS_OK; +} + +NS_IMETHODIMP DocumentViewerImpl::Close() { // All callers are supposed to call close to break circular @@ -1184,66 +1205,60 @@ DocumentViewerImpl::Close() // for an object that can be switched in and out so that we don't need // to disable scripts during paint suppression. - if (mDocument) { + if (!mDocument) + return NS_OK; + #if defined(NS_PRINTING) && defined(NS_PRINT_PREVIEW) - // Turn scripting back on - // after PrintPreview had turned it off - if (GetIsPrintPreview() && mPrintEngine) { - mPrintEngine->TurnScriptingOn(PR_TRUE); - } + // Turn scripting back on + // after PrintPreview had turned it off + if (GetIsPrintPreview() && mPrintEngine) { + mPrintEngine->TurnScriptingOn(PR_TRUE); + } #endif - // Break global object circular reference on the document created - // in the DocViewer Init - nsIScriptGlobalObject* globalObject = mDocument->GetScriptGlobalObject(); - - if (globalObject) { - globalObject->SetNewDocument(nsnull, PR_TRUE, PR_TRUE); - } + // Break global object circular reference on the document created + // in the DocViewer Init + nsIScriptGlobalObject* globalObject = mDocument->GetScriptGlobalObject(); + + if (globalObject) { + globalObject->SetNewDocument(nsnull, PR_TRUE, PR_TRUE); + } #ifdef NS_PRINTING - // A Close was called while we were printing - // so don't clear the ScriptGlobalObject - // or clear the mDocument below - // Also, do an extra addref to keep the viewer from going away. - if (mPrintEngine && !mClosingWhilePrinting) { - mClosingWhilePrinting = PR_TRUE; - NS_ADDREF_THIS(); - } else { - // out of band cleanup of webshell - mDocument->SetScriptGlobalObject(nsnull); - } -#else + // A Close was called while we were printing + // so don't clear the ScriptGlobalObject + // or clear the mDocument below + // Also, do an extra addref to keep the viewer from going away. + if (mPrintEngine && !mClosingWhilePrinting) { + mClosingWhilePrinting = PR_TRUE; + NS_ADDREF_THIS(); + } else { + // out of band cleanup of webshell mDocument->SetScriptGlobalObject(nsnull); + } +#else + mDocument->SetScriptGlobalObject(nsnull); #endif - if (mFocusListener) { - // get the DOM event receiver - nsCOMPtr erP(do_QueryInterface(mDocument)); - NS_WARN_IF_FALSE(erP, "No event receiver in document!"); + if (mFocusListener) { + // get the DOM event receiver + nsCOMPtr erP(do_QueryInterface(mDocument)); + NS_WARN_IF_FALSE(erP, "No event receiver in document!"); - if (erP) { - erP->RemoveEventListenerByIID(mFocusListener, - NS_GET_IID(nsIDOMFocusListener)); - } + if (erP) { + erP->RemoveEventListenerByIID(mFocusListener, + NS_GET_IID(nsIDOMFocusListener)); } } -#ifdef NS_PRINTING - // Don't clear the document if we are printing. - if (!mClosingWhilePrinting) { - mDocument = nsnull; - } -#else - mDocument = nsnull; -#endif - return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::Destroy() { + NS_ASSERTION(mDocument, "No document in Destroy()!"); + #ifdef NS_PRINTING // Here is where we check to see if the docment was still being prepared // for printing when it was asked to be destroy from someone externally @@ -1258,13 +1273,61 @@ DocumentViewerImpl::Destroy() } #endif - // Don't let the document get unloaded while we are printing - // this could happen if we hit the back button during printing + // Don't let the document get unloaded while we are printing. + // this could happen if we hit the back button during printing. + // We also keep the viewer from being cached in session history, since + // we require all documents there to be sanitized. if (mDestroyRefCount != 0) { --mDestroyRefCount; return NS_OK; } + // If we were told to put ourselves into session history instead of destroy + // the presentation, do that now. + if (mSHEntry) { + if (mPresShell) + mPresShell->StopPlugins(); + + // Make sure the presentation isn't torn down by Hide(). + mSHEntry->SetSticky(mIsSticky); + mIsSticky = PR_TRUE; + + mSHEntry->SetContentViewer(this); + + // Remove our root view from the view hierarchy. + if (mPresShell) { + nsIViewManager *vm = mPresShell->GetViewManager(); + if (vm) { + nsIView *rootView = nsnull; + vm->GetRootView(rootView); + + if (rootView) { + nsIView *rootViewParent = rootView->GetParent(); + if (rootViewParent) { + nsIViewManager *parentVM = rootViewParent->GetViewManager(); + if (parentVM) { + parentVM->RemoveChild(rootView); + } + } + } + } + + mPresShell->InvalidateViewManagers(); + } + + mSHEntry = nsnull; + + Hide(); + + // This is after Hide() so that the user doesn't see the inputs clear. + if (mDocument) + mDocument->Sanitize(); + + return NS_OK; + } + + mDocument = nsnull; + // All callers are supposed to call destroy to break circular // references. If we do this stuff in the destructor, the // destructor might never be called (especially if we're being @@ -1323,8 +1386,9 @@ DocumentViewerImpl::Stop(void) mDocument->StopDocumentLoad(); } - if (mEnableRendering && (mLoaded || mStopped) && mPresContext) + if (mEnableRendering && (mLoaded || mStopped) && mPresContext) { mPresContext->SetImageAnimationMode(imgIContainer::kDontAnimMode); + } mStopped = PR_TRUE; @@ -1669,7 +1733,6 @@ DocumentViewerImpl::Hide(void) return NS_OK; } - NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); NS_PRECONDITION(mWindow, "null window"); if (mWindow) { mWindow->Show(PR_FALSE); @@ -1787,6 +1850,13 @@ DocumentViewerImpl::SetSticky(PRBool aSt } NS_IMETHODIMP +DocumentViewerImpl::SetHistoryEntry(nsISHEntry *aEntry) +{ + mSHEntry = aEntry; + return NS_OK; +} + +NS_IMETHODIMP DocumentViewerImpl::GetEnableRendering(PRBool* aResult) { NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); @@ -1811,13 +1881,6 @@ DocumentViewerImpl::RequestWindowClose(P return NS_OK; } - -void -DocumentViewerImpl::ForceRefresh() -{ - mWindow->Invalidate(PR_TRUE); -} - NS_DEFINE_CID(kCSSLoaderCID, NS_CSS_LOADER_CID); PR_STATIC_CALLBACK(PRBool) Index: layout/base/nsIDocumentViewer.h =================================================================== RCS file: /cvsroot/mozilla/layout/base/nsIDocumentViewer.h,v retrieving revision 1.11 diff -u -p -r1.11 nsIDocumentViewer.h --- layout/base/nsIDocumentViewer.h 8 Dec 2004 19:39:48 -0000 1.11 +++ layout/base/nsIDocumentViewer.h 26 Apr 2005 18:31:57 -0000 @@ -45,7 +45,7 @@ class nsIPresShell; class nsIStyleSheet; #define NS_IDOCUMENT_VIEWER_IID \ - { 0xa6cf9057, 0x15b3, 0x11d2,{0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}} + { 0x09ad1126, 0xb397, 0x11d9,{0xa5, 0x2c, 0x00, 0x11, 0x24, 0x78, 0xd6, 0x26}} /** * A document viewer is a kind of content viewer that uses NGLayout Index: layout/base/nsIPresShell.h =================================================================== RCS file: /cvsroot/mozilla/layout/base/nsIPresShell.h,v retrieving revision 3.153 diff -u -p -r3.153 nsIPresShell.h --- layout/base/nsIPresShell.h 8 Feb 2005 00:59:50 -0000 3.153 +++ layout/base/nsIPresShell.h 26 Apr 2005 18:31:57 -0000 @@ -89,8 +89,8 @@ class nsIStyleSheet; class nsCSSFrameConstructor; #define NS_IPRESSHELL_IID \ -{ 0x3b864134, 0x4e25, 0x4cd0, \ - {0xa6, 0x9e, 0x34, 0x14, 0x13, 0x18, 0x39, 0x58} } +{ 0x3861ee48, 0xb397, 0x11d9, \ + {0x86, 0x9e, 0x00, 0x11, 0x24, 0x78, 0xd6, 0x26} } // Constants uses for ScrollFrameIntoView() function #define NS_PRESSHELL_SCROLL_TOP 0 @@ -677,6 +677,22 @@ public: virtual void ListStyleSheets(FILE *out, PRInt32 aIndent = 0) = 0; #endif + /** + * Start all plugins in this shell. + */ + virtual void StartPlugins() = 0; + + /** + * Stop all plugins in this shell. + */ + virtual void StopPlugins() = 0; + + /** + * Call InvalidateHierarchy() on our view manager and the view manager + * of any child documents, recursively. + */ + virtual void InvalidateViewManagers() = 0; + protected: // IMPORTANT: The ownership implicit in the following member variables // has been explicitly checked. If you add any members to this class, Index: layout/base/nsLayoutAtomList.h =================================================================== RCS file: /cvsroot/mozilla/layout/base/nsLayoutAtomList.h,v retrieving revision 1.95 diff -u -p -r1.95 nsLayoutAtomList.h --- layout/base/nsLayoutAtomList.h 1 Apr 2005 19:56:08 -0000 1.95 +++ layout/base/nsLayoutAtomList.h 26 Apr 2005 18:31:57 -0000 @@ -164,6 +164,7 @@ LAYOUT_ATOM(oncontextmenu, "oncontextmen LAYOUT_ATOM(onDOMActivate, "onDOMActivate") LAYOUT_ATOM(onDOMFocusIn, "onDOMFocusIn") LAYOUT_ATOM(onDOMFocusOut, "onDOMFocusOut") +LAYOUT_ATOM(onDOMPageRestore, "onDOMPageRestore") LAYOUT_ATOM(ondblclick, "ondblclick") LAYOUT_ATOM(ondragdrop, "ondragdrop") LAYOUT_ATOM(ondragenter, "ondragenter") Index: layout/base/nsPresShell.cpp =================================================================== RCS file: /cvsroot/mozilla/layout/base/nsPresShell.cpp,v retrieving revision 3.833 diff -u -p -r3.833 nsPresShell.cpp --- layout/base/nsPresShell.cpp 14 Apr 2005 22:41:51 -0000 3.833 +++ layout/base/nsPresShell.cpp 26 Apr 2005 18:32:01 -0000 @@ -151,6 +151,9 @@ #include "nsIDOMWindowInternal.h" #include "nsPIDOMWindow.h" #include "nsIFocusController.h" +#include "nsIPluginInstance.h" +#include "nsIObjectFrame.h" +#include "nsIPluginHost.h" // Drag & Drop, Clipboard #include "nsWidgetsCID.h" @@ -1204,6 +1207,10 @@ public: NS_IMETHOD IsReflowLocked(PRBool* aIsLocked); virtual nsresult ReconstructFrames(void); + virtual void StartPlugins(); + virtual void StopPlugins(); + + virtual void InvalidateViewManagers(); #ifdef IBMBIDI NS_IMETHOD SetCaretBidiLevel(PRUint8 aLevel); @@ -1513,6 +1520,11 @@ private: void FireResizeEvent(); static void sResizeEventCallback(nsITimer* aTimer, void* aPresShell) ; nsCOMPtr mResizeEventTimer; + + typedef void (*nsPluginEnumCallback)(PresShell*, nsIContent*); + void EnumeratePlugins(nsIDOMDocument *aDocument, + const nsString &aPluginTag, + nsPluginEnumCallback aCallback); }; #ifdef PR_LOGGING @@ -6470,6 +6482,97 @@ PresShell::RemoveOverrideStyleSheet(nsIS return mStyleSet->RemoveStyleSheet(nsStyleSet::eOverrideSheet, aSheet); } +static void +StartPluginInstance(PresShell *aShell, nsIContent *aContent) +{ + // For now we just reconstruct the frame. + aShell->RecreateFramesFor(aContent); +} + +void +PresShell::StartPlugins() +{ + nsCOMPtr domDoc = do_QueryInterface(mDocument); + if (domDoc) { + EnumeratePlugins(domDoc, NS_LITERAL_STRING("object"), StartPluginInstance); + EnumeratePlugins(domDoc, NS_LITERAL_STRING("applet"), StartPluginInstance); + EnumeratePlugins(domDoc, NS_LITERAL_STRING("embed"), StartPluginInstance); + } +} + +static void +StopPluginInstance(PresShell *aShell, nsIContent *aContent) +{ + nsIFrame *frame = aShell->FrameManager()->GetPrimaryFrameFor(aContent); + + nsIObjectFrame *objectFrame = nsnull; + if (frame) + CallQueryInterface(frame, &objectFrame); + if (!objectFrame) + return; + + nsCOMPtr instance; + objectFrame->GetPluginInstance(*getter_AddRefs(instance)); + if (!instance) + return; + + // Check whether the plugin wants SetWindow to be called before or after + // Stop/Destroy. This is similar to nsObjectFrame::Destroy(), but we + // don't want to destroy the frame just yet. + + PRBool callSetWindowLast = PR_FALSE; + instance->GetValue(nsPluginInstanceVariable_CallSetWindowAfterDestroyBool, + (void *) &callSetWindowLast); + if (callSetWindowLast) { + instance->Stop(); + instance->Destroy(); + instance->SetWindow(nsnull); + } else { + instance->SetWindow(nsnull); + instance->Stop(); + instance->Destroy(); + } + + nsCOMPtr pluginHost = + do_GetService("@mozilla.org/plugin/host;1"); + if (pluginHost) + pluginHost->StopPluginInstance(instance); +} + +void +PresShell::StopPlugins() +{ + nsCOMPtr domDoc = do_QueryInterface(mDocument); + if (domDoc) { + EnumeratePlugins(domDoc, NS_LITERAL_STRING("object"), StopPluginInstance); + EnumeratePlugins(domDoc, NS_LITERAL_STRING("applet"), StopPluginInstance); + EnumeratePlugins(domDoc, NS_LITERAL_STRING("embed"), StopPluginInstance); + } +} + +static PRBool +InvalidateVMCallback(nsIDocument *aDocument, void *aData) +{ + NS_ASSERTION(aDocument, "null document passed to callback"); + + nsIPresShell *shell = aDocument->GetShellAt(0); + if (shell) + shell->InvalidateViewManagers(); + + return PR_TRUE; +} + +void +PresShell::InvalidateViewManagers() +{ + if (mViewManager) + mViewManager->InvalidateHierarchy(); + + // Get the list of child documents. + if (mDocument) + mDocument->EnumerateSubDocuments(InvalidateVMCallback, nsnull); +} + //-------------------------------------------------------- // Start of protected and private methods on the PresShell //-------------------------------------------------------- @@ -7038,6 +7141,32 @@ PresShell::Observe(nsISupports* aSubject return NS_ERROR_FAILURE; } +void +PresShell::EnumeratePlugins(nsIDOMDocument *aDocument, + const nsString &aPluginTag, + nsPluginEnumCallback aCallback) +{ + nsCOMPtr nodes; + aDocument->GetElementsByTagName(aPluginTag, getter_AddRefs(nodes)); + if (!nodes) + return; + + PRUint32 length; + nodes->GetLength(&length); + + nsCOMPtr node; + nsCOMPtr content; + + // nsFrameManager *fm = FrameManager(); + + for (PRUint32 i = 0; i < length; ++i) { + nodes->Item(i, getter_AddRefs(node)); + content = do_QueryInterface(node); + if (content) + aCallback(this, content); + } +} + //------------------------------------------------------ // End of protected and private methods on the PresShell //------------------------------------------------------ Index: layout/printing/nsPrintEngine.cpp =================================================================== RCS file: /cvsroot/mozilla/layout/printing/nsPrintEngine.cpp,v retrieving revision 1.93 diff -u -p -r1.93 nsPrintEngine.cpp --- layout/printing/nsPrintEngine.cpp 26 Apr 2005 03:17:07 -0000 1.93 +++ layout/printing/nsPrintEngine.cpp 26 Apr 2005 18:32:04 -0000 @@ -4435,10 +4435,11 @@ nsPrintEngine::TurnScriptingOn(PRBool aD // get the script global object nsIScriptGlobalObject *scriptGlobalObj = mDocument->GetScriptGlobalObject(); - NS_ASSERTION(scriptGlobalObj, "Can't get nsIScriptGlobalObject"); - nsIScriptContext *scx = scriptGlobalObj->GetContext(); - NS_ASSERTION(scx, "Can't get nsIScriptContext"); - scx->SetScriptsEnabled(aDoTurnOn, PR_TRUE); + if (scriptGlobalObj) { + nsIScriptContext *scx = scriptGlobalObj->GetContext(); + NS_ASSERTION(scx, "Can't get nsIScriptContext"); + scx->SetScriptsEnabled(aDoTurnOn, PR_TRUE); + } } //----------------------------------------------------------------- Index: layout/xul/base/src/nsMenuPopupFrame.cpp =================================================================== RCS file: /cvsroot/mozilla/layout/xul/base/src/nsMenuPopupFrame.cpp,v retrieving revision 1.252 diff -u -p -r1.252 nsMenuPopupFrame.cpp --- layout/xul/base/src/nsMenuPopupFrame.cpp 6 Apr 2005 03:33:18 -0000 1.252 +++ layout/xul/base/src/nsMenuPopupFrame.cpp 26 Apr 2005 18:32:10 -0000 @@ -941,6 +941,9 @@ nsMenuPopupFrame::SyncViewWithFrame(nsPr // the left or top sides of the screen may be in negative space (main monitor is on the // right, etc). We need to be sure to do the right thing. nsCOMPtr window(do_QueryInterface(document->GetScriptGlobalObject())); + if (!window) + return NS_OK; + nsCOMPtr screen; window->GetScreen(getter_AddRefs(screen)); PRInt32 screenWidth = 0, screenHeight = 0; Index: layout/xul/base/src/nsTitleBarFrame.cpp =================================================================== RCS file: /cvsroot/mozilla/layout/xul/base/src/nsTitleBarFrame.cpp,v retrieving revision 1.17 diff -u -p -r1.17 nsTitleBarFrame.cpp --- layout/xul/base/src/nsTitleBarFrame.cpp 1 Jan 2005 17:26:29 -0000 1.17 +++ layout/xul/base/src/nsTitleBarFrame.cpp 26 Apr 2005 18:32:11 -0000 @@ -169,15 +169,10 @@ nsTitleBarFrame::HandleEvent(nsPresConte nsCOMPtr window(do_QueryInterface(aPresContext->PresShell()->GetDocument()->GetScriptGlobalObject())); - - - nsPoint nsMoveBy; - nsMoveBy = aEvent->refPoint - mLastPoint; - - - window->MoveBy(nsMoveBy.x,nsMoveBy.y); - - + if (window) { + nsPoint nsMoveBy = aEvent->refPoint - mLastPoint; + window->MoveBy(nsMoveBy.x,nsMoveBy.y); + } *aEventStatus = nsEventStatus_eConsumeNoDefault; Index: netwerk/base/public/nsISecureBrowserUI.idl =================================================================== RCS file: /cvsroot/mozilla/netwerk/base/public/nsISecureBrowserUI.idl,v retrieving revision 1.6 diff -u -p -r1.6 nsISecureBrowserUI.idl --- netwerk/base/public/nsISecureBrowserUI.idl 18 Apr 2004 21:59:08 -0000 1.6 +++ netwerk/base/public/nsISecureBrowserUI.idl 26 Apr 2005 18:32:13 -0000 @@ -41,15 +41,31 @@ #include "nsISupports.idl" interface nsIDOMWindow; -interface nsIDOMElement; +interface nsIWebProgress; +interface nsIURI; -[scriptable, uuid(081e31e0-a144-11d3-8c7c-00609792278c)] +[uuid(625481c5-b2dc-11d9-bc8f-00112478d626)] +interface nsISecureBrowserUIState : nsISupports +{ +}; + +[scriptable, uuid(c5ca429c-b5c2-11d9-8547-00112478d626)] interface nsISecureBrowserUI : nsISupports { void init(in nsIDOMWindow window); readonly attribute unsigned long state; readonly attribute AString tooltipText; + + /* Returns an object that encapsulates the current security state. */ + nsISecureBrowserUIState captureState(); + + /** + * Restore the state captured by captureState(), firing transition + * notifications as necessary. + */ + void transitionToState(in nsISecureBrowserUIState state); + }; %{C++ Index: security/manager/boot/src/nsSecureBrowserUIImpl.cpp =================================================================== RCS file: /cvsroot/mozilla/security/manager/boot/src/nsSecureBrowserUIImpl.cpp,v retrieving revision 1.44 diff -u -p -r1.44 nsSecureBrowserUIImpl.cpp --- security/manager/boot/src/nsSecureBrowserUIImpl.cpp 12 Apr 2005 15:25:41 -0000 1.44 +++ security/manager/boot/src/nsSecureBrowserUIImpl.cpp 26 Apr 2005 18:32:15 -0000 @@ -206,12 +206,20 @@ nsSecureBrowserUIImpl::Init(nsIDOMWindow rv = svc->AddObserver(this, NS_FORMSUBMIT_SUBJECT, PR_TRUE); } - /* GetWebProgress(mWindow) */ - // hook up to the webprogress notifications. nsCOMPtr sgo(do_QueryInterface(mWindow)); if (!sgo) return NS_ERROR_FAILURE; - - nsCOMPtr wp(do_GetInterface(sgo->GetDocShell())); + + nsIDocShell *docShell = sgo->GetDocShell(); + + // The Docshell will own the SecureBrowserUI object + if (!docShell) + return NS_ERROR_FAILURE; + + docShell->SetSecurityUI(this); + + /* GetWebProgress(mWindow) */ + // hook up to the webprogress notifications. + nsCOMPtr wp(do_GetInterface(docShell)); if (!wp) return NS_ERROR_FAILURE; /* end GetWebProgress */ @@ -982,12 +990,19 @@ nsresult nsSecureBrowserUIImpl::UpdateSe newSecurityState = lis_no_security; } + return UpdateSecurityState(newSecurityState, aRequest); +} + +nsresult +nsSecureBrowserUIImpl::UpdateSecurityState(lockIconState aNewState, + nsIRequest *aRequest) +{ PR_LOG(gSecureDocLog, PR_LOG_DEBUG, ("SecureUI:%p: UpdateSecurityState: old-new %d - %d\n", this, - mPreviousSecurityState, newSecurityState + mPreviousSecurityState, aNewState )); - if (mPreviousSecurityState != newSecurityState) + if (mPreviousSecurityState != aNewState) { // must show alert @@ -1032,7 +1047,7 @@ nsresult nsSecureBrowserUIImpl::UpdateSe { case lis_no_security: case lis_broken_security: - switch (newSecurityState) + switch (aNewState) { case lis_no_security: case lis_broken_security: @@ -1049,7 +1064,7 @@ nsresult nsSecureBrowserUIImpl::UpdateSe if (showWarning) { - switch (newSecurityState) + switch (aNewState) { case lis_no_security: case lis_broken_security: @@ -1070,9 +1085,9 @@ nsresult nsSecureBrowserUIImpl::UpdateSe } } - mPreviousSecurityState = newSecurityState; + mPreviousSecurityState = aNewState; - if (lis_no_security == newSecurityState) + if (lis_no_security == aNewState) { mSSLStatus = nsnull; mInfoTooltip.Truncate(); @@ -1083,7 +1098,7 @@ nsresult nsSecureBrowserUIImpl::UpdateSe { PRUint32 newState = STATE_IS_INSECURE; - switch (newSecurityState) + switch (aNewState) { case lis_broken_security: newState = STATE_IS_BROKEN; @@ -1483,3 +1498,48 @@ ConfirmPostToInsecureFromSecure() return result; } + +class nsSecureBrowserUIImpl::State : public nsISecureBrowserUIState +{ +public: + State(lockIconState aState, nsISupports *aSSLStatus); + + lockIconState GetState() const { return mState; } + nsISupports* GetSSLStatus() { return mSSLStatus; } + + NS_DECL_ISUPPORTS + NS_DECL_NSISECUREBROWSERUISTATE + +private: + lockIconState mState; + nsCOMPtr mSSLStatus; +}; + +NS_IMPL_ISUPPORTS1(nsSecureBrowserUIImpl::State, nsISecureBrowserUIState) + +nsSecureBrowserUIImpl::State::State(lockIconState aState, + nsISupports *aSSLStatus) + : mState(aState), mSSLStatus(aSSLStatus) +{ +} + +NS_IMETHODIMP +nsSecureBrowserUIImpl::CaptureState(nsISecureBrowserUIState **aState) +{ + *aState = new State(mPreviousSecurityState, mSSLStatus); + NS_ENSURE_TRUE(aState, NS_ERROR_OUT_OF_MEMORY); + + NS_ADDREF(*aState); + return NS_OK; +} + +NS_IMETHODIMP +nsSecureBrowserUIImpl::TransitionToState(nsISecureBrowserUIState *aState) +{ + NS_ENSURE_TRUE(aState, NS_ERROR_NULL_POINTER); + + State *state = NS_STATIC_CAST(State*, aState); + + mSSLStatus = state->GetSSLStatus(); + return UpdateSecurityState(state->GetState(), nsnull); +} Index: security/manager/boot/src/nsSecureBrowserUIImpl.h =================================================================== RCS file: /cvsroot/mozilla/security/manager/boot/src/nsSecureBrowserUIImpl.h,v retrieving revision 1.14 diff -u -p -r1.14 nsSecureBrowserUIImpl.h --- security/manager/boot/src/nsSecureBrowserUIImpl.h 12 Jan 2005 00:00:53 -0000 1.14 +++ security/manager/boot/src/nsSecureBrowserUIImpl.h 26 Apr 2005 18:32:15 -0000 @@ -121,6 +121,7 @@ protected: PRInt32 mSubRequestsNoSecurity; nsresult UpdateSecurityState(nsIRequest* aRequest); + nsresult UpdateSecurityState(lockIconState aNewState, nsIRequest *aRequest); nsresult EvaluateAndUpdateSecurityState(nsIRequest *aRequest); void UpdateSubrequestMembers(nsIRequest *aRequest); @@ -143,6 +144,10 @@ protected: // Support functions nsresult GetNSSDialogs(nsISecurityWarningDialogs **); + class State; + nsresult HandleStateChange(PRBool aIsToplevel, nsIURI *aURI, + PRUint32 aLoadFlags, PRUint32 aProgressStateFlgs); + PLDHashTable mTransferringRequests; }; Index: toolkit/components/passwordmgr/base/nsPasswordManager.cpp =================================================================== RCS file: /cvsroot/mozilla/toolkit/components/passwordmgr/base/nsPasswordManager.cpp,v retrieving revision 1.57 diff -u -p -r1.57 nsPasswordManager.cpp --- toolkit/components/passwordmgr/base/nsPasswordManager.cpp 15 Apr 2005 14:55:55 -0000 1.57 +++ toolkit/components/passwordmgr/base/nsPasswordManager.cpp 26 Apr 2005 18:32:20 -0000 @@ -71,6 +71,8 @@ #include "nsIAutoCompleteResult.h" #include "nsIPK11TokenDB.h" #include "nsIPK11Token.h" +#include "nsIScriptGlobalObject.h" +#include "nsIWindowWatcher.h" static const char kPMPropertiesURL[] = "chrome://passwordmgr/locale/passwordmgr.properties"; static PRBool sRememberPasswords = PR_FALSE; @@ -263,6 +265,37 @@ nsPasswordManager::Init() progress->AddProgressListener(this, nsIWebProgress::NOTIFY_STATE_DOCUMENT); + // Listen for "domwindowopened", this will let us attach our DOMPageRestore + // event listener. + + obsService->AddObserver(this, "domwindowopened", PR_FALSE); + obsService->AddObserver(this, "domwindowclosed", PR_FALSE); + + // Also register on any open windows that already exist, since we don't + // get notifications for those. + + nsCOMPtr watcher = + do_GetService(NS_WINDOWWATCHER_CONTRACTID); + if (watcher) { + nsCOMPtr enumerator; + watcher->GetWindowEnumerator(getter_AddRefs(enumerator)); + if (enumerator) { + PRBool hasMore; + nsCOMPtr item; + nsCOMPtr targ; + + while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore) { + enumerator->GetNext(getter_AddRefs(item)); + targ = do_QueryInterface(item); + if (targ) { + targ->AddEventListener(NS_LITERAL_STRING("DOMPageRestore"), + NS_STATIC_CAST(nsIDOMLoadListener*, this), + PR_FALSE); + } + } + } + } + // Now read in the signon file nsXPIDLCString signonFile; mPrefBranch->GetCharPref("SignonFileName", getter_Copies(signonFile)); @@ -747,6 +780,20 @@ nsPasswordManager::Observe(nsISupports* NS_ASSERTION(branch == mPrefBranch, "unexpected pref change notification"); branch->GetBoolPref("rememberSignons", &sRememberPasswords); + } else if (!strcmp(aTopic, "domwindowopened")) { + nsCOMPtr targ = do_QueryInterface(aSubject); + if (targ) { + targ->AddEventListener(NS_LITERAL_STRING("DOMPageRestore"), + NS_STATIC_CAST(nsIDOMLoadListener*, this), + PR_FALSE); + } + } else if (!strcmp(aTopic, "domwindowclosed")) { + nsCOMPtr targ = do_QueryInterface(aSubject); + if (targ) { + targ->RemoveEventListener(NS_LITERAL_STRING("DOMPageRestore"), + NS_STATIC_CAST(nsIDOMLoadListener*, this), + PR_FALSE); + } } return NS_OK; @@ -765,16 +812,22 @@ nsPasswordManager::OnStateChange(nsIWebP !(aStateFlags & nsIWebProgressListener::STATE_STOP)) return NS_OK; - // Don't do anything if the global signon pref is disabled - if (!SingleSignonEnabled()) - return NS_OK; - nsCOMPtr domWin; nsresult rv = aWebProgress->GetDOMWindow(getter_AddRefs(domWin)); NS_ENSURE_SUCCESS(rv, rv); + return DoPrefill(domWin); +} + +nsresult +nsPasswordManager::DoPrefill(nsIDOMWindow *aDOMWindow) +{ + // Don't do anything if the global signon pref is disabled + if (!SingleSignonEnabled()) + return NS_OK; + nsCOMPtr domDoc; - domWin->GetDocument(getter_AddRefs(domDoc)); + aDOMWindow->GetDocument(getter_AddRefs(domDoc)); NS_ASSERTION(domDoc, "DOM window should always have a document!"); // For now, only prefill forms in HTML documents. @@ -1568,6 +1621,24 @@ nsPasswordManager::Error(nsIDOMEvent* aE return NS_OK; } +NS_IMETHODIMP +nsPasswordManager::PageRestore(nsIDOMEvent* aEvent) +{ + nsCOMPtr target; + aEvent->GetTarget(getter_AddRefs(target)); + + nsCOMPtr doc = do_QueryInterface(target); + if (doc) { + nsCOMPtr win = + do_QueryInterface(doc->GetScriptGlobalObject()); + if (win) { + return DoPrefill(win); + } + } + + return NS_OK; +} + // internal methods Index: toolkit/components/passwordmgr/base/nsPasswordManager.h =================================================================== RCS file: /cvsroot/mozilla/toolkit/components/passwordmgr/base/nsPasswordManager.h,v retrieving revision 1.13 diff -u -p -r1.13 nsPasswordManager.h --- toolkit/components/passwordmgr/base/nsPasswordManager.h 3 Mar 2004 07:51:08 -0000 1.13 +++ toolkit/components/passwordmgr/base/nsPasswordManager.h 26 Apr 2005 18:32:21 -0000 @@ -136,6 +136,7 @@ public: NS_IMETHOD BeforeUnload(nsIDOMEvent* aEvent); NS_IMETHOD Abort(nsIDOMEvent* aEvent); NS_IMETHOD Error(nsIDOMEvent* aEvent); + NS_IMETHOD PageRestore(nsIDOMEvent* aEvent); // Autocomplete PRBool AutoCompleteSearch(const nsAString& aSearchString, @@ -157,6 +158,7 @@ protected: nsresult FillPassword(nsIDOMEvent* aEvent); void AttachToInput(nsIDOMHTMLInputElement* aElement); PRBool GetPasswordRealm(nsIURI* aURI, nsACString& aRealm); + nsresult DoPrefill(nsIDOMWindow *aDOMWindw); static PLDHashOperator PR_CALLBACK FindEntryEnumerator(const nsACString& aKey, SignonHashEntry* aEntry, Index: toolkit/components/satchel/src/nsFormFillController.cpp =================================================================== RCS file: /cvsroot/mozilla/toolkit/components/satchel/src/nsFormFillController.cpp,v retrieving revision 1.48 diff -u -p -r1.48 nsFormFillController.cpp --- toolkit/components/satchel/src/nsFormFillController.cpp 15 Apr 2005 14:55:56 -0000 1.48 +++ toolkit/components/satchel/src/nsFormFillController.cpp 26 Apr 2005 18:32:21 -0000 @@ -870,6 +870,12 @@ nsFormFillController::Error(nsIDOMEvent return NS_OK; } +NS_IMETHODIMP +nsFormFillController::PageRestore(nsIDOMEvent *aLoadEvent) +{ + return NS_OK; +} + //////////////////////////////////////////////////////////////////////// //// nsFormFillController Index: toolkit/components/satchel/src/nsFormFillController.h =================================================================== RCS file: /cvsroot/mozilla/toolkit/components/satchel/src/nsFormFillController.h,v retrieving revision 1.9 diff -u -p -r1.9 nsFormFillController.h --- toolkit/components/satchel/src/nsFormFillController.h 5 Mar 2005 08:19:04 -0000 1.9 +++ toolkit/components/satchel/src/nsFormFillController.h 26 Apr 2005 18:32:21 -0000 @@ -112,6 +112,7 @@ public: NS_IMETHOD Unload(nsIDOMEvent *aLoadEvent); NS_IMETHOD Abort(nsIDOMEvent *aLoadEvent); NS_IMETHOD Error(nsIDOMEvent *aLoadEvent); + NS_IMETHOD PageRestore(nsIDOMEvent* aLoadEvent); nsFormFillController(); virtual ~nsFormFillController(); Index: toolkit/content/widgets/browser.xml =================================================================== RCS file: /cvsroot/mozilla/toolkit/content/widgets/browser.xml,v retrieving revision 1.55 diff -u -p -r1.55 browser.xml --- toolkit/content/widgets/browser.xml 5 Apr 2005 04:41:41 -0000 1.55 +++ toolkit/content/widgets/browser.xml 26 Apr 2005 18:32:21 -0000 @@ -484,9 +484,9 @@ null - - null - + true @@ -544,8 +544,8 @@ const SECUREBROWSERUI_CONTRACTID = "@mozilla.org/secure_browser_ui;1"; if (!this.hasAttribute("disablesecurity") && SECUREBROWSERUI_CONTRACTID in Components.classes) { - this.securityUI = Components.classes[SECUREBROWSERUI_CONTRACTID].createInstance(Components.interfaces.nsISecureBrowserUI); - this.securityUI.init(this.contentWindow); + var securityUI = Components.classes[SECUREBROWSERUI_CONTRACTID].createInstance(Components.interfaces.nsISecureBrowserUI); + securityUI.init(this.contentWindow); } } catch (e) { Index: view/public/nsIViewManager.h =================================================================== RCS file: /cvsroot/mozilla/view/public/nsIViewManager.h,v retrieving revision 3.90 diff -u -p -r3.90 nsIViewManager.h --- view/public/nsIViewManager.h 7 Mar 2005 22:12:53 -0000 3.90 +++ view/public/nsIViewManager.h 26 Apr 2005 18:32:22 -0000 @@ -62,8 +62,8 @@ enum nsRectVisibility { #define NS_IVIEWMANAGER_IID \ -{ 0xd9af8f22, 0xc64d, 0x4036, \ - { 0x9e, 0x8b, 0x69, 0x5a, 0x63, 0x69, 0x3f, 0xd3 } } +{ 0x5a381922, 0xb397, 0x11d9, \ + { 0x8f, 0x7c, 0x00, 0x11, 0x24, 0x78, 0xd6, 0x26 } } class nsIViewManager : public nsISupports { @@ -566,6 +566,12 @@ public: * (aFromScroll is false) or scrolled (aFromScroll is true). */ NS_IMETHOD SynthesizeMouseMove(PRBool aFromScroll)=0; + + /** + * Force any cached information about the view hierarchy (such as the root + * view manager) to be recomputed. Note that this is non-recursive. + */ + NS_IMETHOD InvalidateHierarchy()=0; }; // Paint timing mode flags Index: view/src/nsViewManager.cpp =================================================================== RCS file: /cvsroot/mozilla/view/src/nsViewManager.cpp,v retrieving revision 3.397 diff -u -p -r3.397 nsViewManager.cpp --- view/src/nsViewManager.cpp 26 Apr 2005 02:31:19 -0000 3.397 +++ view/src/nsViewManager.cpp 26 Apr 2005 18:32:23 -0000 @@ -4441,3 +4441,22 @@ nsViewManager::ProcessSynthMouseMoveEven if (!aFromScroll) mSynthMouseMoveEventQueue = nsnull; } + +NS_IMETHODIMP +nsViewManager::InvalidateHierarchy() +{ + if (mRootView) { + if (mRootViewManager != this) { + NS_IF_RELEASE(mRootViewManager); + } + nsView *parent = mRootView->GetParent(); + if (parent) { + mRootViewManager = parent->GetViewManager()->RootViewManager(); + NS_ADDREF(mRootViewManager); + } else { + mRootViewManager = this; + } + } + + return NS_OK; +} Index: view/src/nsViewManager.h =================================================================== RCS file: /cvsroot/mozilla/view/src/nsViewManager.h,v retrieving revision 3.152 diff -u -p -r3.152 nsViewManager.h --- view/src/nsViewManager.h 30 Mar 2005 20:26:54 -0000 3.152 +++ view/src/nsViewManager.h 26 Apr 2005 18:32:24 -0000 @@ -269,6 +269,8 @@ public: NS_IMETHOD SynthesizeMouseMove(PRBool aFromScroll); void ProcessSynthMouseMoveEvent(PRBool aFromScroll); + NS_IMETHOD InvalidateHierarchy(); + protected: virtual ~nsViewManager(); Index: widget/public/nsGUIEvent.h =================================================================== RCS file: /cvsroot/mozilla/widget/public/nsGUIEvent.h,v retrieving revision 3.117 diff -u -p -r3.117 nsGUIEvent.h --- widget/public/nsGUIEvent.h 18 Mar 2005 06:17:59 -0000 3.117 +++ widget/public/nsGUIEvent.h 26 Apr 2005 18:32:24 -0000 @@ -234,6 +234,7 @@ class nsIURI; #define NS_IMAGE_ERROR (NS_STREAM_EVENT_START + 4) #define NS_SCRIPT_LOAD (NS_STREAM_EVENT_START + 5) #define NS_BEFORE_PAGE_UNLOAD (NS_STREAM_EVENT_START + 6) +#define NS_PAGE_RESTORE (NS_STREAM_EVENT_START + 7) #define NS_FORM_EVENT_START 1200 #define NS_FORM_SUBMIT (NS_FORM_EVENT_START) Index: xpcom/threads/nsITimer.idl =================================================================== RCS file: /cvsroot/mozilla/xpcom/threads/nsITimer.idl,v retrieving revision 3.3 diff -u -p -r3.3 nsITimer.idl --- xpcom/threads/nsITimer.idl 18 Apr 2004 14:18:23 -0000 3.3 +++ xpcom/threads/nsITimer.idl 26 Apr 2005 18:32:28 -0000 @@ -43,12 +43,12 @@ interface nsIObserver; %{C++ /** - * The signature of the timer callback function passed to initWithCallback. This - * is the function that will get called when the timer expires if the timer is - * initialized via initWithCallback. + * The signature of the timer callback function passed to initWithFuncCallback. + * This is the function that will get called when the timer expires if the + * timer is initialized via initWithFuncCallback. * * @param aTimer the timer which has expired - * @param aClosure opaque parameter passed to initWithCallback + * @param aClosure opaque parameter passed to initWithFuncCallback * * Implementers should return the following: * @@ -82,7 +82,7 @@ interface nsITimerCallback : nsISupports * delay to avoid the overhead of destroying and creating a timer. It is not * necessary to cancel the timer in that case. */ -[scriptable, uuid(29ee628e-a3ea-471f-965d-dc9f11d1c183)] +[scriptable, uuid(436a83fa-b396-11d9-bcfa-00112478d626)] interface nsITimer : nsISupports { /* Timer types */ @@ -179,9 +179,14 @@ interface nsITimer : nsISupports attribute unsigned long type; /** - * The opaque pointer pass to initWithCallback. + * The opaque pointer pass to initWithFuncCallback. */ [noscript] readonly attribute voidPtr closure; + + /** + * The nsITimerCallback object passed to initWithCallback. + */ + readonly attribute nsITimerCallback callback; }; %{C++ Index: xpcom/threads/nsTimerImpl.cpp =================================================================== RCS file: /cvsroot/mozilla/xpcom/threads/nsTimerImpl.cpp,v retrieving revision 1.34 diff -u -p -r1.34 nsTimerImpl.cpp --- xpcom/threads/nsTimerImpl.cpp 11 May 2004 09:38:49 -0000 1.34 +++ xpcom/threads/nsTimerImpl.cpp 26 Apr 2005 18:32:28 -0000 @@ -331,6 +331,17 @@ NS_IMETHODIMP nsTimerImpl::GetClosure(vo } +NS_IMETHODIMP nsTimerImpl::GetCallback(nsITimerCallback **aCallback) +{ + if (mCallbackType == CALLBACK_TYPE_INTERFACE) + NS_IF_ADDREF(*aCallback = mCallback.i); + else + *aCallback = nsnull; + + return NS_OK; +} + + NS_IMETHODIMP nsTimerImpl::GetIdle(PRBool *aIdle) { *aIdle = mIdle; Index: xpfe/components/shistory/public/nsIHistoryEntry.idl =================================================================== RCS file: /cvsroot/mozilla/xpfe/components/shistory/public/nsIHistoryEntry.idl,v retrieving revision 1.4 diff -u -p -r1.4 nsIHistoryEntry.idl --- xpfe/components/shistory/public/nsIHistoryEntry.idl 17 Apr 2004 16:51:32 -0000 1.4 +++ xpfe/components/shistory/public/nsIHistoryEntry.idl 26 Apr 2005 18:32:30 -0000 @@ -53,30 +53,30 @@ interface nsIURI; interface nsIHistoryEntry : nsISupports { -/** - * A readonly property that returns the URI - * of the current entry. The object returned is - * of type nsIURI - */ -readonly attribute nsIURI URI; - -/** - * A readonly property that returns the title - * of the current entry. The object returned - * is a encoded string - */ -readonly attribute wstring title; - -/** - * A readonly property that returns a boolean - * flag which indicates if the entry was created as a - * result of a subframe navigation. This flag will be - * 'false' when a frameset page is visited for - * the first time. This flag will be 'true' for all - * history entries created as a result of a subframe - * navigation. - */ -readonly attribute boolean isSubFrame; + /** + * A readonly property that returns the URI + * of the current entry. The object returned is + * of type nsIURI + */ + readonly attribute nsIURI URI; + + /** + * A readonly property that returns the title + * of the current entry. The object returned + * is a encoded string + */ + readonly attribute wstring title; + + /** + * A readonly property that returns a boolean + * flag which indicates if the entry was created as a + * result of a subframe navigation. This flag will be + * 'false' when a frameset page is visited for + * the first time. This flag will be 'true' for all + * history entries created as a result of a subframe + * navigation. + */ + readonly attribute boolean isSubFrame; }; Index: xpfe/components/shistory/public/nsISHEntry.idl =================================================================== RCS file: /cvsroot/mozilla/xpfe/components/shistory/public/nsISHEntry.idl,v retrieving revision 1.21 diff -u -p -r1.21 nsISHEntry.idl --- xpfe/components/shistory/public/nsISHEntry.idl 19 Oct 2004 21:53:53 -0000 1.21 +++ xpfe/components/shistory/public/nsISHEntry.idl 26 Apr 2005 18:32:30 -0000 @@ -42,88 +42,126 @@ * hold all information required to recreate the document from history * */ -#include "nsISupports.idl" -#include "nsIURI.idl" -#include "nsIInputStream.idl" +#include "nsIHistoryEntry.idl" interface nsILayoutHistoryState; -interface nsIDOMDocument; +interface nsIContentViewer; +interface nsIURI; +interface nsIInputStream; +interface nsIDocShellTreeItem; +interface nsISecureBrowserUIState; +interface nsISupportsArray; +%{C++ +struct nsRect; +%} +[ref] native nsRect(nsRect); -[scriptable, uuid(6b596e1f-a3bd-40f9-a7ee-ab3edc7f9960)] -interface nsISHEntry : nsISupports +[scriptable, uuid(e47bf412-3bc2-4306-a82f-ea2bdf950432)] +interface nsISHEntry : nsIHistoryEntry { + /** URI for the document */ + void setURI(in nsIURI aURI); -/** URI for the document */ -void SetURI(in nsIURI aURI); - -/** Referrer URI */ -attribute nsIURI referrerURI; + /** Referrer URI */ + attribute nsIURI referrerURI; -/** DOM Document */ -attribute nsIDOMDocument document; + /** Content viewer, for fast restoration of presentation */ + attribute nsIContentViewer contentViewer; -/** Title for the document */ -void SetTitle(in wstring aTitle); - -/** Post Data for the document */ -attribute nsIInputStream postData; - -/** LayoutHistoryState for scroll position and form values */ -attribute nsILayoutHistoryState layoutHistoryState; - -/** parent of this entry */ -attribute nsISHEntry parent; - -/** - * The loadType for this entry. This is typically loadHistory except - * when reload is pressed, it has the appropriate reload flag - */ -attribute unsigned long loadType; - -/** - * An ID to help identify this entry from others during - * subframe navigation - */ -attribute unsigned long ID; - -/** - * pageIdentifier is an integer that should be the same for two entries - * attached to the same docshell only if the two entries are entries for the - * same page in the sense that one could go from the state represented by one - * to the state represented by the other simply by scrolling (so the entries - * are separated by an anchor traversal or a subframe navigation in some other - * frame). - */ -attribute unsigned long pageIdentifier; - -/** attribute to set and get the cache key for the entry */ -attribute nsISupports cacheKey; - -/** attribute to indicate whether layoutHistoryState should be saved */ -attribute boolean saveLayoutStateFlag; - -/** attribute to indicate whether the page is already expired in cache */ -attribute boolean expirationStatus; - -/** attribute to indicate the content-type of the document that this - is a session history entry for */ -attribute ACString contentType; + /** Whether the content viewer is marked "sticky" */ + attribute boolean sticky; + + /** Saved state of the global window object */ + attribute nsISupports windowState; + + /** + * Saved position and dimensions of the content viewer; we must adjust the + * root view's widget accordingly if this has changed when the presentation + * is restored. + */ + [noscript] void getViewerBounds(in nsRect bounds); + [noscript] void setViewerBounds([const] in nsRect bounds); + + /** + * Saved child docshells corresponding to contentViewer. There are weak + * references since it's assumed that the content viewer's document has + * an owning reference to the subdocument for each shell. The child shells + * are restored as children of the parent docshell, in this order, when the + * parent docshell restores a saved presentation. + */ + void addChildShell(in nsIDocShellTreeItem shell); + nsIDocShellTreeItem childShellAt(in long index); + void clearChildShells(); + + /** Saved security state for the content viewer */ + attribute nsISecureBrowserUIState securityState; + + /** Saved refresh URI list for the content viewer */ + attribute nsISupportsArray refreshURIList; + + /** Title for the document */ + void setTitle(in AString aTitle); + + /** Post Data for the document */ + attribute nsIInputStream postData; + + /** LayoutHistoryState for scroll position and form values */ + attribute nsILayoutHistoryState layoutHistoryState; + + /** parent of this entry */ + attribute nsISHEntry parent; + + /** + * The loadType for this entry. This is typically loadHistory except + * when reload is pressed, it has the appropriate reload flag + */ + attribute unsigned long loadType; + + /** + * An ID to help identify this entry from others during + * subframe navigation + */ + attribute unsigned long ID; + + /** + * pageIdentifier is an integer that should be the same for two entries + * attached to the same docshell only if the two entries are entries for + * the same page in the sense that one could go from the state represented + * by one to the state represented by the other simply by scrolling (so the + * entries are separated by an anchor traversal or a subframe navigation in + * some other frame). + */ + attribute unsigned long pageIdentifier; + + /** attribute to set and get the cache key for the entry */ + attribute nsISupports cacheKey; + + /** attribute to indicate whether layoutHistoryState should be saved */ + attribute boolean saveLayoutStateFlag; + + /** attribute to indicate whether the page is already expired in cache */ + attribute boolean expirationStatus; + + /** + * attribute to indicate the content-type of the document that this + * is a session history entry for + */ + attribute ACString contentType; -/** Set/Get scrollers' positon in anchored pages */ -void setScrollPosition(in PRInt32 x, in PRInt32 y); -void getScrollPosition(out PRInt32 x, out PRInt32 y); - -/** Additional ways to create an entry */ -void create(in nsIURI aURI, in wstring aTitle, in nsIDOMDocument aDocument, - in nsIInputStream aInputStream, in nsILayoutHistoryState aHistoryLayoutState, - in nsISupports aCacheKey, in ACString aContentType); - -nsISHEntry clone(); - -/** Attribute that indicates if this entry is for a subframe navigation */ -void SetIsSubFrame(in boolean aFlag); + /** Set/Get scrollers' positon in anchored pages */ + void setScrollPosition(in long x, in long y); + void getScrollPosition(out long x, out long y); + + /** Additional ways to create an entry */ + void create(in nsIURI URI, in AString title, + in nsIInputStream inputStream, + in nsILayoutHistoryState layoutHistoryState, + in nsISupports cacheKey, in ACString contentType); + nsISHEntry clone(); + /** Attribute that indicates if this entry is for a subframe navigation */ + void setIsSubFrame(in boolean aFlag); }; Index: xpfe/components/shistory/src/Makefile.in =================================================================== RCS file: /cvsroot/mozilla/xpfe/components/shistory/src/Makefile.in,v retrieving revision 1.19 diff -u -p -r1.19 Makefile.in --- xpfe/components/shistory/src/Makefile.in 15 Dec 2004 04:06:52 -0000 1.19 +++ xpfe/components/shistory/src/Makefile.in 26 Apr 2005 18:32:30 -0000 @@ -55,6 +55,7 @@ REQUIRES = xpcom \ layout \ docshell \ pref \ + gfx \ $(NULL) CPPSRCS = nsSHEntry.cpp \ Index: xpfe/components/shistory/src/nsSHEntry.cpp =================================================================== RCS file: /cvsroot/mozilla/xpfe/components/shistory/src/nsSHEntry.cpp,v retrieving revision 1.36 diff -u -p -r1.36 nsSHEntry.cpp --- xpfe/components/shistory/src/nsSHEntry.cpp 19 Oct 2004 21:53:53 -0000 1.36 +++ xpfe/components/shistory/src/nsSHEntry.cpp 26 Apr 2005 18:32:30 -0000 @@ -37,11 +37,16 @@ * * ***** END LICENSE BLOCK ***** */ +#ifdef DEBUG_brymer +#define DEBUG_PAGE_CACHE +#endif + // Local Includes #include "nsSHEntry.h" #include "nsXPIDLString.h" #include "nsReadableUtils.h" #include "nsIDocShellLoadInfo.h" +#include "nsIDocShellTreeItem.h" static PRUint32 gEntryID = 0; @@ -58,7 +63,9 @@ nsSHEntry::nsSHEntry() , mIsFrameNavigation(PR_FALSE) , mSaveLayoutState(PR_TRUE) , mExpired(PR_FALSE) + , mSticky(PR_TRUE) , mParent(nsnull) + , mViewerBounds(0, 0, 0, 0) { } @@ -77,12 +84,21 @@ nsSHEntry::nsSHEntry(const nsSHEntry &ot , mIsFrameNavigation(other.mIsFrameNavigation) , mSaveLayoutState(other.mSaveLayoutState) , mExpired(other.mExpired) + , mSticky(other.mSticky) // XXX why not copy mContentType? , mCacheKey(other.mCacheKey) , mParent(other.mParent) + , mViewerBounds(other.mViewerBounds) { } +nsSHEntry::~nsSHEntry() +{ + mChildren.Clear(); + if (mContentViewer) + mContentViewer->Destroy(); +} + //***************************************************************************** // nsSHEntry: nsISupports //***************************************************************************** @@ -133,19 +149,35 @@ NS_IMETHODIMP nsSHEntry::SetReferrerURI( return NS_OK; } -NS_IMETHODIMP nsSHEntry::SetDocument(nsIDOMDocument* aDocument) +NS_IMETHODIMP +nsSHEntry::SetContentViewer(nsIContentViewer *aViewer) { - mDocument = aDocument; + mContentViewer = aViewer; return NS_OK; } -NS_IMETHODIMP nsSHEntry::GetDocument(nsIDOMDocument** aResult) +NS_IMETHODIMP +nsSHEntry::GetContentViewer(nsIContentViewer **aResult) { - *aResult = mDocument; + *aResult = mContentViewer; NS_IF_ADDREF(*aResult); return NS_OK; } +NS_IMETHODIMP +nsSHEntry::SetSticky(PRBool aSticky) +{ + mSticky = aSticky; + return NS_OK; +} + +NS_IMETHODIMP +nsSHEntry::GetSticky(PRBool *aSticky) +{ + *aSticky = mSticky; + return NS_OK; +} + NS_IMETHODIMP nsSHEntry::GetTitle(PRUnichar** aTitle) { // Check for empty title... @@ -160,7 +192,7 @@ NS_IMETHODIMP nsSHEntry::GetTitle(PRUnic return NS_OK; } -NS_IMETHODIMP nsSHEntry::SetTitle(const PRUnichar* aTitle) +NS_IMETHODIMP nsSHEntry::SetTitle(const nsAString &aTitle) { mTitle = aTitle; return NS_OK; @@ -297,14 +329,13 @@ NS_IMETHODIMP nsSHEntry::SetContentType( } NS_IMETHODIMP -nsSHEntry::Create(nsIURI * aURI, const PRUnichar * aTitle, - nsIDOMDocument * aDOMDocument, nsIInputStream * aInputStream, - nsILayoutHistoryState * aHistoryLayoutState, +nsSHEntry::Create(nsIURI * aURI, const nsAString &aTitle, + nsIInputStream * aInputStream, + nsILayoutHistoryState * aLayoutHistoryState, nsISupports * aCacheKey, const nsACString& aContentType) { mURI = aURI; mTitle = aTitle; - mDocument = aDOMDocument; mPostData = aInputStream; mCacheKey = aCacheKey; mContentType = aContentType; @@ -317,9 +348,9 @@ nsSHEntry::Create(nsIURI * aURI, const P // all subframe navigations, sets the flag to true. mIsFrameNavigation = PR_FALSE; - // By default we save HistoryLayoutState + // By default we save LayoutHistoryState mSaveLayoutState = PR_TRUE; - mLayoutHistoryState = aHistoryLayoutState; + mLayoutHistoryState = aLayoutHistoryState; //By default the page is not expired mExpired = PR_FALSE; @@ -358,6 +389,34 @@ nsSHEntry::SetParent(nsISHEntry * aParen return NS_OK; } +NS_IMETHODIMP +nsSHEntry::SetWindowState(nsISupports *aState) +{ + mWindowState = aState; + return NS_OK; +} + +NS_IMETHODIMP +nsSHEntry::GetWindowState(nsISupports **aState) +{ + NS_IF_ADDREF(*aState = mWindowState); + return NS_OK; +} + +NS_IMETHODIMP +nsSHEntry::SetViewerBounds(const nsRect &aBounds) +{ + mViewerBounds = aBounds; + return NS_OK; +} + +NS_IMETHODIMP +nsSHEntry::GetViewerBounds(nsRect &aBounds) +{ + aBounds = mViewerBounds; + return NS_OK; +} + //***************************************************************************** // nsSHEntry: nsISHContainer //***************************************************************************** @@ -416,3 +475,55 @@ nsSHEntry::GetChildAt(PRInt32 aIndex, ns } return NS_OK; } + +NS_IMETHODIMP +nsSHEntry::AddChildShell(nsIDocShellTreeItem *aShell) +{ + NS_ASSERTION(aShell, "Null child shell added to history entry"); + mChildShells.AppendElement(aShell); + return NS_OK; +} + +NS_IMETHODIMP +nsSHEntry::ChildShellAt(PRInt32 aIndex, nsIDocShellTreeItem **aShell) +{ + NS_IF_ADDREF(*aShell = + NS_STATIC_CAST(nsIDocShellTreeItem*, + mChildShells.SafeElementAt(aIndex))); + return NS_OK; +} + +NS_IMETHODIMP +nsSHEntry::ClearChildShells() +{ + mChildShells.Clear(); + return NS_OK; +} + +NS_IMETHODIMP +nsSHEntry::GetSecurityState(nsISecureBrowserUIState **aState) +{ + NS_IF_ADDREF(*aState = mSecurityState); + return NS_OK; +} + +NS_IMETHODIMP +nsSHEntry::SetSecurityState(nsISecureBrowserUIState *aState) +{ + mSecurityState = aState; + return NS_OK; +} + +NS_IMETHODIMP +nsSHEntry::GetRefreshURIList(nsISupportsArray **aList) +{ + NS_IF_ADDREF(*aList = mRefreshURIList); + return NS_OK; +} + +NS_IMETHODIMP +nsSHEntry::SetRefreshURIList(nsISupportsArray *aList) +{ + mRefreshURIList = aList; + return NS_OK; +} Index: xpfe/components/shistory/src/nsSHEntry.h =================================================================== RCS file: /cvsroot/mozilla/xpfe/components/shistory/src/nsSHEntry.h,v retrieving revision 1.20 diff -u -p -r1.20 nsSHEntry.h --- xpfe/components/shistory/src/nsSHEntry.h 19 Oct 2004 21:53:53 -0000 1.20 +++ xpfe/components/shistory/src/nsSHEntry.h 26 Apr 2005 18:32:30 -0000 @@ -44,9 +44,10 @@ #include "nsCOMPtr.h" #include "nsCOMArray.h" #include "nsString.h" +#include "nsVoidArray.h" // Interfaces needed -#include "nsIDOMDocument.h" +#include "nsIContentViewer.h" #include "nsIInputStream.h" #include "nsILayoutHistoryState.h" #include "nsISHEntry.h" @@ -54,9 +55,11 @@ #include "nsIURI.h" #include "nsIEnumerator.h" #include "nsIHistoryEntry.h" +#include "nsRect.h" +#include "nsISecureBrowserUI.h" +#include "nsSupportsArray.h" -class nsSHEntry : public nsIHistoryEntry, - public nsISHEntry, +class nsSHEntry : public nsISHEntry, public nsISHContainer { public: @@ -69,11 +72,11 @@ public: NS_DECL_NSISHCONTAINER private: - ~nsSHEntry() { mChildren.Clear(); } + ~nsSHEntry(); nsCOMPtr mURI; nsCOMPtr mReferrerURI; - nsCOMPtr mDocument; + nsCOMPtr mContentViewer; nsString mTitle; nsCOMPtr mPostData; nsCOMPtr mLayoutHistoryState; @@ -86,9 +89,15 @@ private: PRPackedBool mIsFrameNavigation; PRPackedBool mSaveLayoutState; PRPackedBool mExpired; + PRPackedBool mSticky; nsCString mContentType; nsCOMPtr mCacheKey; nsISHEntry * mParent; // weak reference + nsCOMPtr mWindowState; + nsRect mViewerBounds; + nsVoidArray mChildShells; + nsCOMPtr mSecurityState; + nsCOMPtr mRefreshURIList; }; #endif /* nsSHEntry_h */ Index: xpfe/components/shistory/src/nsSHistory.cpp =================================================================== RCS file: /cvsroot/mozilla/xpfe/components/shistory/src/nsSHistory.cpp,v retrieving revision 1.65 diff -u -p -r1.65 nsSHistory.cpp --- xpfe/components/shistory/src/nsSHistory.cpp 6 Aug 2004 19:34:21 -0000 1.65 +++ xpfe/components/shistory/src/nsSHistory.cpp 26 Apr 2005 18:32:30 -0000 @@ -54,9 +54,14 @@ #include "nsIDocShellLoadInfo.h" #include "nsIServiceManager.h" #include "nsIPrefService.h" +#include "nsIURI.h" +#include "nsIContentViewer.h" #define PREF_SHISTORY_SIZE "browser.sessionhistory.max_entries" +#define PREF_SHISTORY_VIEWERS "browser.sessionhistory.max_viewers" + static PRInt32 gHistoryMaxSize = 50; +static PRInt32 gHistoryMaxViewers = 0; enum HistCmd{ HIST_CMD_BACK, @@ -69,7 +74,7 @@ enum HistCmd{ //*** nsSHistory: Object Management //***************************************************************************** -nsSHistory::nsSHistory() : mListRoot(nsnull), mIndex(-1), mLength(0), mRequestedIndex(-1) +nsSHistory::nsSHistory() : mListRoot(nsnull), mIndex(-1), mLength(0), mRequestedIndex(-1), mNumViewers(0) { } @@ -104,10 +109,10 @@ nsSHistory::Init() { nsCOMPtr prefs = do_GetService(NS_PREFSERVICE_CONTRACTID); if (prefs) { - nsCOMPtr defaultBranch; - prefs->GetDefaultBranch(nsnull, getter_AddRefs(defaultBranch)); - if (defaultBranch) { - defaultBranch->GetIntPref(PREF_SHISTORY_SIZE, &gHistoryMaxSize); + nsCOMPtr branch = do_QueryInterface(prefs); + if (branch) { + branch->GetIntPref(PREF_SHISTORY_SIZE, &gHistoryMaxSize); + branch->GetIntPref(PREF_SHISTORY_VIEWERS, &gHistoryMaxViewers); } } return NS_OK; @@ -171,7 +176,10 @@ nsSHistory::AddEntry(nsISHEntry * aSHEnt //Purge History list if it is too long if ((gHistoryMaxSize >= 0) && (mLength > gHistoryMaxSize)) PurgeHistory(mLength-gHistoryMaxSize); - + + // Evict content viewers if there are too many. + EvictContentViewers(mIndex - 1, mIndex); + return NS_OK; } @@ -207,6 +215,7 @@ nsSHistory::GetEntryAtIndex(PRInt32 aInd if (NS_SUCCEEDED(rv) && (*aResult)) { // Set mIndex to the requested index, if asked to do so.. if (aModifyIndex) { + EvictContentViewers(mIndex, aIndex); mIndex = aIndex; } } //entry @@ -583,12 +592,54 @@ nsSHistory::Reload(PRUint32 aReloadFlags return LoadEntry(mIndex, loadType, HIST_CMD_RELOAD); } +void +nsSHistory::EvictContentViewers(PRInt32 aFromIndex, PRInt32 aToIndex) +{ + // To enforce the limit on cached content viewers, we need to release all + // of the content viewers that are no longer in the "window" that now + // ends/begins at aToIndex. + + PRInt32 startIndex, endIndex; + if (aToIndex > aFromIndex) { // going forward + startIndex = PR_MAX(0, aFromIndex - gHistoryMaxViewers); + endIndex = aToIndex - gHistoryMaxViewers; + } else { // going backward + startIndex = aToIndex + gHistoryMaxViewers; + endIndex = PR_MIN(mLength - 1, aFromIndex + gHistoryMaxViewers); + } + + nsCOMPtr entry; + nsCOMPtr viewer; + nsISHTransaction *temp; + nsCOMPtr trans; + GetTransactionAtIndex(startIndex, getter_AddRefs(trans)); + + for (PRInt32 i = startIndex; trans && i < endIndex; ++i) { + trans->GetSHEntry(getter_AddRefs(entry)); + entry->GetContentViewer(getter_AddRefs(viewer)); + if (viewer) { + viewer->Destroy(); + entry->SetContentViewer(nsnull); + } + + entry->SetWindowState(nsnull); + temp = trans; + temp->GetNext(getter_AddRefs(trans)); + } +} + NS_IMETHODIMP nsSHistory::UpdateIndex() { // Update the actual index with the right value. - if (mIndex != mRequestedIndex && mRequestedIndex != -1) + if (mIndex != mRequestedIndex && mRequestedIndex != -1) { + // We've just finished a history navigation (back or forward), so enforce + // the max number of content viewers. + + EvictContentViewers(mIndex, mRequestedIndex); mIndex = mRequestedIndex; + } + return NS_OK; } Index: xpfe/components/shistory/src/nsSHistory.h =================================================================== RCS file: /cvsroot/mozilla/xpfe/components/shistory/src/nsSHistory.h,v retrieving revision 1.16 diff -u -p -r1.16 nsSHistory.h --- xpfe/components/shistory/src/nsSHistory.h 17 Apr 2004 16:51:32 -0000 1.16 +++ xpfe/components/shistory/src/nsSHistory.h 26 Apr 2005 18:32:30 -0000 @@ -85,11 +85,14 @@ protected: nsresult PrintHistory(); #endif + void EvictContentViewers(PRInt32 aFromIndex, PRInt32 aToIndex); + protected: nsCOMPtr mListRoot; PRInt32 mIndex; PRInt32 mLength; PRInt32 mRequestedIndex; + PRInt32 mNumViewers; // Session History listener nsWeakPtr mListener; // Weak reference. Do not refcount this.