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
Родитель 47bc88d786
Коммит aed69207f0
70 изменённых файлов: 2542 добавлений и 383 удалений

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

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

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

@ -115,6 +115,7 @@
#include "nsIEmbeddingSiteWindow2.h"
#include "nsIWebBrowserFind.h"
#include "nsIWebBrowserFocus.h"
#include "nsIURI.h"
// Printer Includes
#include "nsIWebBrowserPrint.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;

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

@ -53,30 +53,30 @@ interface nsIURI;
interface nsIHistoryEntry : nsISupports
{
/**
* A readonly property that returns the URI
* of the current entry. The object returned is
* of type nsIURI
*/
readonly attribute nsIURI URI;
/**
* A readonly property that returns the 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 the title
* of the current entry. The object returned
* is a encoded string
*/
readonly attribute wstring title;
/**
* A readonly property that returns a boolean
* flag which indicates if the entry was created as a
* result of a subframe navigation. This flag will be
* 'false' when a frameset page is visited for
* the first time. This flag will be 'true' for all
* history entries created as a result of a subframe
* navigation.
*/
readonly attribute boolean isSubFrame;
/**
* A readonly property that returns 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;
};

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

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

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

@ -46,7 +46,7 @@ interface nsIDocShell;
%{C++
#define NS_SHISTORY_INTERNAL_CID \
{0xdd335422, 0xb8b8, 0x11d3, {0xbd, 0xc8, 0x00, 0x50, 0x04, 0x0a, 0x9b, 0x44}}
{0x5b4cba4c, 0xbf67, 0x499a, {0xae, 0x2c, 0x3f, 0x76, 0x65, 0x6f, 0x4a, 0x4e}}
#define NS_SHISTORY_INTERNAL_CONTRACTID "@mozilla.org/browser/shistory-internal;1"
%}
@ -90,4 +90,11 @@ interface nsISHistoryInternal: nsISupports
*/
readonly attribute nsISHistoryListener listener;
/**
* Evict content viewers until the number of content viewers is no more than
* browser.sessionhistory.max_viewers. This is done automatically by
* updateIndex(), but should be called explicitly if a new history entry
* is added and later has a content viewer set.
*/
void evictContentViewers();
};

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

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

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

@ -54,9 +54,14 @@
#include "nsIDocShellLoadInfo.h"
#include "nsIServiceManager.h"
#include "nsIPrefService.h"
#include "nsIURI.h"
#include "nsIContentViewer.h"
#define PREF_SHISTORY_SIZE "browser.sessionhistory.max_entries"
#define PREF_SHISTORY_VIEWERS "browser.sessionhistory.max_viewers"
static PRInt32 gHistoryMaxSize = 50;
static PRInt32 gHistoryMaxViewers = 0;
enum HistCmd{
HIST_CMD_BACK,
@ -104,11 +109,21 @@ nsSHistory::Init()
{
nsCOMPtr<nsIPrefService> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
if (prefs) {
// Session history size is only taken from the default prefs branch.
// This means that it's only configurable on a per-application basis.
// The goal of this is to unbreak users who have inadvertently set their
// session history size to -1.
nsCOMPtr<nsIPrefBranch> defaultBranch;
prefs->GetDefaultBranch(nsnull, getter_AddRefs(defaultBranch));
if (defaultBranch) {
defaultBranch->GetIntPref(PREF_SHISTORY_SIZE, &gHistoryMaxSize);
}
// The size of the content viewer cache does not suffer from this problem,
// so we allow it to be overridden by user prefs.
nsCOMPtr<nsIPrefBranch> branch = do_QueryInterface(prefs);
if (branch)
branch->GetIntPref(PREF_SHISTORY_VIEWERS, &gHistoryMaxViewers);
}
return NS_OK;
}
@ -207,6 +222,7 @@ nsSHistory::GetEntryAtIndex(PRInt32 aIndex, PRBool aModifyIndex, nsISHEntry** aR
if (NS_SUCCEEDED(rv) && (*aResult)) {
// Set mIndex to the requested index, if asked to do so..
if (aModifyIndex) {
EvictContentViewers(mIndex, aIndex);
mIndex = aIndex;
}
} //entry
@ -476,6 +492,14 @@ nsSHistory::GetListener(nsISHistoryListener ** aListener)
return NS_OK;
}
NS_IMETHODIMP
nsSHistory::EvictContentViewers()
{
// This is called after a new entry has been appended to the end of the list.
EvictContentViewers(mIndex - 1, mIndex);
return NS_OK;
}
//*****************************************************************************
// nsSHistory: nsIWebNavigation
//*****************************************************************************
@ -583,12 +607,63 @@ nsSHistory::Reload(PRUint32 aReloadFlags)
return LoadEntry(mIndex, loadType, HIST_CMD_RELOAD);
}
void
nsSHistory::EvictContentViewers(PRInt32 aFromIndex, PRInt32 aToIndex)
{
// To enforce the limit on cached content viewers, we need to release all
// of the content viewers that are no longer in the "window" that now
// ends/begins at aToIndex.
PRInt32 startIndex, endIndex;
if (aToIndex > aFromIndex) { // going forward
startIndex = PR_MAX(0, aFromIndex - gHistoryMaxViewers);
endIndex = PR_MAX(0, aToIndex - gHistoryMaxViewers);
} else { // going backward
startIndex = PR_MIN(mLength - 1, aToIndex + gHistoryMaxViewers);
endIndex = PR_MIN(mLength - 1, aFromIndex + gHistoryMaxViewers);
}
nsCOMPtr<nsISHTransaction> trans;
GetTransactionAtIndex(startIndex, getter_AddRefs(trans));
for (PRInt32 i = startIndex; trans && i < endIndex; ++i) {
nsCOMPtr<nsISHEntry> entry;
trans->GetSHEntry(getter_AddRefs(entry));
nsCOMPtr<nsIContentViewer> viewer;
entry->GetContentViewer(getter_AddRefs(viewer));
if (viewer) {
#ifdef DEBUG_PAGE_CACHE
nsCOMPtr<nsIURI> uri;
entry->GetURI(getter_AddRefs(uri));
nsCAutoString spec;
if (uri)
uri->GetSpec(spec);
printf("Evicting content viewer: %s\n", spec.get());
#endif
viewer->Destroy();
entry->SetContentViewer(nsnull);
entry->SyncPresentationState();
}
nsISHTransaction *temp = trans;
temp->GetNext(getter_AddRefs(trans));
}
}
NS_IMETHODIMP
nsSHistory::UpdateIndex()
{
// Update the actual index with the right value.
if (mIndex != mRequestedIndex && mRequestedIndex != -1)
if (mIndex != mRequestedIndex && mRequestedIndex != -1) {
// We've just finished a history navigation (back or forward), so enforce
// the max number of content viewers.
EvictContentViewers(mIndex, mRequestedIndex);
mIndex = mRequestedIndex;
}
return NS_OK;
}

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

@ -85,6 +85,8 @@ protected:
nsresult PrintHistory();
#endif
void EvictContentViewers(PRInt32 aFromIndex, PRInt32 aToIndex);
protected:
nsCOMPtr<nsISHTransaction> mListRoot;
PRInt32 mIndex;

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

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