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.

This commit is contained in:
bryner%brianryner.com 2005-05-04 20:22:32 +00:00
Родитель ce8807c979
Коммит 592dbdc176
70 изменённых файлов: 2433 добавлений и 1723 удалений

Просмотреть файл

@ -498,7 +498,9 @@ nsAccessNode::GetDocShellTreeItemFor(nsIDOMNode *aStartNode)
NS_ASSERTION(doc, "No document for node passed in");
nsCOMPtr<nsISupports> container = doc->GetContainer();
nsIDocShellTreeItem *docShellTreeItem = nsnull;
CallQueryInterface(container, &docShellTreeItem);
if (container) {
CallQueryInterface(container, &docShellTreeItem);
}
return docShellTreeItem;
}

Просмотреть файл

@ -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()
{

Просмотреть файл

@ -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<nsIPresShell> 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<nsIDOMNodeList> 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<nsIDOMNode> 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<nsIDOMHTMLInputElement> 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<nsIFormControl> 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<nsIDOMHTMLFormElement> 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<nsIDOMEventReceiver> er = do_QueryInterface(mScriptGlobalObject);
if (er) {
nsCOMPtr<nsIEventListenerManager> manager;
er->GetListenerManager(getter_AddRefs(manager));
if (manager && manager->HasUnloadListeners()) {
return PR_FALSE;
}
}
nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
if (loadGroup) {
nsCOMPtr<nsISimpleEnumerator> requests;
loadGroup->GetRequests(getter_AddRefs(requests));
PRBool hasMore = PR_FALSE;
while (NS_SUCCEEDED(requests->HasMoreElements(&hasMore)) && hasMore) {
nsCOMPtr<nsISupports> elem;
requests->GetNext(getter_AddRefs(elem));
nsCOMPtr<nsIRequest> 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<nsIPresShell> shell =
NS_STATIC_CAST(nsIPresShell*, mPresShells[count]);
if (!shell)
continue;
shell->ReleaseAnonymousContent();
}
}

Просмотреть файл

@ -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.

Просмотреть файл

@ -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

Просмотреть файл

@ -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<nsIDOMLoadListener> 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,

Просмотреть файл

@ -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

Просмотреть файл

@ -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:

Просмотреть файл

@ -85,6 +85,7 @@ public:
eDOMEvents_unload,
eDOMEvents_abort,
eDOMEvents_error,
eDOMEvents_DOMPageRestore,
eDOMEvents_submit,
eDOMEvents_reset,
eDOMEvents_change,

Просмотреть файл

@ -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)
{

Просмотреть файл

@ -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

Просмотреть файл

@ -1538,15 +1538,17 @@ nsGenericHTMLElement::HandleDOMEventForAnchors(nsPresContext* aPresContext,
// nothing else.
nsCOMPtr<nsPIDOMWindow> win =
do_QueryInterface(document->GetScriptGlobalObject());
nsIFocusController *focusController =
win->GetRootFocusController();
PRBool isActive = PR_FALSE;
focusController->GetActive(&isActive);
if (!isActive) {
nsCOMPtr<nsIDOMElement> 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<nsIDOMElement> domElement = do_QueryInterface(this);
if(domElement)
focusController->SetFocusedElement(domElement);
break;
}
}
aPresContext->EventStateManager()->

Просмотреть файл

@ -1070,14 +1070,16 @@ nsHTMLInputElement::SetFocus(nsPresContext* aPresContext)
// nothing else.
nsCOMPtr<nsPIDOMWindow> 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<nsPIDOMWindow> 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()!

Просмотреть файл

@ -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<nsIDOMEventTarget> target = do_QueryInterface(mImageContent);
target->RemoveEventListener(NS_LITERAL_STRING("click"), this, PR_FALSE);
}
// Break reference cycle with mImageContent, if we have one
nsCOMPtr<nsIImageLoadingContent> imageLoader = do_QueryInterface(mImageContent);
if (imageLoader) {
imageLoader->RemoveObserver(this);
}
mImageContent = nsnull;
nsMediaDocument::Destroy();
}
void
nsImageDocument::SetScriptGlobalObject(nsIScriptGlobalObject* aScriptGlobalObject)
{
if (!aScriptGlobalObject) {
if (mImageResizingEnabled) {
nsCOMPtr<nsIDOMEventTarget> 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<nsIImageLoadingContent> 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<nsIDOMEventTarget> 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<nsIDOMEventTarget> 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);

Просмотреть файл

@ -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,

Просмотреть файл

@ -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();

Просмотреть файл

@ -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;

Просмотреть файл

@ -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<nsIHistoryEntry> 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<nsIHistoryEntry> srcHE(do_QueryInterface(shEntry));
nsCOMPtr<nsIURI> 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<nsITimer> timer = do_QueryElementAt(mRefreshURIList, i);
if (!timer)
continue; // this must be a nsRefreshURI already
// Replace this timer object with a nsRefreshTimer object.
nsCOMPtr<nsITimerCallback> callback;
timer->GetCallback(getter_AddRefs(callback));
timer->Cancel();
nsCOMPtr<nsRefreshTimer> 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<nsIDocShell> 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<nsIDocShell> 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<nsPIDOMWindow> 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<nsIDocument> doc = do_QueryInterface(pWin->GetExtantDocument());
if (!doc || !doc->CanSavePresentation(aNewRequest))
return PR_FALSE;
return PR_TRUE;
}
nsresult
nsDocShell::CaptureState()
{
nsCOMPtr<nsPIDOMWindow> privWin = do_QueryInterface(mScriptGlobal);
if (!privWin || !mOSHE)
return NS_ERROR_FAILURE;
nsCOMPtr<nsISupports> windowState;
nsresult rv = privWin->SaveWindowState(getter_AddRefs(windowState));
NS_ENSURE_SUCCESS(rv, rv);
#ifdef DEBUG_PAGE_CACHE
nsCOMPtr<nsIURI> 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<nsIPresShell> 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<nsIDocShellTreeItem> childShell = do_QueryInterface(ChildAt(i));
NS_ASSERTION(childShell, "null child shell");
mOSHE->AddChildShell(childShell);
}
// Capture the security state.
nsCOMPtr<nsISupports> 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<nsIDocShell> 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<nsIDocumentViewer> docViewer = do_QueryInterface(mContentViewer);
NS_ASSERTION(docViewer, "should not be called with a null viewer");
nsCOMPtr<nsIPresShell> 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<nsPIDOMWindow> privWin = do_QueryInterface(mScriptGlobal);
NS_ENSURE_TRUE(privWin, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIChromeEventHandler> 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<nsIPrivateDOMEvent> 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<nsIURI> uri;
aSHEntry->GetURI(getter_AddRefs(uri));
nsCOMPtr<nsIContentViewer> 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<nsIPresShell> 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<nsIDocShellTreeItem> 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<nsIPresShell> 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<nsPIDOMWindow> privWin =
do_GetInterface(NS_STATIC_CAST(nsIInterfaceRequestor*, this));
NS_ASSERTION(privWin, "could not get nsPIDOMWindow interface");
nsCOMPtr<nsISupports> 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<nsIDOMNSDocument> 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<nsIDocShell> child = do_QueryInterface(ChildAt(i));
if (child)
child->ResumeRefreshURIs();
}
nsCOMPtr<nsISHistory> rootSH;
GetRootSessionHistory(getter_AddRefs(rootSH));
if (rootSH) {
nsCOMPtr<nsISHistoryInternal> 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<nsISupports> 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<nsILoadGroup> 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<nsISHEntry> 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<nsISHEntry> 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<nsIRequest> 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<nsIHistoryEntry> hEntry;
mSessionHistory->GetIndex(&index);
nsCOMPtr<nsISHistoryInternal> 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<nsIHistoryEntry> 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<nsIHistoryEntry> srcHE(do_QueryInterface(src));
if (!src || !replaceEntry || !srcHE)
if (!src || !replaceEntry)
return NS_ERROR_FAILURE;
if (srcID == aCloneID) {

Просмотреть файл

@ -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<nsIClipboardDragDropHookList> mTransferableHookData;
// Secure browser UI object
nsCOMPtr<nsISecureBrowserUI> mSecurityUI;
// WEAK REFERENCES BELOW HERE.
// Note these are intentionally not addrefd. Doing so will create a cycle.
// For that reasons don't use nsCOMPtr.

Просмотреть файл

@ -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);
};

Просмотреть файл

@ -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
* <browser> 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();
};

