From 592dbdc176c0b6d856a5182e6892ea949ac33cbe Mon Sep 17 00:00:00 2001 From: "bryner%brianryner.com" Date: Wed, 4 May 2005 20:22:32 +0000 Subject: [PATCH] Add support for caching content viewers in session history to speed up back/forward (bug 274784). This initial landing has the feature disabled by default; set browser.sessionhistory.max_viewers to the maximum number of pages to cache to enable the feature. r=bzbarsky, sr/a=brendan. --- accessible/src/base/nsAccessNode.cpp | 4 +- content/base/public/nsIDocument.h | 46 +- content/base/src/nsDocument.cpp | 232 ++++- content/base/src/nsDocument.h | 10 +- content/base/src/nsGenericElement.cpp | 4 +- content/base/src/nsSyncLoadService.cpp | 20 + .../events/public/nsIEventListenerManager.h | 11 +- content/events/src/nsDOMEvent.cpp | 8 +- content/events/src/nsDOMEvent.h | 1 + content/events/src/nsEventListenerManager.cpp | 27 +- content/events/src/nsEventListenerManager.h | 3 + .../html/content/src/nsGenericHTMLElement.cpp | 20 +- .../html/content/src/nsHTMLInputElement.cpp | 34 +- content/html/document/src/nsImageDocument.cpp | 64 +- .../html/document/src/nsPluginDocument.cpp | 10 + content/xbl/src/nsXBLPrototypeHandler.cpp | 2 + content/xbl/src/nsXBLService.cpp | 11 +- docshell/base/nsDocShell.cpp | 587 ++++++++++- docshell/base/nsDocShell.h | 54 +- docshell/base/nsIContentViewer.idl | 21 +- docshell/base/nsIDocShell.idl | 33 +- dom/public/base/nsPIDOMWindow.h | 13 + dom/public/coreEvents/nsIDOMLoadListener.h | 12 +- dom/src/base/nsGlobalWindow.cpp | 396 +++++++- dom/src/base/nsGlobalWindow.h | 8 + .../browser/cocoa/src/CHClickListener.mm | 34 +- embedding/browser/webBrowser/nsWebBrowser.cpp | 5 +- embedding/browser/webBrowser/nsWebBrowser.h | 1 - embedding/tests/mfcembed/StdAfx.h | 132 --- extensions/xmlextras/base/src/nsDOMParser.cpp | 6 + extensions/xmlextras/base/src/nsDOMParser.h | 1 + .../base/src/nsLoadListenerProxy.cpp | 12 + .../xmlextras/base/src/nsLoadListenerProxy.h | 1 + .../xmlextras/base/src/nsXMLHttpRequest.cpp | 6 + .../xmlextras/base/src/nsXMLHttpRequest.h | 1 + extensions/xmlextras/tests/TestXMLExtras.cpp | 1 + layout/base/Makefile.in | 1 + layout/base/nsDocumentViewer.cpp | 267 +++-- layout/base/nsIDocumentViewer.h | 2 +- layout/base/nsIPresShell.h | 17 +- layout/base/nsLayoutAtomList.h | 1 + layout/base/nsPresShell.cpp | 130 +++ layout/printing/nsPrintEngine.cpp | 9 +- layout/xul/base/src/nsMenuPopupFrame.cpp | 3 + layout/xul/base/src/nsTitleBarFrame.cpp | 13 +- netwerk/base/public/nsISecureBrowserUI.idl | 12 +- .../boot/src/nsSecureBrowserUIImpl.cpp | 84 +- .../manager/boot/src/nsSecureBrowserUIImpl.h | 2 + .../passwordmgr/base/nsPasswordManager.cpp | 90 +- .../passwordmgr/base/nsPasswordManager.h | 2 + .../satchel/src/nsFormFillController.cpp | 6 + .../satchel/src/nsFormFillController.h | 1 + .../typeaheadfind/src/nsTypeAheadFind.cpp | 1 + toolkit/content/widgets/browser.xml | 10 +- view/src/nsView.cpp | 27 + view/src/nsView.h | 3 + view/src/nsViewManager.cpp | 19 + view/src/nsViewManager.h | 3 + widget/public/nsGUIEvent.h | 1 + xpcom/threads/nsITimer.idl | 17 +- xpcom/threads/nsTimerImpl.cpp | 11 + .../shistory/public/nsIHistoryEntry.idl | 93 -- .../components/shistory/public/nsISHEntry.idl | 177 ++-- .../shistory/public/nsISHistoryInternal.idl | 93 -- xpfe/components/shistory/src/Makefile.in | 1 + xpfe/components/shistory/src/nsSHEntry.cpp | 155 ++- xpfe/components/shistory/src/nsSHEntry.h | 18 +- xpfe/components/shistory/src/nsSHistory.cpp | 926 ------------------ xpfe/components/shistory/src/nsSHistory.h | 120 --- .../resources/content/bindings/browser.xml | 10 +- 70 files changed, 2433 insertions(+), 1723 deletions(-) diff --git a/accessible/src/base/nsAccessNode.cpp b/accessible/src/base/nsAccessNode.cpp index 921052cc059..fc705e9a073 100755 --- a/accessible/src/base/nsAccessNode.cpp +++ b/accessible/src/base/nsAccessNode.cpp @@ -498,7 +498,9 @@ nsAccessNode::GetDocShellTreeItemFor(nsIDOMNode *aStartNode) 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; } diff --git a/content/base/public/nsIDocument.h b/content/base/public/nsIDocument.h index c6cb6ddddf9..4315f552302 100644 --- a/content/base/public/nsIDocument.h +++ b/content/base/public/nsIDocument.h @@ -88,10 +88,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 +664,47 @@ 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. + * The enumerator callback should return PR_TRUE to continue enumerating, or + * PR_FALSE to stop. + */ + typedef PRBool (*nsSubDocEnumFunc)(nsIDocument *aDocument, void *aData); + virtual void EnumerateSubDocuments(nsSubDocEnumFunc aCallback, + void *aData) = 0; + + /** + * Check whether it is safe to cache the presentation of this document + * and all of its subdocuments. This method checks the following conditions + * recursively: + * - Some document types, such as plugin documents, cannot be safely cached. + * - If there are any pending requests, we don't allow the presentation + * to be cached. Ideally these requests would be suspended and resumed, + * but that is difficult in some cases, such as XMLHttpRequest. + * - If there are any beforeunload or unload listeners, we must fire them + * for correctness, but this likely puts the document into a state where + * it would not function correctly if restored. + * + * |aNewRequest| should be the request for a new document which will + * replace this document in the docshell. The new document's request + * will be ignored when checking for active requests. If there is no + * request associated with the new document, this parameter may be null. + */ + virtual PRBool CanSavePresentation(nsIRequest *aNewRequest) = 0; + + /** + * Notify the document that its associated ContentViewer is being destroyed. + * This releases circular references so that the document can go away. + * Destroy() is only called on documents that have a content viewer. + */ + virtual void Destroy() = 0; + protected: ~nsIDocument() { diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index c6307665da6..2f8102ac775 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -126,6 +126,8 @@ static NS_DEFINE_CID(kDOMEventGroupCID, NS_DOMEVENTGROUP_CID); #include "nsIScriptContext.h" #include "nsBindingManager.h" +#include "nsIDOMHTMLFormElement.h" +#include "nsIRequest.h" #include "nsICharsetAlias.h" static NS_DEFINE_CID(kCharsetAliasCID, NS_CHARSETALIAS_CID); @@ -1851,37 +1853,6 @@ nsDocument::GetScriptGlobalObject() const 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; } @@ -4609,3 +4580,202 @@ nsDocument::UnsetProperty(nsIAtom *aPropertyName, nsresult *aStatus) { 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 = subdoc ? args->callback(subdoc, args->data) : PR_TRUE; + + 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) +CanCacheSubDocument(PLDHashTable *table, PLDHashEntryHdr *hdr, + PRUint32 number, void *arg) +{ + SubDocMapEntry *entry = NS_STATIC_CAST(SubDocMapEntry*, hdr); + PRBool *canCacheArg = 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 canCache = subdoc ? subdoc->CanSavePresentation(nsnull) : PR_FALSE; + if (!canCache) { + *canCacheArg = PR_FALSE; + return PL_DHASH_STOP; + } + + return PL_DHASH_NEXT; +} + +#ifdef DEBUG_bryner +#define DEBUG_PAGE_CACHE +#endif + +PRBool +nsDocument::CanSavePresentation(nsIRequest *aNewRequest) +{ + // Check our event listneer manager for unload/beforeunload listeners. + nsCOMPtr er = do_QueryInterface(mScriptGlobalObject); + if (er) { + nsCOMPtr manager; + er->GetListenerManager(getter_AddRefs(manager)); + if (manager && manager->HasUnloadListeners()) { + return PR_FALSE; + } + } + + nsCOMPtr loadGroup = GetDocumentLoadGroup(); + if (loadGroup) { + nsCOMPtr requests; + loadGroup->GetRequests(getter_AddRefs(requests)); + + PRBool hasMore = PR_FALSE; + + while (NS_SUCCEEDED(requests->HasMoreElements(&hasMore)) && hasMore) { + nsCOMPtr elem; + requests->GetNext(getter_AddRefs(elem)); + + nsCOMPtr request = do_QueryInterface(elem); + if (request && request != aNewRequest) { +#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_FALSE; + } + } + } + + PRBool canCache = PR_TRUE; + if (mSubDocuments) + PL_DHashTableEnumerate(mSubDocuments, CanCacheSubDocument, &canCache); + + return canCache; +} + +void +nsDocument::Destroy() +{ + // The ContentViewer wants to release the document now. So, tell our content + // to drop any references to the document so that it can be destroyed. + PRInt32 count = mChildren.Count(); + + mIsGoingAway = PR_TRUE; + + for (PRInt32 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 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(); + } +} diff --git a/content/base/src/nsDocument.h b/content/base/src/nsDocument.h index 087dffe1c3f..325974af080 100644 --- a/content/base/src/nsDocument.h +++ b/content/base/src/nsDocument.h @@ -530,6 +530,14 @@ 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) CanSavePresentation(nsIRequest *aNewRequest); + virtual NS_HIDDEN_(void) Destroy(); + protected: void RetrieveRelevantHeaders(nsIChannel *aChannel); @@ -592,7 +600,7 @@ protected: nsHashtable mRadioGroups; - // True if the document is being destroyed. + // True if the document has been detached from its content viewer. PRPackedBool mIsGoingAway; // True if the document is being destroyed. diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp index e599a3be161..3fe3d57a96a 100644 --- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -2586,7 +2586,9 @@ nsGenericElement::SetFocus(nsPresContext* aPresContext) PRBool nsGenericElement::ShouldFocus(nsIContent *aContent) { - PRBool visible = PR_TRUE; + // Default to false, since if the document is not attached to a window, + // we should not focus any of its content. + PRBool visible = PR_FALSE; // Figure out if we're focusing an element in an inactive (hidden) // tab (whose docshell is not visible), if so, drop this focus diff --git a/content/base/src/nsSyncLoadService.cpp b/content/base/src/nsSyncLoadService.cpp index 06bc5a0338a..cdb43e0ad94 100644 --- a/content/base/src/nsSyncLoadService.cpp +++ b/content/base/src/nsSyncLoadService.cpp @@ -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* aEvent) 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: @@ -512,6 +526,12 @@ nsSyncLoader::Error(nsIDOMEvent* aEvent) return NS_OK; } +NS_IMETHODIMP +nsSyncLoader::PageRestore(nsIDOMEvent* aEvent) +{ + return NS_OK; +} + NS_IMETHODIMP nsSyncLoader::OnChannelRedirect(nsIChannel *aOldChannel, nsIChannel *aNewChannel, diff --git a/content/events/public/nsIEventListenerManager.h b/content/events/public/nsIEventListenerManager.h index a1f8e715515..7b42fbd85e9 100644 --- a/content/events/public/nsIEventListenerManager.h +++ b/content/events/public/nsIEventListenerManager.h @@ -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 { @@ -185,6 +184,12 @@ public: * Loop pass for evaluation of system event listeners. */ NS_IMETHOD GetSystemEventGroupLM(nsIDOMEventGroup** aGroup) = 0; + + /** + * Allows us to quickly determine whether we have unload or beforeunload + * listeners registered. + */ + virtual PRBool HasUnloadListeners() = 0; }; nsresult diff --git a/content/events/src/nsDOMEvent.cpp b/content/events/src/nsDOMEvent.cpp index c11c32e2ebb..b9116655213 100644 --- a/content/events/src/nsDOMEvent.cpp +++ b/content/events/src/nsDOMEvent.cpp @@ -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& aEventTypeArg) 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(PRUint32 aEventType) 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: diff --git a/content/events/src/nsDOMEvent.h b/content/events/src/nsDOMEvent.h index fa2e9ce955b..df9439cea7d 100644 --- a/content/events/src/nsDOMEvent.h +++ b/content/events/src/nsDOMEvent.h @@ -85,6 +85,7 @@ public: eDOMEvents_unload, eDOMEvents_abort, eDOMEvents_error, + eDOMEvents_DOMPageRestore, eDOMEvents_submit, eDOMEvents_reset, eDOMEvents_change, diff --git a/content/events/src/nsEventListenerManager.cpp b/content/events/src/nsEventListenerManager.cpp index 5e13dcb3964..59319d64520 100644 --- a/content/events/src/nsEventListenerManager.cpp +++ b/content/events/src/nsEventListenerManager.cpp @@ -241,7 +241,8 @@ static const EventDispatchData sLoadEvents[] = { {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[] = { @@ -891,6 +892,10 @@ nsEventListenerManager::GetIdentifiersForType(nsIAtom* aType, *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; @@ -2232,6 +2237,26 @@ nsEventListenerManager::GetCoordinatesFor(nsIDOMElement *aCurrentEl, } } +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) { diff --git a/content/events/src/nsEventListenerManager.h b/content/events/src/nsEventListenerManager.h index d94cd5ec296..2d14c648e8d 100644 --- a/content/events/src/nsEventListenerManager.h +++ b/content/events/src/nsEventListenerManager.h @@ -164,6 +164,8 @@ public: NS_IMETHOD GetSystemEventGroupLM(nsIDOMEventGroup** aGroup); + virtual PRBool HasUnloadListeners(); + static nsresult GetIdentifiersForType(nsIAtom* aType, EventArrayType* aArrayType, PRInt32* aSubType); @@ -301,6 +303,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 diff --git a/content/html/content/src/nsGenericHTMLElement.cpp b/content/html/content/src/nsGenericHTMLElement.cpp index 56040e450b8..456c9ef477e 100644 --- a/content/html/content/src/nsGenericHTMLElement.cpp +++ b/content/html/content/src/nsGenericHTMLElement.cpp @@ -1538,15 +1538,17 @@ nsGenericHTMLElement::HandleDOMEventForAnchors(nsPresContext* aPresContext, // 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()-> diff --git a/content/html/content/src/nsHTMLInputElement.cpp b/content/html/content/src/nsHTMLInputElement.cpp index db09b312e5b..9e3ce555d91 100644 --- a/content/html/content/src/nsHTMLInputElement.cpp +++ b/content/html/content/src/nsHTMLInputElement.cpp @@ -1070,14 +1070,16 @@ nsHTMLInputElement::SetFocus(nsPresContext* aPresContext) // 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, @@ -1120,14 +1122,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()! diff --git a/content/html/document/src/nsImageDocument.cpp b/content/html/document/src/nsImageDocument.cpp index fefb601cf5e..968cb71f51c 100644 --- a/content/html/document/src/nsImageDocument.cpp +++ b/content/html/document/src/nsImageDocument.cpp @@ -104,6 +104,7 @@ public: nsIContentSink* aSink = nsnull); virtual void SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject); + virtual void Destroy(); NS_DECL_NSIIMAGEDOCUMENT @@ -288,27 +289,38 @@ nsImageDocument::StartDocumentLoad(const char* aCommand, return NS_OK; } +void +nsImageDocument::Destroy() +{ + // Remove our event listener from the image content. + if (mImageResizingEnabled) { + nsCOMPtr target = do_QueryInterface(mImageContent); + target->RemoveEventListener(NS_LITERAL_STRING("click"), this, PR_FALSE); + } + + // Break reference cycle with mImageContent, if we have one + nsCOMPtr imageLoader = do_QueryInterface(mImageContent); + if (imageLoader) { + imageLoader->RemoveObserver(this); + } + + mImageContent = nsnull; + + nsMediaDocument::Destroy(); +} + void nsImageDocument::SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject) { - if (!aScriptGlobalObject) { - if (mImageResizingEnabled) { - nsCOMPtr target = do_QueryInterface(mImageContent); - target->RemoveEventListener(NS_LITERAL_STRING("click"), this, PR_FALSE); - - target = do_QueryInterface(mScriptGlobalObject); - target->RemoveEventListener(NS_LITERAL_STRING("resize"), this, PR_FALSE); - target->RemoveEventListener(NS_LITERAL_STRING("keypress"), this, - PR_FALSE); - } - - // Break reference cycle with mImageContent, if we have one - nsCOMPtr imageLoader = do_QueryInterface(mImageContent); - if (imageLoader) { - imageLoader->RemoveObserver(this); - } - - mImageContent = nsnull; + // If the script global object is changing, we need to unhook our event + // listeners on the window. + nsCOMPtr target; + if (mImageResizingEnabled && mScriptGlobalObject && + aScriptGlobalObject != mScriptGlobalObject) { + target = do_QueryInterface(mScriptGlobalObject); + target->RemoveEventListener(NS_LITERAL_STRING("resize"), this, PR_FALSE); + target->RemoveEventListener(NS_LITERAL_STRING("keypress"), this, + PR_FALSE); } // Set the script global object on the superclass before doing @@ -316,16 +328,18 @@ nsImageDocument::SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObjec nsHTMLDocument::SetScriptGlobalObject(aScriptGlobalObject); if (aScriptGlobalObject) { - // Create synthetic document - nsresult rv = CreateSyntheticDocument(); - if (NS_FAILED(rv)) { - return; + if (!mRootContent) { + // Create synthetic document + nsresult rv = CreateSyntheticDocument(); + NS_ASSERTION(NS_SUCCEEDED(rv), "failed to create synthetic document"); + + if (mImageResizingEnabled) { + target = do_QueryInterface(mImageContent); + target->AddEventListener(NS_LITERAL_STRING("click"), this, PR_FALSE); + } } if (mImageResizingEnabled) { - nsCOMPtr target = do_QueryInterface(mImageContent); - target->AddEventListener(NS_LITERAL_STRING("click"), this, PR_FALSE); - target = do_QueryInterface(aScriptGlobalObject); target->AddEventListener(NS_LITERAL_STRING("resize"), this, PR_FALSE); target->AddEventListener(NS_LITERAL_STRING("keypress"), this, PR_FALSE); diff --git a/content/html/document/src/nsPluginDocument.cpp b/content/html/document/src/nsPluginDocument.cpp index 97c769d843f..1a26e803b25 100644 --- a/content/html/document/src/nsPluginDocument.cpp +++ b/content/html/document/src/nsPluginDocument.cpp @@ -63,6 +63,7 @@ public: nsIContentSink* aSink = nsnull); virtual void SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject); + virtual PRBool CanSavePresentation(nsIRequest *aNewRequest); protected: nsresult CreateSyntheticPluginDocument(); @@ -103,6 +104,15 @@ nsPluginDocument::SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObje } +PRBool +nsPluginDocument::CanSavePresentation(nsIRequest *aNewRequest) +{ + // Full-page plugins cannot be cached, currently, because we don't have + // the stream listener data to feed to the plugin instance. + return PR_FALSE; +} + + nsresult nsPluginDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel, diff --git a/content/xbl/src/nsXBLPrototypeHandler.cpp b/content/xbl/src/nsXBLPrototypeHandler.cpp index d81d4941434..9ad07213037 100644 --- a/content/xbl/src/nsXBLPrototypeHandler.cpp +++ b/content/xbl/src/nsXBLPrototypeHandler.cpp @@ -289,6 +289,8 @@ nsXBLPrototypeHandler::ExecuteHandler(nsIDOMEventReceiver* aReceiver, return NS_ERROR_FAILURE; privateWindow = do_QueryInterface(doc->GetScriptGlobalObject()); + if (!privateWindow) + return NS_ERROR_FAILURE; } focusController = privateWindow->GetRootFocusController(); diff --git a/content/xbl/src/nsXBLService.cpp b/content/xbl/src/nsXBLService.cpp index 5eb2a82258a..d870e81eb0e 100644 --- a/content/xbl/src/nsXBLService.cpp +++ b/content/xbl/src/nsXBLService.cpp @@ -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; diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 379adc55be3..c811ecf178b 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -166,9 +166,12 @@ static NS_DEFINE_CID(kDOMScriptObjectFactoryCID, #if defined(DEBUG_bryner) //#define DEBUG_DOCSHELL_FOCUS +#define DEBUG_PAGE_CACHE #endif #include "plevent.h" +#include "nsGUIEvent.h" +#include "nsIPrivateDOMEvent.h" // Number of documents currently loading static PRInt32 gNumberOfDocumentsLoading = 0; @@ -246,6 +249,7 @@ nsDocShell::nsDocShell(): mIsBeingDestroyed(PR_FALSE), mIsExecutingOnLoadHandler(PR_FALSE), mIsPrintingOrPP(PR_FALSE), + mSavingOldViewer(PR_FALSE), mAppType(nsIDocShell::APP_TYPE_UNKNOWN), mChildOffset(0), mBusyFlags(BUSY_FLAGS_NONE), @@ -1355,12 +1359,7 @@ nsDocShell::SetCurrentURI(nsIURI *aURI, nsIRequest *aRequest, 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) { @@ -1675,6 +1674,20 @@ nsDocShell::TabToTreeOwner(PRBool aForward, PRBool* aTookFocus) 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 //***************************************************************************** @@ -3257,12 +3270,11 @@ nsDocShell::LoadPage(nsISupports *aPageDescriptor, PRUint32 aDisplayType) // 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; @@ -3716,7 +3728,7 @@ nsDocShell::SetTitle(const PRUnichar * aTitle) // would suffice. if (mOSHE && (mLoadType != LOAD_BYPASS_HISTORY) && (mLoadType != LOAD_HISTORY) && (mLoadType != LOAD_ERROR_PAGE)) { - mOSHE->SetTitle(mTitle.get()); + mOSHE->SetTitle(mTitle); } @@ -4312,6 +4324,60 @@ nsDocShell::CancelRefreshURITimers() } NS_IMETHODIMP +nsDocShell::SuspendRefreshURIs() +{ + if (mRefreshURIList) { + PRUint32 n = 0; + mRefreshURIList->Count(&n); + + for (PRUint32 i = 0; i < n; ++i) { + nsCOMPtr timer = do_QueryElementAt(mRefreshURIList, i); + 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); + } + } + + // Suspend refresh URIs for our child shells as well. + PRInt32 n = mChildList.Count(); + + for (PRInt32 i = 0; i < n; ++i) { + nsCOMPtr shell = do_QueryInterface(ChildAt(i)); + if (shell) + shell->SuspendRefreshURIs(); + } + + return NS_OK; +} + +NS_IMETHODIMP +nsDocShell::ResumeRefreshURIs() +{ + RefreshURIFromQueue(); + + // Resume refresh URIs for our child shells as well. + PRInt32 n = mChildList.Count(); + + for (PRInt32 i = 0; i < n; ++i) { + nsCOMPtr shell = do_QueryInterface(ChildAt(i)); + if (shell) + shell->ResumeRefreshURIs(); + } + + return NS_OK; +} + +nsresult nsDocShell::RefreshURIFromQueue() { if (!mRefreshURIList) @@ -4697,6 +4763,433 @@ nsDocShell::CreateAboutBlankContentViewer() return rv; } +PRBool +nsDocShell::CanSavePresentation(nsIRequest *aNewRequest) +{ + if (!mOSHE) + return PR_FALSE; // no entry to save into + + // 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 the session history entry has the saveLayoutState flag set to false, + // then we should not cache the presentation. + PRBool canSaveState; + mOSHE->GetSaveLayoutStateFlag(&canSaveState); + if (canSaveState == PR_FALSE) + return PR_FALSE; + + // If the document is not done loading, don't cache it. + nsCOMPtr pWin = do_QueryInterface(mScriptGlobal); + if (!pWin || pWin->IsLoading()) + return PR_FALSE; + + // Avoid doing the work of saving the presentation state in the case where + // the content viewer cache is disabled. + PRInt32 maxViewers = 0; + mPrefs->GetIntPref("browser.sessionhistory.max_viewers", &maxViewers); + if (maxViewers == 0) + return PR_FALSE; + + // If the document does not want its presentation cached, then don't. + nsCOMPtr doc = do_QueryInterface(pWin->GetExtantDocument()); + if (!doc || !doc->CanSavePresentation(aNewRequest)) + return PR_FALSE; + + return PR_TRUE; +} + +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); + } + } + } + } + + // Capture the docshell hierarchy. + mOSHE->ClearChildShells(); + + PRInt32 childCount = mChildList.Count(); + for (PRInt32 i = 0; i < childCount; ++i) { + nsCOMPtr 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); +} + +NS_IMETHODIMP +nsDocShell::FireRestoreEvents() +{ + // These events fire bottom-up, so call this on our children first. + PRInt32 n = mChildList.Count(); + for (PRInt32 i = 0; i < n; ++i) { + nsCOMPtr child = do_QueryInterface(ChildAt(i)); + if (child) { + child->FireRestoreEvents(); + } + } + + // 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. + + nsCOMPtr docViewer = do_QueryInterface(mContentViewer); + NS_ASSERTION(docViewer, "should not be called with a null viewer"); + + nsCOMPtr shell; + docViewer->GetPresShell(getter_AddRefs(shell)); + NS_ENSURE_TRUE(shell, NS_ERROR_UNEXPECTED); + + nsEvent event(PR_TRUE, NS_PAGE_LOAD); + nsEventStatus status = nsEventStatus_eIgnore; + + nsCOMPtr privWin = do_QueryInterface(mScriptGlobal); + NS_ENSURE_TRUE(privWin, NS_ERROR_UNEXPECTED); + + nsCOMPtr handler = privWin->GetChromeEventHandler(); + + 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; + nsPresContext *pc = shell->GetPresContext(); + + nsresult rv = handler->HandleChromeEvent(pc, &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(); + } + } + } + + status = nsEventStatus_eIgnore; + nsEvent restoreEvent(PR_TRUE, NS_PAGE_RESTORE); + + return mScriptGlobal->HandleDOMEvent(pc, &restoreEvent, nsnull, + NS_EVENT_FLAG_INIT, &status); +} + + +nsresult +nsDocShell::RestorePresentation(nsISHEntry *aSHEntry, PRBool aSavePresentation, + PRBool *aRestored) +{ + NS_ASSERTION(mLoadType & LOAD_CMD_HISTORY, + "RestorePresentation should only be called for history loads"); + + 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 + + *aRestored = PR_FALSE; + + if (!viewer) { +#ifdef DEBUG_PAGE_CACHE + printf("no saved presentation for uri: %s\n", spec.get()); +#endif + return NS_OK; + } + + 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. + + if (!aSavePresentation) + FireUnloadNotification(); + + mFiredUnloadEvent = PR_FALSE; + + if (mContentViewer) { + mContentViewer->Close(); + + if (aSavePresentation) + 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(); + + // Now remove it from the cached presentation. + aSHEntry->SetContentViewer(nsnull); + + // Restore our child docshell hierarchy. + DestroyChildren(); + NS_ENSURE_SUCCESS(rv, rv); + + 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. The viewer has set this state + // on the history entry in Destroy() just before marking itself non-sticky, + // to avoid teardown of the presentation. + PRBool sticky; + aSHEntry->GetSticky(&sticky); + mContentViewer->SetSticky(sticky); + + // get the previous content viewer size + nsRect oldBounds(0, 0, 0, 0); + aSHEntry->GetViewerBounds(oldBounds); + + nsCOMPtr shell; + nsDocShell::GetPresShell(getter_AddRefs(shell)); + + nsIViewManager *newVM = shell ? shell->GetViewManager() : nsnull; + nsIView *newRootView = nsnull; + if (newVM) + newVM->GetRootView(newRootView); + + // Insert the new root view at the correct location in the view tree. + if (rootViewParent) { + nsIViewManager *parentVM = rootViewParent->GetViewManager(); + + if (parentVM && newRootView) { + parentVM->InsertChild(rootViewParent, newRootView, + rootViewSibling, PR_TRUE); + + NS_ASSERTION(newRootView->GetNextSibling() == rootViewSibling, + "error in InsertChild"); + } + } + + // 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. The refresh timers will be restarted + // when EndPageLoad() is called. + aSHEntry->GetRefreshURIList(getter_AddRefs(mRefreshURIList)); + aSHEntry->SetRefreshURIList(nsnull); + + // Restore the page title. Re-setting the current title on the document + // will update the docshell title and dispatch DOMTitleChanged. + nsIDocument *doc = shell->GetDocument(); + nsCOMPtr nsDoc = do_QueryInterface(doc); + if (doc && nsDoc) { + const nsAFlatString &title = doc->GetDocumentTitle(); + nsDoc->SetTitle(title); + } + + mOSHE = aSHEntry; + + // mEODForCurrentDocument is true here, so EndPageLoad will not fire + // onload (we fire that below, in a special way so that the content window + // does not see it). + EndPageLoad(nsnull, nsnull, NS_OK); + + // Meta-refresh timers have been restarted for this shell, but not + // for our children. Walk the child shells and restart their timers. + PRInt32 n = mChildList.Count(); + for (i = 0; i < n; ++i) { + nsCOMPtr child = do_QueryInterface(ChildAt(i)); + if (child) + child->ResumeRefreshURIs(); + } + + nsCOMPtr rootSH; + GetRootSessionHistory(getter_AddRefs(rootSH)); + if (rootSH) { + 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). + + if (newRootView) { + nsIWidget *widget = newRootView->GetWidget(); + if (widget && !newBounds.IsEmpty() && newBounds != oldBounds) { +#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 onload and DOMPageRestore. + rv = FireRestoreEvents(); + NS_ENSURE_SUCCESS(rv, rv); + + rv = mContentViewer->Show(); + NS_ENSURE_SUCCESS(rv, rv); + + // Restart plugins + if (shell) + shell->Thaw(); + + // 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? + + rv = mParentWidget->Invalidate(PR_FALSE); + NS_ENSURE_SUCCESS(rv, rv); + + *aRestored = PR_TRUE; + return NS_OK; +} + NS_IMETHODIMP nsDocShell::CreateContentViewer(const char *aContentType, nsIRequest * request, @@ -4723,7 +5216,10 @@ nsDocShell::CreateContentViewer(const char *aContentType, // 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. @@ -4738,6 +5234,18 @@ nsDocShell::CreateContentViewer(const char *aContentType, PRBool onLocationChangeNeeded = OnLoadingSite(aOpenedChannel, PR_FALSE); + if (savePresentation) { + // The old content viewer will be saved during the call to Embed(). + rv = CaptureState(); + if (NS_SUCCEEDED(rv)) { + mSavingOldViewer = PR_TRUE; + } else { + if (mOSHE) { + mOSHE->SyncPresentationState(); + } + } + } + // let's try resetting the load group if we need to... nsCOMPtr currentLoadGroup; NS_ENSURE_SUCCESS(aOpenedChannel-> @@ -4779,6 +5287,7 @@ nsDocShell::CreateContentViewer(const char *aContentType, NS_ENSURE_SUCCESS(Embed(viewer, "", (nsISupports *) nsnull), NS_ERROR_FAILURE); + mSavingOldViewer = PR_FALSE; mEODForCurrentDocument = PR_FALSE; // if this document is part of a multipart document, @@ -5028,6 +5537,13 @@ nsDocShell::SetupNewViewer(nsIContentViewer * aNewViewer) mContentViewer->Close(); aNewViewer->SetPreviousViewer(mContentViewer); + + if (mSavingOldViewer) { + // Tell the old content viewer to hibernate in session history when + // it is destroyed. + mContentViewer->SetHistoryEntry(mOSHE); + } + mContentViewer = nsnull; } @@ -5568,7 +6084,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; @@ -5588,6 +6104,12 @@ nsDocShell::InternalLoad(nsIURI * aURI, } } + // Check for saving the presentation here, before calling Stop(). + // This is necessary so that we can catch any pending requests. + // Since the new request has not been created yet, we pass null for the + // new request parameter. + PRBool savePresentation = CanSavePresentation(nsnull); + // Don't stop current network activity for javascript: URL's since // they might not result in any data, and thus nothing should be // stopped in those cases. In the case where they do result in @@ -5623,6 +6145,30 @@ 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 (savePresentation) { + rv = CaptureState(); + if (NS_FAILED(rv) && mOSHE) + mOSHE->SyncPresentationState(); + } + + nsCOMPtr oldEntry = mOSHE; + PRBool restored; + rv = RestorePresentation(aSHEntry, savePresentation && + NS_SUCCEEDED(rv), &restored); + if (restored) + return rv; + + // We failed to restore the presentation, so clean up. + // Both the old and new history entries could potentially be in + // an inconsistent state. + if (oldEntry) + oldEntry->SyncPresentationState(); + + aSHEntry->SyncPresentationState(); + } + nsCOMPtr req; rv = DoURILoad(aURI, aReferrer, !(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER), @@ -6520,12 +7066,11 @@ nsDocShell::AddToSessionHistory(nsIURI * aURI, } //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 @@ -6556,7 +7101,6 @@ nsDocShell::AddToSessionHistory(nsIURI * aURI, 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 @@ -6601,10 +7145,8 @@ nsDocShell::LoadHistoryEntry(nsISHEntry * aEntry, PRUint32 aLoadType) 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)), @@ -6699,9 +7241,8 @@ nsDocShell::CloneAndReplace(nsISHEntry * src, PRUint32 aCloneID, 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) { diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index fbcde1601bb..4b1c4699a37 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -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,7 @@ protected: NS_IMETHOD EnsureEditorData(); nsresult EnsureTransferableHookData(); NS_IMETHOD EnsureFind(); - NS_IMETHOD RefreshURIFromQueue(); + nsresult RefreshURIFromQueue(); NS_IMETHOD DisplayLoadError(nsresult aError, nsIURI *aURI, const PRUnichar *aURL, nsIChannel* aFailedChannel = nsnull); @@ -395,6 +396,50 @@ 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|. The old presentation + // is saved in session history if |aSavePresentation| is true. + // If a presentation could be restored, |aRestored| is set to true. + nsresult RestorePresentation(nsISHEntry *aSHEntry, + PRBool aSavePresentation, + PRBool *aRestored); + protected: // Override the parent setter from nsDocLoader virtual nsresult SetDocLoaderParent(nsDocLoader * aLoader); @@ -426,6 +471,10 @@ protected: // Indicates that a DocShell in this "docshell tree" is printing PRPackedBool mIsPrintingOrPP; + // Indicates to SetupNewViewer() that we are in the process of saving the + // presentation for mContentViewer. + PRPackedBool mSavingOldViewer; + PRUint32 mAppType; // Offset in the parent's child list. @@ -474,6 +523,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. diff --git a/docshell/base/nsIContentViewer.idl b/docshell/base/nsIContentViewer.idl index 3c491a11d68..b9355d8aef0 100644 --- a/docshell/base/nsIContentViewer.idl +++ b/docshell/base/nsIContentViewer.idl @@ -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,22 @@ 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, in which case + * it will never be saved in session history. + */ + void setHistoryEntry(in nsISHEntry entry); }; diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl index 61af1424d2c..bced3e80656 100644 --- a/docshell/base/nsIDocShell.idl +++ b/docshell/base/nsIDocShell.idl @@ -64,8 +64,9 @@ interface nsIInputStream; interface nsIRequest; interface nsISHEntry; interface nsILayoutHistoryState; +interface nsISecureBrowserUI; -[scriptable, uuid(BBFDF99E-D675-42FD-B3EA-EA341C2331A6)] +[scriptable, uuid(b0228925-9242-467b-842f-dc739a6e478f)] interface nsIDocShell : nsISupports { /** @@ -340,5 +341,35 @@ 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; + + /** + * Cancel the XPCOM timers for each meta-refresh URI in this docshell, + * and this docshell's children, recursively. The meta-refresh timers can be + * restarted using resumeRefreshURIs(). If the timers are already suspended, + * this has no effect. + */ + void suspendRefreshURIs(); + + /** + * Restart the XPCOM timers for each meta-refresh URI in this docshell, + * and this docshell's children, recursively. If the timers are already + * running, this has no effect. + */ + void resumeRefreshURIs(); + + /** + * Fire the onload and DOMPageRestore events as part of restoring a + * presentation from sessino history. The onload event is fired starting + * at the chrome event handler; the DOMPageRestore event is fired starting + * at the window object. This first recurses into child docshells so that + * events fire in a bottom-up order. + */ + void fireRestoreEvents(); }; diff --git a/dom/public/base/nsPIDOMWindow.h b/dom/public/base/nsPIDOMWindow.h index 6448e8f5eef..2f3838190fd 100644 --- a/dom/public/base/nsPIDOMWindow.h +++ b/dom/public/base/nsPIDOMWindow.h @@ -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,13 @@ public: // Clear all pending timeouts and intervals. virtual void ClearAllTimeouts() = 0; + // Returns an object containing the window's state. This also suspends + // all running timeouts in the window. + 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), diff --git a/dom/public/coreEvents/nsIDOMLoadListener.h b/dom/public/coreEvents/nsIDOMLoadListener.h index ca984756a7c..e07060141f7 100644 --- a/dom/public/coreEvents/nsIDOMLoadListener.h +++ b/dom/public/coreEvents/nsIDOMLoadListener.h @@ -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__ diff --git a/dom/src/base/nsGlobalWindow.cpp b/dom/src/base/nsGlobalWindow.cpp index 6fde9bee114..20173697cac 100644 --- a/dom/src/base/nsGlobalWindow.cpp +++ b/dom/src/base/nsGlobalWindow.cpp @@ -153,6 +153,7 @@ #include "nsIBindingManager.h" #include "nsIXBLService.h" +#include "nsInt64.h" // used for popup blocking, needs to be converted to something // belonging to the back-end like nsIContentPolicy @@ -171,6 +172,10 @@ static PRInt32 gRunningTimeoutDepth = 0; PRInt32 gTimeoutCnt = 0; #endif +#ifdef DEBUG_bryner +#define DEBUG_PAGE_CACHE +#endif + #define DOM_MIN_TIMEOUT_VALUE 10 // 10ms // CIDs @@ -4301,10 +4306,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)); + } } } @@ -5797,6 +5804,387 @@ nsGlobalWindow::EnsureSizeUpToDate() } } +#define WINDOWSTATEHOLDER_IID \ +{0xae1c7401, 0xcdee, 0x404a, {0xbd, 0x63, 0x05, 0xc0, 0x35, 0x0d, 0xa7, 0x72}} + +class WindowStateHolder : public nsISupports +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(WINDOWSTATEHOLDER_IID) + NS_DECL_ISUPPORTS + + WindowStateHolder(JSContext *cx, // The JSContext for the window + JSObject *aObject, // An object to save the properties onto + nsGlobalWindow *aWindow); // The window to operate on + + // This is the property store object that holds the window properties. + JSObject* GetObject() { return mJSObj; } + + // Get the listener manager, which holds all event handlers for the window. + nsIEventListenerManager* GetListenerManager() { return mListenerManager; } + + // Get the contents of focus memory when the state was saved + // (if the focus was inside of this window). + nsIDOMElement* GetFocusedElement() { return mFocusedElement; } + nsIDOMWindowInternal* GetFocusedWindow() { return mFocusedWindow; } + + // Manage the list of saved timeouts for the window. + nsTimeout* GetSavedTimeouts() { return mSavedTimeouts; } + nsTimeout** GetTimeoutInsertionPoint() { return mTimeoutInsertionPoint; } + void ClearSavedTimeouts() { mSavedTimeouts = nsnull; } + +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) +{ + 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)); + + nsCOMPtr focusedWindow = do_QueryInterface(focusWinInternal); + + while (focusedWindow) { + if (focusedWindow == aWindow) { + fc->GetFocusedWindow(getter_AddRefs(mFocusedWindow)); + fc->GetFocusedElement(getter_AddRefs(mFocusedElement)); + break; + } + + focusedWindow = + NS_STATIC_CAST(nsGlobalWindow*, + NS_STATIC_CAST(nsPIDOMWindow*, + focusedWindow))->GetPrivateParent(); + } + + aWindow->SuspendTimeouts(); + + // Clear the timeout list for aWindow (but we don't need to for children) + mSavedTimeouts = aWindow->mTimeouts; + mTimeoutInsertionPoint = aWindow->mTimeoutInsertionPoint; + + aWindow->mTimeouts = nsnull; + aWindow->mTimeoutInsertionPoint = &aWindow->mTimeouts; + + ::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; + for (jsint i = 0; i < length; ++i) { + jsval propname_value; + + if (!::JS_IdToValue(cx, props->vector[i], &propname_value) || + !JSVAL_IS_STRING(propname_value)) { + NS_WARNING("Failed to copy non-string-named window property"); + return NS_ERROR_FAILURE; + } + + JSString *propname = JSVAL_TO_STRING(propname_value); + jschar *propname_str = ::JS_GetStringChars(propname); + NS_ENSURE_TRUE(propname_str, NS_ERROR_FAILURE); + + // We exclude the "location" property because restoring it this way is + // problematic. It will "just work" without us explicitly saving or + // restoring the value. + + if (!nsCRT::strcmp(NS_STATIC_CAST(PRUnichar*, propname_str), + NS_LITERAL_STRING("location").get())) { + continue; + } + + size_t propname_len = ::JS_GetStringLength(propname); + + JSPropertyOp getter, setter; + uintN attrs; + JSBool found; + if (!::JS_GetUCPropertyAttrsGetterAndSetter(cx, aSource, propname_str, + propname_len, &attrs, &found, + &getter, &setter)) + return NS_ERROR_FAILURE; + + NS_ENSURE_TRUE(found, NS_ERROR_UNEXPECTED); + + jsval propvalue; + if (!::JS_LookupUCProperty(cx, aSource, propname_str, + propname_len, &propvalue)) + return NS_ERROR_FAILURE; + + PRBool res = ::JS_DefineUCProperty(cx, aDest, propname_str, propname_len, + propvalue, getter, setter, attrs); +#ifdef DEBUG_PAGE_CACHE + if (res) + printf("Copied window property: %s\n", + NS_ConvertUTF16toUTF8(NS_STATIC_CAST(PRUnichar*, + propname_str)).get()); +#endif + + if (!res) { +#ifdef DEBUG + printf("failed to copy property: %s\n", + NS_ConvertUTF16toUTF8(NS_STATIC_CAST(PRUnichar*, + propname_str)).get()); +#endif + return NS_ERROR_FAILURE; + } + } + + return NS_OK; +} + +static nsresult +CopyJSProperties(JSContext *cx, JSObject *aSource, JSObject *aDest) +{ + // Enumerate all of the properties on aSource and install them on aDest. + + JSIdArray *props = ::JS_Enumerate(cx, aSource); + if (!props) { +#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); + + // The window state object will root the JSObject. + *aState = new WindowStateHolder(cx, stateObj, this); + NS_ENSURE_TRUE(*aState, 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); + + 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 would remove the + // XPConnect properties. + + nsCOMPtr holder = do_QueryInterface(aState); + NS_ENSURE_TRUE(holder, NS_ERROR_FAILURE); + +#ifdef DEBUG_PAGE_CACHE + printf("restoring window state, stateObj = %p\n", holder->GetObject()); +#endif + nsresult rv = CopyJSProperties(cx, holder->GetObject(), mJSObject); + NS_ENSURE_SUCCESS(rv, rv); + + mListenerManager = holder->GetListenerManager(); + + nsIDOMElement *focusedElement = holder->GetFocusedElement(); + nsIDOMWindowInternal *focusedWindow = holder->GetFocusedWindow(); + + // If the toplevel window isn't focused, just update the focus controller. + nsIFocusController *fc = nsGlobalWindow::GetRootFocusController(); + NS_ENSURE_TRUE(fc, NS_ERROR_UNEXPECTED); + + PRBool active; + fc->GetActive(&active); + if (active) { + PRBool didFocusContent = PR_FALSE; + nsCOMPtr focusedContent = do_QueryInterface(focusedElement); + + if (focusedContent) { + // We don't bother checking whether the element or frame is focusable. + // If it was focusable when we stored the presentation, it must be + // focusable now. + PRBool didFocusContent = PR_FALSE; + nsIDocument *doc = focusedContent->GetCurrentDoc(); + if (doc) { + nsIPresShell *shell = doc->GetShellAt(0); + if (shell) { + nsPresContext *pc = shell->GetPresContext(); + if (pc) { + pc->EventStateManager()->SetContentState(focusedContent, + NS_EVENT_STATE_FOCUS); + didFocusContent = PR_TRUE; + } + } + } + } + + if (!didFocusContent && focusedWindow) + focusedWindow->Focus(); + } else if (focusedWindow) { + // Just update the saved focus memory. + fc->SetFocusedWindow(focusedWindow); + fc->SetFocusedElement(focusedElement); + } + + mTimeouts = holder->GetSavedTimeouts(); + mTimeoutInsertionPoint = holder->GetTimeoutInsertionPoint(); + + holder->ClearSavedTimeouts(); + + // If our state is being restored from history, we won't be getting an onload + // event. Make sure we're marked as being completely loaded. + mIsDocumentLoaded = PR_TRUE; + + return ResumeTimeouts(); +} + +void +nsGlobalWindow::SuspendTimeouts() +{ + nsInt64 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(nsInt64(0), nsInt64(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); + + for (PRInt32 i = 0; i < childCount; ++i) { + nsCOMPtr childShell; + 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. + + nsInt64 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 + nsInt64(t->mWhen); + + 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); + + for (PRInt32 i = 0; i < childCount; ++i) { + nsCOMPtr childShell; + 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) diff --git a/dom/src/base/nsGlobalWindow.h b/dom/src/base/nsGlobalWindow.h index 4eb413357a8..e9590706e25 100644 --- a/dom/src/base/nsGlobalWindow.h +++ b/dom/src/base/nsGlobalWindow.h @@ -105,6 +105,7 @@ class nsNavigator; class nsScreen; class nsHistory; class nsIDocShellLoadInfo; +class WindowStateHolder; //***************************************************************************** // nsGlobalWindow: Global Object for Scripting @@ -204,6 +205,8 @@ 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); // nsIDOMViewCSS NS_DECL_NSIDOMVIEWCSS @@ -220,6 +223,8 @@ public: static void ShutDown(); static PRBool IsCallerChrome(); + friend class WindowStateHolder; + protected: // Object Management virtual ~nsGlobalWindow(); @@ -304,6 +309,9 @@ protected: already_AddRefed GetMainWidget(); + void SuspendTimeouts(); + nsresult ResumeTimeouts(); + // When adding new member variables, be careful not to create cycles // through JavaScript. If there is any chance that a member variable // could own objects that are implemented in JavaScript, then those diff --git a/embedding/browser/cocoa/src/CHClickListener.mm b/embedding/browser/cocoa/src/CHClickListener.mm index cb62bfe4ffb..8fe9e357302 100644 --- a/embedding/browser/cocoa/src/CHClickListener.mm +++ b/embedding/browser/cocoa/src/CHClickListener.mm @@ -203,28 +203,30 @@ CHClickListener::MouseDown(nsIDOMEvent* aEvent) 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; } diff --git a/embedding/browser/webBrowser/nsWebBrowser.cpp b/embedding/browser/webBrowser/nsWebBrowser.cpp index a78c0ff6705..4e5396eef51 100644 --- a/embedding/browser/webBrowser/nsWebBrowser.cpp +++ b/embedding/browser/webBrowser/nsWebBrowser.cpp @@ -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) diff --git a/embedding/browser/webBrowser/nsWebBrowser.h b/embedding/browser/webBrowser/nsWebBrowser.h index 7f94158735b..aa6241d61af 100644 --- a/embedding/browser/webBrowser/nsWebBrowser.h +++ b/embedding/browser/webBrowser/nsWebBrowser.h @@ -168,7 +168,6 @@ protected: nativeWindow mParentNativeWindow; nsIWebProgressListener *mProgressListener; nsCOMPtr mWebProgress; - nsCOMPtr mSecurityUI; nsCOMPtr mPrintSettings; diff --git a/embedding/tests/mfcembed/StdAfx.h b/embedding/tests/mfcembed/StdAfx.h index 180902f8820..e69de29bb2d 100644 --- a/embedding/tests/mfcembed/StdAfx.h +++ b/embedding/tests/mfcembed/StdAfx.h @@ -1,132 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: Mozilla-sample-code 1.0 - * - * Copyright (c) 2002 Netscape Communications Corporation and - * other contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this Mozilla sample software and associated documentation files - * (the "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to permit - * persons to whom the Software is furnished to do so, subject to the - * following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - * Contributor(s): - * Chak Nanga - * - * ***** END LICENSE BLOCK ***** */ - -// stdafx.h : include file for standard system include files, -// or project specific include files that are used frequently, but -// are changed infrequently -// - -#ifndef _STDAFX_H -#define _STDAFX_H - -#if _MSC_VER > 1000 -#pragma once -#endif // _MSC_VER > 1000 - -#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers - -// -// These headers are very evil, as they will define DEBUG if _DEBUG is -// defined, which is lame and not what we want for things like -// MOZ_TRACE_MALLOC and other tools. -// If we do not detect this, various MOZ/NS debug symbols are undefined -// and we can not build. -// /MDd defines _DEBUG automagically to have the right debug C LIB -// functions get called (so we can get symbols and hook into malloc). -// -#if !defined(DEBUG) -#define THERECANBENODEBUG -#endif - -#include // MFC core and standard components -#include // MFC extensions -#include // MFC support for Internet Explorer 4 Common Controls -#include // Needed for MFC MBCS/Unicode Conversion Macros -#ifndef _AFX_NO_AFXCMN_SUPPORT -#include // MFC support for Windows Common Controls -#endif // _AFX_NO_AFXCMN_SUPPORT - -//{{AFX_INSERT_LOCATION}} -// Microsoft Visual C++ will insert additional declarations immediately before the previous line. - -#if defined(THERECANBENODEBUG) && defined(DEBUG) -#undef DEBUG -#endif - -#include "nsCOMPtr.h" -#include "nsEmbedString.h" -#include "nsCWebBrowser.h" -#include "nsWidgetsCID.h" -#include "nsIDocShell.h" -#include "nsIWebBrowser.h" -#include "nsIBaseWindow.h" -#include "nsIWebNavigation.h" -#include "nsIWebBrowserChrome.h" -#include "nsIWebProgressListener.h" -#include "nsIWebProgress.h" -#include "nsIWindowCreator.h" -#include "nsIInterfaceRequestor.h" -#include "nsIInterfaceRequestorUtils.h" -#include "nsIDocShellTreeOwner.h" -#include "nsIDocShellTreeItem.h" -#include "nsIClipboardCommands.h" -#include "nsIWebBrowserPersist.h" -#include "nsIContextMenuListener2.h" -#include "nsITooltipListener.h" -#include "nsIDOMNode.h" -#include "nsIDOMHTMLAnchorElement.h" -#include "nsIDOMHTMLImageElement.h" -#include "nsIDOMDocument.h" -#include "nsIDOMHTMLDocument.h" -#include "nsIDOMHTMLFrameSetElement.h" -#include "nsIPrompt.h" -#include "nsEmbedAPI.h" -#include "nsISHistory.h" -#include "nsISHEntry.h" -#include "nsIPref.h" -#include "nsAppDirectoryServiceDefs.h" -#include "nsIProfileChangeStatus.h" -#include "nsIObserverService.h" -#include "imgIContainer.h" -#ifdef MOZ_OLD_CACHE -#include "nsINetDataCacheManager.h" -#endif -#include "nsError.h" -#include "nsIObserver.h" -#include "nsWeakReference.h" -#include "nsIEmbeddingSiteWindow2.h" -#include "nsIWebBrowserFind.h" -#include "nsIWebBrowserFocus.h" - -// Printer Includes -#include "nsIWebBrowserPrint.h" -#include "nsIDOMWindow.h" - -// MfcEmbed #defines - -// USE_PROFILES - If defined, nsIProfile will be used which allows for -// multiple profiles. If not defined, a standalone directory service provider -// will be used to provide "profile" locations to one specified directory. -// In the case, the mozilla profile DLL is not needed. - -#define USE_PROFILES 1 - -#endif //_STDAFX_H diff --git a/extensions/xmlextras/base/src/nsDOMParser.cpp b/extensions/xmlextras/base/src/nsDOMParser.cpp index f61a94eac5d..a5788dee8f3 100644 --- a/extensions/xmlextras/base/src/nsDOMParser.cpp +++ b/extensions/xmlextras/base/src/nsDOMParser.cpp @@ -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) { diff --git a/extensions/xmlextras/base/src/nsDOMParser.h b/extensions/xmlextras/base/src/nsDOMParser.h index 4fc7059bd8a..4ab15930069 100644 --- a/extensions/xmlextras/base/src/nsDOMParser.h +++ b/extensions/xmlextras/base/src/nsDOMParser.h @@ -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; diff --git a/extensions/xmlextras/base/src/nsLoadListenerProxy.cpp b/extensions/xmlextras/base/src/nsLoadListenerProxy.cpp index f1527e8fa4c..e4ecdb2dded 100644 --- a/extensions/xmlextras/base/src/nsLoadListenerProxy.cpp +++ b/extensions/xmlextras/base/src/nsLoadListenerProxy.cpp @@ -121,3 +121,15 @@ nsLoadListenerProxy::Error(nsIDOMEvent* aEvent) return NS_OK; } + +NS_IMETHODIMP +nsLoadListenerProxy::PageRestore(nsIDOMEvent* aEvent) +{ + nsCOMPtr listener(do_QueryReferent(mParent)); + + if (listener) { + return listener->PageRestore(aEvent); + } + + return NS_OK; +} diff --git a/extensions/xmlextras/base/src/nsLoadListenerProxy.h b/extensions/xmlextras/base/src/nsLoadListenerProxy.h index d0582d53107..10584725c87 100644 --- a/extensions/xmlextras/base/src/nsLoadListenerProxy.h +++ b/extensions/xmlextras/base/src/nsLoadListenerProxy.h @@ -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; diff --git a/extensions/xmlextras/base/src/nsXMLHttpRequest.cpp b/extensions/xmlextras/base/src/nsXMLHttpRequest.cpp index a1a394842ac..71c7abde886 100644 --- a/extensions/xmlextras/base/src/nsXMLHttpRequest.cpp +++ b/extensions/xmlextras/base/src/nsXMLHttpRequest.cpp @@ -1743,6 +1743,12 @@ nsXMLHttpRequest::Error(nsIDOMEvent* aEvent) return NS_OK; } +NS_IMETHODIMP +nsXMLHttpRequest::PageRestore(nsIDOMEvent* aEvent) +{ + return NS_OK; +} + nsresult nsXMLHttpRequest::ChangeState(PRUint32 aState, PRBool aBroadcast, PRBool aClearEventListeners) diff --git a/extensions/xmlextras/base/src/nsXMLHttpRequest.h b/extensions/xmlextras/base/src/nsXMLHttpRequest.h index 41857074394..77ba6ddb7e0 100644 --- a/extensions/xmlextras/base/src/nsXMLHttpRequest.h +++ b/extensions/xmlextras/base/src/nsXMLHttpRequest.h @@ -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 diff --git a/extensions/xmlextras/tests/TestXMLExtras.cpp b/extensions/xmlextras/tests/TestXMLExtras.cpp index 441b0393bc9..afa4829bb89 100644 --- a/extensions/xmlextras/tests/TestXMLExtras.cpp +++ b/extensions/xmlextras/tests/TestXMLExtras.cpp @@ -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) diff --git a/layout/base/Makefile.in b/layout/base/Makefile.in index 8ce065b9e82..87fcd475e78 100644 --- a/layout/base/Makefile.in +++ b/layout/base/Makefile.in @@ -73,6 +73,7 @@ REQUIRES = xpcom \ util \ windowwatcher \ accessibility \ + shistory \ $(NULL) XPIDLSRCS = \ diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index 2f449032dc6..0db78b4ad7f 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -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,10 @@ static const char sPrintOptionsContractID[] = "@mozilla.org/gfx/printset #include "nsISelectionController.h" #include "nsBidiUtils.h" +#include "nsISHEntry.h" +#include "nsISHistory.h" +#include "nsISHistoryInternal.h" +#include "nsIWebNavigation.h" //paint forcing #include "prenv.h" @@ -346,7 +349,6 @@ protected: virtual ~DocumentViewerImpl(); private: - void ForceRefresh(void); nsresult MakeWindow(nsIWidget* aParentWidget, const nsRect& aBounds); nsresult InitInternal(nsIWidget* aParentWidget, @@ -398,30 +400,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 +443,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 +499,8 @@ void DocumentViewerImpl::PrepareToStartLoad() // 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(); } @@ -511,9 +516,9 @@ NS_IMPL_ISUPPORTS7(DocumentViewerImpl, DocumentViewerImpl::~DocumentViewerImpl() { - NS_ASSERTION(!mDocument, "User did not call nsIContentViewer::Close"); if (mDocument) { Close(); + mDocument->Destroy(); } NS_ASSERTION(!mPresShell && !mPresContext, @@ -795,19 +800,19 @@ DocumentViewerImpl::InitInternal(nsIWidget* aParentWidget, 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)); @@ -1170,6 +1175,28 @@ DocumentViewerImpl::Unload() NS_EVENT_FLAG_INIT, &status); } +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); + + if (mDocument) + mDocument->SetContainer(mContainer); + + SyncParentSubDocMap(); + + // XXX re-enable image animations once that works correctly + + return NS_OK; +} + NS_IMETHODIMP DocumentViewerImpl::Close() { @@ -1184,66 +1211,59 @@ 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(); + // 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); - } + 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 { + // 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 +#endif + { // 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 +1278,93 @@ 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. + PRBool updateHistory = (mSHEntry != nsnull); + + if (mSHEntry) { + if (mPresShell) + mPresShell->Freeze(); + + // 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); + } + } + } + } + } + + Hide(); + + // This is after Hide() so that the user doesn't see the inputs clear. + if (mDocument) { + nsresult rv = mDocument->Sanitize(); + if (NS_FAILED(rv)) { + // If we failed to sanitize, remove the document immediately. + mSHEntry->SetContentViewer(nsnull); + mSHEntry->SyncPresentationState(); + } + } + + + mSHEntry = nsnull; + + // If we put ourselves into session history, make sure there aren't + // too many content viewers around. Note: if max_viewers is set to 0, + // this can reenter Destroy() and dispose of this content viewer! + + nsCOMPtr webNav = do_QueryInterface(mContainer); + if (webNav) { + nsCOMPtr history; + webNav->GetSessionHistory(getter_AddRefs(history)); + nsCOMPtr historyInt = do_QueryInterface(history); + if (historyInt) { + historyInt->EvictContentViewers(); + } + } + + // Break the link from the document/presentation to the docshell, so that + // link traversals cannot affect the currently-loaded document. + // When the presentation is restored, Open() and InitInternal() will reset + // these pointers to their original values. + + if (mDocument) + mDocument->SetContainer(nsnull); + if (mPresContext) + mPresContext->SetLinkHandler(nsnull); + + return NS_OK; + } + + mDocument->Destroy(); + 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,7 +1423,7 @@ DocumentViewerImpl::Stop(void) mDocument->StopDocumentLoad(); } - if (mEnableRendering && (mLoaded || mStopped) && mPresContext) + if (mEnableRendering && (mLoaded || mStopped) && mPresContext && !mSHEntry) mPresContext->SetImageAnimationMode(imgIContainer::kDontAnimMode); mStopped = PR_TRUE; @@ -1669,7 +1769,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); @@ -1786,6 +1885,13 @@ DocumentViewerImpl::SetSticky(PRBool aSticky) return NS_OK; } +NS_IMETHODIMP +DocumentViewerImpl::SetHistoryEntry(nsISHEntry *aEntry) +{ + mSHEntry = aEntry; + return NS_OK; +} + NS_IMETHODIMP DocumentViewerImpl::GetEnableRendering(PRBool* aResult) { @@ -1811,13 +1917,6 @@ DocumentViewerImpl::RequestWindowClose(PRBool* aCanClose) return NS_OK; } - -void -DocumentViewerImpl::ForceRefresh() -{ - mWindow->Invalidate(PR_TRUE); -} - NS_DEFINE_CID(kCSSLoaderCID, NS_CSS_LOADER_CID); PR_STATIC_CALLBACK(PRBool) diff --git a/layout/base/nsIDocumentViewer.h b/layout/base/nsIDocumentViewer.h index 7b3629aff85..c7d8309f67d 100644 --- a/layout/base/nsIDocumentViewer.h +++ b/layout/base/nsIDocumentViewer.h @@ -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 diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h index 392bb7b1e9e..1f29f6edba0 100644 --- a/layout/base/nsIPresShell.h +++ b/layout/base/nsIPresShell.h @@ -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 @@ -679,6 +679,19 @@ public: PRBool IsAccessibilityActive() { return mIsAccessibilityActive; } + /** + * Stop all active elements (plugins and the caret) in this presentation and + * in the presentations of subdocuments. + * XXX this should include image animations + */ + virtual void Freeze() = 0; + + /** + * Restarts active elements (plugins) in this presentation and in the + * presentations of subdocuments. + */ + virtual void Thaw() = 0; + protected: // IMPORTANT: The ownership implicit in the following member variables // has been explicitly checked. If you add any members to this class, diff --git a/layout/base/nsLayoutAtomList.h b/layout/base/nsLayoutAtomList.h index c30f067ab1b..c7e54bd5a5a 100644 --- a/layout/base/nsLayoutAtomList.h +++ b/layout/base/nsLayoutAtomList.h @@ -164,6 +164,7 @@ LAYOUT_ATOM(oncontextmenu, "oncontextmenu") 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") diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 72c8d4fd5e7..aae707382df 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -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,8 @@ public: NS_IMETHOD IsReflowLocked(PRBool* aIsLocked); virtual nsresult ReconstructFrames(void); + virtual void Freeze(); + virtual void Thaw(); #ifdef IBMBIDI NS_IMETHOD SetCaretBidiLevel(PRUint8 aLevel); @@ -1513,6 +1518,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 @@ -6482,6 +6492,103 @@ PresShell::RemoveOverrideStyleSheet(nsIStyleSheet *aSheet) return mStyleSet->RemoveStyleSheet(nsStyleSet::eOverrideSheet, aSheet); } +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); +} + +PR_STATIC_CALLBACK(PRBool) +FreezeSubDocument(nsIDocument *aDocument, void *aData) +{ + nsIPresShell *shell = aDocument->GetShellAt(0); + if (shell) + shell->Freeze(); + + return PR_TRUE; +} + +void +PresShell::Freeze() +{ + 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); + } + + if (mCaret) + mCaret->SetCaretVisible(PR_FALSE); + + if (mDocument) + mDocument->EnumerateSubDocuments(FreezeSubDocument, nsnull); +} + +static void +StartPluginInstance(PresShell *aShell, nsIContent *aContent) +{ + // For now we just reconstruct the frame. + aShell->RecreateFramesFor(aContent); +} + +PR_STATIC_CALLBACK(PRBool) +ThawSubDocument(nsIDocument *aDocument, void *aData) +{ + nsIPresShell *shell = aDocument->GetShellAt(0); + if (shell) + shell->Thaw(); + + return PR_TRUE; +} + +void +PresShell::Thaw() +{ + 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); + } + + if (mDocument) + mDocument->EnumerateSubDocuments(ThawSubDocument, nsnull); +} + //-------------------------------------------------------- // Start of protected and private methods on the PresShell //-------------------------------------------------------- @@ -7050,6 +7157,29 @@ 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); + + for (PRUint32 i = 0; i < length; ++i) { + nsCOMPtr node; + nodes->Item(i, getter_AddRefs(node)); + + nsCOMPtr content = do_QueryInterface(node); + if (content) + aCallback(this, content); + } +} + //------------------------------------------------------ // End of protected and private methods on the PresShell //------------------------------------------------------ diff --git a/layout/printing/nsPrintEngine.cpp b/layout/printing/nsPrintEngine.cpp index 63818cf315c..fb0ffb80637 100644 --- a/layout/printing/nsPrintEngine.cpp +++ b/layout/printing/nsPrintEngine.cpp @@ -4435,10 +4435,11 @@ nsPrintEngine::TurnScriptingOn(PRBool aDoTurnOn) // 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); + } } //----------------------------------------------------------------- diff --git a/layout/xul/base/src/nsMenuPopupFrame.cpp b/layout/xul/base/src/nsMenuPopupFrame.cpp index ab33bdf5270..c28d1338591 100644 --- a/layout/xul/base/src/nsMenuPopupFrame.cpp +++ b/layout/xul/base/src/nsMenuPopupFrame.cpp @@ -840,6 +840,9 @@ nsMenuPopupFrame::SyncViewWithFrame(nsPresContext* aPresContext, // 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; diff --git a/layout/xul/base/src/nsTitleBarFrame.cpp b/layout/xul/base/src/nsTitleBarFrame.cpp index aac390a39cf..70d6daf7a80 100644 --- a/layout/xul/base/src/nsTitleBarFrame.cpp +++ b/layout/xul/base/src/nsTitleBarFrame.cpp @@ -169,15 +169,10 @@ nsTitleBarFrame::HandleEvent(nsPresContext* aPresContext, 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; diff --git a/netwerk/base/public/nsISecureBrowserUI.idl b/netwerk/base/public/nsISecureBrowserUI.idl index 8f62318f2c5..dbfc6ff1680 100644 --- a/netwerk/base/public/nsISecureBrowserUI.idl +++ b/netwerk/base/public/nsISecureBrowserUI.idl @@ -41,15 +41,23 @@ #include "nsISupports.idl" interface nsIDOMWindow; -interface nsIDOMElement; -[scriptable, uuid(081e31e0-a144-11d3-8c7c-00609792278c)] +[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. */ + nsISupports captureState(); + + /** + * Restore the state captured by captureState(), firing transition + * notifications as necessary. + */ + void transitionToState(in nsISupports state); }; %{C++ diff --git a/security/manager/boot/src/nsSecureBrowserUIImpl.cpp b/security/manager/boot/src/nsSecureBrowserUIImpl.cpp index cc8709d1762..89d7bf1848f 100644 --- a/security/manager/boot/src/nsSecureBrowserUIImpl.cpp +++ b/security/manager/boot/src/nsSecureBrowserUIImpl.cpp @@ -206,12 +206,20 @@ nsSecureBrowserUIImpl::Init(nsIDOMWindow *window) 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::UpdateSecurityState(nsIRequest* aRequest) 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::UpdateSecurityState(nsIRequest* aRequest) { 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::UpdateSecurityState(nsIRequest* aRequest) if (showWarning) { - switch (newSecurityState) + switch (aNewState) { case lis_no_security: case lis_broken_security: @@ -1070,9 +1085,9 @@ nsresult nsSecureBrowserUIImpl::UpdateSecurityState(nsIRequest* aRequest) } } - mPreviousSecurityState = newSecurityState; + mPreviousSecurityState = aNewState; - if (lis_no_security == newSecurityState) + if (lis_no_security == aNewState) { mSSLStatus = nsnull; mInfoTooltip.Truncate(); @@ -1083,7 +1098,7 @@ nsresult nsSecureBrowserUIImpl::UpdateSecurityState(nsIRequest* aRequest) { PRUint32 newState = STATE_IS_INSECURE; - switch (newSecurityState) + switch (aNewState) { case lis_broken_security: newState = STATE_IS_BROKEN; @@ -1483,3 +1498,50 @@ ConfirmPostToInsecureFromSecure() return result; } + +#define NS_SECUREBROWSERUISTATE_IID \ +{0x086c5daf, 0xbb0a, 0x45cb, {0x98, 0x2b, 0xf1, 0x62, 0x49, 0xd5, 0x0e, 0x28}} + +class nsSecureBrowserUIImpl::State : public nsISupports +{ +public: + NS_DEFINE_STATIC_IID_ACCESSOR(NS_SECUREBROWSERUISTATE_IID) + NS_DECL_ISUPPORTS + + State(lockIconState aState, nsISupports *aSSLStatus); + + lockIconState GetState() const { return mState; } + nsISupports* GetSSLStatus() { return mSSLStatus; } + +private: + lockIconState mState; + nsCOMPtr mSSLStatus; +}; + +NS_IMPL_ISUPPORTS1(nsSecureBrowserUIImpl::State, nsSecureBrowserUIImpl::State) + +nsSecureBrowserUIImpl::State::State(lockIconState aState, + nsISupports *aSSLStatus) + : mState(aState), mSSLStatus(aSSLStatus) +{ +} + +NS_IMETHODIMP +nsSecureBrowserUIImpl::CaptureState(nsISupports **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(nsISupports *aState) +{ + nsCOMPtr state = do_QueryInterface(aState); + NS_ENSURE_TRUE(state, NS_ERROR_NULL_POINTER); + + mSSLStatus = state->GetSSLStatus(); + return UpdateSecurityState(state->GetState(), nsnull); +} diff --git a/security/manager/boot/src/nsSecureBrowserUIImpl.h b/security/manager/boot/src/nsSecureBrowserUIImpl.h index 364bd812378..053f618b647 100644 --- a/security/manager/boot/src/nsSecureBrowserUIImpl.h +++ b/security/manager/boot/src/nsSecureBrowserUIImpl.h @@ -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); @@ -144,6 +145,7 @@ protected: nsresult GetNSSDialogs(nsISecurityWarningDialogs **); PLDHashTable mTransferringRequests; + class State; }; diff --git a/toolkit/components/passwordmgr/base/nsPasswordManager.cpp b/toolkit/components/passwordmgr/base/nsPasswordManager.cpp index 4e7fe6f4657..0dfab6ef98f 100644 --- a/toolkit/components/passwordmgr/base/nsPasswordManager.cpp +++ b/toolkit/components/passwordmgr/base/nsPasswordManager.cpp @@ -71,6 +71,9 @@ #include "nsIAutoCompleteResult.h" #include "nsIPK11TokenDB.h" #include "nsIPK11Token.h" +#include "nsIScriptGlobalObject.h" +#include "nsIWindowWatcher.h" +#include "nsIDOMNSEvent.h" static const char kPMPropertiesURL[] = "chrome://passwordmgr/locale/passwordmgr.properties"; static PRBool sRememberPasswords = PR_FALSE; @@ -263,6 +266,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; + + while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore) { + nsCOMPtr item; + enumerator->GetNext(getter_AddRefs(item)); + + nsCOMPtr 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 +781,20 @@ nsPasswordManager::Observe(nsISupports* aSubject, 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 +813,22 @@ nsPasswordManager::OnStateChange(nsIWebProgress* aWebProgress, !(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 +1622,32 @@ nsPasswordManager::Error(nsIDOMEvent* aEvent) return NS_OK; } +NS_IMETHODIMP +nsPasswordManager::PageRestore(nsIDOMEvent* aEvent) +{ + // Only autofill for trusted events. + nsCOMPtr nsevent = do_QueryInterface(aEvent); + PRBool trusted = PR_FALSE; + if (nsevent) + nsevent->GetIsTrusted(&trusted); + if (!trusted) + return NS_OK; + + 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 diff --git a/toolkit/components/passwordmgr/base/nsPasswordManager.h b/toolkit/components/passwordmgr/base/nsPasswordManager.h index a99bd2461c0..e628616178c 100644 --- a/toolkit/components/passwordmgr/base/nsPasswordManager.h +++ b/toolkit/components/passwordmgr/base/nsPasswordManager.h @@ -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, diff --git a/toolkit/components/satchel/src/nsFormFillController.cpp b/toolkit/components/satchel/src/nsFormFillController.cpp index 08baa010736..5a0d3df71b4 100644 --- a/toolkit/components/satchel/src/nsFormFillController.cpp +++ b/toolkit/components/satchel/src/nsFormFillController.cpp @@ -880,6 +880,12 @@ nsFormFillController::Error(nsIDOMEvent *aLoadEvent) return NS_OK; } +NS_IMETHODIMP +nsFormFillController::PageRestore(nsIDOMEvent *aLoadEvent) +{ + return NS_OK; +} + //////////////////////////////////////////////////////////////////////// //// nsFormFillController diff --git a/toolkit/components/satchel/src/nsFormFillController.h b/toolkit/components/satchel/src/nsFormFillController.h index 7dee267b2ad..42f02af540d 100644 --- a/toolkit/components/satchel/src/nsFormFillController.h +++ b/toolkit/components/satchel/src/nsFormFillController.h @@ -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(); diff --git a/toolkit/components/typeaheadfind/src/nsTypeAheadFind.cpp b/toolkit/components/typeaheadfind/src/nsTypeAheadFind.cpp index 9e73b554b68..5ab4fed1e26 100755 --- a/toolkit/components/typeaheadfind/src/nsTypeAheadFind.cpp +++ b/toolkit/components/typeaheadfind/src/nsTypeAheadFind.cpp @@ -104,6 +104,7 @@ NS_INTERFACE_MAP_BEGIN(nsTypeAheadFind) NS_INTERFACE_MAP_ENTRY(nsITypeAheadFind) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsITypeAheadFind) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) + NS_INTERFACE_MAP_ENTRY(nsIObserver) NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsTypeAheadFind) diff --git a/toolkit/content/widgets/browser.xml b/toolkit/content/widgets/browser.xml index 7b4a3231637..66c0b82da3d 100644 --- a/toolkit/content/widgets/browser.xml +++ b/toolkit/content/widgets/browser.xml @@ -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) { diff --git a/view/src/nsView.cpp b/view/src/nsView.cpp index c31d113f1e4..a0b5ef0b5f9 100644 --- a/view/src/nsView.cpp +++ b/view/src/nsView.cpp @@ -491,6 +491,15 @@ NS_IMETHODIMP nsView::SetFloating(PRBool aFloatingView) return NS_OK; } +void nsView::InvalidateHierarchy() +{ + if (mViewManager->GetRootView() == this) + mViewManager->InvalidateHierarchy(); + + for (nsView *child = mFirstChild; child; child = child->GetNextSibling()) + child->InvalidateHierarchy(); +} + void nsView::InsertChild(nsView *aChild, nsView *aSibling) { NS_PRECONDITION(nsnull != aChild, "null ptr"); @@ -512,6 +521,15 @@ void nsView::InsertChild(nsView *aChild, nsView *aSibling) mFirstChild = aChild; } aChild->SetParent(this); + + // If we just inserted a root view, then update the RootViewManager + // on all view managers in the new subtree. + + nsViewManager *vm = aChild->GetViewManager(); + if (vm->GetRootView() == aChild) + { + aChild->InvalidateHierarchy(); + } } } @@ -540,6 +558,15 @@ void nsView::RemoveChild(nsView *child) kid = kid->GetNextSibling(); } NS_ASSERTION(found, "tried to remove non child"); + + // If we just removed a root view, then update the RootViewManager + // on all view managers in the removed subtree. + + nsViewManager *vm = child->GetViewManager(); + if (vm->GetRootView() == child) + { + child->InvalidateHierarchy(); + } } } diff --git a/view/src/nsView.h b/view/src/nsView.h index 14eb620d97e..d6eee6fe01f 100644 --- a/view/src/nsView.h +++ b/view/src/nsView.h @@ -291,6 +291,9 @@ public: void SetPositionIgnoringChildWidgets(nscoord aX, nscoord aY); nsresult LoadWidget(const nsCID &aClassIID); + // Update the cached RootViewManager for all view manager descendents. + void InvalidateHierarchy(); + virtual ~nsView(); protected: diff --git a/view/src/nsViewManager.cpp b/view/src/nsViewManager.cpp index 48d7253a4e6..20b30f0e483 100644 --- a/view/src/nsViewManager.cpp +++ b/view/src/nsViewManager.cpp @@ -4440,3 +4440,22 @@ nsViewManager::ProcessSynthMouseMoveEvent(PRBool aFromScroll) if (!aFromScroll) mSynthMouseMoveEventQueue = nsnull; } + +void +nsViewManager::InvalidateHierarchy() +{ + if (mRootView) { + if (mRootViewManager != this) { + NS_IF_RELEASE(mRootViewManager); + } + nsView *parent = mRootView->GetParent(); + if (parent) { + mRootViewManager = parent->GetViewManager()->RootViewManager(); + NS_ADDREF(mRootViewManager); + NS_ASSERTION(mRootViewManager != this, + "Root view had a parent, but it has the same view manager"); + } else { + mRootViewManager = this; + } + } +} diff --git a/view/src/nsViewManager.h b/view/src/nsViewManager.h index 3d3a059b128..d4df215c75b 100644 --- a/view/src/nsViewManager.h +++ b/view/src/nsViewManager.h @@ -267,6 +267,9 @@ public: NS_IMETHOD SynthesizeMouseMove(PRBool aFromScroll); void ProcessSynthMouseMoveEvent(PRBool aFromScroll); + /* Update the cached RootViewManager pointer on this view manager. */ + void InvalidateHierarchy(); + protected: virtual ~nsViewManager(); diff --git a/widget/public/nsGUIEvent.h b/widget/public/nsGUIEvent.h index 4149db29ac4..f5e41141d67 100644 --- a/widget/public/nsGUIEvent.h +++ b/widget/public/nsGUIEvent.h @@ -235,6 +235,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) diff --git a/xpcom/threads/nsITimer.idl b/xpcom/threads/nsITimer.idl index 855d538d6e4..85489386c24 100644 --- a/xpcom/threads/nsITimer.idl +++ b/xpcom/threads/nsITimer.idl @@ -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++ diff --git a/xpcom/threads/nsTimerImpl.cpp b/xpcom/threads/nsTimerImpl.cpp index dc19452fa42..2f003f04a63 100644 --- a/xpcom/threads/nsTimerImpl.cpp +++ b/xpcom/threads/nsTimerImpl.cpp @@ -331,6 +331,17 @@ NS_IMETHODIMP nsTimerImpl::GetClosure(void** aClosure) } +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; diff --git a/xpfe/components/shistory/public/nsIHistoryEntry.idl b/xpfe/components/shistory/public/nsIHistoryEntry.idl index cb2ff7b9273..e69de29bb2d 100644 --- a/xpfe/components/shistory/public/nsIHistoryEntry.idl +++ b/xpfe/components/shistory/public/nsIHistoryEntry.idl @@ -1,93 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1998 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Radha Kulkarni - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -/** - * An interface to individual entries in session history. Each - * document or frame will have a nsIHistoryEntry associated with - * it. nsIHistoryEntry provides access to information like URI, - * title and frame traversal status for that document. - * This interface is accessible from javascript. - * - * @status FROZEN - */ -#include "nsISupports.idl" - -interface nsIURI; - -[scriptable, uuid(A41661D4-1417-11D5-9882-00C04FA02F40)] -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; - -}; - - -%{ C++ -// {A41661D5-1417-11D5-9882-00C04FA02F40} -#define NS_HISTORYENTRY_CID \ -{0xa41661d5, 0x1417, 0x11d5, {0x98, 0x82, 0x0, 0xc0, 0x4f, 0xa0, 0x2f, 0x40}} - -#define NS_HISTORYENTRY_CONTRACTID \ - "@mozilla.org/browser/history-entry;1" - -%} - diff --git a/xpfe/components/shistory/public/nsISHEntry.idl b/xpfe/components/shistory/public/nsISHEntry.idl index 9e5d7336489..f3836dbcba5 100644 --- a/xpfe/components/shistory/public/nsISHEntry.idl +++ b/xpfe/components/shistory/public/nsISHEntry.idl @@ -42,88 +42,145 @@ * 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; + /** Content viewer, for fast restoration of presentation */ + attribute nsIContentViewer contentViewer; -/** DOM Document */ -attribute nsIDOMDocument document; + /** Whether the content viewer is marked "sticky" */ + attribute boolean sticky; -/** Title for the document */ -void SetTitle(in wstring aTitle); + /** Saved state of the global window object */ + attribute nsISupports windowState; -/** Post Data for the document */ -attribute nsIInputStream postData; + /** + * 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); -/** LayoutHistoryState for scroll position and form values */ -attribute nsILayoutHistoryState layoutHistoryState; + /** + * 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. + */ -/** parent of this entry */ -attribute nsISHEntry parent; + /** Append a child shell to the end of our list. */ + void addChildShell(in nsIDocShellTreeItem shell); -/** - * The loadType for this entry. This is typically loadHistory except - * when reload is pressed, it has the appropriate reload flag - */ -attribute unsigned long loadType; + /** + * Get the child shell at |index|; returns null if |index| is out of bounds. + */ + nsIDocShellTreeItem childShellAt(in long index); -/** - * An ID to help identify this entry from others during - * subframe navigation - */ -attribute unsigned long ID; + /** + * Clear the child shell list. + */ + void clearChildShells(); -/** - * 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; + /** Saved security state for the content viewer */ + attribute nsISupports securityState; -/** attribute to set and get the cache key for the entry */ -attribute nsISupports cacheKey; + /** Saved refresh URI list for the content viewer */ + attribute nsISupportsArray refreshURIList; -/** attribute to indicate whether layoutHistoryState should be saved */ -attribute boolean saveLayoutStateFlag; + /** + * Ensure that the cached presentation members are self-consistent. + * If either |contentViewer| or |windowState| are null, then all of the + * following members are cleared/reset: + * contentViewer, sticky, windowState, viewerBounds, childShells, + * refreshURIList. + */ + void syncPresentationState(); -/** attribute to indicate whether the page is already expired in cache */ -attribute boolean expirationStatus; + /** Title for the document */ + void setTitle(in AString aTitle); -/** attribute to indicate the content-type of the document that this - is a session history entry for */ -attribute ACString contentType; + /** 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); + /** 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 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); + /** 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); }; diff --git a/xpfe/components/shistory/public/nsISHistoryInternal.idl b/xpfe/components/shistory/public/nsISHistoryInternal.idl index 318c8e33bc2..e69de29bb2d 100644 --- a/xpfe/components/shistory/public/nsISHistoryInternal.idl +++ b/xpfe/components/shistory/public/nsISHistoryInternal.idl @@ -1,93 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is mozilla.org code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Radha Kulkarni (radha@netscape.com) - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "nsISupports.idl" -#include "nsIFactory.idl" -#include "nsISHEntry.idl" -#include "nsISHTransaction.idl" - -interface nsISHistoryListener; -interface nsIDocShell; - -%{C++ -#define NS_SHISTORY_INTERNAL_CID \ -{0xdd335422, 0xb8b8, 0x11d3, {0xbd, 0xc8, 0x00, 0x50, 0x04, 0x0a, 0x9b, 0x44}} - -#define NS_SHISTORY_INTERNAL_CONTRACTID "@mozilla.org/browser/shistory-internal;1" -%} - -[scriptable, uuid(DD335421-B8B8-11d3-BDC8-0050040A9B44)] -interface nsISHistoryInternal: nsISupports -{ - /** - * Add a new Entry to the History List - * @param aEntry - The entry to add - * @param aPersist - If true this specifies that the entry should persist - * in the list. If false, this means that when new entries are added - * this element will not appear in the session history list. - */ - void addEntry(in nsISHEntry aEntry, in boolean aPersist); - - /** - * Get the root transaction - */ - readonly attribute nsISHTransaction rootTransaction; - - /** - * The toplevel docshell object to which this SHistory object belongs to. - */ - attribute nsIDocShell rootDocShell; - - /** - * Update the index maintained by sessionHistory - */ - void updateIndex(); - - /** - * Replace the nsISHEntry at a particular index - * @param aIndex - The index at which the entry shoud be replaced - * @param aReplaceEntry - The replacement entry for the index. - */ - void replaceEntry(in long aIndex, in nsISHEntry aReplaceEntry); - - /** - * Get handle to the history listener - */ - readonly attribute nsISHistoryListener listener; - -}; diff --git a/xpfe/components/shistory/src/Makefile.in b/xpfe/components/shistory/src/Makefile.in index 6db8eeb7ad8..907d812d51b 100644 --- a/xpfe/components/shistory/src/Makefile.in +++ b/xpfe/components/shistory/src/Makefile.in @@ -55,6 +55,7 @@ REQUIRES = xpcom \ layout \ docshell \ pref \ + gfx \ $(NULL) CPPSRCS = nsSHEntry.cpp \ diff --git a/xpfe/components/shistory/src/nsSHEntry.cpp b/xpfe/components/shistory/src/nsSHEntry.cpp index 313e507b16b..03a2b47ad5f 100644 --- a/xpfe/components/shistory/src/nsSHEntry.cpp +++ b/xpfe/components/shistory/src/nsSHEntry.cpp @@ -37,11 +37,16 @@ * * ***** END LICENSE BLOCK ***** */ +#ifdef DEBUG_bryner +#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 &other) , mIsFrameNavigation(other.mIsFrameNavigation) , mSaveLayoutState(other.mSaveLayoutState) , mExpired(other.mExpired) + , mSticky(PR_TRUE) // XXX why not copy mContentType? , mCacheKey(other.mCacheKey) , mParent(other.mParent) + , mViewerBounds(0, 0, 0, 0) { } +nsSHEntry::~nsSHEntry() +{ + mChildren.Clear(); + if (mContentViewer) + mContentViewer->Destroy(); +} + //***************************************************************************** // nsSHEntry: nsISupports //***************************************************************************** @@ -133,19 +149,35 @@ NS_IMETHODIMP nsSHEntry::SetReferrerURI(nsIURI *aReferrerURI) 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(PRUnichar** aTitle) 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(const nsACString& aContentType) } 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 PRUnichar * aTitle, // 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 * aParent) 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,77 @@ nsSHEntry::GetChildAt(PRInt32 aIndex, nsISHEntry ** aResult) } 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(nsISupports **aState) +{ + NS_IF_ADDREF(*aState = mSecurityState); + return NS_OK; +} + +NS_IMETHODIMP +nsSHEntry::SetSecurityState(nsISupports *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; +} + +NS_IMETHODIMP +nsSHEntry::SyncPresentationState() +{ + if (mContentViewer && mWindowState) { + // If we have a content viewer and a window state, we should be ok. + return NS_OK; + } + + // If not, then nuke all of the presentation-related members. + if (mContentViewer) + mContentViewer->SetHistoryEntry(nsnull); + + mContentViewer = nsnull; + mSticky = PR_TRUE; + mWindowState = nsnull; + mViewerBounds.SetRect(0, 0, 0, 0); + mChildShells.Clear(); + mSecurityState = nsnull; + mRefreshURIList = nsnull; + return NS_OK; +} diff --git a/xpfe/components/shistory/src/nsSHEntry.h b/xpfe/components/shistory/src/nsSHEntry.h index f4fa459a004..db207f7e99a 100644 --- a/xpfe/components/shistory/src/nsSHEntry.h +++ b/xpfe/components/shistory/src/nsSHEntry.h @@ -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,10 @@ #include "nsIURI.h" #include "nsIEnumerator.h" #include "nsIHistoryEntry.h" +#include "nsRect.h" +#include "nsSupportsArray.h" -class nsSHEntry : public nsIHistoryEntry, - public nsISHEntry, +class nsSHEntry : public nsISHEntry, public nsISHContainer { public: @@ -69,11 +71,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 +88,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 */ diff --git a/xpfe/components/shistory/src/nsSHistory.cpp b/xpfe/components/shistory/src/nsSHistory.cpp index 0334d2bc910..e69de29bb2d 100644 --- a/xpfe/components/shistory/src/nsSHistory.cpp +++ b/xpfe/components/shistory/src/nsSHistory.cpp @@ -1,926 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Mozilla browser. - * - * The Initial Developer of the Original Code is - * Netscape Communications, Inc. - * Portions created by the Initial Developer are Copyright (C) 1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Radha Kulkarni - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -// Local Includes -#include "nsSHistory.h" - -// Helper Classes -#include "nsXPIDLString.h" -#include "nsReadableUtils.h" - -// Interfaces Needed -#include "nsILayoutHistoryState.h" -#include "nsIDocShell.h" -#include "nsIDocShellLoadInfo.h" -#include "nsISHContainer.h" -#include "nsIDocShellTreeItem.h" -#include "nsIDocShellTreeNode.h" -#include "nsIDocShellLoadInfo.h" -#include "nsIServiceManager.h" -#include "nsIPrefService.h" - -#define PREF_SHISTORY_SIZE "browser.sessionhistory.max_entries" -static PRInt32 gHistoryMaxSize = 50; - -enum HistCmd{ - HIST_CMD_BACK, - HIST_CMD_FORWARD, - HIST_CMD_GOTOINDEX, - HIST_CMD_RELOAD -} ; - -//***************************************************************************** -//*** nsSHistory: Object Management -//***************************************************************************** - -nsSHistory::nsSHistory() : mListRoot(nsnull), mIndex(-1), mLength(0), mRequestedIndex(-1) -{ -} - - -nsSHistory::~nsSHistory() -{ -} - -//***************************************************************************** -// nsSHistory: nsISupports -//***************************************************************************** - -NS_IMPL_ADDREF(nsSHistory) -NS_IMPL_RELEASE(nsSHistory) - -NS_INTERFACE_MAP_BEGIN(nsSHistory) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISHistory) - NS_INTERFACE_MAP_ENTRY(nsISHistory) - NS_INTERFACE_MAP_ENTRY(nsIWebNavigation) - NS_INTERFACE_MAP_ENTRY(nsISHistoryInternal) -NS_INTERFACE_MAP_END - -//***************************************************************************** -// nsSHistory: nsISHistory -//***************************************************************************** - -/* - * Init method to get pref settings - */ -NS_IMETHODIMP -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); - } - } - return NS_OK; -} - - -/* Add an entry to the History list at mIndex and - * increment the index to point to the new entry - */ -NS_IMETHODIMP -nsSHistory::AddEntry(nsISHEntry * aSHEntry, PRBool aPersist) -{ - NS_ENSURE_ARG(aSHEntry); - - nsCOMPtr currentTxn; - - if(mListRoot) - GetTransactionAtIndex(mIndex, getter_AddRefs(currentTxn)); - - PRBool currentPersist = PR_TRUE; - if(currentTxn) - currentTxn->GetPersist(¤tPersist); - - if(!currentPersist) - { - NS_ENSURE_SUCCESS(currentTxn->SetSHEntry(aSHEntry),NS_ERROR_FAILURE); - currentTxn->SetPersist(aPersist); - return NS_OK; - } - - nsCOMPtr txn(do_CreateInstance(NS_SHTRANSACTION_CONTRACTID)); - NS_ENSURE_TRUE(txn, NS_ERROR_FAILURE); - - // Notify any listener about the new addition - if (mListener) { - nsCOMPtr listener(do_QueryReferent(mListener)); - if (listener) { - nsCOMPtr uri; - nsCOMPtr hEntry(do_QueryInterface(aSHEntry)); - if (hEntry) { - hEntry->GetURI(getter_AddRefs(uri)); - listener->OnHistoryNewEntry(uri); - } - } - } - - // Set the ShEntry and parent for the transaction. setting the - // parent will properly set the parent child relationship - txn->SetPersist(aPersist); - NS_ENSURE_SUCCESS(txn->Create(aSHEntry, currentTxn), NS_ERROR_FAILURE); - - // A little tricky math here... Basically when adding an object regardless of - // what the length was before, it should always be set back to the current and - // lop off the forward. - mLength = (++mIndex + 1); - - // If this is the very first transaction, initialize the list - if(!mListRoot) - mListRoot = txn; - - //Purge History list if it is too long - if ((gHistoryMaxSize >= 0) && (mLength > gHistoryMaxSize)) - PurgeHistory(mLength-gHistoryMaxSize); - - return NS_OK; -} - -/* Get size of the history list */ -NS_IMETHODIMP -nsSHistory::GetCount(PRInt32 * aResult) -{ - NS_ENSURE_ARG_POINTER(aResult); - *aResult = mLength; - return NS_OK; -} - -/* Get index of the history list */ -NS_IMETHODIMP -nsSHistory::GetIndex(PRInt32 * aResult) -{ - NS_ENSURE_ARG_POINTER(aResult); - *aResult = mIndex; - return NS_OK; -} - -NS_IMETHODIMP -nsSHistory::GetEntryAtIndex(PRInt32 aIndex, PRBool aModifyIndex, nsISHEntry** aResult) -{ - nsresult rv; - nsCOMPtr txn; - - /* GetTransactionAtIndex ensures aResult is valid and validates aIndex */ - rv = GetTransactionAtIndex(aIndex, getter_AddRefs(txn)); - if (NS_SUCCEEDED(rv) && txn) { - //Get the Entry from the transaction - rv = txn->GetSHEntry(aResult); - if (NS_SUCCEEDED(rv) && (*aResult)) { - // Set mIndex to the requested index, if asked to do so.. - if (aModifyIndex) { - mIndex = aIndex; - } - } //entry - } //Transaction - return rv; -} - - -/* Get the entry at a given index */ -NS_IMETHODIMP -nsSHistory::GetEntryAtIndex(PRInt32 aIndex, PRBool aModifyIndex, nsIHistoryEntry** aResult) -{ - nsresult rv; - nsCOMPtr shEntry; - rv = GetEntryAtIndex(aIndex, aModifyIndex, getter_AddRefs(shEntry)); - if (NS_SUCCEEDED(rv) && shEntry) - rv = CallQueryInterface(shEntry, aResult); - - return rv; -} - -/* Get the transaction at a given index */ -NS_IMETHODIMP -nsSHistory::GetTransactionAtIndex(PRInt32 aIndex, nsISHTransaction ** aResult) -{ - nsresult rv; - NS_ENSURE_ARG_POINTER(aResult); - - if ((mLength <= 0) || (aIndex < 0) || (aIndex >= mLength)) - return NS_ERROR_FAILURE; - - if (!mListRoot) - return NS_ERROR_FAILURE; - - if (aIndex == 0) - { - *aResult = mListRoot; - NS_ADDREF(*aResult); - return NS_OK; - } - PRInt32 cnt=0; - nsCOMPtr tempPtr; - - rv = GetRootTransaction(getter_AddRefs(tempPtr)); - if (NS_FAILED(rv) || !tempPtr) - return NS_ERROR_FAILURE; - - while(1) { - nsCOMPtr ptr; - rv = tempPtr->GetNext(getter_AddRefs(ptr)); - if (NS_SUCCEEDED(rv) && ptr) { - cnt++; - if (cnt == aIndex) { - *aResult = ptr; - NS_ADDREF(*aResult); - break; - } - else { - tempPtr = ptr; - continue; - } - } //NS_SUCCEEDED - else - return NS_ERROR_FAILURE; - } // while - - return NS_OK; -} - -#ifdef DEBUG -nsresult -nsSHistory::PrintHistory() -{ - - nsCOMPtr txn; - PRInt32 index = 0; - nsresult rv; - - if (!mListRoot) - return NS_ERROR_FAILURE; - - txn = mListRoot; - - while (1) { - if (!txn) - break; - nsCOMPtr entry; - rv = txn->GetSHEntry(getter_AddRefs(entry)); - if (NS_FAILED(rv) && !entry) - return NS_ERROR_FAILURE; - - nsCOMPtr layoutHistoryState; - nsCOMPtr uri; - PRUnichar * title; - - entry->GetLayoutHistoryState(getter_AddRefs(layoutHistoryState)); - nsCOMPtr hEntry(do_QueryInterface(entry)); - if (hEntry) { - hEntry->GetURI(getter_AddRefs(uri)); - hEntry->GetTitle(&title); - } - -#if 0 - nsCAutoString url; - if (uri) - uri->GetSpec(url); - - printf("**** SH Transaction #%d, Entry = %x\n", index, entry.get()); - printf("\t\t URL = %s\n", url); - printf("\t\t Title = %s\n", NS_LossyConvertUCS2toASCII(title).get()); - printf("\t\t layout History Data = %x\n", layoutHistoryState); -#endif - - nsMemory::Free(title); - - - nsCOMPtr next; - rv = txn->GetNext(getter_AddRefs(next)); - if (NS_SUCCEEDED(rv) && next) { - txn = next; - index++; - continue; - } - else - break; - } - - return NS_OK; -} -#endif - - -NS_IMETHODIMP -nsSHistory::GetRootTransaction(nsISHTransaction ** aResult) -{ - NS_ENSURE_ARG_POINTER(aResult); - *aResult=mListRoot; - NS_IF_ADDREF(*aResult); - return NS_OK; -} - -/* Get the max size of the history list */ -NS_IMETHODIMP -nsSHistory::GetMaxLength(PRInt32 * aResult) -{ - NS_ENSURE_ARG_POINTER(aResult); - *aResult = gHistoryMaxSize; - return NS_OK; -} - -/* Set the max size of the history list */ -NS_IMETHODIMP -nsSHistory::SetMaxLength(PRInt32 aMaxSize) -{ - if (aMaxSize < 0) - return NS_ERROR_ILLEGAL_VALUE; - - gHistoryMaxSize = aMaxSize; - if (mLength > aMaxSize) - PurgeHistory(mLength-aMaxSize); - return NS_OK; -} - -NS_IMETHODIMP -nsSHistory::PurgeHistory(PRInt32 aEntries) -{ - if (mLength <= 0 || aEntries <= 0) - return NS_ERROR_FAILURE; - - aEntries = PR_MIN(aEntries, mLength); - - PRBool purgeHistory = PR_TRUE; - // Notify the listener about the history purge - if (mListener) { - nsCOMPtr listener(do_QueryReferent(mListener)); - if (listener) { - listener->OnHistoryPurge(aEntries, &purgeHistory); - } - } - - if (!purgeHistory) { - // Listener asked us not to purge - return NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA; - } - - PRInt32 cnt = 0; - while (cnt < aEntries) { - nsCOMPtr nextTxn; - if (mListRoot) - mListRoot->GetNext(getter_AddRefs(nextTxn)); - mListRoot = nextTxn; - cnt++; - } - mLength -= cnt; - mIndex -= cnt; - - // Now if we were not at the end of the history, mIndex could have - // become far too negative. If so, just set it to -1. - if (mIndex < -1) { - mIndex = -1; - } - return NS_OK; -} - - -NS_IMETHODIMP -nsSHistory::AddSHistoryListener(nsISHistoryListener * aListener) -{ - NS_ENSURE_ARG_POINTER(aListener); - - // Check if the listener supports Weak Reference. This is a must. - // This listener functionality is used by embedders and we want to - // have the right ownership with who ever listens to SHistory - nsWeakPtr listener = do_GetWeakReference(aListener); - if (!listener) return NS_ERROR_FAILURE; - mListener = listener; - return NS_OK; -} - - -NS_IMETHODIMP -nsSHistory::RemoveSHistoryListener(nsISHistoryListener * aListener) -{ - // Make sure the listener that wants to be removed is the - // one we have in store. - nsWeakPtr listener = do_GetWeakReference(aListener); - if (listener == mListener) { - mListener = nsnull; - return NS_OK; - } - return NS_ERROR_FAILURE; -} - - -/* Replace an entry in the History list at a particular index. - * Do not update index or count. - */ -NS_IMETHODIMP -nsSHistory::ReplaceEntry(PRInt32 aIndex, nsISHEntry * aReplaceEntry) -{ - NS_ENSURE_ARG(aReplaceEntry); - nsresult rv; - nsCOMPtr currentTxn; - - if (!mListRoot) // Session History is not initialised. - return NS_ERROR_FAILURE; - - rv = GetTransactionAtIndex(aIndex, getter_AddRefs(currentTxn)); - - if(currentTxn) - { - // Set the replacement entry in the transaction - rv = currentTxn->SetSHEntry(aReplaceEntry); - rv = currentTxn->SetPersist(PR_TRUE); - } - return rv; -} - -/* Get a handle to the Session history listener */ -NS_IMETHODIMP -nsSHistory::GetListener(nsISHistoryListener ** aListener) -{ - NS_ENSURE_ARG_POINTER(aListener); - if (mListener) - CallQueryReferent(mListener.get(), aListener); - // Don't addref aListener. It is a weak pointer. - return NS_OK; -} - -//***************************************************************************** -// nsSHistory: nsIWebNavigation -//***************************************************************************** - -NS_IMETHODIMP -nsSHistory::GetCanGoBack(PRBool * aCanGoBack) -{ - NS_ENSURE_ARG_POINTER(aCanGoBack); - *aCanGoBack = PR_FALSE; - - PRInt32 index = -1; - NS_ENSURE_SUCCESS(GetIndex(&index), NS_ERROR_FAILURE); - if(index > 0) - *aCanGoBack = PR_TRUE; - - return NS_OK; -} - -NS_IMETHODIMP -nsSHistory::GetCanGoForward(PRBool * aCanGoForward) -{ - NS_ENSURE_ARG_POINTER(aCanGoForward); - *aCanGoForward = PR_FALSE; - - PRInt32 index = -1; - PRInt32 count = -1; - - NS_ENSURE_SUCCESS(GetIndex(&index), NS_ERROR_FAILURE); - NS_ENSURE_SUCCESS(GetCount(&count), NS_ERROR_FAILURE); - - if((index >= 0) && (index < (count - 1))) - *aCanGoForward = PR_TRUE; - - return NS_OK; -} - -NS_IMETHODIMP -nsSHistory::GoBack() -{ - PRBool canGoBack = PR_FALSE; - - GetCanGoBack(&canGoBack); - if (!canGoBack) // Can't go back - return NS_ERROR_UNEXPECTED; - return LoadEntry(mIndex-1, nsIDocShellLoadInfo::loadHistory, HIST_CMD_BACK); -} - - -NS_IMETHODIMP -nsSHistory::GoForward() -{ - PRBool canGoForward = PR_FALSE; - - GetCanGoForward(&canGoForward); - if (!canGoForward) // Can't go forward - return NS_ERROR_UNEXPECTED; - return LoadEntry(mIndex+1, nsIDocShellLoadInfo::loadHistory, HIST_CMD_FORWARD); - -} - -NS_IMETHODIMP -nsSHistory::Reload(PRUint32 aReloadFlags) -{ - nsresult rv; - nsDocShellInfoLoadType loadType; - if (aReloadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY && - aReloadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE) - { - loadType = nsIDocShellLoadInfo::loadReloadBypassProxyAndCache; - } - else if (aReloadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_PROXY) - { - loadType = nsIDocShellLoadInfo::loadReloadBypassProxy; - } - else if (aReloadFlags & nsIWebNavigation::LOAD_FLAGS_BYPASS_CACHE) - { - loadType = nsIDocShellLoadInfo::loadReloadBypassCache; - } - else if (aReloadFlags & nsIWebNavigation::LOAD_FLAGS_CHARSET_CHANGE) - { - loadType = nsIDocShellLoadInfo::loadReloadCharsetChange; - } - else - { - loadType = nsIDocShellLoadInfo::loadReloadNormal; - } - - // Notify listeners - PRBool canNavigate = PR_TRUE; - if (mListener) { - nsCOMPtr listener(do_QueryReferent(mListener)); - // We are reloading. Send Reload notifications. - // nsDocShellLoadFlagType is not public, where as nsIWebNavigation - // is public. So send the reload notifications with the - // nsIWebNavigation flags. - if (listener) { - nsCOMPtr currentURI; - rv = GetCurrentURI(getter_AddRefs(currentURI)); - listener->OnHistoryReload(currentURI, aReloadFlags, &canNavigate); - } - } - if (!canNavigate) - return NS_OK; - - return LoadEntry(mIndex, loadType, HIST_CMD_RELOAD); -} - -NS_IMETHODIMP -nsSHistory::UpdateIndex() -{ - // Update the actual index with the right value. - if (mIndex != mRequestedIndex && mRequestedIndex != -1) - mIndex = mRequestedIndex; - return NS_OK; -} - -NS_IMETHODIMP -nsSHistory::Stop(PRUint32 aStopFlags) -{ - //Not implemented - return NS_OK; -} - - -NS_IMETHODIMP -nsSHistory::GetDocument(nsIDOMDocument** aDocument) -{ - - // Not implemented - return NS_OK; -} - - -NS_IMETHODIMP -nsSHistory::GetCurrentURI(nsIURI** aResultURI) -{ - NS_ENSURE_ARG_POINTER(aResultURI); - nsresult rv; - - nsCOMPtr currentEntry; - rv = GetEntryAtIndex(mIndex, PR_FALSE, getter_AddRefs(currentEntry)); - if (NS_FAILED(rv) && !currentEntry) return rv; - rv = currentEntry->GetURI(aResultURI); - return rv; -} - - -NS_IMETHODIMP -nsSHistory::GetReferringURI(nsIURI** aURI) -{ - *aURI = nsnull; - // Not implemented - return NS_OK; -} - - -NS_IMETHODIMP -nsSHistory::SetSessionHistory(nsISHistory* aSessionHistory) -{ - // Not implemented - return NS_OK; -} - - -NS_IMETHODIMP -nsSHistory::GetSessionHistory(nsISHistory** aSessionHistory) -{ - // Not implemented - return NS_OK; -} - - -NS_IMETHODIMP -nsSHistory::LoadURI(const PRUnichar* aURI, - PRUint32 aLoadFlags, - nsIURI* aReferringURI, - nsIInputStream* aPostStream, - nsIInputStream* aExtraHeaderStream) -{ - return NS_OK; -} - -NS_IMETHODIMP -nsSHistory::GotoIndex(PRInt32 aIndex) -{ - return LoadEntry(aIndex, nsIDocShellLoadInfo::loadHistory, HIST_CMD_GOTOINDEX); -} - -NS_IMETHODIMP -nsSHistory::LoadEntry(PRInt32 aIndex, long aLoadType, PRUint32 aHistCmd) -{ - nsCOMPtr docShell; - nsCOMPtr shEntry; - // Keep note of requested history index in mRequestedIndex. - mRequestedIndex = aIndex; - - nsCOMPtr prevEntry; - GetEntryAtIndex(mIndex, PR_FALSE, getter_AddRefs(prevEntry)); - - nsCOMPtr nextEntry; - GetEntryAtIndex(mRequestedIndex, PR_FALSE, getter_AddRefs(nextEntry)); - nsCOMPtr nHEntry(do_QueryInterface(nextEntry)); - if (!nextEntry || !prevEntry || !nHEntry) { - mRequestedIndex = -1; - return NS_ERROR_FAILURE; - } - - // Send appropriate listener notifications - PRBool canNavigate = PR_TRUE; - // Get the uri for the entry we are about to visit - nsCOMPtr nextURI; - nHEntry->GetURI(getter_AddRefs(nextURI)); - - if(mListener) { - nsCOMPtr listener(do_QueryReferent(mListener)); - if (listener) { - if (aHistCmd == HIST_CMD_BACK) { - // We are going back one entry. Send GoBack notifications - listener->OnHistoryGoBack(nextURI, &canNavigate); - } - else if (aHistCmd == HIST_CMD_FORWARD) { - // We are going forward. Send GoForward notification - listener->OnHistoryGoForward(nextURI, &canNavigate); - } - else if (aHistCmd == HIST_CMD_GOTOINDEX) { - // We are going somewhere else. This is not reload either - listener->OnHistoryGotoIndex(aIndex, nextURI, &canNavigate); - } - } - } - - if (!canNavigate) { - // If the listener asked us not to proceed with - // the operation, simply return. - return NS_OK; // XXX Maybe I can return some other error code? - } - - nsCOMPtr nexturi; - PRInt32 pCount=0, nCount=0; - nsCOMPtr prevAsContainer(do_QueryInterface(prevEntry)); - nsCOMPtr nextAsContainer(do_QueryInterface(nextEntry)); - if (prevAsContainer && nextAsContainer) { - prevAsContainer->GetChildCount(&pCount); - nextAsContainer->GetChildCount(&nCount); - } - - nsCOMPtr loadInfo; - if (mRequestedIndex == mIndex) { - // Possibly a reload case - docShell = mRootDocShell; - } - else { - // Going back or forward. - if ((pCount > 0) && (nCount > 0)) { - /* THis is a subframe navigation. Go find - * the docshell in which load should happen - */ - PRBool frameFound = PR_FALSE; - nsresult rv = CompareFrames(prevEntry, nextEntry, mRootDocShell, aLoadType, &frameFound); - if (!frameFound) { - // we did not successfully find the subframe in which - // the new url was to be loaded. return error. - mRequestedIndex = -1; - return NS_ERROR_FAILURE; - } - return rv; - } // (pCount >0) - else - docShell = mRootDocShell; - } - - - if (!docShell) { - // we did not successfully go to the proper index. - // return error. - mRequestedIndex = -1; - return NS_ERROR_FAILURE; - } - - // Start the load on the appropriate docshell - return InitiateLoad(nextEntry, docShell, aLoadType); -} - - - -nsresult -nsSHistory::CompareFrames(nsISHEntry * aPrevEntry, nsISHEntry * aNextEntry, nsIDocShell * aParent, long aLoadType, PRBool * aIsFrameFound) -{ - if (!aPrevEntry || !aNextEntry || !aParent) - return PR_FALSE; - - nsresult result = NS_OK; - PRUint32 prevID, nextID; - - aPrevEntry->GetID(&prevID); - aNextEntry->GetID(&nextID); - - // Check the IDs to verify if the pages are different. - if (prevID != nextID) { - if (aIsFrameFound) - *aIsFrameFound = PR_TRUE; - // Set the Subframe flag of the entry to indicate that - // it is subframe navigation - aNextEntry->SetIsSubFrame(PR_TRUE); - InitiateLoad(aNextEntry, aParent, aLoadType); - return NS_OK; - } - - /* The root entries are the same, so compare any child frames */ - PRInt32 pcnt=0, ncnt=0, dsCount=0; - nsCOMPtr prevContainer(do_QueryInterface(aPrevEntry)); - nsCOMPtr nextContainer(do_QueryInterface(aNextEntry)); - nsCOMPtr dsTreeNode(do_QueryInterface(aParent)); - - if (!dsTreeNode) - return NS_ERROR_FAILURE; - if (!prevContainer || !nextContainer) - return NS_ERROR_FAILURE; - - prevContainer->GetChildCount(&pcnt); - nextContainer->GetChildCount(&ncnt); - dsTreeNode->GetChildCount(&dsCount); - - //XXX What to do if the children count don't match - - for (PRInt32 i=0; i pChild, nChild; - nsCOMPtr dsTreeItemChild; - - prevContainer->GetChildAt(i, getter_AddRefs(pChild)); - nextContainer->GetChildAt(i, getter_AddRefs(nChild)); - if (dsCount > 0) - dsTreeNode->GetChildAt(i, getter_AddRefs(dsTreeItemChild)); - - if (!dsTreeItemChild) - return NS_ERROR_FAILURE; - - nsCOMPtr dsChild(do_QueryInterface(dsTreeItemChild)); - - CompareFrames(pChild, nChild, dsChild, aLoadType, aIsFrameFound); - } - return result; -} - - -nsresult -nsSHistory::InitiateLoad(nsISHEntry * aFrameEntry, nsIDocShell * aFrameDS, long aLoadType) -{ - nsCOMPtr loadInfo; - - /* Set the loadType in the SHEntry too to what was passed on. - * This will be passed on to child subframes later in nsDocShell, - * so that proper loadType is maintained through out a frameset - */ - aFrameEntry->SetLoadType(aLoadType); - aFrameDS->CreateLoadInfo (getter_AddRefs(loadInfo)); - - loadInfo->SetLoadType(aLoadType); - loadInfo->SetSHEntry(aFrameEntry); - - nsCOMPtr nextURI; - nsCOMPtr hEntry(do_QueryInterface(aFrameEntry)); - hEntry->GetURI(getter_AddRefs(nextURI)); - // Time to initiate a document load - return aFrameDS->LoadURI(nextURI, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, PR_FALSE); - -} - - - -NS_IMETHODIMP -nsSHistory::SetRootDocShell(nsIDocShell * aDocShell) -{ - mRootDocShell = aDocShell; - return NS_OK; -} - -NS_IMETHODIMP -nsSHistory::GetRootDocShell(nsIDocShell ** aDocShell) -{ - NS_ENSURE_ARG_POINTER(aDocShell); - - *aDocShell = mRootDocShell; - //Not refcounted. May this method should not be available for public - // NS_IF_ADDREF(*aDocShell); - return NS_OK; -} - - -NS_IMETHODIMP -nsSHistory::GetSHistoryEnumerator(nsISimpleEnumerator** aEnumerator) -{ - nsresult status = NS_OK; - - NS_ENSURE_ARG_POINTER(aEnumerator); - nsSHEnumerator * iterator = new nsSHEnumerator(this); - if (iterator && NS_FAILED(status = CallQueryInterface(iterator, aEnumerator))) - delete iterator; - return status; -} - - -//***************************************************************************** -//*** nsSHEnumerator: Object Management -//***************************************************************************** - -nsSHEnumerator::nsSHEnumerator(nsSHistory * aSHistory):mIndex(-1) -{ - mSHistory = aSHistory; -} - -nsSHEnumerator::~nsSHEnumerator() -{ - mSHistory = nsnull; -} - -NS_IMPL_ISUPPORTS1(nsSHEnumerator, nsISimpleEnumerator) - -NS_IMETHODIMP -nsSHEnumerator::HasMoreElements(PRBool * aReturn) -{ - PRInt32 cnt; - *aReturn = PR_FALSE; - mSHistory->GetCount(&cnt); - if (mIndex >= -1 && mIndex < (cnt-1) ) { - *aReturn = PR_TRUE; - } - return NS_OK; -} - - -NS_IMETHODIMP -nsSHEnumerator::GetNext(nsISupports **aItem) -{ - NS_ENSURE_ARG_POINTER(aItem); - PRInt32 cnt= 0; - - nsresult result = NS_ERROR_FAILURE; - mSHistory->GetCount(&cnt); - if (mIndex < (cnt-1)) { - mIndex++; - nsCOMPtr hEntry; - result = mSHistory->GetEntryAtIndex(mIndex, PR_FALSE, getter_AddRefs(hEntry)); - if (hEntry) - result = CallQueryInterface(hEntry, aItem); - } - return result; -} diff --git a/xpfe/components/shistory/src/nsSHistory.h b/xpfe/components/shistory/src/nsSHistory.h index d96cc9d5d34..e69de29bb2d 100644 --- a/xpfe/components/shistory/src/nsSHistory.h +++ b/xpfe/components/shistory/src/nsSHistory.h @@ -1,120 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Mozilla browser. - * - * The Initial Developer of the Original Code is - * Netscape Communications, Inc. - * Portions created by the Initial Developer are Copyright (C) 1999 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Radha Kulkarni - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef nsSHistory_h -#define nsSHistory_h - -// Helper Classes -#include "nsCOMPtr.h" - -//Interfaces Needed -#include "nsISHistory.h" -#include "nsISHistoryInternal.h" -#include "nsISHTransaction.h" -#include "nsIWebNavigation.h" -#include "nsIWeakReference.h" -#include "nsISimpleEnumerator.h" -#include "nsISHistoryListener.h" -#include "nsIHistoryEntry.h" - -class nsIDocShell; -class nsSHEnumerator; -class nsSHistory: public nsISHistory, - public nsISHistoryInternal, - public nsIWebNavigation -{ -public: - nsSHistory(); - - NS_DECL_ISUPPORTS - NS_DECL_NSISHISTORY - NS_DECL_NSISHISTORYINTERNAL - NS_DECL_NSIWEBNAVIGATION - - NS_IMETHOD Init(); - -protected: - virtual ~nsSHistory(); - friend class nsSHEnumerator; - - // Could become part of nsIWebNavigation - NS_IMETHOD GetEntryAtIndex(PRInt32 aIndex, PRBool aModifyIndex, nsISHEntry** aResult); - NS_IMETHOD GetTransactionAtIndex(PRInt32 aIndex, nsISHTransaction ** aResult); - nsresult CompareFrames(nsISHEntry * prevEntry, nsISHEntry * nextEntry, nsIDocShell * rootDocShell, long aLoadType, PRBool * aIsFrameFound); - nsresult InitiateLoad(nsISHEntry * aFrameEntry, nsIDocShell * aFrameDS, long aLoadType); - - NS_IMETHOD LoadEntry(PRInt32 aIndex, long aLoadType, PRUint32 histCmd); - -#ifdef DEBUG - nsresult PrintHistory(); -#endif - -protected: - nsCOMPtr mListRoot; - PRInt32 mIndex; - PRInt32 mLength; - PRInt32 mRequestedIndex; - // Session History listener - nsWeakPtr mListener; - // Weak reference. Do not refcount this. - nsIDocShell * mRootDocShell; -}; -//***************************************************************************** -//*** nsSHEnumerator: Object Management -//***************************************************************************** -class nsSHEnumerator : public nsISimpleEnumerator -{ -public: - - NS_DECL_ISUPPORTS - NS_DECL_NSISIMPLEENUMERATOR - - nsSHEnumerator(nsSHistory * aHistory); - -protected: - friend class nsSHistory; - virtual ~nsSHEnumerator(); -private: - PRInt32 mIndex; - nsSHistory * mSHistory; -}; - - - -#endif /* nsSHistory */ diff --git a/xpfe/global/resources/content/bindings/browser.xml b/xpfe/global/resources/content/bindings/browser.xml index b35c2744e27..a8db6e2d49a 100644 --- a/xpfe/global/resources/content/bindings/browser.xml +++ b/xpfe/global/resources/content/bindings/browser.xml @@ -305,9 +305,9 @@ null - - null - + 1 @@ -356,8 +356,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) {