Просмотреть файл

@ -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),

Просмотреть файл

@ -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__

Просмотреть файл

@ -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<nsIDOMWindow> tempParent;
parent->GetTop(getter_AddRefs(tempParent));
return NS_STATIC_CAST(nsGlobalWindow *,
NS_STATIC_CAST(nsIDOMWindow*, tempParent));
if (parent) {
nsCOMPtr<nsIDOMWindow> 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<nsIEventListenerManager> mListenerManager;
nsCOMPtr<nsIDOMElement> mFocusedElement;
nsCOMPtr<nsIDOMWindowInternal> 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<nsIDOMWindowInternal> focusWinInternal;
fc->GetFocusedWindow(getter_AddRefs(focusWinInternal));
nsCOMPtr<nsPIDOMWindow> 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<WindowStateHolder> 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<nsIContent> focusedContent = do_QueryInterface(focusedElement);
if (focusedContent) {
// We don't bother checking whether the element or frame is focusable.
// If it was focusable when we stored the presentation, it must be
// focusable now.
PRBool didFocusContent = PR_FALSE;
nsIDocument *doc = focusedContent->GetCurrentDoc();
if (doc) {
nsIPresShell *shell = doc->GetShellAt(0);
if (shell) {
nsPresContext *pc = shell->GetPresContext();
if (pc) {
pc->EventStateManager()->SetContentState(focusedContent,
NS_EVENT_STATE_FOCUS);
didFocusContent = PR_TRUE;
}
}
}
}
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<nsIDocShellTreeNode> node = do_QueryInterface(mDocShell);
if (node) {
PRInt32 childCount = 0;
node->GetChildCount(&childCount);
for (PRInt32 i = 0; i < childCount; ++i) {
nsCOMPtr<nsIDocShellTreeItem> childShell;
node->GetChildAt(i, getter_AddRefs(childShell));
NS_ASSERTION(childShell, "null child shell");
nsCOMPtr<nsPIDOMWindow> 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<nsIDocShellTreeNode> node = do_QueryInterface(mDocShell);
if (node) {
PRInt32 childCount = 0;
node->GetChildCount(&childCount);
for (PRInt32 i = 0; i < childCount; ++i) {
nsCOMPtr<nsIDocShellTreeItem> childShell;
node->GetChildAt(i, getter_AddRefs(childShell));
NS_ASSERTION(childShell, "null child shell");
nsCOMPtr<nsPIDOMWindow> 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)

Просмотреть файл

@ -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<nsIWidget> 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

Просмотреть файл

@ -203,28 +203,30 @@ CHClickListener::MouseDown(nsIDOMEvent* aEvent)
nsCOMPtr<nsIScriptGlobalObject> sgo;
doc->GetScriptGlobalObject(getter_AddRefs(sgo));
nsCOMPtr<nsIDOMWindow> 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;
}

Просмотреть файл

@ -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<nsISecureBrowserUI> 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)

Просмотреть файл

@ -168,7 +168,6 @@ protected:
nativeWindow mParentNativeWindow;
nsIWebProgressListener *mProgressListener;
nsCOMPtr<nsIWebProgress> mWebProgress;
nsCOMPtr<nsISecureBrowserUI> mSecurityUI;
nsCOMPtr<nsIPrintSettings> mPrintSettings;

Просмотреть файл

@ -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 <chak@netscape.com>
*
* ***** 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 <afxwin.h> // MFC core and standard components
#include <afxext.h> // MFC extensions
#include <afxdtctl.h> // MFC support for Internet Explorer 4 Common Controls
#include <afxpriv.h> // Needed for MFC MBCS/Unicode Conversion Macros
#ifndef _AFX_NO_AFXCMN_SUPPORT
#include <afxcmn.h> // 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

Просмотреть файл

@ -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)
{

Просмотреть файл

@ -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<nsIURI> mBaseURI;

Просмотреть файл

@ -121,3 +121,15 @@ nsLoadListenerProxy::Error(nsIDOMEvent* aEvent)
return NS_OK;
}
NS_IMETHODIMP
nsLoadListenerProxy::PageRestore(nsIDOMEvent* aEvent)
{
nsCOMPtr<nsIDOMLoadListener> listener(do_QueryReferent(mParent));
if (listener) {
return listener->PageRestore(aEvent);
}
return NS_OK;
}

Просмотреть файл

@ -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;

Просмотреть файл

@ -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)

Просмотреть файл

@ -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

Просмотреть файл

@ -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)

Просмотреть файл

@ -73,6 +73,7 @@ REQUIRES = xpcom \
util \
windowwatcher \
accessibility \
shistory \
$(NULL)
XPIDLSRCS = \

Просмотреть файл

@ -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<nsIDOMFocusListener> mFocusListener;
nsCOMPtr<nsIContentViewer> mPreviousViewer;
PRPackedBool mEnableRendering;
PRPackedBool mStopped;
PRPackedBool mLoaded;
PRPackedBool mDeferredWindowClose;
PRInt16 mNumURLStarts;
PRInt16 mDestroyRefCount; // a second "refcount" for the document viewer's "destroy"
nsCOMPtr<nsISHEntry> 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<nsIDOMWindowInternal> 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<nsIPrintSettings> mCachedPrintSettings;
nsCOMPtr<nsIWebProgressListener> mCachedPrintWebProgressListner;
PRPackedBool mPrintIsPending;
PRPackedBool mPrintDocIsFullyLoaded;
#endif // NS_PRINT_PREVIEW
nsPrintEngine* mPrintEngine;
nsCOMPtr<nsIDOMWindowInternal> 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<nsIInterfaceRequestor> 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<nsIDOMEventReceiver> erP(do_QueryInterface(mDocument));
NS_WARN_IF_FALSE(erP, "No event receiver in document!");
if (mFocusListener) {
// get the DOM event receiver
nsCOMPtr<nsIDOMEventReceiver> 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<nsIWebNavigation> webNav = do_QueryInterface(mContainer);
if (webNav) {
nsCOMPtr<nsISHistory> history;
webNav->GetSessionHistory(getter_AddRefs(history));
nsCOMPtr<nsISHistoryInternal> 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)

Просмотреть файл

@ -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

Просмотреть файл

@ -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,

Просмотреть файл

@ -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")

Просмотреть файл

@ -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<nsITimer> 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<nsIPluginInstance> 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<nsIPluginHost> 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<nsIDOMDocument> 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<nsIDOMDocument> 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<nsIDOMNodeList> nodes;
aDocument->GetElementsByTagName(aPluginTag, getter_AddRefs(nodes));
if (!nodes)
return;
PRUint32 length;
nodes->GetLength(&length);
for (PRUint32 i = 0; i < length; ++i) {
nsCOMPtr<nsIDOMNode> node;
nodes->Item(i, getter_AddRefs(node));
nsCOMPtr<nsIContent> content = do_QueryInterface(node);
if (content)
aCallback(this, content);
}
}
//------------------------------------------------------
// End of protected and private methods on the PresShell
//------------------------------------------------------

Просмотреть файл

@ -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);
}
}
//-----------------------------------------------------------------

Просмотреть файл

@ -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<nsIDOMWindowInternal> window(do_QueryInterface(document->GetScriptGlobalObject()));
if (!window)
return NS_OK;
nsCOMPtr<nsIDOMScreen> screen;
window->GetScreen(getter_AddRefs(screen));
PRInt32 screenWidth = 0, screenHeight = 0;

Просмотреть файл

@ -169,15 +169,10 @@ nsTitleBarFrame::HandleEvent(nsPresContext* aPresContext,
nsCOMPtr<nsIDOMWindowInternal>
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;

Просмотреть файл

@ -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++

Просмотреть файл

@ -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<nsIScriptGlobalObject> sgo(do_QueryInterface(mWindow));
if (!sgo) return NS_ERROR_FAILURE;
nsCOMPtr<nsIWebProgress> 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<nsIWebProgress> 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<nsISupports> 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<nsSecureBrowserUIImpl::State> state = do_QueryInterface(aState);
NS_ENSURE_TRUE(state, NS_ERROR_NULL_POINTER);
mSSLStatus = state->GetSSLStatus();
return UpdateSecurityState(state->GetState(), nsnull);
}

Просмотреть файл

@ -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;
};

Просмотреть файл

@ -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<nsIWindowWatcher> watcher =
do_GetService(NS_WINDOWWATCHER_CONTRACTID);
if (watcher) {
nsCOMPtr<nsISimpleEnumerator> enumerator;
watcher->GetWindowEnumerator(getter_AddRefs(enumerator));
if (enumerator) {
PRBool hasMore;
while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore) {
nsCOMPtr<nsISupports> item;
enumerator->GetNext(getter_AddRefs(item));
nsCOMPtr<nsIDOMEventTarget> 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<nsIDOMEventTarget> 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<nsIDOMEventTarget> 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<nsIDOMWindow> 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<nsIDOMDocument> 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<nsIDOMNSEvent> nsevent = do_QueryInterface(aEvent);
PRBool trusted = PR_FALSE;
if (nsevent)
nsevent->GetIsTrusted(&trusted);
if (!trusted)
return NS_OK;
nsCOMPtr<nsIDOMEventTarget> target;
aEvent->GetTarget(getter_AddRefs(target));
nsCOMPtr<nsIDocument> doc = do_QueryInterface(target);
if (doc) {
nsCOMPtr<nsIDOMWindow> win =
do_QueryInterface(doc->GetScriptGlobalObject());
if (win) {
return DoPrefill(win);
}
}
return NS_OK;
}
// internal methods

Просмотреть файл

@ -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,

Просмотреть файл

@ -880,6 +880,12 @@ nsFormFillController::Error(nsIDOMEvent *aLoadEvent)
return NS_OK;
}
NS_IMETHODIMP
nsFormFillController::PageRestore(nsIDOMEvent *aLoadEvent)
{
return NS_OK;
}
////////////////////////////////////////////////////////////////////////
//// nsFormFillController

Просмотреть файл

@ -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();

Просмотреть файл

@ -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)

Просмотреть файл

@ -484,9 +484,9 @@
null
</field>
<field name="securityUI">
null
</field>
<property name="securityUI"
onget="return this.docShell.securityUI;"
onset="this.docShell.securityUI = val;"/>
<field name="userTypedClear">
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) {

Просмотреть файл

@ -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();
}
}
}

Просмотреть файл

@ -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:

Просмотреть файл

@ -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;
}
}
}

Просмотреть файл

@ -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();

Просмотреть файл

@ -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)

Просмотреть файл

@ -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++

Просмотреть файл

@ -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;

Просмотреть файл

@ -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 <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 ***** */
/**
* 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"
%}

Просмотреть файл

@ -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);
};

Просмотреть файл

@ -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;
};

Просмотреть файл

@ -55,6 +55,7 @@ REQUIRES = xpcom \
layout \
docshell \
pref \
gfx \
$(NULL)
CPPSRCS = 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;
}

Просмотреть файл

@ -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<nsIURI> mURI;
nsCOMPtr<nsIURI> mReferrerURI;
nsCOMPtr<nsIDOMDocument> mDocument;
nsCOMPtr<nsIContentViewer> mContentViewer;
nsString mTitle;
nsCOMPtr<nsIInputStream> mPostData;
nsCOMPtr<nsILayoutHistoryState> mLayoutHistoryState;
@ -86,9 +88,15 @@ private:
PRPackedBool mIsFrameNavigation;
PRPackedBool mSaveLayoutState;
PRPackedBool mExpired;
PRPackedBool mSticky;
nsCString mContentType;
nsCOMPtr<nsISupports> mCacheKey;
nsISHEntry * mParent; // weak reference
nsCOMPtr<nsISupports> mWindowState;
nsRect mViewerBounds;
nsVoidArray mChildShells;
nsCOMPtr<nsISupports> mSecurityState;
nsCOMPtr<nsISupportsArray> mRefreshURIList;
};
#endif /* nsSHEntry_h */

Просмотреть файл

@ -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 <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 ***** */
// 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<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
if (prefs) {
nsCOMPtr<nsIPrefBranch> 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<nsISHTransaction> currentTxn;
if(mListRoot)
GetTransactionAtIndex(mIndex, getter_AddRefs(currentTxn));
PRBool currentPersist = PR_TRUE;
if(currentTxn)
currentTxn->GetPersist(&currentPersist);
if(!currentPersist)
{
NS_ENSURE_SUCCESS(currentTxn->SetSHEntry(aSHEntry),NS_ERROR_FAILURE);
currentTxn->SetPersist(aPersist);
return NS_OK;
}
nsCOMPtr<nsISHTransaction> txn(do_CreateInstance(NS_SHTRANSACTION_CONTRACTID));
NS_ENSURE_TRUE(txn, NS_ERROR_FAILURE);
// Notify any listener about the new addition
if (mListener) {
nsCOMPtr<nsISHistoryListener> listener(do_QueryReferent(mListener));
if (listener) {
nsCOMPtr<nsIURI> uri;
nsCOMPtr<nsIHistoryEntry> 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<nsISHTransaction> 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<nsISHEntry> 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<nsISHTransaction> tempPtr;
rv = GetRootTransaction(getter_AddRefs(tempPtr));
if (NS_FAILED(rv) || !tempPtr)
return NS_ERROR_FAILURE;
while(1) {
nsCOMPtr<nsISHTransaction> 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<nsISHTransaction> txn;
PRInt32 index = 0;
nsresult rv;
if (!mListRoot)
return NS_ERROR_FAILURE;
txn = mListRoot;
while (1) {
if (!txn)
break;
nsCOMPtr<nsISHEntry> entry;
rv = txn->GetSHEntry(getter_AddRefs(entry));
if (NS_FAILED(rv) && !entry)
return NS_ERROR_FAILURE;
nsCOMPtr<nsILayoutHistoryState> layoutHistoryState;
nsCOMPtr<nsIURI> uri;
PRUnichar * title;
entry->GetLayoutHistoryState(getter_AddRefs(layoutHistoryState));
nsCOMPtr<nsIHistoryEntry> 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<nsISHTransaction> 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<nsISHistoryListener> 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<nsISHTransaction> 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<nsISHTransaction> 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<nsISHistoryListener> 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<nsIURI> 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<nsIHistoryEntry> 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<nsIDocShell> docShell;
nsCOMPtr<nsISHEntry> shEntry;
// Keep note of requested history index in mRequestedIndex.
mRequestedIndex = aIndex;
nsCOMPtr<nsISHEntry> prevEntry;
GetEntryAtIndex(mIndex, PR_FALSE, getter_AddRefs(prevEntry));
nsCOMPtr<nsISHEntry> nextEntry;
GetEntryAtIndex(mRequestedIndex, PR_FALSE, getter_AddRefs(nextEntry));
nsCOMPtr<nsIHistoryEntry> 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<nsIURI> nextURI;
nHEntry->GetURI(getter_AddRefs(nextURI));
if(mListener) {
nsCOMPtr<nsISHistoryListener> 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<nsIURI> nexturi;
PRInt32 pCount=0, nCount=0;
nsCOMPtr<nsISHContainer> prevAsContainer(do_QueryInterface(prevEntry));
nsCOMPtr<nsISHContainer> nextAsContainer(do_QueryInterface(nextEntry));
if (prevAsContainer && nextAsContainer) {
prevAsContainer->GetChildCount(&pCount);
nextAsContainer->GetChildCount(&nCount);
}
nsCOMPtr<nsIDocShellLoadInfo> 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<nsISHContainer> prevContainer(do_QueryInterface(aPrevEntry));
nsCOMPtr<nsISHContainer> nextContainer(do_QueryInterface(aNextEntry));
nsCOMPtr<nsIDocShellTreeNode> 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<ncnt; i++){
nsCOMPtr<nsISHEntry> pChild, nChild;
nsCOMPtr<nsIDocShellTreeItem> 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<nsIDocShell> dsChild(do_QueryInterface(dsTreeItemChild));
CompareFrames(pChild, nChild, dsChild, aLoadType, aIsFrameFound);
}
return result;
}
nsresult
nsSHistory::InitiateLoad(nsISHEntry * aFrameEntry, nsIDocShell * aFrameDS, long aLoadType)
{
nsCOMPtr<nsIDocShellLoadInfo> 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<nsIURI> nextURI;
nsCOMPtr<nsIHistoryEntry> 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<nsIHistoryEntry> hEntry;
result = mSHistory->GetEntryAtIndex(mIndex, PR_FALSE, getter_AddRefs(hEntry));
if (hEntry)
result = CallQueryInterface(hEntry, aItem);
}
return result;
}

Просмотреть файл

@ -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 <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 ***** */
#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<nsISHTransaction> 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 */

Просмотреть файл

@ -305,9 +305,9 @@
null
</field>
<field name="securityUI">
null
</field>
<property name="securityUI"
onget="return this.docShell.securityUI;"
onset="this.docShell.securityUI = val;"/>
<field name="userTypedClear">
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) {