2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=2 sw=2 et tw=78: */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is mozilla.org code.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is
|
|
|
|
* Netscape Communications Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Johnny Stenback <jst@netscape.com>
|
|
|
|
* L. David Baron <dbaron@dbaron.org>
|
|
|
|
* Pierre Phaneuf <pp@ludusdesign.com>
|
|
|
|
* Pete Collins <petejc@collab.net>
|
|
|
|
* James Ross <silver@warwickcompsoc.co.uk>
|
2008-08-17 19:10:28 -07:00
|
|
|
* Ryan Jones <sciguyryan@gmail.com>
|
2007-03-22 10:30:00 -07:00
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Base class for all our document implementations.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "plstr.h"
|
2007-11-09 14:54:35 -08:00
|
|
|
#include "prprf.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#include "nsIInterfaceRequestor.h"
|
|
|
|
#include "nsIInterfaceRequestorUtils.h"
|
|
|
|
#include "nsDocument.h"
|
|
|
|
#include "nsUnicharUtils.h"
|
|
|
|
#include "nsIPrivateDOMEvent.h"
|
|
|
|
#include "nsIEventStateManager.h"
|
|
|
|
#include "nsContentList.h"
|
|
|
|
#include "nsIObserver.h"
|
|
|
|
#include "nsIBaseWindow.h"
|
|
|
|
#include "nsIDocShell.h"
|
|
|
|
#include "nsIDocShellTreeItem.h"
|
|
|
|
#include "nsIScriptRuntime.h"
|
|
|
|
#include "nsCOMArray.h"
|
|
|
|
|
|
|
|
#include "nsGUIEvent.h"
|
|
|
|
|
|
|
|
#include "nsIDOMStyleSheet.h"
|
|
|
|
#include "nsDOMAttribute.h"
|
|
|
|
#include "nsIDOMDOMStringList.h"
|
|
|
|
#include "nsIDOMDOMImplementation.h"
|
|
|
|
#include "nsIDOMDocumentView.h"
|
|
|
|
#include "nsIDOMAbstractView.h"
|
|
|
|
#include "nsIDOMDocumentXBL.h"
|
|
|
|
#include "nsGenericElement.h"
|
2008-08-17 19:10:28 -07:00
|
|
|
#include "nsGenericHTMLElement.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIDOMEventGroup.h"
|
|
|
|
#include "nsIDOMCDATASection.h"
|
|
|
|
#include "nsIDOMProcessingInstruction.h"
|
|
|
|
#include "nsDOMString.h"
|
|
|
|
#include "nsNodeUtils.h"
|
2007-08-29 13:38:44 -07:00
|
|
|
#include "nsLayoutUtils.h" // for GetFrameForPoint
|
|
|
|
#include "nsIFrame.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
#include "nsRange.h"
|
|
|
|
#include "nsIDOMText.h"
|
|
|
|
#include "nsIDOMComment.h"
|
|
|
|
#include "nsDOMDocumentType.h"
|
2008-07-21 17:35:38 -07:00
|
|
|
#include "nsNodeIterator.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsTreeWalker.h"
|
|
|
|
|
|
|
|
#include "nsIServiceManager.h"
|
|
|
|
|
|
|
|
#include "nsContentCID.h"
|
|
|
|
#include "nsDOMError.h"
|
|
|
|
#include "nsIPresShell.h"
|
|
|
|
#include "nsPresContext.h"
|
|
|
|
#include "nsThreadUtils.h"
|
|
|
|
#include "nsNodeInfoManager.h"
|
|
|
|
#include "nsIXBLService.h"
|
|
|
|
#include "nsIXPointer.h"
|
|
|
|
#include "nsIFileChannel.h"
|
|
|
|
#include "nsIMultiPartChannel.h"
|
|
|
|
#include "nsIRefreshURI.h"
|
|
|
|
#include "nsIWebNavigation.h"
|
|
|
|
#include "nsIScriptError.h"
|
|
|
|
|
|
|
|
#include "nsNetUtil.h" // for NS_MakeAbsoluteURI
|
|
|
|
|
|
|
|
#include "nsIScriptSecurityManager.h"
|
|
|
|
#include "nsIPrincipal.h"
|
|
|
|
#include "nsIPrivateDOMImplementation.h"
|
|
|
|
|
|
|
|
#include "nsIDOMWindowInternal.h"
|
|
|
|
#include "nsPIDOMWindow.h"
|
|
|
|
#include "nsIDOMElement.h"
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
#include "nsFocusManager.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// for radio group stuff
|
|
|
|
#include "nsIDOMHTMLInputElement.h"
|
|
|
|
#include "nsIRadioVisitor.h"
|
|
|
|
#include "nsIFormControl.h"
|
|
|
|
|
|
|
|
#include "nsXMLEventsManager.h"
|
|
|
|
|
|
|
|
#include "nsBidiUtils.h"
|
|
|
|
|
|
|
|
static NS_DEFINE_CID(kDOMEventGroupCID, NS_DOMEVENTGROUP_CID);
|
|
|
|
|
|
|
|
#include "nsIDOMUserDataHandler.h"
|
|
|
|
#include "nsScriptEventManager.h"
|
|
|
|
#include "nsIDOMXPathEvaluator.h"
|
|
|
|
#include "nsIXPathEvaluatorInternal.h"
|
|
|
|
#include "nsIParserService.h"
|
|
|
|
#include "nsContentCreatorFunctions.h"
|
|
|
|
|
|
|
|
#include "nsIScriptContext.h"
|
|
|
|
#include "nsBindingManager.h"
|
|
|
|
#include "nsIDOMHTMLDocument.h"
|
|
|
|
#include "nsIDOMHTMLFormElement.h"
|
|
|
|
#include "nsIRequest.h"
|
|
|
|
#include "nsILink.h"
|
|
|
|
|
|
|
|
#include "nsICharsetAlias.h"
|
|
|
|
#include "nsIParser.h"
|
|
|
|
#include "nsIContentSink.h"
|
|
|
|
|
|
|
|
#include "nsDateTimeFormatCID.h"
|
|
|
|
#include "nsIDateTimeFormat.h"
|
|
|
|
#include "nsEventDispatcher.h"
|
2007-03-24 05:18:02 -07:00
|
|
|
#include "nsMutationEvent.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIDOMXPathEvaluator.h"
|
|
|
|
#include "nsDOMCID.h"
|
|
|
|
|
2009-06-19 09:31:48 -07:00
|
|
|
#include "jsapi.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
#include "nsIJSContextStack.h"
|
|
|
|
#include "nsIXPConnect.h"
|
|
|
|
#include "nsCycleCollector.h"
|
2007-05-10 13:21:12 -07:00
|
|
|
#include "nsCCUncollectableMarker.h"
|
2007-06-12 14:56:06 -07:00
|
|
|
#include "nsIContentPolicy.h"
|
2008-10-04 13:00:09 -07:00
|
|
|
#include "nsContentPolicyUtils.h"
|
|
|
|
#include "nsICategoryManager.h"
|
|
|
|
#include "nsIDocumentLoaderFactory.h"
|
|
|
|
#include "nsIContentViewer.h"
|
|
|
|
#include "nsIXMLContentSink.h"
|
|
|
|
#include "nsContentErrors.h"
|
|
|
|
#include "nsIXULDocument.h"
|
|
|
|
#include "nsIPrompt.h"
|
2008-11-18 14:54:36 -08:00
|
|
|
#include "nsIPropertyBag2.h"
|
2009-06-24 06:33:02 -07:00
|
|
|
#include "nsIDOMPageTransitionEvent.h"
|
2008-02-26 06:47:51 -08:00
|
|
|
#include "nsFrameLoader.h"
|
2009-10-29 16:55:05 -07:00
|
|
|
#ifdef MOZ_MEDIA
|
2009-10-01 07:10:13 -07:00
|
|
|
#include "nsHTMLMediaElement.h"
|
2009-10-29 16:55:05 -07:00
|
|
|
#endif // MOZ_MEDIA
|
2008-02-26 06:47:51 -08:00
|
|
|
|
2008-04-11 10:29:06 -07:00
|
|
|
#include "mozAutoDocUpdate.h"
|
|
|
|
|
2009-01-14 20:38:07 -08:00
|
|
|
#ifdef MOZ_SMIL
|
|
|
|
#include "nsSMILAnimationController.h"
|
|
|
|
#include "imgIContainer.h"
|
2009-03-09 18:20:17 -07:00
|
|
|
#include "nsSVGUtils.h"
|
2009-01-14 20:38:07 -08:00
|
|
|
#endif // MOZ_SMIL
|
|
|
|
|
2008-10-04 13:00:09 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
#ifdef MOZ_LOGGING
|
|
|
|
// so we can get logging even in release builds
|
|
|
|
#define FORCE_PR_LOG 1
|
|
|
|
#endif
|
|
|
|
#include "prlog.h"
|
|
|
|
|
|
|
|
#ifdef PR_LOGGING
|
|
|
|
static PRLogModuleInfo* gDocumentLeakPRLog;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void
|
|
|
|
nsUint32ToContentHashEntry::Destroy()
|
|
|
|
{
|
|
|
|
HashSet* set = GetHashSet();
|
|
|
|
if (set) {
|
|
|
|
delete set;
|
|
|
|
} else {
|
|
|
|
nsIContent* content = GetContent();
|
|
|
|
NS_IF_RELEASE(content);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUint32ToContentHashEntry::PutContent(nsIContent* aVal)
|
|
|
|
{
|
|
|
|
// Add the value to the hash if it is there
|
|
|
|
HashSet* set = GetHashSet();
|
|
|
|
if (set) {
|
|
|
|
nsISupportsHashKey* entry = set->PutEntry(aVal);
|
|
|
|
return entry ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If an element is already there, create a hashtable and both of these to it
|
|
|
|
nsIContent* oldVal = GetContent();
|
|
|
|
if (oldVal) {
|
|
|
|
nsresult rv = InitHashSet(&set);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsISupportsHashKey* entry = set->PutEntry(oldVal);
|
|
|
|
if (!entry) {
|
|
|
|
// OOM - we can't insert aVal, but we can at least put oldVal back (even
|
|
|
|
// if we didn't, we'd still have to release oldVal so that we don't leak)
|
|
|
|
delete set;
|
|
|
|
SetContent(oldVal);
|
|
|
|
// SetContent adds another reference, so release the one we had
|
|
|
|
NS_RELEASE(oldVal);
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
// The hashset adds its own reference, so release the one we had
|
|
|
|
NS_RELEASE(oldVal);
|
|
|
|
|
|
|
|
entry = set->PutEntry(aVal);
|
|
|
|
return entry ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Nothing exists in the hash right now, so just set the single pointer
|
|
|
|
return SetContent(aVal);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsUint32ToContentHashEntry::RemoveContent(nsIContent* aVal)
|
|
|
|
{
|
|
|
|
// Remove from the hash if the hash is there
|
|
|
|
HashSet* set = GetHashSet();
|
|
|
|
if (set) {
|
|
|
|
set->RemoveEntry(aVal);
|
|
|
|
if (set->Count() == 0) {
|
|
|
|
delete set;
|
|
|
|
mValOrHash = nsnull;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove the ptr if there is just a ptr
|
|
|
|
nsIContent* v = GetContent();
|
|
|
|
if (v == aVal) {
|
|
|
|
NS_IF_RELEASE(v);
|
|
|
|
mValOrHash = nsnull;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsUint32ToContentHashEntry::InitHashSet(HashSet** aSet)
|
|
|
|
{
|
|
|
|
HashSet* newSet = new HashSet();
|
|
|
|
if (!newSet) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult rv = newSet->Init();
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
mValOrHash = newSet;
|
|
|
|
*aSet = newSet;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-10-10 08:04:34 -07:00
|
|
|
static PLDHashOperator
|
2007-03-22 10:30:00 -07:00
|
|
|
nsUint32ToContentHashEntryVisitorCallback(nsISupportsHashKey* aEntry,
|
|
|
|
void* aClosure)
|
|
|
|
{
|
|
|
|
nsUint32ToContentHashEntry::Visitor* visitor =
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<nsUint32ToContentHashEntry::Visitor*>(aClosure);
|
|
|
|
visitor->Visit(static_cast<nsIContent*>(aEntry->GetKey()));
|
2007-03-22 10:30:00 -07:00
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsUint32ToContentHashEntry::VisitContent(Visitor* aVisitor)
|
|
|
|
{
|
|
|
|
HashSet* set = GetHashSet();
|
|
|
|
if (set) {
|
|
|
|
set->EnumerateEntries(nsUint32ToContentHashEntryVisitorCallback, aVisitor);
|
|
|
|
if (set->Count() == 0) {
|
|
|
|
delete set;
|
|
|
|
mValOrHash = nsnull;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIContent* v = GetContent();
|
|
|
|
if (v) {
|
|
|
|
aVisitor->Visit(v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-22 16:12:40 -07:00
|
|
|
#define NAME_NOT_VALID ((nsBaseContentList*)1)
|
|
|
|
|
|
|
|
nsIdentifierMapEntry::~nsIdentifierMapEntry()
|
|
|
|
{
|
|
|
|
if (mNameContentList && mNameContentList != NAME_NOT_VALID) {
|
|
|
|
NS_RELEASE(mNameContentList);
|
|
|
|
}
|
2009-10-13 13:51:02 -07:00
|
|
|
|
|
|
|
for (PRInt32 i = 0; i < mIdContentList.Count(); ++i) {
|
|
|
|
nsIContent* content = static_cast<nsIContent*>(mIdContentList[i]);
|
|
|
|
NS_RELEASE(content);
|
|
|
|
}
|
2008-06-22 16:12:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsIdentifierMapEntry::Traverse(nsCycleCollectionTraversalCallback* aCallback)
|
|
|
|
{
|
2008-09-08 11:26:46 -07:00
|
|
|
if (mNameContentList != NAME_NOT_VALID) {
|
|
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
|
|
|
|
"mIdentifierMap mNameContentList");
|
2008-09-10 20:15:29 -07:00
|
|
|
aCallback->NoteXPCOMChild(static_cast<nsIDOMNodeList*>(mNameContentList));
|
2008-09-08 11:26:46 -07:00
|
|
|
}
|
2008-06-22 16:12:40 -07:00
|
|
|
|
2008-09-08 11:26:46 -07:00
|
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback, "mIdentifierMap mDocAllList");
|
2008-06-22 16:12:40 -07:00
|
|
|
aCallback->NoteXPCOMChild(static_cast<nsIDOMNodeList*>(mDocAllList));
|
2009-10-13 13:51:02 -07:00
|
|
|
|
|
|
|
for (PRInt32 i = 0; i < mIdContentList.Count(); ++i) {
|
|
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback,
|
|
|
|
"mIdentifierMap mIdContentList element");
|
|
|
|
aCallback->NoteXPCOMChild(static_cast<nsIContent*>(mIdContentList[i]));
|
|
|
|
}
|
2008-06-22 16:12:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsIdentifierMapEntry::SetInvalidName()
|
|
|
|
{
|
|
|
|
mNameContentList = NAME_NOT_VALID;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsIdentifierMapEntry::IsInvalidName()
|
|
|
|
{
|
|
|
|
return mNameContentList == NAME_NOT_VALID;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsIdentifierMapEntry::CreateNameContentList()
|
|
|
|
{
|
|
|
|
mNameContentList = new nsBaseContentList();
|
|
|
|
NS_ENSURE_TRUE(mNameContentList, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
NS_ADDREF(mNameContentList);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIContent*
|
2009-03-23 07:04:40 -07:00
|
|
|
nsIdentifierMapEntry::GetIdContent()
|
2008-06-22 16:12:40 -07:00
|
|
|
{
|
2009-03-23 07:04:40 -07:00
|
|
|
return static_cast<nsIContent*>(mIdContentList.SafeElementAt(0));
|
2008-06-22 16:12:40 -07:00
|
|
|
}
|
|
|
|
|
2008-06-22 18:48:05 -07:00
|
|
|
void
|
|
|
|
nsIdentifierMapEntry::AppendAllIdContent(nsCOMArray<nsIContent>* aElements)
|
|
|
|
{
|
|
|
|
for (PRInt32 i = 0; i < mIdContentList.Count(); ++i) {
|
|
|
|
aElements->AppendObject(static_cast<nsIContent*>(mIdContentList[i]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-24 18:55:01 -07:00
|
|
|
void
|
|
|
|
nsIdentifierMapEntry::AddContentChangeCallback(nsIDocument::IDTargetObserver aCallback,
|
|
|
|
void* aData)
|
|
|
|
{
|
|
|
|
if (!mChangeCallbacks) {
|
|
|
|
mChangeCallbacks = new nsTHashtable<ChangeCallbackEntry>;
|
|
|
|
if (!mChangeCallbacks)
|
|
|
|
return;
|
|
|
|
mChangeCallbacks->Init();
|
|
|
|
}
|
|
|
|
|
|
|
|
ChangeCallback cc = { aCallback, aData };
|
|
|
|
mChangeCallbacks->PutEntry(cc);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsIdentifierMapEntry::RemoveContentChangeCallback(nsIDocument::IDTargetObserver aCallback,
|
|
|
|
void* aData)
|
|
|
|
{
|
|
|
|
if (!mChangeCallbacks)
|
|
|
|
return;
|
|
|
|
ChangeCallback cc = { aCallback, aData };
|
|
|
|
mChangeCallbacks->RemoveEntry(cc);
|
|
|
|
if (mChangeCallbacks->Count() == 0) {
|
|
|
|
mChangeCallbacks = nsnull;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct FireChangeArgs {
|
|
|
|
nsIContent* mFrom;
|
|
|
|
nsIContent* mTo;
|
|
|
|
};
|
|
|
|
|
2008-10-10 08:04:34 -07:00
|
|
|
static PLDHashOperator
|
2008-06-24 18:55:01 -07:00
|
|
|
FireChangeEnumerator(nsIdentifierMapEntry::ChangeCallbackEntry *aEntry, void *aArg)
|
|
|
|
{
|
|
|
|
FireChangeArgs* args = static_cast<FireChangeArgs*>(aArg);
|
|
|
|
return aEntry->mKey.mCallback(args->mFrom, args->mTo, aEntry->mKey.mData)
|
|
|
|
? PL_DHASH_NEXT : PL_DHASH_REMOVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsIdentifierMapEntry::FireChangeCallbacks(nsIContent* aOldContent,
|
|
|
|
nsIContent* aNewContent)
|
|
|
|
{
|
|
|
|
if (!mChangeCallbacks)
|
|
|
|
return;
|
|
|
|
|
|
|
|
FireChangeArgs args = { aOldContent, aNewContent };
|
|
|
|
mChangeCallbacks->EnumerateEntries(FireChangeEnumerator, &args);
|
|
|
|
}
|
|
|
|
|
2008-06-22 16:12:40 -07:00
|
|
|
PRBool
|
|
|
|
nsIdentifierMapEntry::AddIdContent(nsIContent* aContent)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aContent, "Must have content");
|
|
|
|
NS_PRECONDITION(mIdContentList.IndexOf(nsnull) < 0,
|
|
|
|
"Why is null in our list?");
|
|
|
|
|
2009-03-23 07:04:40 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
nsIContent* currentContent =
|
|
|
|
static_cast<nsIContent*>(mIdContentList.SafeElementAt(0));
|
|
|
|
#endif
|
2008-06-22 16:12:40 -07:00
|
|
|
|
|
|
|
// Common case
|
|
|
|
if (mIdContentList.Count() == 0) {
|
2008-06-24 18:55:01 -07:00
|
|
|
if (!mIdContentList.AppendElement(aContent))
|
|
|
|
return PR_FALSE;
|
2009-10-13 13:51:02 -07:00
|
|
|
NS_ADDREF(aContent);
|
2009-03-23 07:04:40 -07:00
|
|
|
NS_ASSERTION(currentContent == nsnull, "How did that happen?");
|
2008-06-24 18:55:01 -07:00
|
|
|
FireChangeCallbacks(nsnull, aContent);
|
|
|
|
return PR_TRUE;
|
2008-06-22 16:12:40 -07:00
|
|
|
}
|
|
|
|
|
2009-03-23 07:04:40 -07:00
|
|
|
// We seem to have multiple content nodes for the same id, or XUL is messing
|
|
|
|
// with us. Search for the right place to insert the content.
|
2008-06-22 16:12:40 -07:00
|
|
|
PRInt32 start = 0;
|
|
|
|
PRInt32 end = mIdContentList.Count();
|
|
|
|
do {
|
|
|
|
NS_ASSERTION(start < end, "Bogus start/end");
|
|
|
|
|
|
|
|
PRInt32 cur = (start + end) / 2;
|
|
|
|
NS_ASSERTION(cur >= start && cur < end, "What happened here?");
|
|
|
|
|
|
|
|
nsIContent* curContent = static_cast<nsIContent*>(mIdContentList[cur]);
|
|
|
|
if (curContent == aContent) {
|
|
|
|
// Already in the list, so already in the right spot. Get out of here.
|
2009-03-23 07:04:40 -07:00
|
|
|
// XXXbz this only happens because XUL does all sorts of random
|
|
|
|
// UpdateIdTableEntry calls. Hate, hate, hate!
|
2008-06-22 16:12:40 -07:00
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nsContentUtils::PositionIsBefore(aContent, curContent)) {
|
|
|
|
end = cur;
|
|
|
|
} else {
|
|
|
|
start = cur + 1;
|
|
|
|
}
|
|
|
|
} while (start != end);
|
2008-06-24 18:55:01 -07:00
|
|
|
|
|
|
|
if (!mIdContentList.InsertElementAt(aContent, start))
|
|
|
|
return PR_FALSE;
|
2009-10-13 13:51:02 -07:00
|
|
|
NS_ADDREF(aContent);
|
2008-06-24 18:55:01 -07:00
|
|
|
if (start == 0) {
|
2009-03-23 07:04:40 -07:00
|
|
|
nsIContent* oldContent =
|
|
|
|
static_cast<nsIContent*>(mIdContentList.SafeElementAt(1));
|
|
|
|
NS_ASSERTION(currentContent == oldContent, "How did that happen?");
|
|
|
|
FireChangeCallbacks(oldContent, aContent);
|
2008-06-24 18:55:01 -07:00
|
|
|
}
|
|
|
|
return PR_TRUE;
|
2008-06-22 16:12:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsIdentifierMapEntry::RemoveIdContent(nsIContent* aContent)
|
|
|
|
{
|
2008-06-24 18:55:01 -07:00
|
|
|
// This should only be called while the document is in an update.
|
|
|
|
// Assertions near the call to this method guarantee this.
|
|
|
|
|
2008-06-22 16:12:40 -07:00
|
|
|
// XXXbz should this ever Compact() I guess when all the content is gone
|
|
|
|
// we'll just get cleaned up in the natural order of things...
|
2008-06-24 18:55:01 -07:00
|
|
|
nsIContent* currentContent = static_cast<nsIContent*>(mIdContentList.SafeElementAt(0));
|
|
|
|
if (!mIdContentList.RemoveElement(aContent))
|
|
|
|
return PR_FALSE;
|
|
|
|
if (currentContent == aContent) {
|
|
|
|
FireChangeCallbacks(currentContent,
|
|
|
|
static_cast<nsIContent*>(mIdContentList.SafeElementAt(0)));
|
|
|
|
}
|
2009-10-13 16:34:41 -07:00
|
|
|
// Make sure the release happens after the check above, since it'll
|
|
|
|
// null out aContent.
|
|
|
|
NS_RELEASE(aContent);
|
2008-06-24 18:55:01 -07:00
|
|
|
return mIdContentList.Count() == 0 && !mNameContentList && !mChangeCallbacks;
|
2008-06-22 16:12:40 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsIdentifierMapEntry::AddNameContent(nsIContent* aContent)
|
|
|
|
{
|
|
|
|
if (!mNameContentList || mNameContentList == NAME_NOT_VALID)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// NOTE: this indexof is absolutely needed, since we don't flush
|
|
|
|
// content notifications when we do document.foo resolution. So
|
|
|
|
// aContent may be in our list already and just now getting notified
|
|
|
|
// for!
|
|
|
|
if (mNameContentList->IndexOf(aContent, PR_FALSE) < 0) {
|
|
|
|
mNameContentList->AppendElement(aContent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsIdentifierMapEntry::RemoveNameContent(nsIContent* aContent)
|
|
|
|
{
|
|
|
|
if (mNameContentList && mNameContentList != NAME_NOT_VALID) {
|
|
|
|
mNameContentList->RemoveElement(aContent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Helper structs for the content->subdoc map
|
|
|
|
|
|
|
|
class SubDocMapEntry : public PLDHashEntryHdr
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
// Both of these are strong references
|
|
|
|
nsIContent *mKey; // must be first, to look like PLDHashEntryStub
|
|
|
|
nsIDocument *mSubDocument;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct FindContentData
|
|
|
|
{
|
|
|
|
FindContentData(nsIDocument *aSubDoc)
|
|
|
|
: mSubDocument(aSubDoc), mResult(nsnull)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
nsISupports *mSubDocument;
|
|
|
|
nsIContent *mResult;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* A struct that holds all the information about a radio group.
|
|
|
|
*/
|
|
|
|
struct nsRadioGroupStruct
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* A strong pointer to the currently selected radio button.
|
|
|
|
*/
|
|
|
|
nsCOMPtr<nsIDOMHTMLInputElement> mSelectedRadioButton;
|
2007-09-27 11:17:32 -07:00
|
|
|
nsCOMArray<nsIFormControl> mRadioButtons;
|
2007-03-22 10:30:00 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
nsDOMStyleSheetList::nsDOMStyleSheetList(nsIDocument *aDocument)
|
|
|
|
{
|
|
|
|
mLength = -1;
|
|
|
|
// Not reference counted to avoid circular references.
|
|
|
|
// The document will tell us when its going away.
|
|
|
|
mDocument = aDocument;
|
|
|
|
mDocument->AddObserver(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsDOMStyleSheetList::~nsDOMStyleSheetList()
|
|
|
|
{
|
|
|
|
if (mDocument) {
|
|
|
|
mDocument->RemoveObserver(this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX couldn't we use the GetIIDs method from CSSStyleSheetList here?
|
|
|
|
// QueryInterface implementation for nsDOMStyleSheetList
|
2007-12-14 21:43:10 -08:00
|
|
|
NS_INTERFACE_TABLE_HEAD(nsDOMStyleSheetList)
|
|
|
|
NS_INTERFACE_TABLE3(nsDOMStyleSheetList,
|
|
|
|
nsIDOMStyleSheetList,
|
|
|
|
nsIDocumentObserver,
|
|
|
|
nsIMutationObserver)
|
|
|
|
NS_INTERFACE_TABLE_TO_MAP_SEGUE
|
2009-06-23 03:09:13 -07:00
|
|
|
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(StyleSheetList)
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMPL_ADDREF(nsDOMStyleSheetList)
|
|
|
|
NS_IMPL_RELEASE(nsDOMStyleSheetList)
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDOMStyleSheetList::GetLength(PRUint32* aLength)
|
|
|
|
{
|
|
|
|
if (mDocument) {
|
|
|
|
// XXX Find the number and then cache it. We'll use the
|
|
|
|
// observer notification to figure out if new ones have
|
|
|
|
// been added or removed.
|
|
|
|
if (-1 == mLength) {
|
|
|
|
mLength = mDocument->GetNumberOfStyleSheets();
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
PRInt32 i;
|
|
|
|
for (i = 0; i < mLength; i++) {
|
|
|
|
nsIStyleSheet *sheet = mDocument->GetStyleSheetAt(i);
|
|
|
|
nsCOMPtr<nsIDOMStyleSheet> domss(do_QueryInterface(sheet));
|
|
|
|
NS_ASSERTION(domss, "All \"normal\" sheets implement nsIDOMStyleSheet");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
*aLength = mLength;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*aLength = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-10-22 07:31:14 -07:00
|
|
|
nsIStyleSheet*
|
|
|
|
nsDOMStyleSheetList::GetItemAt(PRUint32 aIndex)
|
|
|
|
{
|
|
|
|
if (!mDocument || aIndex >= (PRUint32)mDocument->GetNumberOfStyleSheets()) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIStyleSheet *sheet = mDocument->GetStyleSheetAt(aIndex);
|
|
|
|
NS_ASSERTION(sheet, "Must have a sheet");
|
|
|
|
|
|
|
|
return sheet;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDOMStyleSheetList::Item(PRUint32 aIndex, nsIDOMStyleSheet** aReturn)
|
|
|
|
{
|
2008-10-22 07:31:14 -07:00
|
|
|
nsIStyleSheet *sheet = GetItemAt(aIndex);
|
|
|
|
if (!sheet) {
|
|
|
|
*aReturn = nsnull;
|
|
|
|
|
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-10-22 07:31:14 -07:00
|
|
|
return CallQueryInterface(sheet, aReturn);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDOMStyleSheetList::NodeWillBeDestroyed(const nsINode *aNode)
|
|
|
|
{
|
|
|
|
mDocument = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDOMStyleSheetList::StyleSheetAdded(nsIDocument *aDocument,
|
|
|
|
nsIStyleSheet* aStyleSheet,
|
|
|
|
PRBool aDocumentSheet)
|
|
|
|
{
|
|
|
|
if (aDocumentSheet && -1 != mLength) {
|
|
|
|
nsCOMPtr<nsIDOMStyleSheet> domss(do_QueryInterface(aStyleSheet));
|
|
|
|
if (domss) {
|
|
|
|
mLength++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDOMStyleSheetList::StyleSheetRemoved(nsIDocument *aDocument,
|
|
|
|
nsIStyleSheet* aStyleSheet,
|
|
|
|
PRBool aDocumentSheet)
|
|
|
|
{
|
|
|
|
if (aDocumentSheet && -1 != mLength) {
|
|
|
|
nsCOMPtr<nsIDOMStyleSheet> domss(do_QueryInterface(aStyleSheet));
|
|
|
|
if (domss) {
|
|
|
|
mLength--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// nsOnloadBlocker implementation
|
|
|
|
NS_IMPL_ISUPPORTS1(nsOnloadBlocker, nsIRequest)
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsOnloadBlocker::GetName(nsACString &aResult)
|
|
|
|
{
|
|
|
|
aResult.AssignLiteral("about:document-onload-blocker");
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsOnloadBlocker::IsPending(PRBool *_retval)
|
|
|
|
{
|
|
|
|
*_retval = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsOnloadBlocker::GetStatus(nsresult *status)
|
|
|
|
{
|
|
|
|
*status = NS_OK;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsOnloadBlocker::Cancel(nsresult status)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsOnloadBlocker::Suspend(void)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsOnloadBlocker::Resume(void)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsOnloadBlocker::GetLoadGroup(nsILoadGroup * *aLoadGroup)
|
|
|
|
{
|
|
|
|
*aLoadGroup = nsnull;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsOnloadBlocker::SetLoadGroup(nsILoadGroup * aLoadGroup)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsOnloadBlocker::GetLoadFlags(nsLoadFlags *aLoadFlags)
|
|
|
|
{
|
|
|
|
*aLoadFlags = nsIRequest::LOAD_NORMAL;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsOnloadBlocker::SetLoadFlags(nsLoadFlags aLoadFlags)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-10-04 13:00:09 -07:00
|
|
|
// ==================================================================
|
|
|
|
|
|
|
|
nsExternalResourceMap::nsExternalResourceMap()
|
|
|
|
: mHaveShutDown(PR_FALSE)
|
|
|
|
{
|
|
|
|
mMap.Init();
|
|
|
|
mPendingLoads.Init();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIDocument*
|
|
|
|
nsExternalResourceMap::RequestResource(nsIURI* aURI,
|
|
|
|
nsINode* aRequestingNode,
|
|
|
|
nsDocument* aDisplayDocument,
|
|
|
|
ExternalResourceLoad** aPendingLoad)
|
|
|
|
{
|
|
|
|
// If we ever start allowing non-same-origin loads here, we might need to do
|
|
|
|
// something interesting with aRequestingPrincipal even for the hashtable
|
|
|
|
// gets.
|
|
|
|
NS_PRECONDITION(aURI, "Must have a URI");
|
|
|
|
NS_PRECONDITION(aRequestingNode, "Must have a node");
|
|
|
|
*aPendingLoad = nsnull;
|
|
|
|
if (mHaveShutDown) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
// First, make sure we strip the ref from aURI.
|
|
|
|
nsCOMPtr<nsIURI> clone;
|
|
|
|
aURI->Clone(getter_AddRefs(clone));
|
|
|
|
if (!clone) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
nsCOMPtr<nsIURL> url(do_QueryInterface(clone));
|
|
|
|
if (url) {
|
|
|
|
url->SetRef(EmptyCString());
|
|
|
|
}
|
|
|
|
|
|
|
|
ExternalResource* resource;
|
|
|
|
mMap.Get(clone, &resource);
|
|
|
|
if (resource) {
|
|
|
|
return resource->mDocument;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRefPtr<PendingLoad> load;
|
|
|
|
mPendingLoads.Get(clone, getter_AddRefs(load));
|
|
|
|
if (load) {
|
|
|
|
NS_ADDREF(*aPendingLoad = load);
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
load = new PendingLoad(aDisplayDocument);
|
|
|
|
if (!load) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mPendingLoads.Put(clone, load)) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_FAILED(load->StartLoad(clone, aRequestingNode))) {
|
|
|
|
// Make sure we don't thrash things by trying this load again, since
|
|
|
|
// chances are it failed for good reasons (security check, etc).
|
|
|
|
AddExternalResource(clone, nsnull, nsnull, aDisplayDocument);
|
|
|
|
} else {
|
|
|
|
NS_ADDREF(*aPendingLoad = load);
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct
|
|
|
|
nsExternalResourceEnumArgs
|
|
|
|
{
|
|
|
|
nsIDocument::nsSubDocEnumFunc callback;
|
|
|
|
void *data;
|
|
|
|
};
|
|
|
|
|
2008-10-20 23:50:05 -07:00
|
|
|
static PLDHashOperator
|
2008-10-04 13:00:09 -07:00
|
|
|
ExternalResourceEnumerator(nsIURI* aKey,
|
|
|
|
nsExternalResourceMap::ExternalResource* aData,
|
|
|
|
void* aClosure)
|
|
|
|
{
|
|
|
|
nsExternalResourceEnumArgs* args =
|
|
|
|
static_cast<nsExternalResourceEnumArgs*>(aClosure);
|
2008-10-14 07:24:55 -07:00
|
|
|
PRBool next =
|
|
|
|
aData->mDocument ? args->callback(aData->mDocument, args->data) : PR_TRUE;
|
2008-10-04 13:00:09 -07:00
|
|
|
return next ? PL_DHASH_NEXT : PL_DHASH_STOP;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsExternalResourceMap::EnumerateResources(nsIDocument::nsSubDocEnumFunc aCallback,
|
|
|
|
void* aData)
|
|
|
|
{
|
|
|
|
nsExternalResourceEnumArgs args = { aCallback, aData };
|
|
|
|
mMap.EnumerateRead(ExternalResourceEnumerator, &args);
|
|
|
|
}
|
|
|
|
|
2008-10-20 23:50:05 -07:00
|
|
|
static PLDHashOperator
|
2008-10-04 13:00:09 -07:00
|
|
|
ExternalResourceTraverser(nsIURI* aKey,
|
|
|
|
nsExternalResourceMap::ExternalResource* aData,
|
|
|
|
void* aClosure)
|
|
|
|
{
|
|
|
|
nsCycleCollectionTraversalCallback *cb =
|
|
|
|
static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
|
|
|
|
|
|
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
|
|
|
|
"mExternalResourceMap.mMap entry"
|
|
|
|
"->mDocument");
|
|
|
|
cb->NoteXPCOMChild(aData->mDocument);
|
|
|
|
|
|
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
|
|
|
|
"mExternalResourceMap.mMap entry"
|
|
|
|
"->mViewer");
|
|
|
|
cb->NoteXPCOMChild(aData->mViewer);
|
|
|
|
|
|
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
|
|
|
|
"mExternalResourceMap.mMap entry"
|
|
|
|
"->mLoadGroup");
|
|
|
|
cb->NoteXPCOMChild(aData->mLoadGroup);
|
|
|
|
|
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsExternalResourceMap::Traverse(nsCycleCollectionTraversalCallback* aCallback) const
|
|
|
|
{
|
|
|
|
// mPendingLoads will get cleared out as the requests complete, so
|
|
|
|
// no need to worry about those here.
|
|
|
|
mMap.EnumerateRead(ExternalResourceTraverser, aCallback);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsExternalResourceMap::AddExternalResource(nsIURI* aURI,
|
|
|
|
nsIDocumentViewer* aViewer,
|
|
|
|
nsILoadGroup* aLoadGroup,
|
|
|
|
nsIDocument* aDisplayDocument)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aURI, "Unexpected call");
|
|
|
|
NS_PRECONDITION((aViewer && aLoadGroup) || (!aViewer && !aLoadGroup),
|
|
|
|
"Must have both or neither");
|
|
|
|
|
|
|
|
nsRefPtr<PendingLoad> load;
|
|
|
|
mPendingLoads.Get(aURI, getter_AddRefs(load));
|
|
|
|
mPendingLoads.Remove(aURI);
|
|
|
|
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDocument> doc;
|
|
|
|
if (aViewer) {
|
|
|
|
aViewer->GetDocument(getter_AddRefs(doc));
|
|
|
|
NS_ASSERTION(doc, "Must have a document");
|
|
|
|
|
|
|
|
nsCOMPtr<nsIXULDocument> xulDoc = do_QueryInterface(doc);
|
|
|
|
if (xulDoc) {
|
|
|
|
// We don't handle XUL stuff here yet.
|
|
|
|
rv = NS_ERROR_NOT_AVAILABLE;
|
|
|
|
} else {
|
|
|
|
doc->SetDisplayDocument(aDisplayDocument);
|
|
|
|
|
2009-01-14 19:27:09 -08:00
|
|
|
rv = aViewer->Init(nsnull, nsIntRect(0, 0, 0, 0));
|
2008-10-04 13:00:09 -07:00
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
rv = aViewer->Open(nsnull, nsnull);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
doc = nsnull;
|
|
|
|
aViewer = nsnull;
|
|
|
|
aLoadGroup = nsnull;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ExternalResource* newResource = new ExternalResource();
|
|
|
|
if (newResource && !mMap.Put(aURI, newResource)) {
|
|
|
|
delete newResource;
|
|
|
|
newResource = nsnull;
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
rv = NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (newResource) {
|
|
|
|
newResource->mDocument = doc;
|
|
|
|
newResource->mViewer = aViewer;
|
|
|
|
newResource->mLoadGroup = aLoadGroup;
|
|
|
|
}
|
|
|
|
|
|
|
|
const nsTArray< nsCOMPtr<nsIObserver> > & obs = load->Observers();
|
|
|
|
for (PRUint32 i = 0; i < obs.Length(); ++i) {
|
|
|
|
obs[i]->Observe(doc, "external-resource-document-created", nsnull);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS2(nsExternalResourceMap::PendingLoad,
|
|
|
|
nsIStreamListener,
|
|
|
|
nsIRequestObserver)
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsExternalResourceMap::PendingLoad::OnStartRequest(nsIRequest *aRequest,
|
|
|
|
nsISupports *aContext)
|
|
|
|
{
|
|
|
|
nsExternalResourceMap& map = mDisplayDocument->ExternalResourceMap();
|
|
|
|
if (map.HaveShutDown()) {
|
|
|
|
return NS_BINDING_ABORTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDocumentViewer> viewer;
|
|
|
|
nsCOMPtr<nsILoadGroup> loadGroup;
|
|
|
|
nsresult rv = SetupViewer(aRequest, getter_AddRefs(viewer),
|
|
|
|
getter_AddRefs(loadGroup));
|
|
|
|
|
|
|
|
// Make sure to do this no matter what
|
|
|
|
nsresult rv2 = map.AddExternalResource(mURI, viewer, loadGroup,
|
|
|
|
mDisplayDocument);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
if (NS_FAILED(rv2)) {
|
|
|
|
mTargetListener = nsnull;
|
|
|
|
return rv2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return mTargetListener->OnStartRequest(aRequest, aContext);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsExternalResourceMap::PendingLoad::SetupViewer(nsIRequest* aRequest,
|
|
|
|
nsIDocumentViewer** aViewer,
|
|
|
|
nsILoadGroup** aLoadGroup)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(!mTargetListener, "Unexpected call to OnStartRequest");
|
|
|
|
*aViewer = nsnull;
|
|
|
|
*aLoadGroup = nsnull;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
|
|
|
|
NS_ENSURE_TRUE(chan, NS_ERROR_UNEXPECTED);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aRequest));
|
|
|
|
if (httpChannel) {
|
|
|
|
PRBool requestSucceeded;
|
|
|
|
if (NS_FAILED(httpChannel->GetRequestSucceeded(&requestSucceeded)) ||
|
|
|
|
!requestSucceeded) {
|
|
|
|
// Bail out on this load, since it looks like we have an HTTP error page
|
|
|
|
return NS_BINDING_ABORTED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCAutoString type;
|
|
|
|
chan->GetContentType(type);
|
|
|
|
|
|
|
|
nsCOMPtr<nsILoadGroup> loadGroup;
|
|
|
|
chan->GetLoadGroup(getter_AddRefs(loadGroup));
|
|
|
|
|
|
|
|
// Give this document its own loadgroup
|
|
|
|
nsCOMPtr<nsILoadGroup> newLoadGroup =
|
|
|
|
do_CreateInstance(NS_LOADGROUP_CONTRACTID);
|
|
|
|
NS_ENSURE_TRUE(newLoadGroup, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
newLoadGroup->SetLoadGroup(loadGroup);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIInterfaceRequestor> callbacks;
|
|
|
|
loadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
|
|
|
|
|
|
|
|
nsCOMPtr<nsIInterfaceRequestor> newCallbacks =
|
|
|
|
new LoadgroupCallbacks(callbacks);
|
|
|
|
newLoadGroup->SetNotificationCallbacks(newCallbacks);
|
|
|
|
|
|
|
|
// This is some serious hackery cribbed from docshell
|
|
|
|
nsCOMPtr<nsICategoryManager> catMan =
|
|
|
|
do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
|
|
|
|
NS_ENSURE_TRUE(catMan, NS_ERROR_NOT_AVAILABLE);
|
|
|
|
nsXPIDLCString contractId;
|
|
|
|
nsresult rv = catMan->GetCategoryEntry("Gecko-Content-Viewers", type.get(),
|
|
|
|
getter_Copies(contractId));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
nsCOMPtr<nsIDocumentLoaderFactory> docLoaderFactory =
|
|
|
|
do_GetService(contractId);
|
|
|
|
NS_ENSURE_TRUE(docLoaderFactory, NS_ERROR_NOT_AVAILABLE);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContentViewer> viewer;
|
|
|
|
nsCOMPtr<nsIStreamListener> listener;
|
|
|
|
rv = docLoaderFactory->CreateInstance("external-resource", chan, newLoadGroup,
|
|
|
|
type.get(), nsnull, nsnull,
|
|
|
|
getter_AddRefs(listener),
|
|
|
|
getter_AddRefs(viewer));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDocumentViewer> docViewer = do_QueryInterface(viewer);
|
|
|
|
NS_ENSURE_TRUE(docViewer, NS_ERROR_UNEXPECTED);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIParser> parser = do_QueryInterface(listener);
|
|
|
|
if (!parser) {
|
|
|
|
/// We don't want to deal with the various fake documents yet
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We can't handle HTML and other weird things here yet.
|
|
|
|
nsIContentSink* sink = parser->GetContentSink();
|
|
|
|
nsCOMPtr<nsIXMLContentSink> xmlSink = do_QueryInterface(sink);
|
|
|
|
if (!xmlSink) {
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
listener.swap(mTargetListener);
|
|
|
|
docViewer.swap(*aViewer);
|
|
|
|
newLoadGroup.swap(*aLoadGroup);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsExternalResourceMap::PendingLoad::OnDataAvailable(nsIRequest* aRequest,
|
|
|
|
nsISupports* aContext,
|
|
|
|
nsIInputStream* aStream,
|
|
|
|
PRUint32 aOffset,
|
|
|
|
PRUint32 aCount)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(mTargetListener, "Shouldn't be getting called!");
|
|
|
|
if (mDisplayDocument->ExternalResourceMap().HaveShutDown()) {
|
|
|
|
return NS_BINDING_ABORTED;
|
|
|
|
}
|
|
|
|
return mTargetListener->OnDataAvailable(aRequest, aContext, aStream, aOffset,
|
|
|
|
aCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsExternalResourceMap::PendingLoad::OnStopRequest(nsIRequest* aRequest,
|
|
|
|
nsISupports* aContext,
|
|
|
|
nsresult aStatus)
|
|
|
|
{
|
|
|
|
// mTargetListener might be null if SetupViewer or AddExternalResource failed
|
|
|
|
if (mTargetListener) {
|
|
|
|
nsCOMPtr<nsIStreamListener> listener;
|
|
|
|
mTargetListener.swap(listener);
|
|
|
|
return listener->OnStopRequest(aRequest, aContext, aStatus);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsExternalResourceMap::PendingLoad::StartLoad(nsIURI* aURI,
|
|
|
|
nsINode* aRequestingNode)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aURI, "Must have a URI");
|
|
|
|
NS_PRECONDITION(aRequestingNode, "Must have a node");
|
|
|
|
|
|
|
|
// Time to start a load. First, the security checks.
|
|
|
|
|
|
|
|
nsIPrincipal* requestingPrincipal = aRequestingNode->NodePrincipal();
|
|
|
|
|
|
|
|
nsresult rv = nsContentUtils::GetSecurityManager()->
|
|
|
|
CheckLoadURIWithPrincipal(requestingPrincipal, aURI,
|
|
|
|
nsIScriptSecurityManager::STANDARD);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
rv = requestingPrincipal->CheckMayLoad(aURI, PR_TRUE);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
PRInt16 shouldLoad = nsIContentPolicy::ACCEPT;
|
|
|
|
rv = NS_CheckContentLoadPolicy(nsIContentPolicy::TYPE_OTHER,
|
|
|
|
aURI,
|
|
|
|
requestingPrincipal,
|
|
|
|
aRequestingNode,
|
|
|
|
EmptyCString(), //mime guess
|
|
|
|
nsnull, //extra
|
|
|
|
&shouldLoad,
|
|
|
|
nsContentUtils::GetContentPolicy(),
|
|
|
|
nsContentUtils::GetSecurityManager());
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
|
|
|
if (NS_CP_REJECTED(shouldLoad)) {
|
|
|
|
// Disallowed by content policy
|
|
|
|
return NS_ERROR_CONTENT_BLOCKED;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIDocument* doc = aRequestingNode->GetOwnerDoc();
|
|
|
|
if (!doc) {
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
}
|
|
|
|
|
2008-11-25 17:50:04 -08:00
|
|
|
nsCOMPtr<nsIInterfaceRequestor> req = nsContentUtils::GetSameOriginChecker();
|
|
|
|
NS_ENSURE_TRUE(req, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
2008-10-04 13:00:09 -07:00
|
|
|
nsCOMPtr<nsILoadGroup> loadGroup = doc->GetDocumentLoadGroup();
|
|
|
|
nsCOMPtr<nsIChannel> channel;
|
2008-11-25 17:50:04 -08:00
|
|
|
rv = NS_NewChannel(getter_AddRefs(channel), aURI, nsnull, loadGroup, req);
|
2008-10-04 13:00:09 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
mURI = aURI;
|
|
|
|
|
|
|
|
return channel->AsyncOpen(this, nsnull);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS1(nsExternalResourceMap::LoadgroupCallbacks,
|
|
|
|
nsIInterfaceRequestor)
|
|
|
|
|
2008-11-24 10:32:04 -08:00
|
|
|
#define IMPL_SHIM(_i) \
|
|
|
|
NS_IMPL_ISUPPORTS1(nsExternalResourceMap::LoadgroupCallbacks::_i##Shim, _i)
|
|
|
|
|
|
|
|
IMPL_SHIM(nsILoadContext)
|
2008-11-24 10:41:07 -08:00
|
|
|
IMPL_SHIM(nsIProgressEventSink)
|
|
|
|
IMPL_SHIM(nsIChannelEventSink)
|
|
|
|
IMPL_SHIM(nsISecurityEventSink)
|
|
|
|
IMPL_SHIM(nsIApplicationCacheContainer)
|
2008-11-24 10:32:04 -08:00
|
|
|
|
|
|
|
#undef IMPL_SHIM
|
|
|
|
|
|
|
|
#define IID_IS(_i) aIID.Equals(NS_GET_IID(_i))
|
|
|
|
|
|
|
|
#define TRY_SHIM(_i) \
|
|
|
|
PR_BEGIN_MACRO \
|
|
|
|
if (IID_IS(_i)) { \
|
|
|
|
nsCOMPtr<_i> real = do_GetInterface(mCallbacks); \
|
|
|
|
if (!real) { \
|
|
|
|
return NS_NOINTERFACE; \
|
|
|
|
} \
|
|
|
|
nsCOMPtr<_i> shim = new _i##Shim(this, real); \
|
|
|
|
if (!shim) { \
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY; \
|
|
|
|
} \
|
|
|
|
*aSink = shim.forget().get(); \
|
|
|
|
return NS_OK; \
|
|
|
|
} \
|
|
|
|
PR_END_MACRO
|
|
|
|
|
2008-10-04 13:00:09 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsExternalResourceMap::LoadgroupCallbacks::GetInterface(const nsIID & aIID,
|
|
|
|
void **aSink)
|
|
|
|
{
|
|
|
|
if (mCallbacks &&
|
2008-11-24 10:32:04 -08:00
|
|
|
(IID_IS(nsIPrompt) || IID_IS(nsIAuthPrompt) || IID_IS(nsIAuthPrompt2))) {
|
2008-10-04 13:00:09 -07:00
|
|
|
return mCallbacks->GetInterface(aIID, aSink);
|
|
|
|
}
|
|
|
|
|
|
|
|
*aSink = nsnull;
|
2008-11-24 10:32:04 -08:00
|
|
|
|
|
|
|
TRY_SHIM(nsILoadContext);
|
|
|
|
TRY_SHIM(nsIProgressEventSink);
|
|
|
|
TRY_SHIM(nsIChannelEventSink);
|
|
|
|
TRY_SHIM(nsISecurityEventSink);
|
|
|
|
TRY_SHIM(nsIApplicationCacheContainer);
|
|
|
|
|
2008-10-04 13:00:09 -07:00
|
|
|
return NS_NOINTERFACE;
|
|
|
|
}
|
|
|
|
|
2008-11-24 10:32:04 -08:00
|
|
|
#undef TRY_SHIM
|
|
|
|
#undef IID_IS
|
|
|
|
|
2008-10-04 13:00:09 -07:00
|
|
|
nsExternalResourceMap::ExternalResource::~ExternalResource()
|
|
|
|
{
|
|
|
|
if (mViewer) {
|
|
|
|
mViewer->Close(nsnull);
|
|
|
|
mViewer->Destroy();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// ==================================================================
|
|
|
|
// =
|
|
|
|
// ==================================================================
|
|
|
|
|
|
|
|
// If we ever have an nsIDocumentObserver notification for stylesheet title
|
|
|
|
// changes, we could make this inherit from nsDOMStringList instead of
|
|
|
|
// reimplementing nsIDOMDOMStringList.
|
|
|
|
class nsDOMStyleSheetSetList : public nsIDOMDOMStringList
|
|
|
|
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
|
|
|
|
NS_DECL_NSIDOMDOMSTRINGLIST
|
|
|
|
|
|
|
|
nsDOMStyleSheetSetList(nsIDocument* aDocument);
|
|
|
|
|
|
|
|
void Disconnect()
|
|
|
|
{
|
|
|
|
mDocument = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
// Rebuild our list of style sets
|
2009-01-18 12:14:14 -08:00
|
|
|
nsresult GetSets(nsTArray<nsString>& aStyleSets);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsIDocument* mDocument; // Our document; weak ref. It'll let us know if it
|
|
|
|
// dies.
|
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMPL_ADDREF(nsDOMStyleSheetSetList)
|
|
|
|
NS_IMPL_RELEASE(nsDOMStyleSheetSetList)
|
2008-11-03 02:31:47 -08:00
|
|
|
NS_INTERFACE_TABLE_HEAD(nsDOMStyleSheetSetList)
|
|
|
|
NS_OFFSET_AND_INTERFACE_TABLE_BEGIN(nsDOMStyleSheetSetList)
|
|
|
|
NS_INTERFACE_TABLE_ENTRY(nsDOMStyleSheetSetList, nsIDOMDOMStringList)
|
|
|
|
NS_OFFSET_AND_INTERFACE_TABLE_END
|
|
|
|
NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(DOMStringList)
|
|
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
|
|
|
nsDOMStyleSheetSetList::nsDOMStyleSheetSetList(nsIDocument* aDocument)
|
|
|
|
: mDocument(aDocument)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(mDocument, "Must have document!");
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDOMStyleSheetSetList::Item(PRUint32 aIndex, nsAString& aResult)
|
|
|
|
{
|
2009-01-18 12:14:14 -08:00
|
|
|
nsTArray<nsString> styleSets;
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult rv = GetSets(styleSets);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2009-01-18 12:14:14 -08:00
|
|
|
if (aIndex >= styleSets.Length()) {
|
2007-03-22 10:30:00 -07:00
|
|
|
SetDOMStringToNull(aResult);
|
|
|
|
} else {
|
2009-01-18 12:14:14 -08:00
|
|
|
aResult = styleSets[aIndex];
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDOMStyleSheetSetList::GetLength(PRUint32 *aLength)
|
|
|
|
{
|
2009-01-18 12:14:14 -08:00
|
|
|
nsTArray<nsString> styleSets;
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult rv = GetSets(styleSets);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2009-01-18 12:14:14 -08:00
|
|
|
*aLength = styleSets.Length();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDOMStyleSheetSetList::Contains(const nsAString& aString, PRBool *aResult)
|
|
|
|
{
|
2009-01-18 12:14:14 -08:00
|
|
|
nsTArray<nsString> styleSets;
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult rv = GetSets(styleSets);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2009-01-18 12:14:14 -08:00
|
|
|
*aResult = styleSets.Contains(aString);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2009-01-18 12:14:14 -08:00
|
|
|
nsDOMStyleSheetSetList::GetSets(nsTArray<nsString>& aStyleSets)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
if (!mDocument) {
|
|
|
|
return NS_OK; // Spec says "no exceptions", and we have no style sets if we
|
|
|
|
// have no document, for sure
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32 count = mDocument->GetNumberOfStyleSheets();
|
|
|
|
nsAutoString title;
|
|
|
|
nsAutoString temp;
|
|
|
|
for (PRInt32 index = 0; index < count; index++) {
|
|
|
|
nsIStyleSheet* sheet = mDocument->GetStyleSheetAt(index);
|
|
|
|
NS_ASSERTION(sheet, "Null sheet in sheet list!");
|
|
|
|
sheet->GetTitle(title);
|
2009-01-18 12:14:14 -08:00
|
|
|
if (!title.IsEmpty() && !aStyleSets.Contains(title) &&
|
|
|
|
!aStyleSets.AppendElement(title)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ==================================================================
|
|
|
|
// =
|
|
|
|
// ==================================================================
|
|
|
|
|
|
|
|
class nsDOMImplementation : public nsIDOMDOMImplementation,
|
|
|
|
public nsIPrivateDOMImplementation
|
|
|
|
{
|
|
|
|
public:
|
2007-10-01 03:02:32 -07:00
|
|
|
nsDOMImplementation(nsIScriptGlobalObject* aScriptObject,
|
|
|
|
nsIURI* aDocumentURI,
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIURI* aBaseURI,
|
|
|
|
nsIPrincipal* aPrincipal);
|
|
|
|
virtual ~nsDOMImplementation();
|
|
|
|
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
|
|
|
|
// nsIDOMDOMImplementation
|
|
|
|
NS_DECL_NSIDOMDOMIMPLEMENTATION
|
|
|
|
|
|
|
|
// nsIPrivateDOMImplementation
|
|
|
|
NS_IMETHOD Init(nsIURI* aDocumentURI, nsIURI* aBaseURI,
|
|
|
|
nsIPrincipal* aPrincipal);
|
|
|
|
|
|
|
|
protected:
|
2007-10-01 03:02:32 -07:00
|
|
|
nsWeakPtr mScriptObject;
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIURI> mDocumentURI;
|
|
|
|
nsCOMPtr<nsIURI> mBaseURI;
|
|
|
|
nsCOMPtr<nsIPrincipal> mPrincipal;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
NS_NewDOMImplementation(nsIDOMDOMImplementation** aInstancePtrResult)
|
|
|
|
{
|
2007-10-01 03:02:32 -07:00
|
|
|
*aInstancePtrResult = new nsDOMImplementation(nsnull, nsnull, nsnull, nsnull);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!*aInstancePtrResult) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ADDREF(*aInstancePtrResult);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-10-01 03:02:32 -07:00
|
|
|
nsDOMImplementation::nsDOMImplementation(nsIScriptGlobalObject* aScriptObject,
|
|
|
|
nsIURI* aDocumentURI,
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIURI* aBaseURI,
|
|
|
|
nsIPrincipal* aPrincipal)
|
2007-10-01 03:02:32 -07:00
|
|
|
: mScriptObject(do_GetWeakReference(aScriptObject)),
|
|
|
|
mDocumentURI(aDocumentURI),
|
2007-03-22 10:30:00 -07:00
|
|
|
mBaseURI(aBaseURI),
|
|
|
|
mPrincipal(aPrincipal)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
nsDOMImplementation::~nsDOMImplementation()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
// QueryInterface implementation for nsDOMImplementation
|
|
|
|
NS_INTERFACE_MAP_BEGIN(nsDOMImplementation)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIDOMDOMImplementation)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsIPrivateDOMImplementation)
|
|
|
|
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMDOMImplementation)
|
|
|
|
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(DOMImplementation)
|
|
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMPL_ADDREF(nsDOMImplementation)
|
|
|
|
NS_IMPL_RELEASE(nsDOMImplementation)
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDOMImplementation::HasFeature(const nsAString& aFeature,
|
|
|
|
const nsAString& aVersion,
|
|
|
|
PRBool* aReturn)
|
|
|
|
{
|
|
|
|
return nsGenericElement::InternalIsSupported(
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<nsIDOMDOMImplementation*>(this),
|
2007-03-22 10:30:00 -07:00
|
|
|
aFeature, aVersion, aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDOMImplementation::CreateDocumentType(const nsAString& aQualifiedName,
|
|
|
|
const nsAString& aPublicId,
|
|
|
|
const nsAString& aSystemId,
|
|
|
|
nsIDOMDocumentType** aReturn)
|
|
|
|
{
|
|
|
|
*aReturn = nsnull;
|
|
|
|
|
|
|
|
nsresult rv = nsContentUtils::CheckQName(aQualifiedName);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAtom> name = do_GetAtom(aQualifiedName);
|
|
|
|
NS_ENSURE_TRUE(name, NS_ERROR_OUT_OF_MEMORY);
|
2008-06-14 01:24:13 -07:00
|
|
|
|
|
|
|
// Indicate that there is no internal subset (not just an empty one)
|
|
|
|
nsAutoString voidString;
|
|
|
|
voidString.SetIsVoid(PR_TRUE);
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_NewDOMDocumentType(aReturn, nsnull, mPrincipal, name, nsnull,
|
2008-06-14 01:24:13 -07:00
|
|
|
nsnull, aPublicId, aSystemId, voidString);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDOMImplementation::CreateDocument(const nsAString& aNamespaceURI,
|
|
|
|
const nsAString& aQualifiedName,
|
|
|
|
nsIDOMDocumentType* aDoctype,
|
|
|
|
nsIDOMDocument** aReturn)
|
|
|
|
{
|
|
|
|
*aReturn = nsnull;
|
|
|
|
|
|
|
|
nsresult rv;
|
|
|
|
if (!aQualifiedName.IsEmpty()) {
|
|
|
|
nsIParserService *parserService = nsContentUtils::GetParserService();
|
|
|
|
NS_ENSURE_TRUE(parserService, NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
const nsAFlatString& qName = PromiseFlatString(aQualifiedName);
|
|
|
|
const PRUnichar *colon;
|
|
|
|
rv = parserService->CheckQName(qName, PR_TRUE, &colon);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (colon &&
|
|
|
|
(DOMStringIsNull(aNamespaceURI) ||
|
|
|
|
(Substring(qName.get(), colon).EqualsLiteral("xml") &&
|
|
|
|
!aNamespaceURI.EqualsLiteral("http://www.w3.org/XML/1998/namespace")))) {
|
|
|
|
return NS_ERROR_DOM_NAMESPACE_ERR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (DOMStringIsNull(aQualifiedName) &&
|
|
|
|
!DOMStringIsNull(aNamespaceURI)) {
|
|
|
|
return NS_ERROR_DOM_NAMESPACE_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aDoctype) {
|
|
|
|
nsCOMPtr<nsIDOMDocument> owner;
|
|
|
|
aDoctype->GetOwnerDocument(getter_AddRefs(owner));
|
|
|
|
if (owner) {
|
|
|
|
return NS_ERROR_DOM_WRONG_DOCUMENT_ERR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-01 03:02:32 -07:00
|
|
|
nsCOMPtr<nsIScriptGlobalObject> scriptHandlingObject =
|
|
|
|
do_QueryReferent(mScriptObject);
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return nsContentUtils::CreateDocument(aNamespaceURI, aQualifiedName, aDoctype,
|
|
|
|
mDocumentURI, mBaseURI, mPrincipal,
|
2007-10-01 03:02:32 -07:00
|
|
|
scriptHandlingObject, aReturn);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDOMImplementation::Init(nsIURI* aDocumentURI, nsIURI* aBaseURI,
|
|
|
|
nsIPrincipal* aPrincipal)
|
|
|
|
{
|
|
|
|
// Note: can't require that the args be non-null, since at least one
|
|
|
|
// caller (XMLHttpRequest) doesn't have decent args to pass in.
|
|
|
|
mDocumentURI = aDocumentURI;
|
|
|
|
mBaseURI = aBaseURI;
|
|
|
|
mPrincipal = aPrincipal;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ==================================================================
|
|
|
|
// =
|
|
|
|
// ==================================================================
|
|
|
|
|
|
|
|
// NOTE! nsDocument::operator new() zeroes out all members, so don't
|
|
|
|
// bother initializing members to 0.
|
|
|
|
|
|
|
|
nsDocument::nsDocument(const char* aContentType)
|
2009-10-04 21:13:11 -07:00
|
|
|
: nsIDocument()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
mContentType = aContentType;
|
|
|
|
|
|
|
|
#ifdef PR_LOGGING
|
|
|
|
if (!gDocumentLeakPRLog)
|
|
|
|
gDocumentLeakPRLog = PR_NewLogModule("DocumentLeak");
|
|
|
|
|
|
|
|
if (gDocumentLeakPRLog)
|
|
|
|
PR_LOG(gDocumentLeakPRLog, PR_LOG_DEBUG,
|
|
|
|
("DOCUMENT %p created", this));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Start out mLastStyleSheetSet as null, per spec
|
|
|
|
SetDOMStringToNull(mLastStyleSheetSet);
|
|
|
|
}
|
|
|
|
|
2008-10-10 08:04:34 -07:00
|
|
|
static PLDHashOperator
|
2008-02-14 12:45:07 -08:00
|
|
|
ClearAllBoxObjects(const void* aKey, nsPIBoxObject* aBoxObject, void* aUserArg)
|
|
|
|
{
|
|
|
|
if (aBoxObject) {
|
|
|
|
aBoxObject->Clear();
|
|
|
|
}
|
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsDocument::~nsDocument()
|
|
|
|
{
|
|
|
|
#ifdef PR_LOGGING
|
|
|
|
if (gDocumentLeakPRLog)
|
|
|
|
PR_LOG(gDocumentLeakPRLog, PR_LOG_DEBUG,
|
|
|
|
("DOCUMENT %p destroyed", this));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2007-07-08 00:08:04 -07:00
|
|
|
nsCycleCollector_DEBUG_wasFreed(static_cast<nsIDocument*>(this));
|
2007-03-22 10:30:00 -07:00
|
|
|
#endif
|
|
|
|
|
|
|
|
mInDestructor = PR_TRUE;
|
|
|
|
|
|
|
|
// Clear mObservers to keep it in sync with the mutationobserver list
|
|
|
|
mObservers.Clear();
|
|
|
|
|
|
|
|
if (mStyleSheetSetList) {
|
|
|
|
mStyleSheetSetList->Disconnect();
|
|
|
|
}
|
|
|
|
|
|
|
|
mParentDocument = nsnull;
|
|
|
|
|
|
|
|
// Kill the subdocument map, doing this will release its strong
|
|
|
|
// references, if any.
|
|
|
|
if (mSubDocuments) {
|
|
|
|
PL_DHashTableDestroy(mSubDocuments);
|
|
|
|
|
|
|
|
mSubDocuments = nsnull;
|
|
|
|
}
|
|
|
|
|
2007-12-11 18:26:09 -08:00
|
|
|
// Destroy link map now so we don't waste time removing
|
|
|
|
// links one by one
|
|
|
|
DestroyLinkMap();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-04-11 10:29:06 -07:00
|
|
|
nsAutoScriptBlocker scriptBlocker;
|
|
|
|
|
2007-12-11 18:26:09 -08:00
|
|
|
PRInt32 indx; // must be signed
|
|
|
|
PRUint32 count = mChildren.ChildCount();
|
|
|
|
for (indx = PRInt32(count) - 1; indx >= 0; --indx) {
|
|
|
|
mChildren.ChildAt(indx)->UnbindFromTree();
|
|
|
|
mChildren.RemoveChildAt(indx);
|
|
|
|
}
|
|
|
|
mCachedRootContent = nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Let the stylesheets know we're going away
|
|
|
|
indx = mStyleSheets.Count();
|
|
|
|
while (--indx >= 0) {
|
|
|
|
mStyleSheets[indx]->SetOwningDocument(nsnull);
|
|
|
|
}
|
|
|
|
indx = mCatalogSheets.Count();
|
|
|
|
while (--indx >= 0) {
|
|
|
|
mCatalogSheets[indx]->SetOwningDocument(nsnull);
|
|
|
|
}
|
|
|
|
if (mAttrStyleSheet)
|
|
|
|
mAttrStyleSheet->SetOwningDocument(nsnull);
|
|
|
|
if (mStyleAttrStyleSheet)
|
|
|
|
mStyleAttrStyleSheet->SetOwningDocument(nsnull);
|
|
|
|
|
|
|
|
if (mListenerManager) {
|
|
|
|
mListenerManager->Disconnect();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mScriptLoader) {
|
|
|
|
mScriptLoader->DropDocumentReference();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mCSSLoader) {
|
|
|
|
// Could be null here if Init() failed
|
|
|
|
mCSSLoader->DropDocumentReference();
|
|
|
|
NS_RELEASE(mCSSLoader);
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX Ideally we'd do this cleanup in the nsIDocument destructor.
|
|
|
|
if (mNodeInfoManager) {
|
|
|
|
mNodeInfoManager->DropDocumentReference();
|
|
|
|
NS_RELEASE(mNodeInfoManager);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mAttrStyleSheet) {
|
|
|
|
mAttrStyleSheet->SetOwningDocument(nsnull);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mStyleAttrStyleSheet) {
|
|
|
|
mStyleAttrStyleSheet->SetOwningDocument(nsnull);
|
|
|
|
}
|
|
|
|
|
|
|
|
delete mHeaderData;
|
2008-02-14 12:45:07 -08:00
|
|
|
|
|
|
|
if (mBoxObjectTable) {
|
|
|
|
mBoxObjectTable->EnumerateRead(ClearAllBoxObjects, nsnull);
|
|
|
|
delete mBoxObjectTable;
|
|
|
|
}
|
2009-05-06 13:46:01 -07:00
|
|
|
|
|
|
|
mPendingTitleChangeEvent.Revoke();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocument)
|
|
|
|
|
2008-02-21 12:39:20 -08:00
|
|
|
NS_INTERFACE_TABLE_HEAD(nsDocument)
|
2008-11-13 08:54:52 -08:00
|
|
|
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
2008-11-03 02:31:47 -08:00
|
|
|
NS_DOCUMENT_INTERFACE_TABLE_BEGIN(nsDocument)
|
2008-02-21 12:39:20 -08:00
|
|
|
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsINode)
|
|
|
|
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDocument)
|
|
|
|
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOM3DocumentEvent)
|
|
|
|
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMDocumentStyle)
|
|
|
|
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMNSDocumentStyle)
|
|
|
|
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMDocumentRange)
|
|
|
|
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMDocumentXBL)
|
|
|
|
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIScriptObjectPrincipal)
|
|
|
|
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOM3EventTarget)
|
|
|
|
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMNSEventTarget)
|
|
|
|
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsPIDOMEventTarget)
|
|
|
|
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsISupportsWeakReference)
|
|
|
|
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIRadioGroupContainer)
|
|
|
|
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIMutationObserver)
|
2008-07-21 17:55:52 -07:00
|
|
|
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMNodeSelector)
|
2008-08-26 16:09:02 -07:00
|
|
|
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIApplicationCacheContainer)
|
2009-06-14 11:06:22 -07:00
|
|
|
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsIDOMXPathNSResolver)
|
2008-11-03 02:31:47 -08:00
|
|
|
NS_OFFSET_AND_INTERFACE_TABLE_END
|
|
|
|
NS_OFFSET_AND_INTERFACE_TABLE_TO_MAP_SEGUE
|
|
|
|
NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsDocument)
|
2008-02-21 12:39:20 -08:00
|
|
|
if (aIID.Equals(NS_GET_IID(nsIDOMXPathEvaluator)) ||
|
|
|
|
aIID.Equals(NS_GET_IID(nsIXPathEvaluatorInternal))) {
|
|
|
|
if (!mXPathEvaluatorTearoff) {
|
|
|
|
nsresult rv;
|
|
|
|
mXPathEvaluatorTearoff =
|
|
|
|
do_CreateInstance(NS_XPATH_EVALUATOR_CONTRACTID,
|
|
|
|
static_cast<nsIDocument *>(this), &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
return mXPathEvaluatorTearoff->QueryInterface(aIID, aInstancePtr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
NS_INTERFACE_MAP_END
|
|
|
|
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTING_ADDREF_AMBIGUOUS(nsDocument, nsIDocument)
|
|
|
|
NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUOUS_WITH_DESTROY(nsDocument,
|
|
|
|
nsIDocument,
|
2007-05-12 08:36:28 -07:00
|
|
|
nsNodeUtils::LastRelease(this))
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-05-12 13:20:42 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_ROOT_BEGIN(nsDocument)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_ROOT_END
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-10-10 08:04:34 -07:00
|
|
|
static PLDHashOperator
|
2007-03-22 10:30:00 -07:00
|
|
|
SubDocTraverser(PLDHashTable *table, PLDHashEntryHdr *hdr, PRUint32 number,
|
|
|
|
void *arg)
|
|
|
|
{
|
2007-07-08 00:08:04 -07:00
|
|
|
SubDocMapEntry *entry = static_cast<SubDocMapEntry*>(hdr);
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCycleCollectionTraversalCallback *cb =
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<nsCycleCollectionTraversalCallback*>(arg);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-03-17 16:11:08 -07:00
|
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mSubDocuments entry->mKey");
|
2007-03-22 10:30:00 -07:00
|
|
|
cb->NoteXPCOMChild(entry->mKey);
|
2008-03-17 16:11:08 -07:00
|
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mSubDocuments entry->mSubDocument");
|
2007-03-22 10:30:00 -07:00
|
|
|
cb->NoteXPCOMChild(entry->mSubDocument);
|
|
|
|
|
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
|
|
|
|
2008-10-10 08:04:34 -07:00
|
|
|
static PLDHashOperator
|
2008-10-04 13:00:09 -07:00
|
|
|
RadioGroupsTraverser(const nsAString& aKey, nsRadioGroupStruct* aData,
|
|
|
|
void* aClosure)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
nsCycleCollectionTraversalCallback *cb =
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<nsCycleCollectionTraversalCallback*>(aClosure);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-03-17 16:11:08 -07:00
|
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
|
|
|
|
"mRadioGroups entry->mSelectedRadioButton");
|
2007-09-27 11:17:32 -07:00
|
|
|
cb->NoteXPCOMChild(aData->mSelectedRadioButton);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-09-27 11:17:32 -07:00
|
|
|
PRUint32 i, count = aData->mRadioButtons.Count();
|
2007-03-22 10:30:00 -07:00
|
|
|
for (i = 0; i < count; ++i) {
|
2008-03-17 16:11:08 -07:00
|
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb,
|
|
|
|
"mRadioGroups entry->mRadioButtons[i]");
|
2007-09-27 11:17:32 -07:00
|
|
|
cb->NoteXPCOMChild(aData->mRadioButtons[i]);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-09-27 11:17:32 -07:00
|
|
|
return PL_DHASH_NEXT;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-10-10 08:04:34 -07:00
|
|
|
static PLDHashOperator
|
2008-02-14 12:45:07 -08:00
|
|
|
BoxObjectTraverser(const void* key, nsPIBoxObject* boxObject, void* userArg)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
nsCycleCollectionTraversalCallback *cb =
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<nsCycleCollectionTraversalCallback*>(userArg);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-03-17 16:11:08 -07:00
|
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "mBoxObjectTable entry");
|
2007-03-22 10:30:00 -07:00
|
|
|
cb->NoteXPCOMChild(boxObject);
|
|
|
|
|
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
class LinkMapTraversalVisitor : public nsUint32ToContentHashEntry::Visitor
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
nsCycleCollectionTraversalCallback *mCb;
|
|
|
|
virtual void Visit(nsIContent* aContent)
|
|
|
|
{
|
2008-09-08 11:26:46 -07:00
|
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*mCb, "mLinkMap entry");
|
2007-03-22 10:30:00 -07:00
|
|
|
mCb->NoteXPCOMChild(aContent);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2008-10-10 08:04:34 -07:00
|
|
|
static PLDHashOperator
|
2007-03-22 10:30:00 -07:00
|
|
|
LinkMapTraverser(nsUint32ToContentHashEntry* aEntry, void* userArg)
|
|
|
|
{
|
|
|
|
LinkMapTraversalVisitor visitor;
|
2007-07-08 00:08:04 -07:00
|
|
|
visitor.mCb = static_cast<nsCycleCollectionTraversalCallback*>(userArg);
|
2007-03-22 10:30:00 -07:00
|
|
|
aEntry->VisitContent(&visitor);
|
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
|
|
|
|
2008-10-10 08:04:34 -07:00
|
|
|
static PLDHashOperator
|
2008-06-22 16:12:40 -07:00
|
|
|
IdentifierMapEntryTraverse(nsIdentifierMapEntry *aEntry, void *aArg)
|
|
|
|
{
|
|
|
|
nsCycleCollectionTraversalCallback *cb =
|
|
|
|
static_cast<nsCycleCollectionTraversalCallback*>(aArg);
|
|
|
|
aEntry->Traverse(cb);
|
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDocument)
|
2009-05-12 13:20:42 -07:00
|
|
|
// Always need to traverse script objects, so do that before we check
|
|
|
|
// if we're uncollectable.
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
|
|
|
|
2009-07-08 18:10:29 -07:00
|
|
|
if (nsCCUncollectableMarker::InGeneration(cb, tmp->GetMarkedCCGeneration())) {
|
2009-03-03 04:14:13 -08:00
|
|
|
return NS_SUCCESS_INTERRUPTED_TRAVERSE;
|
2007-05-10 13:21:12 -07:00
|
|
|
}
|
|
|
|
|
2008-06-22 16:12:40 -07:00
|
|
|
tmp->mIdentifierMap.EnumerateEntries(IdentifierMapEntryTraverse, &cb);
|
|
|
|
|
2008-10-04 13:00:09 -07:00
|
|
|
tmp->mExternalResourceMap.Traverse(&cb);
|
|
|
|
|
2008-03-28 07:09:00 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mNodeInfo)
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Traverse the mChildren nsAttrAndChildArray.
|
|
|
|
for (PRInt32 indx = PRInt32(tmp->mChildren.ChildCount()); indx > 0; --indx) {
|
2008-03-17 16:11:08 -07:00
|
|
|
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mChildren[i]");
|
2007-03-22 10:30:00 -07:00
|
|
|
cb.NoteXPCOMChild(tmp->mChildren.ChildAt(indx - 1));
|
|
|
|
}
|
|
|
|
|
2007-05-12 08:36:28 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_USERDATA
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Traverse all nsIDocument pointer members.
|
2007-12-11 18:26:09 -08:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mCachedRootContent)
|
2008-03-28 07:09:00 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mNodeInfoManager,
|
|
|
|
nsNodeInfoManager)
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mSecurityInfo)
|
2008-10-04 13:00:09 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDisplayDocument)
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Traverse all nsDocument nsCOMPtrs.
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParser)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptGlobalObject)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mListenerManager)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDOMStyleSheets)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptLoader)
|
|
|
|
|
2008-10-04 13:00:09 -07:00
|
|
|
tmp->mRadioGroups.EnumerateRead(RadioGroupsTraverser, &cb);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// The boxobject for an element will only exist as long as it's in the
|
|
|
|
// document, so we'll traverse the table here instead of from the element.
|
|
|
|
if (tmp->mBoxObjectTable) {
|
|
|
|
tmp->mBoxObjectTable->EnumerateRead(BoxObjectTraverser, &cb);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mChannel)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mStyleAttrStyleSheet)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mScriptEventManager)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mXPathEvaluatorTearoff)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mLayoutHistoryState)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnloadBlocker)
|
2009-09-25 09:50:26 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFirstBaseNodeWithHref)
|
2009-10-18 09:39:52 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDOMImplementation)
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// An element will only be in the linkmap as long as it's in the
|
|
|
|
// document, so we'll traverse the table here instead of from the element.
|
|
|
|
if (tmp->mLinkMap.IsInitialized()) {
|
|
|
|
tmp->mLinkMap.EnumerateEntries(LinkMapTraverser, &cb);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Traverse all our nsCOMArrays.
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mStyleSheets)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mCatalogSheets)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mVisitednessChangedURIs)
|
2009-07-07 22:23:20 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mPreloadingImages)
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-01-14 20:38:07 -08:00
|
|
|
#ifdef MOZ_SMIL
|
|
|
|
// Traverse animation components
|
|
|
|
if (tmp->mAnimationController) {
|
|
|
|
tmp->mAnimationController->Traverse(&cb);
|
|
|
|
}
|
|
|
|
#endif // MOZ_SMIL
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (tmp->mSubDocuments && tmp->mSubDocuments->ops) {
|
|
|
|
PL_DHashTableEnumerate(tmp->mSubDocuments, SubDocTraverser, &cb);
|
|
|
|
}
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
|
|
|
|
|
2009-05-12 13:20:42 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDocument)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
|
|
|
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument)
|
2007-11-30 09:57:03 -08:00
|
|
|
// Tear down linkmap. This is a performance optimization so that we
|
|
|
|
// don't waste time removing links one by one as they are removed
|
|
|
|
// from the doc.
|
|
|
|
tmp->DestroyLinkMap();
|
|
|
|
|
2008-10-04 13:00:09 -07:00
|
|
|
// Clear out our external resources
|
|
|
|
tmp->mExternalResourceMap.Shutdown();
|
|
|
|
|
2008-04-11 10:29:06 -07:00
|
|
|
nsAutoScriptBlocker scriptBlocker;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Unlink the mChildren nsAttrAndChildArray.
|
|
|
|
for (PRInt32 indx = PRInt32(tmp->mChildren.ChildCount()) - 1;
|
|
|
|
indx >= 0; --indx) {
|
|
|
|
tmp->mChildren.ChildAt(indx)->UnbindFromTree();
|
|
|
|
tmp->mChildren.RemoveChildAt(indx);
|
|
|
|
}
|
|
|
|
|
2007-12-11 18:26:09 -08:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mCachedRootContent)
|
2008-10-04 13:00:09 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDisplayDocument)
|
2009-09-25 09:50:26 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mFirstBaseNodeWithHref)
|
2009-10-18 09:39:52 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDOMImplementation)
|
2007-12-11 18:26:09 -08:00
|
|
|
|
2007-05-12 08:36:28 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_USERDATA
|
|
|
|
|
2008-11-06 06:01:22 -08:00
|
|
|
tmp->mParentDocument = nsnull;
|
2008-11-06 03:09:30 -08:00
|
|
|
|
2009-07-07 22:23:20 -07:00
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mPreloadingImages)
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// nsDocument has a pretty complex destructor, so we're going to
|
|
|
|
// assume that *most* cycles you actually want to break somewhere
|
|
|
|
// else, and not unlink an awful lot here.
|
|
|
|
//
|
|
|
|
// In rare cases where you think an unlink will help here, add one
|
|
|
|
// manually.
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDocument::Init()
|
|
|
|
{
|
2008-03-28 07:09:00 -07:00
|
|
|
if (mCSSLoader || mNodeInfoManager || mScriptLoader) {
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_ERROR_ALREADY_INITIALIZED;
|
|
|
|
}
|
|
|
|
|
2008-06-22 16:12:40 -07:00
|
|
|
mIdentifierMap.Init();
|
2007-03-22 10:30:00 -07:00
|
|
|
mLinkMap.Init();
|
2007-09-27 11:17:32 -07:00
|
|
|
mRadioGroups.Init();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Force initialization.
|
|
|
|
nsINode::nsSlots* slots = GetSlots();
|
2007-12-04 10:37:54 -08:00
|
|
|
NS_ENSURE_TRUE(slots,NS_ERROR_OUT_OF_MEMORY);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Prepend self as mutation-observer whether we need it or not (some
|
|
|
|
// subclasses currently do, other don't). This is because the code in
|
|
|
|
// nsNodeUtils always notifies the first observer first, expecting the
|
|
|
|
// first observer to be the document.
|
2007-12-21 05:44:58 -08:00
|
|
|
NS_ENSURE_TRUE(slots->mMutationObservers.PrependElementUnlessExists(static_cast<nsIMutationObserver*>(this)),
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
|
|
|
|
mOnloadBlocker = new nsOnloadBlocker();
|
|
|
|
NS_ENSURE_TRUE(mOnloadBlocker, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
NS_NewCSSLoader(this, &mCSSLoader);
|
|
|
|
NS_ENSURE_TRUE(mCSSLoader, NS_ERROR_OUT_OF_MEMORY);
|
2009-09-28 23:07:45 -07:00
|
|
|
// Assume we're not quirky, until we know otherwise
|
2007-03-22 10:30:00 -07:00
|
|
|
mCSSLoader->SetCompatibilityMode(eCompatibility_FullStandards);
|
|
|
|
|
2008-02-02 15:41:24 -08:00
|
|
|
mNodeInfoManager = new nsNodeInfoManager();
|
|
|
|
NS_ENSURE_TRUE(mNodeInfoManager, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
NS_ADDREF(mNodeInfoManager);
|
|
|
|
|
|
|
|
nsresult rv = mNodeInfoManager->Init(this);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
mNodeInfo = mNodeInfoManager->GetDocumentNodeInfo();
|
|
|
|
NS_ENSURE_TRUE(mNodeInfo, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ASSERTION(GetOwnerDoc() == this, "Our nodeinfo is busted!");
|
|
|
|
|
2007-05-30 13:43:41 -07:00
|
|
|
mScriptLoader = new nsScriptLoader(this);
|
|
|
|
NS_ENSURE_TRUE(mScriptLoader, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDocument::AddXMLEventsContent(nsIContent *aXMLEventsElement)
|
|
|
|
{
|
|
|
|
if (!mXMLEventsManager) {
|
|
|
|
mXMLEventsManager = new nsXMLEventsManager();
|
|
|
|
NS_ENSURE_TRUE(mXMLEventsManager, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
AddObserver(mXMLEventsManager);
|
|
|
|
}
|
|
|
|
mXMLEventsManager->AddXMLEventsContent(aXMLEventsElement);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
nsCOMPtr<nsIPrincipal> principal;
|
|
|
|
if (aChannel) {
|
|
|
|
// Note: this code is duplicated in nsXULDocument::StartDocumentLoad and
|
|
|
|
// nsScriptSecurityManager::GetChannelPrincipal.
|
|
|
|
// Note: this should match nsDocShell::OnLoadingSite
|
2007-10-23 14:56:41 -07:00
|
|
|
NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsIScriptSecurityManager *securityManager =
|
|
|
|
nsContentUtils::GetSecurityManager();
|
|
|
|
if (securityManager) {
|
|
|
|
securityManager->GetChannelPrincipal(aChannel,
|
|
|
|
getter_AddRefs(principal));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ResetToURI(uri, aLoadGroup, principal);
|
|
|
|
|
2008-11-18 14:54:36 -08:00
|
|
|
nsCOMPtr<nsIPropertyBag2> bag = do_QueryInterface(aChannel);
|
|
|
|
if (bag) {
|
|
|
|
nsCOMPtr<nsIURI> baseURI;
|
|
|
|
bag->GetPropertyAsInterface(NS_LITERAL_STRING("baseURI"),
|
|
|
|
NS_GET_IID(nsIURI), getter_AddRefs(baseURI));
|
|
|
|
if (baseURI) {
|
|
|
|
mDocumentBaseURI = baseURI;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
mChannel = aChannel;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::ResetToURI(nsIURI *aURI, nsILoadGroup *aLoadGroup,
|
|
|
|
nsIPrincipal* aPrincipal)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aURI, "Null URI passed to ResetToURI");
|
|
|
|
|
|
|
|
#ifdef PR_LOGGING
|
|
|
|
if (gDocumentLeakPRLog && PR_LOG_TEST(gDocumentLeakPRLog, PR_LOG_DEBUG)) {
|
|
|
|
nsCAutoString spec;
|
|
|
|
aURI->GetSpec(spec);
|
|
|
|
PR_LogPrint("DOCUMENT %p ResetToURI %s", this, spec.get());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2008-06-22 16:12:40 -07:00
|
|
|
mIdentifierMap.Clear();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
SetPrincipal(nsnull);
|
|
|
|
mSecurityInfo = nsnull;
|
|
|
|
|
|
|
|
mDocumentLoadGroup = nsnull;
|
|
|
|
|
|
|
|
// Delete references to sub-documents and kill the subdocument map,
|
|
|
|
// if any. It holds strong references
|
|
|
|
if (mSubDocuments) {
|
|
|
|
PL_DHashTableDestroy(mSubDocuments);
|
|
|
|
|
|
|
|
mSubDocuments = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Destroy link map now so we don't waste time removing
|
|
|
|
// links one by one
|
|
|
|
DestroyLinkMap();
|
|
|
|
|
|
|
|
PRUint32 count = mChildren.ChildCount();
|
2008-02-13 13:44:28 -08:00
|
|
|
{ // Scope for update
|
|
|
|
MOZ_AUTO_DOC_UPDATE(this, UPDATE_CONTENT_MODEL, PR_TRUE);
|
|
|
|
for (PRInt32 i = PRInt32(count) - 1; i >= 0; i--) {
|
|
|
|
nsCOMPtr<nsIContent> content = mChildren.ChildAt(i);
|
|
|
|
|
2009-09-25 09:50:26 -07:00
|
|
|
mChildren.RemoveChildAt(i);
|
2008-02-13 13:44:28 -08:00
|
|
|
nsNodeUtils::ContentRemoved(this, content, i);
|
|
|
|
content->UnbindFromTree();
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-12-11 18:26:09 -08:00
|
|
|
mCachedRootContent = nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Reset our stylesheets
|
|
|
|
ResetStylesheetsToURI(aURI);
|
|
|
|
|
|
|
|
// Release the listener manager
|
|
|
|
if (mListenerManager) {
|
|
|
|
mListenerManager->Disconnect();
|
|
|
|
mListenerManager = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release the stylesheets list.
|
|
|
|
mDOMStyleSheets = nsnull;
|
|
|
|
|
|
|
|
SetDocumentURI(aURI);
|
2009-09-25 09:50:26 -07:00
|
|
|
// If mDocumentBaseURI is null, nsIDocument::GetBaseURI() returns
|
|
|
|
// mDocumentURI.
|
|
|
|
mDocumentBaseURI = nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (aLoadGroup) {
|
|
|
|
mDocumentLoadGroup = do_GetWeakReference(aLoadGroup);
|
|
|
|
// there was an assertion here that aLoadGroup was not null. This
|
2009-05-07 12:21:53 -07:00
|
|
|
// is no longer valid: nsDocShell::SetDocument does not create a
|
|
|
|
// load group, and it works just fine
|
|
|
|
|
|
|
|
// XXXbz what does "just fine" mean exactly? And given that there
|
|
|
|
// is no nsDocShell::SetDocument, what is this talking about?
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
mLastModified.Truncate();
|
|
|
|
// XXXbz I guess we're assuming that the caller will either pass in
|
|
|
|
// a channel with a useful type or call SetContentType?
|
|
|
|
mContentType.Truncate();
|
|
|
|
mContentLanguage.Truncate();
|
|
|
|
mBaseTarget.Truncate();
|
|
|
|
mReferrer.Truncate();
|
|
|
|
|
|
|
|
mXMLDeclarationBits = 0;
|
|
|
|
|
|
|
|
// Now get our new principal
|
|
|
|
if (aPrincipal) {
|
|
|
|
SetPrincipal(aPrincipal);
|
|
|
|
} else {
|
|
|
|
nsIScriptSecurityManager *securityManager =
|
|
|
|
nsContentUtils::GetSecurityManager();
|
|
|
|
if (securityManager) {
|
|
|
|
nsCOMPtr<nsIPrincipal> principal;
|
|
|
|
nsresult rv =
|
|
|
|
securityManager->GetCodebasePrincipal(mDocumentURI,
|
|
|
|
getter_AddRefs(principal));
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
SetPrincipal(principal);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDocument::ResetStylesheetsToURI(nsIURI* aURI)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aURI, "Null URI passed to ResetStylesheetsToURI");
|
|
|
|
|
|
|
|
mozAutoDocUpdate upd(this, UPDATE_STYLE, PR_TRUE);
|
|
|
|
|
|
|
|
// The stylesheets should forget us
|
|
|
|
PRInt32 indx = mStyleSheets.Count();
|
|
|
|
while (--indx >= 0) {
|
|
|
|
nsIStyleSheet* sheet = mStyleSheets[indx];
|
|
|
|
sheet->SetOwningDocument(nsnull);
|
|
|
|
|
|
|
|
PRBool applicable;
|
|
|
|
sheet->GetApplicable(applicable);
|
|
|
|
if (applicable) {
|
|
|
|
RemoveStyleSheetFromStyleSets(sheet);
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX Tell observers?
|
|
|
|
}
|
|
|
|
|
|
|
|
indx = mCatalogSheets.Count();
|
|
|
|
while (--indx >= 0) {
|
|
|
|
nsIStyleSheet* sheet = mCatalogSheets[indx];
|
|
|
|
sheet->SetOwningDocument(nsnull);
|
|
|
|
|
|
|
|
PRBool applicable;
|
|
|
|
sheet->GetApplicable(applicable);
|
|
|
|
if (applicable) {
|
2007-05-22 14:45:03 -07:00
|
|
|
nsPresShellIterator iter(this);
|
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
while ((shell = iter.GetNextShell())) {
|
|
|
|
shell->StyleSet()->RemoveStyleSheet(nsStyleSet::eAgentSheet, sheet);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// XXX Tell observers?
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Release all the sheets
|
|
|
|
mStyleSheets.Clear();
|
|
|
|
// NOTE: We don't release the catalog sheets. It doesn't really matter
|
|
|
|
// now, but it could in the future -- in which case not releasing them
|
|
|
|
// is probably the right thing to do.
|
|
|
|
|
|
|
|
// Now reset our inline style and attribute sheets.
|
|
|
|
nsresult rv;
|
|
|
|
nsStyleSet::sheetType attrSheetType = GetAttrSheetType();
|
|
|
|
if (mAttrStyleSheet) {
|
|
|
|
// Remove this sheet from all style sets
|
2007-05-22 14:45:03 -07:00
|
|
|
nsPresShellIterator iter(this);
|
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
while ((shell = iter.GetNextShell())) {
|
|
|
|
shell->StyleSet()->RemoveStyleSheet(attrSheetType, mAttrStyleSheet);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
rv = mAttrStyleSheet->Reset(aURI);
|
|
|
|
} else {
|
|
|
|
rv = NS_NewHTMLStyleSheet(getter_AddRefs(mAttrStyleSheet), aURI, this);
|
|
|
|
}
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// Don't use AddStyleSheet, since it'll put the sheet into style
|
|
|
|
// sets in the document level, which is not desirable here.
|
|
|
|
mAttrStyleSheet->SetOwningDocument(this);
|
|
|
|
|
|
|
|
if (mStyleAttrStyleSheet) {
|
|
|
|
// Remove this sheet from all style sets
|
2007-05-22 14:45:03 -07:00
|
|
|
nsPresShellIterator iter(this);
|
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
while ((shell = iter.GetNextShell())) {
|
|
|
|
shell->StyleSet()->
|
2007-03-22 10:30:00 -07:00
|
|
|
RemoveStyleSheet(nsStyleSet::eStyleAttrSheet, mStyleAttrStyleSheet);
|
|
|
|
}
|
|
|
|
rv = mStyleAttrStyleSheet->Reset(aURI);
|
|
|
|
} else {
|
|
|
|
rv = NS_NewHTMLCSSStyleSheet(getter_AddRefs(mStyleAttrStyleSheet), aURI,
|
|
|
|
this);
|
|
|
|
}
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// The loop over style sets below will handle putting this sheet
|
|
|
|
// into style sets as needed.
|
|
|
|
mStyleAttrStyleSheet->SetOwningDocument(this);
|
|
|
|
|
|
|
|
// Now set up our style sets
|
2007-05-22 14:45:03 -07:00
|
|
|
nsPresShellIterator iter(this);
|
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
while ((shell = iter.GetNextShell())) {
|
|
|
|
FillStyleSet(shell->StyleSet());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsStyleSet::sheetType
|
|
|
|
nsDocument::GetAttrSheetType()
|
|
|
|
{
|
|
|
|
return nsStyleSet::ePresHintSheet;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::FillStyleSet(nsStyleSet* aStyleSet)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aStyleSet, "Must have a style set");
|
|
|
|
NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::ePresHintSheet) == 0,
|
|
|
|
"Style set already has a preshint sheet?");
|
|
|
|
NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::eHTMLPresHintSheet) == 0,
|
|
|
|
"Style set already has a HTML preshint sheet?");
|
|
|
|
NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::eDocSheet) == 0,
|
|
|
|
"Style set already has document sheets?");
|
|
|
|
NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::eStyleAttrSheet) == 0,
|
|
|
|
"Style set already has style attr sheets?");
|
|
|
|
NS_PRECONDITION(mStyleAttrStyleSheet, "No style attr stylesheet?");
|
|
|
|
NS_PRECONDITION(mAttrStyleSheet, "No attr stylesheet?");
|
|
|
|
|
|
|
|
aStyleSet->AppendStyleSheet(GetAttrSheetType(), mAttrStyleSheet);
|
|
|
|
|
|
|
|
aStyleSet->AppendStyleSheet(nsStyleSet::eStyleAttrSheet,
|
|
|
|
mStyleAttrStyleSheet);
|
|
|
|
|
|
|
|
PRInt32 i;
|
|
|
|
for (i = mStyleSheets.Count() - 1; i >= 0; --i) {
|
|
|
|
nsIStyleSheet* sheet = mStyleSheets[i];
|
|
|
|
PRBool sheetApplicable;
|
|
|
|
sheet->GetApplicable(sheetApplicable);
|
|
|
|
if (sheetApplicable) {
|
|
|
|
aStyleSet->AddDocStyleSheet(sheet, this);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = mCatalogSheets.Count() - 1; i >= 0; --i) {
|
|
|
|
nsIStyleSheet* sheet = mCatalogSheets[i];
|
|
|
|
PRBool sheetApplicable;
|
|
|
|
sheet->GetApplicable(sheetApplicable);
|
|
|
|
if (sheetApplicable) {
|
|
|
|
aStyleSet->AppendStyleSheet(nsStyleSet::eAgentSheet, sheet);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
|
|
|
|
nsILoadGroup* aLoadGroup,
|
|
|
|
nsISupports* aContainer,
|
|
|
|
nsIStreamListener **aDocListener,
|
|
|
|
PRBool aReset, nsIContentSink* aSink)
|
|
|
|
{
|
|
|
|
#ifdef PR_LOGGING
|
|
|
|
if (gDocumentLeakPRLog && PR_LOG_TEST(gDocumentLeakPRLog, PR_LOG_DEBUG)) {
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
aChannel->GetURI(getter_AddRefs(uri));
|
|
|
|
nsCAutoString spec;
|
|
|
|
if (uri)
|
|
|
|
uri->GetSpec(spec);
|
|
|
|
PR_LogPrint("DOCUMENT %p StartDocumentLoad %s", this, spec.get());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-01-09 09:12:09 -08:00
|
|
|
SetReadyStateInternal(READYSTATE_LOADING);
|
|
|
|
|
2007-07-26 19:49:18 -07:00
|
|
|
if (nsCRT::strcmp(kLoadAsData, aCommand) == 0) {
|
|
|
|
mLoadedAsData = PR_TRUE;
|
|
|
|
// We need to disable script & style loading in this case.
|
|
|
|
// We leave them disabled even in EndLoad(), and let anyone
|
|
|
|
// who puts the document on display to worry about enabling.
|
|
|
|
|
|
|
|
// Do not load/process scripts when loading as data
|
|
|
|
ScriptLoader()->SetEnabled(PR_FALSE);
|
|
|
|
|
|
|
|
// styles
|
|
|
|
CSSLoader()->SetEnabled(PR_FALSE); // Do not load/process styles when loading as data
|
2008-10-04 13:00:09 -07:00
|
|
|
} else if (nsCRT::strcmp("external-resource", aCommand) == 0) {
|
|
|
|
// Allow CSS, but not scripts
|
|
|
|
ScriptLoader()->SetEnabled(PR_FALSE);
|
2007-07-26 19:49:18 -07:00
|
|
|
}
|
|
|
|
|
2008-01-20 10:02:02 -08:00
|
|
|
mMayStartLayout = PR_FALSE;
|
|
|
|
|
2008-08-06 13:59:37 -07:00
|
|
|
mHaveInputEncoding = PR_TRUE;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (aReset) {
|
|
|
|
Reset(aChannel, aLoadGroup);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCAutoString contentType;
|
|
|
|
if (NS_SUCCEEDED(aChannel->GetContentType(contentType))) {
|
|
|
|
// XXX this is only necessary for viewsource:
|
|
|
|
nsACString::const_iterator start, end, semicolon;
|
|
|
|
contentType.BeginReading(start);
|
|
|
|
contentType.EndReading(end);
|
|
|
|
semicolon = start;
|
|
|
|
FindCharInReadable(';', semicolon, end);
|
|
|
|
mContentType = Substring(start, semicolon);
|
|
|
|
}
|
|
|
|
|
|
|
|
RetrieveRelevantHeaders(aChannel);
|
|
|
|
|
|
|
|
mChannel = aChannel;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::StopDocumentLoad()
|
|
|
|
{
|
|
|
|
if (mParser) {
|
|
|
|
mParser->Terminate();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::SetDocumentURI(nsIURI* aURI)
|
|
|
|
{
|
2009-09-25 09:50:26 -07:00
|
|
|
nsCOMPtr<nsIURI> oldBase = nsIDocument::GetBaseURI();
|
2007-03-22 10:30:00 -07:00
|
|
|
mDocumentURI = NS_TryToMakeImmutable(aURI);
|
2009-09-25 09:50:26 -07:00
|
|
|
nsIURI* newBase = nsIDocument::GetBaseURI();
|
|
|
|
|
|
|
|
PRBool equalBases = PR_FALSE;
|
|
|
|
if (oldBase && newBase) {
|
|
|
|
oldBase->Equals(newBase, &equalBases);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
equalBases = !oldBase && !newBase;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If changing the document's URI changed the base URI of the document, we
|
|
|
|
// need to refresh the hrefs of all the links on the page.
|
|
|
|
if (!equalBases) {
|
|
|
|
RefreshLinkHrefs();
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetLastModified(nsAString& aLastModified)
|
|
|
|
{
|
|
|
|
if (!mLastModified.IsEmpty()) {
|
|
|
|
aLastModified.Assign(mLastModified);
|
|
|
|
} else {
|
|
|
|
// If we for whatever reason failed to find the last modified time
|
|
|
|
// (or even the current time), fall back to what NS4.x returned.
|
|
|
|
aLastModified.Assign(NS_LITERAL_STRING("01/01/1970 00:00:00"));
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-06-22 16:12:40 -07:00
|
|
|
void
|
|
|
|
nsDocument::UpdateNameTableEntry(nsIContent *aContent)
|
|
|
|
{
|
|
|
|
if (!mIsRegularHTML)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsIAtom* name = nsContentUtils::IsNamedItem(aContent);
|
|
|
|
if (!name)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(name);
|
|
|
|
if (!entry) {
|
|
|
|
// We're not tracking the elements with this name
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry->AddNameContent(aContent);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::RemoveFromNameTable(nsIContent *aContent)
|
|
|
|
{
|
|
|
|
if (!mIsRegularHTML)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsIAtom* name = nsContentUtils::IsNamedItem(aContent);
|
|
|
|
if (!name)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(name);
|
|
|
|
if (!entry) {
|
|
|
|
// We're not tracking the elements with this name
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry->RemoveNameContent(aContent);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::UpdateIdTableEntry(nsIContent *aContent)
|
|
|
|
{
|
|
|
|
nsIAtom* id = aContent->GetID();
|
|
|
|
if (!id)
|
|
|
|
return;
|
|
|
|
|
2009-03-23 07:04:40 -07:00
|
|
|
nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(id);
|
2008-06-22 16:12:40 -07:00
|
|
|
|
2009-03-23 07:04:40 -07:00
|
|
|
if (entry) { /* True except on OOM */
|
2008-06-22 16:12:40 -07:00
|
|
|
entry->AddIdContent(aContent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::RemoveFromIdTable(nsIContent *aContent)
|
|
|
|
{
|
|
|
|
nsIAtom* id = aContent->GetID();
|
|
|
|
if (!id)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(id);
|
2009-03-23 07:04:40 -07:00
|
|
|
if (!entry) /* Should be false unless we had OOM when adding the entry */
|
2008-06-22 16:12:40 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (entry->RemoveIdContent(aContent)) {
|
|
|
|
mIdentifierMap.RemoveEntry(id);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::UnregisterNamedItems(nsIContent *aContent)
|
|
|
|
{
|
2009-03-23 07:04:40 -07:00
|
|
|
if (!aContent->IsNodeOfType(nsINode::eELEMENT)) {
|
|
|
|
// non-element nodes are not named items nor can they have children.
|
2008-06-22 16:12:40 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
RemoveFromNameTable(aContent);
|
|
|
|
RemoveFromIdTable(aContent);
|
|
|
|
|
2009-04-09 18:36:41 -07:00
|
|
|
for (nsINode::ChildIterator iter(aContent); !iter.IsDone(); iter.Next()) {
|
|
|
|
UnregisterNamedItems(iter);
|
2008-06-22 16:12:40 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::RegisterNamedItems(nsIContent *aContent)
|
|
|
|
{
|
2009-03-23 07:04:40 -07:00
|
|
|
if (!aContent->IsNodeOfType(nsINode::eELEMENT)) {
|
|
|
|
// non-element nodes are not named items nor can they have children.
|
2008-06-22 16:12:40 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
UpdateNameTableEntry(aContent);
|
|
|
|
UpdateIdTableEntry(aContent);
|
|
|
|
|
2009-04-09 18:36:41 -07:00
|
|
|
for (nsINode::ChildIterator iter(aContent); !iter.IsDone(); iter.Next()) {
|
|
|
|
RegisterNamedItems(iter);
|
2008-06-22 16:12:40 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::ContentAppended(nsIDocument* aDocument,
|
|
|
|
nsIContent* aContainer,
|
|
|
|
PRInt32 aNewIndexInContainer)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(aDocument == this, "unexpected doc");
|
|
|
|
|
2009-04-09 18:36:41 -07:00
|
|
|
for (nsINode::ChildIterator iter(aContainer, aNewIndexInContainer);
|
|
|
|
!iter.IsDone();
|
|
|
|
iter.Next()) {
|
|
|
|
RegisterNamedItems(iter);
|
2008-06-22 16:12:40 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::ContentInserted(nsIDocument* aDocument,
|
|
|
|
nsIContent* aContainer,
|
|
|
|
nsIContent* aContent,
|
|
|
|
PRInt32 aIndexInContainer)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(aDocument == this, "unexpected doc");
|
|
|
|
|
|
|
|
NS_ABORT_IF_FALSE(aContent, "Null content!");
|
|
|
|
|
|
|
|
RegisterNamedItems(aContent);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::ContentRemoved(nsIDocument* aDocument,
|
|
|
|
nsIContent* aContainer,
|
|
|
|
nsIContent* aChild,
|
|
|
|
PRInt32 aIndexInContainer)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(aDocument == this, "unexpected doc");
|
|
|
|
|
|
|
|
NS_ABORT_IF_FALSE(aChild, "Null content!");
|
|
|
|
|
|
|
|
UnregisterNamedItems(aChild);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-06-29 11:36:25 -07:00
|
|
|
nsDocument::AttributeWillChange(nsIDocument* aDocument,
|
|
|
|
nsIContent* aContent, PRInt32 aNameSpaceID,
|
|
|
|
nsIAtom* aAttribute, PRInt32 aModType)
|
2008-06-22 16:12:40 -07:00
|
|
|
{
|
|
|
|
NS_ABORT_IF_FALSE(aContent, "Null content!");
|
|
|
|
NS_PRECONDITION(aAttribute, "Must have an attribute that's changing!");
|
|
|
|
|
|
|
|
if (aNameSpaceID != kNameSpaceID_None)
|
|
|
|
return;
|
|
|
|
if (aAttribute == nsGkAtoms::name) {
|
|
|
|
RemoveFromNameTable(aContent);
|
|
|
|
} else if (aAttribute == aContent->GetIDAttributeName()) {
|
|
|
|
RemoveFromIdTable(aContent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::AttributeChanged(nsIDocument* aDocument,
|
|
|
|
nsIContent* aContent, PRInt32 aNameSpaceID,
|
|
|
|
nsIAtom* aAttribute, PRInt32 aModType,
|
|
|
|
PRUint32 aStateMask)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(aDocument == this, "unexpected doc");
|
|
|
|
|
|
|
|
NS_ABORT_IF_FALSE(aContent, "Null content!");
|
|
|
|
NS_PRECONDITION(aAttribute, "Must have an attribute that's changing!");
|
|
|
|
|
|
|
|
if (aNameSpaceID != kNameSpaceID_None)
|
|
|
|
return;
|
|
|
|
if (aAttribute == nsGkAtoms::name) {
|
|
|
|
UpdateNameTableEntry(aContent);
|
|
|
|
} else if (aAttribute == aContent->GetIDAttributeName()) {
|
|
|
|
UpdateIdTableEntry(aContent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIPrincipal*
|
|
|
|
nsDocument::GetPrincipal()
|
|
|
|
{
|
|
|
|
return NodePrincipal();
|
|
|
|
}
|
|
|
|
|
2009-05-17 07:22:54 -07:00
|
|
|
extern PRBool sDisablePrefetchHTTPSPref;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
void
|
|
|
|
nsDocument::SetPrincipal(nsIPrincipal *aNewPrincipal)
|
|
|
|
{
|
2009-05-17 07:22:54 -07:00
|
|
|
if (aNewPrincipal && mAllowDNSPrefetch && sDisablePrefetchHTTPSPref) {
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
aNewPrincipal->GetURI(getter_AddRefs(uri));
|
|
|
|
PRBool isHTTPS;
|
|
|
|
if (!uri || NS_FAILED(uri->SchemeIs("https", &isHTTPS)) ||
|
|
|
|
isHTTPS) {
|
|
|
|
mAllowDNSPrefetch = PR_FALSE;
|
|
|
|
}
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
mNodeInfoManager->SetDocumentPrincipal(aNewPrincipal);
|
|
|
|
}
|
|
|
|
|
2008-08-26 16:09:02 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetApplicationCache(nsIApplicationCache **aApplicationCache)
|
|
|
|
{
|
|
|
|
NS_IF_ADDREF(*aApplicationCache = mApplicationCache);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::SetApplicationCache(nsIApplicationCache *aApplicationCache)
|
|
|
|
{
|
|
|
|
mApplicationCache = aApplicationCache;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetContentType(nsAString& aContentType)
|
|
|
|
{
|
|
|
|
CopyUTF8toUTF16(mContentType, aContentType);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::SetContentType(const nsAString& aContentType)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(mContentType.IsEmpty() ||
|
|
|
|
mContentType.Equals(NS_ConvertUTF16toUTF8(aContentType)),
|
|
|
|
"Do you really want to change the content-type?");
|
|
|
|
|
|
|
|
CopyUTF16toUTF8(aContentType, mContentType);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return true if the document is in the focused top-level window, and is an
|
|
|
|
* ancestor of the focused DOMWindow. */
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::HasFocus(PRBool* aResult)
|
|
|
|
{
|
|
|
|
*aResult = PR_FALSE;
|
|
|
|
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
|
|
|
if (!fm)
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Is there a focused DOMWindow?
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
nsCOMPtr<nsIDOMWindow> focusedWindow;
|
|
|
|
fm->GetFocusedWindow(getter_AddRefs(focusedWindow));
|
|
|
|
if (!focusedWindow)
|
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// Are we an ancestor of the focused DOMWindow?
|
|
|
|
nsCOMPtr<nsIDOMDocument> domDocument;
|
|
|
|
focusedWindow->GetDocument(getter_AddRefs(domDocument));
|
|
|
|
nsCOMPtr<nsIDocument> document = do_QueryInterface(domDocument);
|
|
|
|
|
|
|
|
for (nsIDocument* currentDoc = document; currentDoc;
|
|
|
|
currentDoc = currentDoc->GetParentDocument()) {
|
|
|
|
if (currentDoc == this) {
|
|
|
|
// Yes, we are an ancestor
|
|
|
|
*aResult = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetReferrer(nsAString& aReferrer)
|
|
|
|
{
|
|
|
|
CopyUTF8toUTF16(mReferrer, aReferrer);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetActiveElement(nsIDOMElement **aElement)
|
|
|
|
{
|
|
|
|
*aElement = nsnull;
|
|
|
|
|
|
|
|
// Get the focused element.
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
nsCOMPtr<nsPIDOMWindow> window = GetWindow();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!window) {
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
|
|
|
}
|
|
|
|
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
|
|
|
if (!fm)
|
|
|
|
return NS_ERROR_NOT_AVAILABLE;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
nsCOMPtr<nsPIDOMWindow> focusedWindow;
|
|
|
|
nsIContent* focusedContent =
|
|
|
|
nsFocusManager::GetFocusedDescendant(window, PR_FALSE, getter_AddRefs(focusedWindow));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
// an element in this document is focused, so return it
|
|
|
|
if (focusedContent) {
|
|
|
|
// be safe and make sure the element is from this document
|
|
|
|
if (focusedContent->GetOwnerDoc() != this) {
|
|
|
|
NS_WARNING("Focused element found from another document");
|
|
|
|
return NS_ERROR_FAILURE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
CallQueryInterface(focusedContent, aElement);
|
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// No focused element anywhere in this document. Try to get the BODY.
|
|
|
|
nsCOMPtr<nsIDOMHTMLDocument> htmlDoc =
|
2007-07-08 00:08:04 -07:00
|
|
|
do_QueryInterface(static_cast<nsIDocument*>(this));
|
2007-03-22 10:30:00 -07:00
|
|
|
if (htmlDoc) {
|
|
|
|
nsCOMPtr<nsIDOMHTMLElement> bodyElement;
|
|
|
|
htmlDoc->GetBody(getter_AddRefs(bodyElement));
|
|
|
|
if (bodyElement) {
|
|
|
|
*aElement = bodyElement;
|
|
|
|
NS_ADDREF(*aElement);
|
|
|
|
}
|
2007-11-12 04:45:39 -08:00
|
|
|
// Because of IE compatibility, return null when html document doesn't have
|
|
|
|
// a body.
|
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// If we couldn't get a BODY, return the root element.
|
|
|
|
return GetDocumentElement(aElement);
|
|
|
|
}
|
|
|
|
|
2007-08-29 13:38:44 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::ElementFromPoint(PRInt32 aX, PRInt32 aY, nsIDOMElement** aReturn)
|
2008-11-04 19:58:22 -08:00
|
|
|
{
|
|
|
|
return ElementFromPointHelper(aX, aY, PR_FALSE, PR_TRUE, aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDocument::ElementFromPointHelper(PRInt32 aX, PRInt32 aY,
|
|
|
|
PRBool aIgnoreRootScrollFrame,
|
|
|
|
PRBool aFlushLayout,
|
|
|
|
nsIDOMElement** aReturn)
|
2007-08-29 13:38:44 -07:00
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aReturn);
|
|
|
|
*aReturn = nsnull;
|
|
|
|
// As per the the spec, we return null if either coord is negative
|
2009-08-07 21:10:05 -07:00
|
|
|
if (!aIgnoreRootScrollFrame && (aX < 0 || aY < 0))
|
2007-08-29 13:38:44 -07:00
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
nscoord x = nsPresContext::CSSPixelsToAppUnits(aX);
|
|
|
|
nscoord y = nsPresContext::CSSPixelsToAppUnits(aY);
|
|
|
|
nsPoint pt(x, y);
|
|
|
|
|
|
|
|
// Make sure the layout information we get is up-to-date, and
|
|
|
|
// ensure we get a root frame (for everything but XUL)
|
2008-11-04 19:58:22 -08:00
|
|
|
if (aFlushLayout)
|
|
|
|
FlushPendingNotifications(Flush_Layout);
|
2007-08-29 13:38:44 -07:00
|
|
|
|
|
|
|
nsIPresShell *ps = GetPrimaryShell();
|
|
|
|
NS_ENSURE_STATE(ps);
|
|
|
|
nsIFrame *rootFrame = ps->GetRootFrame();
|
|
|
|
|
|
|
|
// XUL docs, unlike HTML, have no frame tree until everything's done loading
|
|
|
|
if (!rootFrame)
|
|
|
|
return NS_OK; // return null to premature XUL callers as a reminder to wait
|
|
|
|
|
2008-11-04 19:58:22 -08:00
|
|
|
nsIFrame *ptFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, pt, PR_TRUE,
|
|
|
|
aIgnoreRootScrollFrame);
|
2007-08-29 13:38:44 -07:00
|
|
|
if (!ptFrame)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
nsIContent* ptContent = ptFrame->GetContent();
|
|
|
|
NS_ENSURE_STATE(ptContent);
|
|
|
|
|
|
|
|
// If the content is in a subdocument, try to get the element from |this| doc
|
|
|
|
nsIDocument *currentDoc = ptContent->GetCurrentDoc();
|
|
|
|
if (currentDoc && (currentDoc != this)) {
|
|
|
|
*aReturn = CheckAncestryAndGetFrame(currentDoc).get();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we have an anonymous element (such as an internal div from a textbox),
|
|
|
|
// or a node that isn't an element (such as a text frame node),
|
|
|
|
// replace it with the first non-anonymous parent node of type element.
|
|
|
|
while (ptContent &&
|
2009-03-10 19:23:10 -07:00
|
|
|
(!ptContent->IsNodeOfType(nsINode::eELEMENT) ||
|
|
|
|
ptContent->IsInAnonymousSubtree())) {
|
2008-07-22 21:50:20 -07:00
|
|
|
// XXXldb: Faster to jump to GetBindingParent if non-null?
|
2007-08-29 13:38:44 -07:00
|
|
|
ptContent = ptContent->GetParent();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ptContent)
|
|
|
|
CallQueryInterface(ptContent, aReturn);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetElementsByClassName(const nsAString& aClasses,
|
|
|
|
nsIDOMNodeList** aReturn)
|
|
|
|
{
|
2007-09-20 15:10:27 -07:00
|
|
|
return GetElementsByClassNameHelper(this, aClasses, aReturn);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-01-13 11:32:30 -08:00
|
|
|
struct ClassMatchingInfo {
|
|
|
|
nsCOMArray<nsIAtom> mClasses;
|
|
|
|
nsCaseTreatment mCaseTreatment;
|
|
|
|
};
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// static GetElementsByClassName helpers
|
|
|
|
nsresult
|
2007-09-20 15:10:27 -07:00
|
|
|
nsDocument::GetElementsByClassNameHelper(nsINode* aRootNode,
|
2007-03-22 10:30:00 -07:00
|
|
|
const nsAString& aClasses,
|
|
|
|
nsIDOMNodeList** aReturn)
|
|
|
|
{
|
2007-09-20 15:10:27 -07:00
|
|
|
NS_PRECONDITION(aRootNode, "Must have root node");
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsAttrValue attrValue;
|
|
|
|
attrValue.ParseAtomArray(aClasses);
|
|
|
|
// nsAttrValue::Equals is sensitive to order, so we'll send an array
|
2009-01-13 11:32:30 -08:00
|
|
|
ClassMatchingInfo* info = new ClassMatchingInfo;
|
|
|
|
NS_ENSURE_TRUE(info, NS_ERROR_OUT_OF_MEMORY);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (attrValue.Type() == nsAttrValue::eAtomArray) {
|
2009-01-13 11:32:30 -08:00
|
|
|
info->mClasses.AppendObjects(*(attrValue.GetAtomArrayValue()));
|
2008-09-26 03:39:18 -07:00
|
|
|
} else if (attrValue.Type() == nsAttrValue::eAtom) {
|
2009-01-13 11:32:30 -08:00
|
|
|
info->mClasses.AppendObject(attrValue.GetAtomValue());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2009-01-13 11:32:30 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsBaseContentList* elements;
|
2009-01-13 11:32:30 -08:00
|
|
|
if (info->mClasses.Count() > 0) {
|
|
|
|
info->mCaseTreatment =
|
|
|
|
aRootNode->GetOwnerDoc()->GetCompatibilityMode() ==
|
|
|
|
eCompatibility_NavQuirks ?
|
|
|
|
eIgnoreCase : eCaseMatters;
|
|
|
|
|
2007-09-20 15:10:27 -07:00
|
|
|
elements = new nsContentList(aRootNode, MatchClassNames,
|
2009-01-13 11:32:30 -08:00
|
|
|
DestroyClassNameArray, info);
|
2007-03-22 10:30:00 -07:00
|
|
|
} else {
|
2009-01-13 11:32:30 -08:00
|
|
|
delete info;
|
|
|
|
info = nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
elements = new nsBaseContentList();
|
|
|
|
}
|
|
|
|
if (!elements) {
|
2009-01-13 11:32:30 -08:00
|
|
|
delete info;
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
*aReturn = elements;
|
|
|
|
NS_ADDREF(*aReturn);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
PRBool
|
|
|
|
nsDocument::MatchClassNames(nsIContent* aContent,
|
|
|
|
PRInt32 aNamespaceID,
|
|
|
|
nsIAtom* aAtom, void* aData)
|
|
|
|
{
|
|
|
|
// We can't match if there are no class names
|
|
|
|
const nsAttrValue* classAttr = aContent->GetClasses();
|
|
|
|
if (!classAttr) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// need to match *all* of the classes
|
2009-01-13 11:32:30 -08:00
|
|
|
ClassMatchingInfo* info = static_cast<ClassMatchingInfo*>(aData);
|
|
|
|
PRInt32 length = info->mClasses.Count();
|
2007-03-22 10:30:00 -07:00
|
|
|
PRInt32 i;
|
|
|
|
for (i = 0; i < length; ++i) {
|
2009-01-13 11:32:30 -08:00
|
|
|
if (!classAttr->Contains(info->mClasses.ObjectAt(i),
|
|
|
|
info->mCaseTreatment)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
|
|
|
void
|
|
|
|
nsDocument::DestroyClassNameArray(void* aData)
|
|
|
|
{
|
2009-01-13 11:32:30 -08:00
|
|
|
ClassMatchingInfo* info = static_cast<ClassMatchingInfo*>(aData);
|
|
|
|
delete info;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-09-13 06:13:16 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::ReleaseCapture()
|
|
|
|
{
|
|
|
|
// only release the capture if the caller can access it. This prevents a
|
|
|
|
// page from stopping a scrollbar grab for example.
|
|
|
|
nsCOMPtr<nsIDOMNode> node = do_QueryInterface(nsIPresShell::GetCapturingContent());
|
|
|
|
if (node && nsContentUtils::CanCallerAccess(node)) {
|
|
|
|
nsIPresShell::SetCapturingContent(nsnull, 0);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult
|
|
|
|
nsDocument::SetBaseURI(nsIURI* aURI)
|
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
|
|
|
|
2009-09-25 09:50:26 -07:00
|
|
|
nsCOMPtr<nsIURI> oldBase = nsIDocument::GetBaseURI();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (aURI) {
|
|
|
|
rv = nsContentUtils::GetSecurityManager()->
|
|
|
|
CheckLoadURIWithPrincipal(NodePrincipal(), aURI,
|
|
|
|
nsIScriptSecurityManager::STANDARD);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
mDocumentBaseURI = NS_TryToMakeImmutable(aURI);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
mDocumentBaseURI = nsnull;
|
|
|
|
}
|
|
|
|
|
2009-09-25 09:50:26 -07:00
|
|
|
nsIURI* newBase = nsIDocument::GetBaseURI();
|
|
|
|
PRBool equalBases = PR_FALSE;
|
|
|
|
if (oldBase && newBase) {
|
|
|
|
oldBase->Equals(newBase, &equalBases);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
equalBases = !oldBase && !newBase;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the document's base URI has changed, we need to re-resolve all the
|
|
|
|
// cached link hrefs relative to the new base.
|
|
|
|
if (!equalBases) {
|
|
|
|
RefreshLinkHrefs();
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::GetBaseTarget(nsAString &aBaseTarget) const
|
|
|
|
{
|
|
|
|
aBaseTarget.Assign(mBaseTarget);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::SetBaseTarget(const nsAString &aBaseTarget)
|
|
|
|
{
|
|
|
|
mBaseTarget.Assign(aBaseTarget);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::SetDocumentCharacterSet(const nsACString& aCharSetID)
|
|
|
|
{
|
|
|
|
if (!mCharacterSet.Equals(aCharSetID)) {
|
|
|
|
mCharacterSet = aCharSetID;
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
nsCOMPtr<nsICharsetAlias> calias(do_GetService(NS_CHARSETALIAS_CONTRACTID));
|
|
|
|
if (calias) {
|
|
|
|
nsCAutoString canonicalName;
|
|
|
|
calias->GetPreferred(aCharSetID, canonicalName);
|
|
|
|
NS_ASSERTION(canonicalName.Equals(aCharSetID),
|
|
|
|
"charset name must be canonical");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-03-20 01:15:35 -07:00
|
|
|
PRInt32 n = mCharSetObservers.Length();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
for (PRInt32 i = 0; i < n; i++) {
|
2009-03-20 01:15:35 -07:00
|
|
|
nsIObserver* observer = mCharSetObservers.ElementAt(i);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-08 00:08:04 -07:00
|
|
|
observer->Observe(static_cast<nsIDocument *>(this), "charset",
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ConvertASCIItoUTF16(aCharSetID).get());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDocument::AddCharSetObserver(nsIObserver* aObserver)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aObserver);
|
|
|
|
|
|
|
|
NS_ENSURE_TRUE(mCharSetObservers.AppendElement(aObserver), NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::RemoveCharSetObserver(nsIObserver* aObserver)
|
|
|
|
{
|
|
|
|
mCharSetObservers.RemoveElement(aObserver);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::GetHeaderData(nsIAtom* aHeaderField, nsAString& aData) const
|
|
|
|
{
|
|
|
|
aData.Truncate();
|
|
|
|
const nsDocHeaderData* data = mHeaderData;
|
|
|
|
while (data) {
|
|
|
|
if (data->mField == aHeaderField) {
|
|
|
|
aData = data->mData;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
data = data->mNext;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::SetHeaderData(nsIAtom* aHeaderField, const nsAString& aData)
|
|
|
|
{
|
|
|
|
if (!aHeaderField) {
|
|
|
|
NS_ERROR("null headerField");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mHeaderData) {
|
|
|
|
if (!aData.IsEmpty()) { // don't bother storing empty string
|
|
|
|
mHeaderData = new nsDocHeaderData(aHeaderField, aData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
nsDocHeaderData* data = mHeaderData;
|
|
|
|
nsDocHeaderData** lastPtr = &mHeaderData;
|
|
|
|
PRBool found = PR_FALSE;
|
|
|
|
do { // look for existing and replace
|
|
|
|
if (data->mField == aHeaderField) {
|
|
|
|
if (!aData.IsEmpty()) {
|
|
|
|
data->mData.Assign(aData);
|
|
|
|
}
|
|
|
|
else { // don't store empty string
|
|
|
|
*lastPtr = data->mNext;
|
|
|
|
data->mNext = nsnull;
|
|
|
|
delete data;
|
|
|
|
}
|
|
|
|
found = PR_TRUE;
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
lastPtr = &(data->mNext);
|
|
|
|
data = *lastPtr;
|
|
|
|
} while (data);
|
|
|
|
|
|
|
|
if (!aData.IsEmpty() && !found) {
|
|
|
|
// didn't find, append
|
|
|
|
*lastPtr = new nsDocHeaderData(aHeaderField, aData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aHeaderField == nsGkAtoms::headerContentLanguage) {
|
|
|
|
CopyUTF16toUTF8(aData, mContentLanguage);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the default script-type on the root element.
|
|
|
|
if (aHeaderField == nsGkAtoms::headerContentScriptType) {
|
|
|
|
nsIContent *root = GetRootContent();
|
|
|
|
if (root) {
|
|
|
|
// Get the script-type ID for this value.
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIScriptRuntime> runtime;
|
|
|
|
rv = NS_GetScriptRuntime(aData, getter_AddRefs(runtime));
|
|
|
|
if (NS_FAILED(rv) || runtime == nsnull) {
|
|
|
|
NS_WARNING("The script-type is unknown");
|
|
|
|
} else {
|
|
|
|
root->SetScriptTypeID(runtime->GetScriptTypeID());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aHeaderField == nsGkAtoms::headerDefaultStyle) {
|
|
|
|
// Only mess with our stylesheets if we don't have a lastStyleSheetSet, per
|
|
|
|
// spec.
|
|
|
|
if (DOMStringIsNull(mLastStyleSheetSet)) {
|
|
|
|
// Calling EnableStyleSheetsForSetInternal, not SetSelectedStyleSheetSet,
|
|
|
|
// per spec. The idea here is that we're changing our preferred set and
|
|
|
|
// that shouldn't change the value of lastStyleSheetSet. Also, we're
|
|
|
|
// using the Internal version so we can update the CSSLoader and not have
|
|
|
|
// to worry about null strings.
|
|
|
|
EnableStyleSheetsForSetInternal(aData, PR_TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aHeaderField == nsGkAtoms::refresh) {
|
|
|
|
// We get into this code before we have a script global yet, so get to
|
|
|
|
// our container via mDocumentContainer.
|
|
|
|
nsCOMPtr<nsIRefreshURI> refresher = do_QueryReferent(mDocumentContainer);
|
|
|
|
if (refresher) {
|
|
|
|
// Note: using mDocumentURI instead of mBaseURI here, for consistency
|
|
|
|
// (used to just use the current URI of our webnavigation, but that
|
|
|
|
// should really be the same thing). Note that this code can run
|
|
|
|
// before the current URI of the webnavigation has been updated, so we
|
|
|
|
// can't assert equality here.
|
|
|
|
refresher->SetupRefreshURIFromHeader(mDocumentURI,
|
2007-09-28 07:35:11 -07:00
|
|
|
NS_ConvertUTF16toUTF8(aData));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
2009-05-17 07:22:54 -07:00
|
|
|
|
|
|
|
if (aHeaderField == nsGkAtoms::headerDNSPrefetchControl &&
|
|
|
|
mAllowDNSPrefetch) {
|
|
|
|
// Chromium treats any value other than 'on' (case insensitive) as 'off'.
|
|
|
|
mAllowDNSPrefetch = aData.IsEmpty() || aData.LowerCaseEqualsLiteral("on");
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsDocument::TryChannelCharset(nsIChannel *aChannel,
|
|
|
|
PRInt32& aCharsetSource,
|
|
|
|
nsACString& aCharset)
|
|
|
|
{
|
|
|
|
if(kCharsetFromChannel <= aCharsetSource) {
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aChannel) {
|
|
|
|
nsCAutoString charsetVal;
|
|
|
|
nsresult rv = aChannel->GetContentCharset(charsetVal);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
nsCOMPtr<nsICharsetAlias> calias(do_GetService(NS_CHARSETALIAS_CONTRACTID));
|
|
|
|
if (calias) {
|
|
|
|
nsCAutoString preferred;
|
|
|
|
rv = calias->GetPreferred(charsetVal,
|
|
|
|
preferred);
|
|
|
|
if(NS_SUCCEEDED(rv)) {
|
|
|
|
aCharset = preferred;
|
|
|
|
aCharsetSource = kCharsetFromChannel;
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDocument::CreateShell(nsPresContext* aContext, nsIViewManager* aViewManager,
|
|
|
|
nsStyleSet* aStyleSet,
|
|
|
|
nsIPresShell** aInstancePtrResult)
|
|
|
|
{
|
|
|
|
// Don't add anything here. Add it to |doCreateShell| instead.
|
|
|
|
// This exists so that subclasses can pass other values for the 4th
|
|
|
|
// parameter some of the time.
|
|
|
|
return doCreateShell(aContext, aViewManager, aStyleSet,
|
|
|
|
eCompatibility_FullStandards, aInstancePtrResult);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDocument::doCreateShell(nsPresContext* aContext,
|
|
|
|
nsIViewManager* aViewManager, nsStyleSet* aStyleSet,
|
|
|
|
nsCompatibility aCompatMode,
|
|
|
|
nsIPresShell** aInstancePtrResult)
|
|
|
|
{
|
|
|
|
*aInstancePtrResult = nsnull;
|
|
|
|
|
|
|
|
NS_ENSURE_FALSE(mShellsAreHidden, NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
FillStyleSet(aStyleSet);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
nsresult rv = NS_NewPresShell(getter_AddRefs(shell));
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = shell->Init(this, aContext, aViewManager, aStyleSet, aCompatMode);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// Note: we don't hold a ref to the shell (it holds a ref to us)
|
2007-12-19 23:30:04 -08:00
|
|
|
NS_ENSURE_TRUE(mPresShells.AppendElementUnlessExists(shell),
|
2007-12-13 17:41:48 -08:00
|
|
|
NS_ERROR_OUT_OF_MEMORY);
|
2007-03-22 10:30:00 -07:00
|
|
|
shell.swap(*aInstancePtrResult);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsDocument::DeleteShell(nsIPresShell* aShell)
|
|
|
|
{
|
2007-12-19 23:30:04 -08:00
|
|
|
return mPresShells.RemoveElement(aShell);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-05-01 15:24:20 -07:00
|
|
|
nsIPresShell *
|
|
|
|
nsDocument::GetPrimaryShell() const
|
|
|
|
{
|
2007-12-19 23:30:04 -08:00
|
|
|
return mShellsAreHidden ? nsnull : mPresShells.SafeElementAt(0, nsnull);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-10-10 08:04:34 -07:00
|
|
|
static void
|
2007-03-22 10:30:00 -07:00
|
|
|
SubDocClearEntry(PLDHashTable *table, PLDHashEntryHdr *entry)
|
|
|
|
{
|
2007-07-08 00:08:04 -07:00
|
|
|
SubDocMapEntry *e = static_cast<SubDocMapEntry *>(entry);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
NS_RELEASE(e->mKey);
|
2007-11-30 09:57:03 -08:00
|
|
|
if (e->mSubDocument) {
|
|
|
|
e->mSubDocument->SetParentDocument(nsnull);
|
|
|
|
NS_RELEASE(e->mSubDocument);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-10-10 08:04:34 -07:00
|
|
|
static PRBool
|
2007-03-22 10:30:00 -07:00
|
|
|
SubDocInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry, const void *key)
|
|
|
|
{
|
|
|
|
SubDocMapEntry *e =
|
2007-07-08 00:08:04 -07:00
|
|
|
const_cast<SubDocMapEntry *>
|
|
|
|
(static_cast<const SubDocMapEntry *>(entry));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-08 00:08:04 -07:00
|
|
|
e->mKey = const_cast<nsIContent *>
|
|
|
|
(static_cast<const nsIContent *>(key));
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ADDREF(e->mKey);
|
|
|
|
|
|
|
|
e->mSubDocument = nsnull;
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDocument::SetSubDocumentFor(nsIContent *aContent, nsIDocument* aSubDoc)
|
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(aContent, NS_ERROR_UNEXPECTED);
|
|
|
|
|
|
|
|
if (!aSubDoc) {
|
|
|
|
// aSubDoc is nsnull, remove the mapping
|
|
|
|
|
|
|
|
if (mSubDocuments) {
|
|
|
|
SubDocMapEntry *entry =
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<SubDocMapEntry*>
|
|
|
|
(PL_DHashTableOperate(mSubDocuments, aContent,
|
2007-03-22 10:30:00 -07:00
|
|
|
PL_DHASH_LOOKUP));
|
|
|
|
|
|
|
|
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
|
|
|
|
PL_DHashTableRawRemove(mSubDocuments, entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (!mSubDocuments) {
|
|
|
|
// Create a new hashtable
|
|
|
|
|
|
|
|
static PLDHashTableOps hash_table_ops =
|
|
|
|
{
|
|
|
|
PL_DHashAllocTable,
|
|
|
|
PL_DHashFreeTable,
|
|
|
|
PL_DHashVoidPtrKeyStub,
|
|
|
|
PL_DHashMatchEntryStub,
|
|
|
|
PL_DHashMoveEntryStub,
|
|
|
|
SubDocClearEntry,
|
|
|
|
PL_DHashFinalizeStub,
|
|
|
|
SubDocInitEntry
|
|
|
|
};
|
|
|
|
|
|
|
|
mSubDocuments = PL_NewDHashTable(&hash_table_ops, nsnull,
|
|
|
|
sizeof(SubDocMapEntry), 16);
|
|
|
|
if (!mSubDocuments) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add a mapping to the hash table
|
|
|
|
SubDocMapEntry *entry =
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<SubDocMapEntry*>
|
|
|
|
(PL_DHashTableOperate(mSubDocuments, aContent,
|
2007-03-22 10:30:00 -07:00
|
|
|
PL_DHASH_ADD));
|
|
|
|
|
|
|
|
if (!entry) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entry->mSubDocument) {
|
|
|
|
entry->mSubDocument->SetParentDocument(nsnull);
|
|
|
|
|
|
|
|
// Release the old sub document
|
|
|
|
NS_RELEASE(entry->mSubDocument);
|
|
|
|
}
|
|
|
|
|
|
|
|
entry->mSubDocument = aSubDoc;
|
|
|
|
NS_ADDREF(entry->mSubDocument);
|
|
|
|
|
|
|
|
aSubDoc->SetParentDocument(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIDocument*
|
|
|
|
nsDocument::GetSubDocumentFor(nsIContent *aContent) const
|
|
|
|
{
|
|
|
|
if (mSubDocuments) {
|
|
|
|
SubDocMapEntry *entry =
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<SubDocMapEntry*>
|
|
|
|
(PL_DHashTableOperate(mSubDocuments, aContent,
|
2007-03-22 10:30:00 -07:00
|
|
|
PL_DHASH_LOOKUP));
|
|
|
|
|
|
|
|
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
|
|
|
|
return entry->mSubDocument;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
2008-10-10 08:04:34 -07:00
|
|
|
static PLDHashOperator
|
2007-03-22 10:30:00 -07:00
|
|
|
FindContentEnumerator(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
|
|
|
PRUint32 number, void *arg)
|
|
|
|
{
|
2007-07-08 00:08:04 -07:00
|
|
|
SubDocMapEntry *entry = static_cast<SubDocMapEntry*>(hdr);
|
|
|
|
FindContentData *data = static_cast<FindContentData*>(arg);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
if (entry->mSubDocument == data->mSubDocument) {
|
|
|
|
data->mResult = entry->mKey;
|
|
|
|
|
|
|
|
return PL_DHASH_STOP;
|
|
|
|
}
|
|
|
|
|
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIContent*
|
|
|
|
nsDocument::FindContentForSubDocument(nsIDocument *aDocument) const
|
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(aDocument, nsnull);
|
|
|
|
|
|
|
|
if (!mSubDocuments) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
FindContentData data(aDocument);
|
|
|
|
PL_DHashTableEnumerate(mSubDocuments, FindContentEnumerator, &data);
|
|
|
|
|
|
|
|
return data.mResult;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsDocument::IsNodeOfType(PRUint32 aFlags) const
|
|
|
|
{
|
|
|
|
return !(aFlags & ~eDOCUMENT);
|
|
|
|
}
|
|
|
|
|
2007-12-11 18:26:09 -08:00
|
|
|
nsIContent*
|
|
|
|
nsDocument::GetRootContentInternal() const
|
|
|
|
{
|
|
|
|
// Loop backwards because any non-elements, such as doctypes and PIs
|
|
|
|
// are likely to appear before the root element.
|
|
|
|
PRUint32 i;
|
|
|
|
for (i = mChildren.ChildCount(); i > 0; --i) {
|
|
|
|
nsIContent* child = mChildren.ChildAt(i - 1);
|
|
|
|
if (child->IsNodeOfType(nsINode::eELEMENT)) {
|
|
|
|
const_cast<nsDocument*>(this)->mCachedRootContent = child;
|
|
|
|
return child;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const_cast<nsDocument*>(this)->mCachedRootContent = nsnull;
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsIContent *
|
|
|
|
nsDocument::GetChildAt(PRUint32 aIndex) const
|
|
|
|
{
|
|
|
|
return mChildren.GetSafeChildAt(aIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32
|
|
|
|
nsDocument::IndexOf(nsINode* aPossibleChild) const
|
|
|
|
{
|
|
|
|
return mChildren.IndexOfChild(aPossibleChild);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint32
|
|
|
|
nsDocument::GetChildCount() const
|
|
|
|
{
|
|
|
|
return mChildren.ChildCount();
|
|
|
|
}
|
|
|
|
|
2008-07-11 13:42:19 -07:00
|
|
|
nsIContent * const *
|
2008-12-03 06:02:03 -08:00
|
|
|
nsDocument::GetChildArray(PRUint32* aChildCount) const
|
2008-07-11 13:42:19 -07:00
|
|
|
{
|
2008-12-03 06:02:03 -08:00
|
|
|
return mChildren.GetChildArray(aChildCount);
|
2008-07-11 13:42:19 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsresult
|
|
|
|
nsDocument::InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
|
|
|
|
PRBool aNotify)
|
|
|
|
{
|
2007-12-11 18:26:09 -08:00
|
|
|
if (aKid->IsNodeOfType(nsINode::eELEMENT) &&
|
|
|
|
GetRootContent()) {
|
|
|
|
NS_ERROR("Inserting element child when we already have one");
|
|
|
|
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-12-11 18:26:09 -08:00
|
|
|
return nsGenericElement::doInsertChildAt(aKid, aIndex, aNotify,
|
|
|
|
nsnull, this, mChildren);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDocument::AppendChildTo(nsIContent* aKid, PRBool aNotify)
|
|
|
|
{
|
|
|
|
// Make sure to _not_ call the subclass InsertChildAt here. If
|
|
|
|
// subclasses wanted to hook into this stuff, they would have
|
|
|
|
// overridden AppendChildTo.
|
|
|
|
// XXXbz maybe this should just be a non-virtual method on nsINode?
|
|
|
|
// Feels that way to me...
|
|
|
|
return nsDocument::InsertChildAt(aKid, GetChildCount(), aNotify);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2009-06-28 15:44:22 -07:00
|
|
|
nsDocument::RemoveChildAt(PRUint32 aIndex, PRBool aNotify, PRBool aMutationEvent)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-06-28 15:44:22 -07:00
|
|
|
NS_ASSERTION(aMutationEvent, "Someone tried to inhibit mutations on document child removal.");
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIContent> oldKid = GetChildAt(aIndex);
|
2007-12-11 18:26:09 -08:00
|
|
|
if (!oldKid) {
|
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-12-11 18:26:09 -08:00
|
|
|
if (oldKid->IsNodeOfType(nsINode::eELEMENT)) {
|
|
|
|
// Destroy the link map up front before we mess with the child list.
|
|
|
|
DestroyLinkMap();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-12-11 18:26:09 -08:00
|
|
|
nsresult rv = nsGenericElement::doRemoveChildAt(aIndex, aNotify, oldKid,
|
2009-06-28 15:44:22 -07:00
|
|
|
nsnull, this, mChildren,
|
|
|
|
aMutationEvent);
|
2007-12-11 18:26:09 -08:00
|
|
|
mCachedRootContent = nsnull;
|
|
|
|
return rv;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32
|
|
|
|
nsDocument::GetNumberOfStyleSheets() const
|
|
|
|
{
|
|
|
|
return mStyleSheets.Count();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIStyleSheet*
|
|
|
|
nsDocument::GetStyleSheetAt(PRInt32 aIndex) const
|
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(0 <= aIndex && aIndex < mStyleSheets.Count(), nsnull);
|
|
|
|
return mStyleSheets[aIndex];
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32
|
|
|
|
nsDocument::GetIndexOfStyleSheet(nsIStyleSheet* aSheet) const
|
|
|
|
{
|
|
|
|
return mStyleSheets.IndexOf(aSheet);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::AddStyleSheetToStyleSets(nsIStyleSheet* aSheet)
|
|
|
|
{
|
2007-05-22 14:45:03 -07:00
|
|
|
nsPresShellIterator iter(this);
|
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
while ((shell = iter.GetNextShell())) {
|
|
|
|
shell->StyleSet()->AddDocStyleSheet(aSheet, this);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::AddStyleSheet(nsIStyleSheet* aSheet)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aSheet, "null arg");
|
|
|
|
mStyleSheets.AppendObject(aSheet);
|
|
|
|
aSheet->SetOwningDocument(this);
|
|
|
|
|
|
|
|
PRBool applicable;
|
|
|
|
aSheet->GetApplicable(applicable);
|
|
|
|
|
|
|
|
if (applicable) {
|
|
|
|
AddStyleSheetToStyleSets(aSheet);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded, (this, aSheet, PR_TRUE));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::RemoveStyleSheetFromStyleSets(nsIStyleSheet* aSheet)
|
|
|
|
{
|
2007-05-22 14:45:03 -07:00
|
|
|
nsPresShellIterator iter(this);
|
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
while ((shell = iter.GetNextShell())) {
|
|
|
|
shell->StyleSet()->RemoveStyleSheet(nsStyleSet::eDocSheet, aSheet);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::RemoveStyleSheet(nsIStyleSheet* aSheet)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aSheet, "null arg");
|
|
|
|
nsCOMPtr<nsIStyleSheet> sheet = aSheet; // hold ref so it won't die too soon
|
|
|
|
|
|
|
|
if (!mStyleSheets.RemoveObject(aSheet)) {
|
|
|
|
NS_NOTREACHED("stylesheet not found");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mIsGoingAway) {
|
|
|
|
PRBool applicable = PR_TRUE;
|
|
|
|
aSheet->GetApplicable(applicable);
|
|
|
|
if (applicable) {
|
|
|
|
RemoveStyleSheetFromStyleSets(aSheet);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetRemoved, (this, aSheet, PR_TRUE));
|
|
|
|
}
|
|
|
|
|
|
|
|
aSheet->SetOwningDocument(nsnull);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::UpdateStyleSheets(nsCOMArray<nsIStyleSheet>& aOldSheets,
|
|
|
|
nsCOMArray<nsIStyleSheet>& aNewSheets)
|
|
|
|
{
|
|
|
|
BeginUpdate(UPDATE_STYLE);
|
|
|
|
|
|
|
|
// XXX Need to set the sheet on the ownernode, if any
|
|
|
|
NS_PRECONDITION(aOldSheets.Count() == aNewSheets.Count(),
|
|
|
|
"The lists must be the same length!");
|
|
|
|
PRInt32 count = aOldSheets.Count();
|
|
|
|
|
|
|
|
nsCOMPtr<nsIStyleSheet> oldSheet;
|
|
|
|
PRInt32 i;
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
|
|
oldSheet = aOldSheets[i];
|
|
|
|
|
|
|
|
// First remove the old sheet.
|
|
|
|
NS_ASSERTION(oldSheet, "None of the old sheets should be null");
|
|
|
|
PRInt32 oldIndex = mStyleSheets.IndexOf(oldSheet);
|
|
|
|
RemoveStyleSheet(oldSheet); // This does the right notifications
|
|
|
|
|
|
|
|
// Now put the new one in its place. If it's null, just ignore it.
|
|
|
|
nsIStyleSheet* newSheet = aNewSheets[i];
|
|
|
|
if (newSheet) {
|
|
|
|
mStyleSheets.InsertObjectAt(newSheet, oldIndex);
|
|
|
|
newSheet->SetOwningDocument(this);
|
|
|
|
PRBool applicable = PR_TRUE;
|
|
|
|
newSheet->GetApplicable(applicable);
|
|
|
|
if (applicable) {
|
|
|
|
AddStyleSheetToStyleSets(newSheet);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded, (this, newSheet, PR_TRUE));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
EndUpdate(UPDATE_STYLE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::InsertStyleSheetAt(nsIStyleSheet* aSheet, PRInt32 aIndex)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aSheet, "null ptr");
|
|
|
|
mStyleSheets.InsertObjectAt(aSheet, aIndex);
|
|
|
|
|
|
|
|
aSheet->SetOwningDocument(this);
|
|
|
|
|
|
|
|
PRBool applicable;
|
|
|
|
aSheet->GetApplicable(applicable);
|
|
|
|
|
|
|
|
if (applicable) {
|
|
|
|
AddStyleSheetToStyleSets(aSheet);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded, (this, aSheet, PR_TRUE));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::SetStyleSheetApplicableState(nsIStyleSheet* aSheet,
|
|
|
|
PRBool aApplicable)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aSheet, "null arg");
|
|
|
|
|
|
|
|
// If we're actually in the document style sheet list
|
|
|
|
if (-1 != mStyleSheets.IndexOf(aSheet)) {
|
|
|
|
if (aApplicable) {
|
|
|
|
AddStyleSheetToStyleSets(aSheet);
|
|
|
|
} else {
|
|
|
|
RemoveStyleSheetFromStyleSets(aSheet);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// We have to always notify, since this will be called for sheets
|
|
|
|
// that are children of sheets in our style set, as well as some
|
|
|
|
// sheets for nsHTMLEditor.
|
|
|
|
|
|
|
|
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetApplicableStateChanged,
|
|
|
|
(this, aSheet, aApplicable));
|
|
|
|
}
|
|
|
|
|
|
|
|
// These three functions are a lot like the implementation of the
|
|
|
|
// corresponding API for regular stylesheets.
|
|
|
|
|
|
|
|
PRInt32
|
|
|
|
nsDocument::GetNumberOfCatalogStyleSheets() const
|
|
|
|
{
|
|
|
|
return mCatalogSheets.Count();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIStyleSheet*
|
|
|
|
nsDocument::GetCatalogStyleSheetAt(PRInt32 aIndex) const
|
|
|
|
{
|
|
|
|
NS_ENSURE_TRUE(0 <= aIndex && aIndex < mCatalogSheets.Count(), nsnull);
|
|
|
|
return mCatalogSheets[aIndex];
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::AddCatalogStyleSheet(nsIStyleSheet* aSheet)
|
|
|
|
{
|
|
|
|
mCatalogSheets.AppendObject(aSheet);
|
|
|
|
aSheet->SetOwningDocument(this);
|
|
|
|
|
|
|
|
PRBool applicable;
|
|
|
|
aSheet->GetApplicable(applicable);
|
|
|
|
|
|
|
|
if (applicable) {
|
|
|
|
// This is like |AddStyleSheetToStyleSets|, but for an agent sheet.
|
2007-05-22 14:45:03 -07:00
|
|
|
nsPresShellIterator iter(this);
|
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
while ((shell = iter.GetNextShell())) {
|
|
|
|
shell->StyleSet()->AppendStyleSheet(nsStyleSet::eAgentSheet, aSheet);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded, (this, aSheet, PR_FALSE));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::EnsureCatalogStyleSheet(const char *aStyleSheetURI)
|
|
|
|
{
|
|
|
|
nsICSSLoader* cssLoader = CSSLoader();
|
|
|
|
PRBool enabled;
|
|
|
|
if (NS_SUCCEEDED(cssLoader->GetEnabled(&enabled)) && enabled) {
|
|
|
|
PRInt32 sheetCount = GetNumberOfCatalogStyleSheets();
|
|
|
|
for (PRInt32 i = 0; i < sheetCount; i++) {
|
|
|
|
nsIStyleSheet* sheet = GetCatalogStyleSheetAt(i);
|
|
|
|
NS_ASSERTION(sheet, "unexpected null stylesheet in the document");
|
|
|
|
if (sheet) {
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
sheet->GetSheetURI(getter_AddRefs(uri));
|
|
|
|
nsCAutoString uriStr;
|
|
|
|
uri->GetSpec(uriStr);
|
|
|
|
if (uriStr.Equals(aStyleSheetURI))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
NS_NewURI(getter_AddRefs(uri), aStyleSheetURI);
|
|
|
|
if (uri) {
|
|
|
|
nsCOMPtr<nsICSSStyleSheet> sheet;
|
2009-03-16 18:38:36 -07:00
|
|
|
cssLoader->LoadSheetSync(uri, PR_TRUE, PR_TRUE, getter_AddRefs(sheet));
|
2007-03-22 10:30:00 -07:00
|
|
|
if (sheet) {
|
|
|
|
BeginUpdate(UPDATE_STYLE);
|
|
|
|
AddCatalogStyleSheet(sheet);
|
|
|
|
EndUpdate(UPDATE_STYLE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIScriptGlobalObject*
|
|
|
|
nsDocument::GetScriptGlobalObject() const
|
|
|
|
{
|
|
|
|
// If we're going away, we've already released the reference to our
|
|
|
|
// ScriptGlobalObject. We can, however, try to obtain it for the
|
|
|
|
// caller through our docshell.
|
|
|
|
|
2008-04-18 03:02:03 -07:00
|
|
|
// We actually need to start returning the docshell's script global
|
|
|
|
// object as soon as nsDocumentViewer::Close has called
|
|
|
|
// RemovedFromDocShell on us.
|
|
|
|
if (mRemovedFromDocShell) {
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIInterfaceRequestor> requestor =
|
|
|
|
do_QueryReferent(mDocumentContainer);
|
|
|
|
if (requestor) {
|
|
|
|
nsCOMPtr<nsIScriptGlobalObject> globalObject = do_GetInterface(requestor);
|
|
|
|
return globalObject;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return mScriptGlobalObject;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIScriptGlobalObject*
|
|
|
|
nsDocument::GetScopeObject()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIScriptGlobalObject> scope(do_QueryReferent(mScopeObject));
|
|
|
|
return scope;
|
|
|
|
}
|
|
|
|
|
2009-10-01 07:10:13 -07:00
|
|
|
static void
|
|
|
|
NotifyActivityChanged(nsIContent *aContent, void *aUnused)
|
|
|
|
{
|
|
|
|
#ifdef MOZ_MEDIA
|
|
|
|
nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aContent));
|
|
|
|
if (domMediaElem) {
|
|
|
|
nsHTMLMediaElement* mediaElem = static_cast<nsHTMLMediaElement*>(aContent);
|
|
|
|
mediaElem->NotifyOwnerDocumentActivityChanged();
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsIDocument::SetContainer(nsISupports* aContainer)
|
|
|
|
{
|
|
|
|
mDocumentContainer = do_GetWeakReference(aContainer);
|
|
|
|
EnumerateFreezableElements(NotifyActivityChanged, nsnull);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
void
|
|
|
|
nsDocument::SetScriptGlobalObject(nsIScriptGlobalObject *aScriptGlobalObject)
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(aScriptGlobalObject));
|
|
|
|
|
|
|
|
NS_ASSERTION(!win || win->IsInnerWindow(),
|
|
|
|
"Script global object must be an inner window!");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (mScriptGlobalObject && !aScriptGlobalObject) {
|
|
|
|
// We're detaching from the window. We need to grab a pointer to
|
|
|
|
// our layout history state now.
|
|
|
|
mLayoutHistoryState = GetLayoutHistoryState();
|
|
|
|
|
|
|
|
// Also make sure to remove our onload blocker now if we haven't done it yet
|
|
|
|
if (mOnloadBlockCount != 0) {
|
|
|
|
nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
|
|
|
|
if (loadGroup) {
|
|
|
|
loadGroup->RemoveRequest(mOnloadBlocker, nsnull, NS_OK);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mScriptGlobalObject = aScriptGlobalObject;
|
|
|
|
|
|
|
|
if (aScriptGlobalObject) {
|
2008-08-24 08:00:49 -07:00
|
|
|
mScriptObject = nsnull;
|
2007-10-01 03:02:32 -07:00
|
|
|
mHasHadScriptHandlingObject = PR_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
// Go back to using the docshell for the layout history state
|
|
|
|
mLayoutHistoryState = nsnull;
|
|
|
|
mScopeObject = do_GetWeakReference(aScriptGlobalObject);
|
2009-05-17 07:22:54 -07:00
|
|
|
|
2009-06-25 06:13:38 -07:00
|
|
|
#ifdef DEBUG
|
2009-07-25 04:27:42 -07:00
|
|
|
if (!mWillReparent) {
|
|
|
|
// We really shouldn't have a wrapper here but if we do we need to make sure
|
|
|
|
// it has the correct parent.
|
|
|
|
JSObject *obj = GetWrapper();
|
|
|
|
if (obj) {
|
|
|
|
JSObject *newScope = aScriptGlobalObject->GetGlobalJSObject();
|
|
|
|
nsIScriptContext *scx = aScriptGlobalObject->GetContext();
|
|
|
|
JSContext *cx = scx ? (JSContext *)scx->GetNativeContext() : nsnull;
|
2009-06-19 09:31:48 -07:00
|
|
|
if (!cx) {
|
2009-07-25 04:27:42 -07:00
|
|
|
nsContentUtils::ThreadJSContextStack()->Peek(&cx);
|
|
|
|
if (!cx) {
|
|
|
|
nsContentUtils::ThreadJSContextStack()->GetSafeJSContext(&cx);
|
|
|
|
NS_ASSERTION(cx, "Uhoh, no context, this is bad!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (cx) {
|
|
|
|
NS_ASSERTION(JS_GetGlobalForObject(cx, obj) == newScope,
|
|
|
|
"Wrong scope, this is really bad!");
|
2009-06-19 09:31:48 -07:00
|
|
|
}
|
2009-05-12 13:20:42 -07:00
|
|
|
}
|
2009-06-19 09:31:48 -07:00
|
|
|
}
|
2009-06-25 06:13:38 -07:00
|
|
|
#endif
|
2009-06-19 09:31:48 -07:00
|
|
|
|
2009-05-17 07:22:54 -07:00
|
|
|
if (mAllowDNSPrefetch) {
|
|
|
|
nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocumentContainer);
|
|
|
|
if (docShell) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
nsCOMPtr<nsIWebNavigation> webNav =
|
|
|
|
do_GetInterface(aScriptGlobalObject);
|
|
|
|
NS_ASSERTION(SameCOMIdentity(webNav, docShell),
|
|
|
|
"Unexpected container or script global?");
|
|
|
|
#endif
|
|
|
|
PRBool allowDNSPrefetch;
|
|
|
|
docShell->GetAllowDNSPrefetch(&allowDNSPrefetch);
|
|
|
|
mAllowDNSPrefetch = allowDNSPrefetch;
|
|
|
|
}
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-12-21 05:44:58 -08:00
|
|
|
|
|
|
|
// Remember the pointer to our window (or lack there of), to avoid
|
|
|
|
// having to QI every time it's asked for.
|
|
|
|
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mScriptGlobalObject);
|
|
|
|
mWindow = window;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-10-01 03:02:32 -07:00
|
|
|
nsIScriptGlobalObject*
|
|
|
|
nsDocument::GetScriptHandlingObject(PRBool& aHasHadScriptHandlingObject) const
|
|
|
|
{
|
|
|
|
aHasHadScriptHandlingObject = mHasHadScriptHandlingObject;
|
|
|
|
if (mScriptGlobalObject) {
|
|
|
|
return mScriptGlobalObject;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIScriptGlobalObject> scriptHandlingObject =
|
|
|
|
do_QueryReferent(mScriptObject);
|
2007-11-16 01:51:09 -08:00
|
|
|
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(scriptHandlingObject);
|
|
|
|
if (win) {
|
2007-12-12 00:33:32 -08:00
|
|
|
NS_ASSERTION(win->IsInnerWindow(), "Should have inner window here!");
|
2007-11-16 01:51:09 -08:00
|
|
|
nsPIDOMWindow* outer = win->GetOuterWindow();
|
|
|
|
if (!outer || outer->GetCurrentInnerWindow() != win) {
|
|
|
|
NS_WARNING("Wrong inner/outer window combination!");
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
}
|
2007-10-01 03:02:32 -07:00
|
|
|
return scriptHandlingObject;
|
|
|
|
}
|
|
|
|
void
|
|
|
|
nsDocument::SetScriptHandlingObject(nsIScriptGlobalObject* aScriptObject)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(!mScriptGlobalObject ||
|
|
|
|
mScriptGlobalObject == aScriptObject,
|
|
|
|
"Wrong script object!");
|
2007-12-12 00:33:32 -08:00
|
|
|
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(aScriptObject);
|
|
|
|
NS_ASSERTION(!win || win->IsInnerWindow(), "Should have inner window here!");
|
2008-07-02 09:24:46 -07:00
|
|
|
mScopeObject = mScriptObject = do_GetWeakReference(aScriptObject);
|
2007-10-01 03:02:32 -07:00
|
|
|
if (aScriptObject) {
|
|
|
|
mHasHadScriptHandlingObject = PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsPIDOMWindow *
|
|
|
|
nsDocument::GetWindow()
|
|
|
|
{
|
2007-12-21 05:44:58 -08:00
|
|
|
if (mWindow) {
|
|
|
|
return mWindow->GetOuterWindow();
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(GetScriptGlobalObject()));
|
|
|
|
|
|
|
|
if (!win) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
return win->GetOuterWindow();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsPIDOMWindow *
|
|
|
|
nsDocument::GetInnerWindow()
|
|
|
|
{
|
2008-12-03 01:22:39 -08:00
|
|
|
if (!mRemovedFromDocShell) {
|
|
|
|
return mWindow;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(GetScriptGlobalObject()));
|
|
|
|
|
|
|
|
return win;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsScriptLoader*
|
2007-05-30 13:43:41 -07:00
|
|
|
nsDocument::ScriptLoader()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
return mScriptLoader;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note: We don't hold a reference to the document observer; we assume
|
|
|
|
// that it has a live reference to the document.
|
|
|
|
void
|
|
|
|
nsDocument::AddObserver(nsIDocumentObserver* aObserver)
|
|
|
|
{
|
|
|
|
// The array makes sure the observer isn't already in the list
|
2007-12-19 23:30:04 -08:00
|
|
|
mObservers.AppendElementUnlessExists(aObserver);
|
2007-03-22 10:30:00 -07:00
|
|
|
AddMutationObserver(aObserver);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsDocument::RemoveObserver(nsIDocumentObserver* aObserver)
|
|
|
|
{
|
|
|
|
// If we're in the process of destroying the document (and we're
|
|
|
|
// informing the observers of the destruction), don't remove the
|
|
|
|
// observers from the list. This is not a big deal, since we
|
|
|
|
// don't hold a live reference to the observers.
|
|
|
|
if (!mInDestructor) {
|
|
|
|
RemoveMutationObserver(aObserver);
|
2007-12-19 23:30:04 -08:00
|
|
|
return mObservers.RemoveElement(aObserver);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return mObservers.Contains(aObserver);
|
|
|
|
}
|
|
|
|
|
2009-01-31 04:53:01 -08:00
|
|
|
void
|
|
|
|
nsDocument::MaybeEndOutermostXBLUpdate()
|
|
|
|
{
|
|
|
|
// Only call BindingManager()->EndOutermostUpdate() when
|
|
|
|
// we're not in an update and it is safe to run scripts.
|
|
|
|
if (mUpdateNestLevel == 0 && mInXBLUpdate) {
|
|
|
|
if (nsContentUtils::IsSafeToRunScript()) {
|
|
|
|
mInXBLUpdate = PR_FALSE;
|
|
|
|
BindingManager()->EndOutermostUpdate();
|
|
|
|
} else if (!mInDestructor) {
|
|
|
|
nsContentUtils::AddScriptRunner(
|
|
|
|
NS_NEW_RUNNABLE_METHOD(nsDocument, this, MaybeEndOutermostXBLUpdate));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
void
|
|
|
|
nsDocument::BeginUpdate(nsUpdateType aUpdateType)
|
|
|
|
{
|
2009-01-31 04:53:01 -08:00
|
|
|
if (mUpdateNestLevel == 0 && !mInXBLUpdate) {
|
|
|
|
mInXBLUpdate = PR_TRUE;
|
2008-03-28 07:09:00 -07:00
|
|
|
BindingManager()->BeginOutermostUpdate();
|
2007-05-30 18:36:06 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
++mUpdateNestLevel;
|
2008-04-14 16:59:21 -07:00
|
|
|
if (aUpdateType == UPDATE_CONTENT_MODEL) {
|
|
|
|
nsContentUtils::AddRemovableScriptBlocker();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
nsContentUtils::AddScriptBlocker();
|
|
|
|
}
|
2009-03-16 04:46:32 -07:00
|
|
|
NS_DOCUMENT_NOTIFY_OBSERVERS(BeginUpdate, (this, aUpdateType));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::EndUpdate(nsUpdateType aUpdateType)
|
|
|
|
{
|
2009-03-16 04:46:32 -07:00
|
|
|
NS_DOCUMENT_NOTIFY_OBSERVERS(EndUpdate, (this, aUpdateType));
|
|
|
|
|
2008-03-14 16:08:57 -07:00
|
|
|
if (aUpdateType == UPDATE_CONTENT_MODEL) {
|
2008-04-14 16:59:21 -07:00
|
|
|
nsContentUtils::RemoveRemovableScriptBlocker();
|
2008-03-14 16:08:57 -07:00
|
|
|
}
|
2008-04-14 16:59:21 -07:00
|
|
|
else {
|
|
|
|
nsContentUtils::RemoveScriptBlocker();
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
--mUpdateNestLevel;
|
|
|
|
|
2009-01-31 04:53:01 -08:00
|
|
|
// This set of updates may have created XBL bindings. Let the
|
|
|
|
// binding manager know we're done.
|
|
|
|
MaybeEndOutermostXBLUpdate();
|
|
|
|
|
|
|
|
MaybeInitializeFinalizeFrameLoaders();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::BeginLoad()
|
|
|
|
{
|
|
|
|
// Block onload here to prevent having to deal with blocking and
|
|
|
|
// unblocking it while we know the document is loading.
|
|
|
|
BlockOnload();
|
|
|
|
|
2008-07-25 19:42:12 -07:00
|
|
|
if (mScriptLoader) {
|
|
|
|
mScriptLoader->BeginDeferringScripts();
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_DOCUMENT_NOTIFY_OBSERVERS(BeginLoad, (this));
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
2008-06-24 18:55:01 -07:00
|
|
|
nsDocument::CheckGetElementByIdArg(const nsIAtom* aId)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2008-06-24 18:55:01 -07:00
|
|
|
if (aId == nsGkAtoms::_empty) {
|
2007-03-22 10:30:00 -07:00
|
|
|
nsContentUtils::ReportToConsole(
|
|
|
|
nsContentUtils::eDOM_PROPERTIES,
|
|
|
|
"EmptyGetElementByIdParam",
|
|
|
|
nsnull, 0,
|
|
|
|
nsnull,
|
|
|
|
EmptyString(), 0, 0,
|
|
|
|
nsIScriptError::warningFlag,
|
|
|
|
"DOM");
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
2008-06-24 18:55:01 -07:00
|
|
|
nsIdentifierMapEntry*
|
|
|
|
nsDocument::GetElementByIdInternal(nsIAtom* aID)
|
|
|
|
{
|
2008-06-22 16:12:40 -07:00
|
|
|
// We don't have to flush before we do the initial hashtable lookup, since if
|
|
|
|
// the id is already in the hashtable it couldn't have been removed without
|
|
|
|
// us being notified (all removals notify immediately, as far as I can tell).
|
|
|
|
// So do the lookup first.
|
2008-06-24 18:55:01 -07:00
|
|
|
nsIdentifierMapEntry *entry = mIdentifierMap.PutEntry(aID);
|
|
|
|
NS_ENSURE_TRUE(entry, nsnull);
|
|
|
|
|
|
|
|
if (entry->GetIdContent())
|
|
|
|
return entry;
|
2008-06-22 16:12:40 -07:00
|
|
|
|
2009-03-23 07:04:40 -07:00
|
|
|
// Now we have to flush. It could be that we know nothing about this ID yet
|
|
|
|
// but more content has been added to the document since. Note that we have
|
|
|
|
// to flush notifications, so that the entry will get updated properly.
|
2008-06-24 18:55:01 -07:00
|
|
|
|
|
|
|
// Make sure to stash away the current generation so we can check whether
|
|
|
|
// the table changes when we flush.
|
|
|
|
PRUint32 generation = mIdentifierMap.GetGeneration();
|
|
|
|
|
|
|
|
FlushPendingNotifications(Flush_ContentAndNotify);
|
|
|
|
|
|
|
|
if (generation != mIdentifierMap.GetGeneration()) {
|
|
|
|
// Table changed, so the entry pointer is no longer valid; look up the
|
|
|
|
// entry again, adding if necessary (the adding may be necessary in case
|
|
|
|
// the flush actually deleted entries).
|
|
|
|
entry = mIdentifierMap.PutEntry(aID);
|
|
|
|
}
|
|
|
|
|
|
|
|
return entry;
|
|
|
|
}
|
2008-06-22 16:12:40 -07:00
|
|
|
|
2008-06-24 18:55:01 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetElementById(const nsAString& aElementId,
|
|
|
|
nsIDOMElement** aReturn)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aReturn);
|
|
|
|
*aReturn = nsnull;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAtom> idAtom(do_GetAtom(aElementId));
|
|
|
|
NS_ENSURE_TRUE(idAtom, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
if (!CheckGetElementByIdArg(idAtom))
|
2008-06-22 16:12:40 -07:00
|
|
|
return NS_OK;
|
|
|
|
|
2008-06-24 18:55:01 -07:00
|
|
|
nsIdentifierMapEntry *entry = GetElementByIdInternal(idAtom);
|
|
|
|
NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
|
2008-06-22 16:12:40 -07:00
|
|
|
|
2009-03-23 07:04:40 -07:00
|
|
|
nsIContent *e = entry->GetIdContent();
|
|
|
|
if (!e)
|
2008-06-24 18:55:01 -07:00
|
|
|
return NS_OK;
|
2008-06-22 16:12:40 -07:00
|
|
|
|
2008-06-24 18:55:01 -07:00
|
|
|
return CallQueryInterface(e, aReturn);
|
|
|
|
}
|
2008-06-22 16:12:40 -07:00
|
|
|
|
2008-06-24 18:55:01 -07:00
|
|
|
nsIContent*
|
|
|
|
nsDocument::AddIDTargetObserver(nsIAtom* aID, IDTargetObserver aObserver,
|
|
|
|
void* aData)
|
|
|
|
{
|
|
|
|
if (!CheckGetElementByIdArg(aID))
|
|
|
|
return nsnull;
|
2008-06-22 16:12:40 -07:00
|
|
|
|
2008-06-24 18:55:01 -07:00
|
|
|
nsIdentifierMapEntry *entry = GetElementByIdInternal(aID);
|
|
|
|
NS_ENSURE_TRUE(entry, nsnull);
|
2008-06-22 16:12:40 -07:00
|
|
|
|
2008-06-24 18:55:01 -07:00
|
|
|
entry->AddContentChangeCallback(aObserver, aData);
|
|
|
|
return entry->GetIdContent();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::RemoveIDTargetObserver(nsIAtom* aID,
|
|
|
|
IDTargetObserver aObserver, void* aData)
|
|
|
|
{
|
|
|
|
if (!CheckGetElementByIdArg(aID))
|
|
|
|
return;
|
|
|
|
|
2008-12-12 00:20:30 -08:00
|
|
|
nsIdentifierMapEntry *entry = mIdentifierMap.GetEntry(aID);
|
|
|
|
if (!entry) {
|
|
|
|
// We don't need to do the stuff that GetElementByIdInternal does;
|
|
|
|
// if there's no entry already in mIdentifierMap, then there's no
|
|
|
|
// callback to remove.
|
2008-06-24 18:55:01 -07:00
|
|
|
return;
|
2008-12-12 00:20:30 -08:00
|
|
|
}
|
2008-06-24 18:55:01 -07:00
|
|
|
|
|
|
|
entry->RemoveContentChangeCallback(aObserver, aData);
|
2008-06-22 16:12:40 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
void
|
|
|
|
nsDocument::DispatchContentLoadedEvents()
|
|
|
|
{
|
2007-09-21 10:30:37 -07:00
|
|
|
// If you add early returns from this method, make sure you're
|
|
|
|
// calling UnblockOnload properly.
|
|
|
|
|
2009-07-07 22:23:20 -07:00
|
|
|
// Unpin references to preloaded images
|
|
|
|
mPreloadingImages.Clear();
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Fire a DOM event notifying listeners that this document has been
|
|
|
|
// loaded (excluding images and other loads initiated by this
|
|
|
|
// document).
|
2007-07-08 00:08:04 -07:00
|
|
|
nsContentUtils::DispatchTrustedEvent(this, static_cast<nsIDocument*>(this),
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_LITERAL_STRING("DOMContentLoaded"),
|
|
|
|
PR_TRUE, PR_TRUE);
|
|
|
|
|
|
|
|
// If this document is a [i]frame, fire a DOMFrameContentLoaded
|
|
|
|
// event on all parent documents notifying that the HTML (excluding
|
|
|
|
// other external files such as images and stylesheets) in a frame
|
|
|
|
// has finished loading.
|
|
|
|
|
|
|
|
// target_frame is the [i]frame element that will be used as the
|
|
|
|
// target for the event. It's the [i]frame whose content is done
|
|
|
|
// loading.
|
|
|
|
nsCOMPtr<nsIDOMEventTarget> target_frame;
|
|
|
|
|
2008-02-08 13:44:04 -08:00
|
|
|
if (mParentDocument) {
|
|
|
|
target_frame =
|
|
|
|
do_QueryInterface(mParentDocument->FindContentForSubDocument(this));
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (target_frame) {
|
2008-02-08 13:44:04 -08:00
|
|
|
nsCOMPtr<nsIDocument> parent = mParentDocument;
|
2008-05-04 20:53:42 -07:00
|
|
|
do {
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIDOMDocumentEvent> document_event =
|
2008-02-08 13:44:04 -08:00
|
|
|
do_QueryInterface(parent);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMEvent> event;
|
|
|
|
nsCOMPtr<nsIPrivateDOMEvent> privateEvent;
|
|
|
|
if (document_event) {
|
|
|
|
document_event->CreateEvent(NS_LITERAL_STRING("Events"),
|
|
|
|
getter_AddRefs(event));
|
|
|
|
|
|
|
|
privateEvent = do_QueryInterface(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (event && privateEvent) {
|
|
|
|
event->InitEvent(NS_LITERAL_STRING("DOMFrameContentLoaded"), PR_TRUE,
|
|
|
|
PR_TRUE);
|
|
|
|
|
|
|
|
privateEvent->SetTarget(target_frame);
|
|
|
|
privateEvent->SetTrusted(PR_TRUE);
|
|
|
|
|
|
|
|
// To dispatch this event we must manually call
|
|
|
|
// nsEventDispatcher::Dispatch() on the ancestor document since the
|
|
|
|
// target is not in the same document, so the event would never reach
|
|
|
|
// the ancestor document if we used the normal event
|
|
|
|
// dispatching code.
|
|
|
|
|
2008-10-09 16:23:07 -07:00
|
|
|
nsEvent* innerEvent = privateEvent->GetInternalNSEvent();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (innerEvent) {
|
|
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
|
|
|
2008-02-08 13:44:04 -08:00
|
|
|
nsIPresShell *shell = parent->GetPrimaryShell();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (shell) {
|
|
|
|
nsCOMPtr<nsPresContext> context = shell->GetPresContext();
|
|
|
|
|
|
|
|
if (context) {
|
2008-02-08 13:44:04 -08:00
|
|
|
nsEventDispatcher::Dispatch(parent, context, innerEvent, event,
|
|
|
|
&status);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-05-04 20:53:42 -07:00
|
|
|
|
|
|
|
parent = parent->GetParentDocument();
|
|
|
|
} while (parent);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-09-21 10:30:37 -07:00
|
|
|
|
2009-02-22 11:09:10 -08:00
|
|
|
// If the document has a manifest attribute, fire a MozApplicationManifest
|
|
|
|
// event.
|
|
|
|
nsIContent* root = GetRootContent();
|
|
|
|
if (root && root->HasAttr(kNameSpaceID_None, nsGkAtoms::manifest)) {
|
|
|
|
nsContentUtils::DispatchChromeEvent(this, static_cast<nsIDocument*>(this),
|
|
|
|
NS_LITERAL_STRING("MozApplicationManifest"),
|
|
|
|
PR_TRUE, PR_TRUE);
|
|
|
|
}
|
|
|
|
|
2007-09-21 10:30:37 -07:00
|
|
|
UnblockOnload(PR_TRUE);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::EndLoad()
|
|
|
|
{
|
2007-09-20 20:54:11 -07:00
|
|
|
// Drop the ref to our parser, if any, but keep hold of the sink so that we
|
|
|
|
// can flush it from FlushPendingNotifications as needed. We might have to
|
|
|
|
// do that to get a StartLayout() to happen.
|
2007-09-20 19:41:08 -07:00
|
|
|
if (mParser) {
|
|
|
|
mWeakSink = do_GetWeakReference(mParser->GetContentSink());
|
|
|
|
mParser = nsnull;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
NS_DOCUMENT_NOTIFY_OBSERVERS(EndLoad, (this));
|
2009-01-23 15:08:41 -08:00
|
|
|
|
|
|
|
if (!mSynchronousDOMContentLoaded) {
|
|
|
|
nsRefPtr<nsIRunnable> ev =
|
|
|
|
new nsRunnableMethod<nsDocument>(this,
|
|
|
|
&nsDocument::DispatchContentLoadedEvents);
|
|
|
|
NS_DispatchToCurrentThread(ev);
|
|
|
|
} else {
|
|
|
|
DispatchContentLoadedEvents();
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::ContentStatesChanged(nsIContent* aContent1, nsIContent* aContent2,
|
|
|
|
PRInt32 aStateMask)
|
|
|
|
{
|
|
|
|
NS_DOCUMENT_NOTIFY_OBSERVERS(ContentStatesChanged,
|
|
|
|
(this, aContent1, aContent2, aStateMask));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::StyleRuleChanged(nsIStyleSheet* aStyleSheet,
|
|
|
|
nsIStyleRule* aOldStyleRule,
|
|
|
|
nsIStyleRule* aNewStyleRule)
|
|
|
|
{
|
|
|
|
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleChanged,
|
|
|
|
(this, aStyleSheet,
|
|
|
|
aOldStyleRule, aNewStyleRule));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::StyleRuleAdded(nsIStyleSheet* aStyleSheet,
|
|
|
|
nsIStyleRule* aStyleRule)
|
|
|
|
{
|
|
|
|
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleAdded,
|
|
|
|
(this, aStyleSheet, aStyleRule));
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::StyleRuleRemoved(nsIStyleSheet* aStyleSheet,
|
|
|
|
nsIStyleRule* aStyleRule)
|
|
|
|
{
|
|
|
|
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleRemoved,
|
|
|
|
(this, aStyleSheet, aStyleRule));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// nsIDOMDocument interface
|
|
|
|
//
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetDoctype(nsIDOMDocumentType** aDoctype)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aDoctype);
|
|
|
|
|
|
|
|
*aDoctype = nsnull;
|
|
|
|
PRInt32 i, count;
|
|
|
|
count = mChildren.ChildCount();
|
|
|
|
for (i = 0; i < count; i++) {
|
2007-12-11 18:26:09 -08:00
|
|
|
CallQueryInterface(mChildren.ChildAt(i), aDoctype);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-12-11 18:26:09 -08:00
|
|
|
if (*aDoctype) {
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetImplementation(nsIDOMDOMImplementation** aImplementation)
|
|
|
|
{
|
2009-10-18 09:39:52 -07:00
|
|
|
if (!mDOMImplementation) {
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
NS_NewURI(getter_AddRefs(uri), "about:blank");
|
|
|
|
NS_ENSURE_TRUE(uri, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
PRBool hasHadScriptObject = PR_TRUE;
|
|
|
|
nsIScriptGlobalObject* scriptObject =
|
|
|
|
GetScriptHandlingObject(hasHadScriptObject);
|
|
|
|
NS_ENSURE_STATE(scriptObject || !hasHadScriptObject);
|
|
|
|
mDOMImplementation = new nsDOMImplementation(scriptObject, uri, uri,
|
|
|
|
NodePrincipal());
|
|
|
|
if (!mDOMImplementation) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-10-18 09:39:52 -07:00
|
|
|
NS_ADDREF(*aImplementation = mDOMImplementation);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetDocumentElement(nsIDOMElement** aDocumentElement)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aDocumentElement);
|
|
|
|
|
2007-12-11 18:26:09 -08:00
|
|
|
nsIContent* root = GetRootContent();
|
|
|
|
if (root) {
|
|
|
|
return CallQueryInterface(root, aDocumentElement);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-12-11 18:26:09 -08:00
|
|
|
*aDocumentElement = nsnull;
|
|
|
|
|
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::CreateElement(const nsAString& aTagName,
|
|
|
|
nsIDOMElement** aReturn)
|
|
|
|
{
|
|
|
|
*aReturn = nsnull;
|
|
|
|
|
|
|
|
nsresult rv = nsContentUtils::CheckQName(aTagName, PR_FALSE);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2009-08-25 10:15:55 -07:00
|
|
|
NS_ASSERTION(!IsHTML(),
|
2007-03-22 10:30:00 -07:00
|
|
|
"nsDocument::CreateElement() called on document that is not "
|
|
|
|
"case sensitive. Fix caller, or fix "
|
|
|
|
"nsDocument::CreateElement()!");
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAtom> name = do_GetAtom(aTagName);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> content;
|
|
|
|
rv = CreateElem(name, nsnull, GetDefaultNamespaceID(), PR_TRUE,
|
|
|
|
getter_AddRefs(content));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
return CallQueryInterface(content, aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::CreateElementNS(const nsAString& aNamespaceURI,
|
|
|
|
const nsAString& aQualifiedName,
|
|
|
|
nsIDOMElement** aReturn)
|
|
|
|
{
|
|
|
|
*aReturn = nsnull;
|
|
|
|
|
|
|
|
nsCOMPtr<nsINodeInfo> nodeInfo;
|
|
|
|
nsresult rv = nsContentUtils::GetNodeInfoFromQName(aNamespaceURI,
|
|
|
|
aQualifiedName,
|
|
|
|
mNodeInfoManager,
|
|
|
|
getter_AddRefs(nodeInfo));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> content;
|
2008-04-17 15:30:51 -07:00
|
|
|
NS_NewElement(getter_AddRefs(content), nodeInfo->NamespaceID(), nodeInfo,
|
|
|
|
PR_FALSE);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
return CallQueryInterface(content, aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::CreateTextNode(const nsAString& aData, nsIDOMText** aReturn)
|
|
|
|
{
|
|
|
|
*aReturn = nsnull;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> text;
|
|
|
|
nsresult rv = NS_NewTextNode(getter_AddRefs(text), mNodeInfoManager);
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
// Don't notify; this node is still being created.
|
|
|
|
text->SetText(aData, PR_FALSE);
|
|
|
|
|
|
|
|
rv = CallQueryInterface(text, aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::CreateDocumentFragment(nsIDOMDocumentFragment** aReturn)
|
|
|
|
{
|
|
|
|
return NS_NewDocumentFragment(aReturn, mNodeInfoManager);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::CreateComment(const nsAString& aData, nsIDOMComment** aReturn)
|
|
|
|
{
|
|
|
|
*aReturn = nsnull;
|
|
|
|
|
|
|
|
// Make sure the substring "--" is not present in aData. Otherwise
|
|
|
|
// we'll create a document that can't be serialized.
|
|
|
|
if (FindInReadable(NS_LITERAL_STRING("--"), aData)) {
|
|
|
|
return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> comment;
|
|
|
|
nsresult rv = NS_NewCommentNode(getter_AddRefs(comment), mNodeInfoManager);
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
// Don't notify; this node is still being created.
|
|
|
|
comment->SetText(aData, PR_FALSE);
|
|
|
|
|
|
|
|
rv = CallQueryInterface(comment, aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::CreateCDATASection(const nsAString& aData,
|
|
|
|
nsIDOMCDATASection** aReturn)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aReturn);
|
|
|
|
*aReturn = nsnull;
|
|
|
|
|
|
|
|
if (FindInReadable(NS_LITERAL_STRING("]]>"), aData))
|
|
|
|
return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> content;
|
|
|
|
nsresult rv = NS_NewXMLCDATASection(getter_AddRefs(content),
|
|
|
|
mNodeInfoManager);
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
// Don't notify; this node is still being created.
|
|
|
|
content->SetText(aData, PR_FALSE);
|
|
|
|
|
|
|
|
rv = CallQueryInterface(content, aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::CreateProcessingInstruction(const nsAString& aTarget,
|
|
|
|
const nsAString& aData,
|
|
|
|
nsIDOMProcessingInstruction** aReturn)
|
|
|
|
{
|
|
|
|
*aReturn = nsnull;
|
|
|
|
|
|
|
|
nsresult rv = nsContentUtils::CheckQName(aTarget, PR_FALSE);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (FindInReadable(NS_LITERAL_STRING("?>"), aData)) {
|
|
|
|
return NS_ERROR_DOM_INVALID_CHARACTER_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> content;
|
|
|
|
rv = NS_NewXMLProcessingInstruction(getter_AddRefs(content),
|
|
|
|
mNodeInfoManager, aTarget, aData);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CallQueryInterface(content, aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::CreateAttribute(const nsAString& aName,
|
|
|
|
nsIDOMAttr** aReturn)
|
|
|
|
{
|
|
|
|
*aReturn = nsnull;
|
|
|
|
NS_ENSURE_TRUE(mNodeInfoManager, NS_ERROR_NOT_INITIALIZED);
|
|
|
|
|
|
|
|
nsresult rv = nsContentUtils::CheckQName(aName, PR_FALSE);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsAutoString value;
|
|
|
|
nsDOMAttribute* attribute;
|
|
|
|
|
|
|
|
nsCOMPtr<nsINodeInfo> nodeInfo;
|
|
|
|
rv = mNodeInfoManager->GetNodeInfo(aName, nsnull, kNameSpaceID_None,
|
|
|
|
getter_AddRefs(nodeInfo));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2008-02-02 15:41:24 -08:00
|
|
|
attribute = new nsDOMAttribute(nsnull, nodeInfo, value);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_TRUE(attribute, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
return CallQueryInterface(attribute, aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::CreateAttributeNS(const nsAString & aNamespaceURI,
|
|
|
|
const nsAString & aQualifiedName,
|
|
|
|
nsIDOMAttr **aResult)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aResult);
|
|
|
|
*aResult = nsnull;
|
|
|
|
|
|
|
|
nsCOMPtr<nsINodeInfo> nodeInfo;
|
|
|
|
nsresult rv = nsContentUtils::GetNodeInfoFromQName(aNamespaceURI,
|
|
|
|
aQualifiedName,
|
|
|
|
mNodeInfoManager,
|
|
|
|
getter_AddRefs(nodeInfo));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsAutoString value;
|
2008-02-02 15:41:24 -08:00
|
|
|
nsDOMAttribute* attribute = new nsDOMAttribute(nsnull, nodeInfo, value);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_TRUE(attribute, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
return CallQueryInterface(attribute, aResult);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::CreateEntityReference(const nsAString& aName,
|
|
|
|
nsIDOMEntityReference** aReturn)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aReturn);
|
|
|
|
|
|
|
|
*aReturn = nsnull;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetElementsByTagName(const nsAString& aTagname,
|
|
|
|
nsIDOMNodeList** aReturn)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aTagname);
|
|
|
|
NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
nsContentList *list = NS_GetContentList(this, nameAtom, kNameSpaceID_Unknown).get();
|
|
|
|
NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
// transfer ref to aReturn
|
|
|
|
*aReturn = list;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
|
|
|
|
const nsAString& aLocalName,
|
|
|
|
nsIDOMNodeList** aReturn)
|
|
|
|
{
|
|
|
|
PRInt32 nameSpaceId = kNameSpaceID_Wildcard;
|
|
|
|
|
|
|
|
if (!aNamespaceURI.EqualsLiteral("*")) {
|
|
|
|
nsresult rv =
|
|
|
|
nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
|
|
|
|
nameSpaceId);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aLocalName);
|
|
|
|
NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
nsContentList *list = NS_GetContentList(this, nameAtom, nameSpaceId).get();
|
|
|
|
NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
// transfer ref to aReturn
|
|
|
|
*aReturn = list;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetAsync(PRBool *aAsync)
|
|
|
|
{
|
|
|
|
NS_ERROR("nsDocument::GetAsync() should be overriden by subclass!");
|
|
|
|
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::SetAsync(PRBool aAsync)
|
|
|
|
{
|
|
|
|
NS_ERROR("nsDocument::SetAsync() should be overriden by subclass!");
|
|
|
|
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::Load(const nsAString& aUrl, PRBool *aReturn)
|
|
|
|
{
|
|
|
|
NS_ERROR("nsDocument::Load() should be overriden by subclass!");
|
|
|
|
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::EvaluateFIXptr(const nsAString& aExpression, nsIDOMRange **aRange)
|
|
|
|
{
|
|
|
|
NS_ERROR("nsDocument::EvaluateFIXptr() should be overriden by subclass!");
|
|
|
|
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::EvaluateXPointer(const nsAString& aExpression,
|
|
|
|
nsIXPointerResult **aResult)
|
|
|
|
{
|
|
|
|
NS_ERROR("nsDocument::EvaluateXPointer() should be overriden by subclass!");
|
|
|
|
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetStyleSheets(nsIDOMStyleSheetList** aStyleSheets)
|
|
|
|
{
|
|
|
|
if (!mDOMStyleSheets) {
|
|
|
|
mDOMStyleSheets = new nsDOMStyleSheetList(this);
|
|
|
|
if (!mDOMStyleSheets) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*aStyleSheets = mDOMStyleSheets;
|
|
|
|
NS_ADDREF(*aStyleSheets);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetSelectedStyleSheetSet(nsAString& aSheetSet)
|
|
|
|
{
|
|
|
|
aSheetSet.Truncate();
|
|
|
|
|
|
|
|
// Look through our sheets, find the selected set title
|
|
|
|
PRInt32 count = GetNumberOfStyleSheets();
|
|
|
|
nsAutoString title;
|
|
|
|
for (PRInt32 index = 0; index < count; index++) {
|
|
|
|
nsIStyleSheet* sheet = GetStyleSheetAt(index);
|
|
|
|
NS_ASSERTION(sheet, "Null sheet in sheet list!");
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMStyleSheet> domSheet = do_QueryInterface(sheet);
|
|
|
|
NS_ASSERTION(domSheet, "Sheet must QI to nsIDOMStyleSheet");
|
|
|
|
PRBool disabled;
|
|
|
|
domSheet->GetDisabled(&disabled);
|
|
|
|
if (disabled) {
|
|
|
|
// Disabled sheets don't affect the currently selected set
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
sheet->GetTitle(title);
|
|
|
|
|
|
|
|
if (aSheetSet.IsEmpty()) {
|
|
|
|
aSheetSet = title;
|
|
|
|
} else if (!title.IsEmpty() && !aSheetSet.Equals(title)) {
|
|
|
|
// Sheets from multiple sets enabled; return null string, per spec.
|
|
|
|
SetDOMStringToNull(aSheetSet);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::SetSelectedStyleSheetSet(const nsAString& aSheetSet)
|
|
|
|
{
|
|
|
|
if (DOMStringIsNull(aSheetSet)) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Must update mLastStyleSheetSet before doing anything else with stylesheets
|
|
|
|
// or CSSLoaders.
|
|
|
|
mLastStyleSheetSet = aSheetSet;
|
|
|
|
EnableStyleSheetsForSetInternal(aSheetSet, PR_TRUE);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetLastStyleSheetSet(nsAString& aSheetSet)
|
|
|
|
{
|
|
|
|
aSheetSet = mLastStyleSheetSet;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetPreferredStyleSheetSet(nsAString& aSheetSet)
|
|
|
|
{
|
|
|
|
GetHeaderData(nsGkAtoms::headerDefaultStyle, aSheetSet);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetStyleSheetSets(nsIDOMDOMStringList** aList)
|
|
|
|
{
|
|
|
|
if (!mStyleSheetSetList) {
|
|
|
|
mStyleSheetSetList = new nsDOMStyleSheetSetList(this);
|
|
|
|
if (!mStyleSheetSetList) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ADDREF(*aList = mStyleSheetSetList);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::EnableStyleSheetsForSet(const nsAString& aSheetSet)
|
|
|
|
{
|
|
|
|
// Per spec, passing in null is a no-op.
|
|
|
|
if (!DOMStringIsNull(aSheetSet)) {
|
|
|
|
// Note: must make sure to not change the CSSLoader's preferred sheet --
|
|
|
|
// that value should be equal to either our lastStyleSheetSet (if that's
|
|
|
|
// non-null) or to our preferredStyleSheetSet. And this method doesn't
|
|
|
|
// change either of those.
|
|
|
|
EnableStyleSheetsForSetInternal(aSheetSet, PR_FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::EnableStyleSheetsForSetInternal(const nsAString& aSheetSet,
|
|
|
|
PRBool aUpdateCSSLoader)
|
|
|
|
{
|
|
|
|
BeginUpdate(UPDATE_STYLE);
|
|
|
|
PRInt32 count = GetNumberOfStyleSheets();
|
|
|
|
nsAutoString title;
|
|
|
|
for (PRInt32 index = 0; index < count; index++) {
|
|
|
|
nsIStyleSheet* sheet = GetStyleSheetAt(index);
|
|
|
|
NS_ASSERTION(sheet, "Null sheet in sheet list!");
|
|
|
|
sheet->GetTitle(title);
|
|
|
|
if (!title.IsEmpty()) {
|
|
|
|
sheet->SetEnabled(title.Equals(aSheetSet));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (aUpdateCSSLoader) {
|
|
|
|
CSSLoader()->SetPreferredSheet(aSheetSet);
|
|
|
|
}
|
|
|
|
EndUpdate(UPDATE_STYLE);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetCharacterSet(nsAString& aCharacterSet)
|
|
|
|
{
|
|
|
|
CopyASCIItoUTF16(GetDocumentCharacterSet(), aCharacterSet);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::ImportNode(nsIDOMNode* aImportedNode,
|
|
|
|
PRBool aDeep,
|
|
|
|
nsIDOMNode** aResult)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aImportedNode);
|
|
|
|
|
|
|
|
*aResult = nsnull;
|
|
|
|
|
|
|
|
nsresult rv = nsContentUtils::CheckSameOrigin(this, aImportedNode);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint16 nodeType;
|
|
|
|
aImportedNode->GetNodeType(&nodeType);
|
|
|
|
switch (nodeType) {
|
|
|
|
case nsIDOMNode::ATTRIBUTE_NODE:
|
|
|
|
case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
|
|
|
|
case nsIDOMNode::ELEMENT_NODE:
|
|
|
|
case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
|
|
|
|
case nsIDOMNode::TEXT_NODE:
|
|
|
|
case nsIDOMNode::CDATA_SECTION_NODE:
|
|
|
|
case nsIDOMNode::COMMENT_NODE:
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsINode> imported = do_QueryInterface(aImportedNode);
|
|
|
|
NS_ENSURE_TRUE(imported, NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNode> newNode;
|
|
|
|
nsCOMArray<nsINode> nodesWithProperties;
|
|
|
|
rv = nsNodeUtils::Clone(imported, aDeep, mNodeInfoManager,
|
|
|
|
nodesWithProperties, getter_AddRefs(newNode));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsIDocument *ownerDoc = imported->GetOwnerDoc();
|
|
|
|
if (ownerDoc) {
|
|
|
|
rv = nsNodeUtils::CallUserDataHandlers(nodesWithProperties, ownerDoc,
|
|
|
|
nsIDOMUserDataHandler::NODE_IMPORTED,
|
|
|
|
PR_TRUE);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
newNode.swap(*aResult);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
case nsIDOMNode::ENTITY_NODE:
|
|
|
|
case nsIDOMNode::ENTITY_REFERENCE_NODE:
|
|
|
|
case nsIDOMNode::NOTATION_NODE:
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
NS_WARNING("Don't know how to clone this nodetype for importNode.");
|
|
|
|
|
|
|
|
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::AddBinding(nsIDOMElement* aContent, const nsAString& aURI)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aContent);
|
|
|
|
|
|
|
|
nsresult rv = nsContentUtils::CheckSameOrigin(this, aContent);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> content(do_QueryInterface(aContent));
|
|
|
|
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
rv = NS_NewURI(getter_AddRefs(uri), aURI);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
2007-07-18 14:56:57 -07:00
|
|
|
|
|
|
|
// Figure out the right principal to use
|
|
|
|
nsCOMPtr<nsIPrincipal> subject;
|
|
|
|
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
|
|
|
|
if (secMan) {
|
|
|
|
rv = secMan->GetSubjectPrincipal(getter_AddRefs(subject));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!subject) {
|
|
|
|
// Fall back to our principal. Or should we fall back to the null
|
|
|
|
// principal? The latter would just mean no binding loads....
|
|
|
|
subject = NodePrincipal();
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-03-28 07:09:00 -07:00
|
|
|
return BindingManager()->AddLayeredBinding(content, uri, subject);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::RemoveBinding(nsIDOMElement* aContent, const nsAString& aURI)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aContent);
|
|
|
|
|
|
|
|
nsresult rv = nsContentUtils::CheckSameOrigin(this, aContent);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
rv = NS_NewURI(getter_AddRefs(uri), aURI);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> content(do_QueryInterface(aContent));
|
2008-03-28 07:09:00 -07:00
|
|
|
return BindingManager()->RemoveLayeredBinding(content, uri);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2007-06-12 14:56:06 -07:00
|
|
|
nsDocument::LoadBindingDocument(const nsAString& aURI)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
nsresult rv = NS_NewURI(getter_AddRefs(uri), aURI,
|
|
|
|
mCharacterSet.get(),
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<nsIDocument *>(this)->GetBaseURI());
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
2007-07-18 14:56:57 -07:00
|
|
|
// Figure out the right principal to use
|
|
|
|
nsCOMPtr<nsIPrincipal> subject;
|
|
|
|
nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
|
|
|
|
if (secMan) {
|
|
|
|
rv = secMan->GetSubjectPrincipal(getter_AddRefs(subject));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!subject) {
|
|
|
|
// Fall back to our principal. Or should we fall back to the null
|
|
|
|
// principal? The latter would just mean no binding loads....
|
|
|
|
subject = NodePrincipal();
|
|
|
|
}
|
|
|
|
|
2008-03-28 07:09:00 -07:00
|
|
|
BindingManager()->LoadBindingDocument(this, uri, subject);
|
2007-06-12 14:56:06 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetBindingParent(nsIDOMNode* aNode, nsIDOMElement** aResult)
|
|
|
|
{
|
|
|
|
*aResult = nsnull;
|
|
|
|
nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
|
|
|
|
if (!content)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMElement> elt(do_QueryInterface(content->GetBindingParent()));
|
|
|
|
NS_IF_ADDREF(*aResult = elt);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static nsresult
|
|
|
|
GetElementByAttribute(nsIContent* aContent, nsIAtom* aAttrName,
|
|
|
|
const nsAString& aAttrValue, PRBool aUniversalMatch,
|
|
|
|
nsIDOMElement** aResult)
|
|
|
|
{
|
|
|
|
if (aUniversalMatch ? aContent->HasAttr(kNameSpaceID_None, aAttrName) :
|
|
|
|
aContent->AttrValueIs(kNameSpaceID_None, aAttrName,
|
|
|
|
aAttrValue, eCaseMatters)) {
|
|
|
|
return CallQueryInterface(aContent, aResult);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint32 childCount = aContent->GetChildCount();
|
|
|
|
|
|
|
|
for (PRUint32 i = 0; i < childCount; ++i) {
|
|
|
|
nsIContent *current = aContent->GetChildAt(i);
|
|
|
|
|
|
|
|
GetElementByAttribute(current, aAttrName, aAttrValue, aUniversalMatch,
|
|
|
|
aResult);
|
|
|
|
|
|
|
|
if (*aResult)
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetAnonymousElementByAttribute(nsIDOMElement* aElement,
|
|
|
|
const nsAString& aAttrName,
|
|
|
|
const nsAString& aAttrValue,
|
|
|
|
nsIDOMElement** aResult)
|
|
|
|
{
|
|
|
|
*aResult = nsnull;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMNodeList> nodeList;
|
|
|
|
GetAnonymousNodes(aElement, getter_AddRefs(nodeList));
|
|
|
|
|
|
|
|
if (!nodeList)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIAtom> attribute = do_GetAtom(aAttrName);
|
|
|
|
|
|
|
|
PRUint32 length;
|
|
|
|
nodeList->GetLength(&length);
|
|
|
|
|
|
|
|
PRBool universalMatch = aAttrValue.EqualsLiteral("*");
|
|
|
|
|
|
|
|
for (PRUint32 i = 0; i < length; ++i) {
|
|
|
|
nsCOMPtr<nsIDOMNode> current;
|
|
|
|
nodeList->Item(i, getter_AddRefs(current));
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> content(do_QueryInterface(current));
|
|
|
|
|
|
|
|
GetElementByAttribute(content, attribute, aAttrValue, universalMatch,
|
|
|
|
aResult);
|
|
|
|
if (*aResult)
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetAnonymousNodes(nsIDOMElement* aElement,
|
|
|
|
nsIDOMNodeList** aResult)
|
|
|
|
{
|
|
|
|
*aResult = nsnull;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIContent> content(do_QueryInterface(aElement));
|
2008-03-28 07:09:00 -07:00
|
|
|
return BindingManager()->GetAnonymousNodesFor(content, aResult);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::CreateRange(nsIDOMRange** aReturn)
|
|
|
|
{
|
|
|
|
nsresult rv = NS_NewRange(aReturn);
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
(*aReturn)->SetStart(this, 0);
|
|
|
|
(*aReturn)->SetEnd(this, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::CreateNodeIterator(nsIDOMNode *aRoot,
|
|
|
|
PRUint32 aWhatToShow,
|
|
|
|
nsIDOMNodeFilter *aFilter,
|
|
|
|
PRBool aEntityReferenceExpansion,
|
|
|
|
nsIDOMNodeIterator **_retval)
|
|
|
|
{
|
2008-07-21 17:35:38 -07:00
|
|
|
*_retval = nsnull;
|
|
|
|
|
|
|
|
if (!aRoot)
|
|
|
|
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
|
|
|
|
|
|
|
nsresult rv = nsContentUtils::CheckSameOrigin(this, aRoot);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
NS_ENSURE_ARG_POINTER(_retval);
|
|
|
|
|
|
|
|
nsCOMPtr<nsINode> root = do_QueryInterface(aRoot);
|
|
|
|
NS_ENSURE_TRUE(root, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
|
|
|
|
|
|
|
nsNodeIterator *iterator = new nsNodeIterator(root,
|
|
|
|
aWhatToShow,
|
|
|
|
aFilter,
|
|
|
|
aEntityReferenceExpansion);
|
|
|
|
NS_ENSURE_TRUE(iterator, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
NS_ADDREF(*_retval = iterator);
|
|
|
|
|
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::CreateTreeWalker(nsIDOMNode *aRoot,
|
|
|
|
PRUint32 aWhatToShow,
|
|
|
|
nsIDOMNodeFilter *aFilter,
|
|
|
|
PRBool aEntityReferenceExpansion,
|
|
|
|
nsIDOMTreeWalker **_retval)
|
|
|
|
{
|
|
|
|
*_retval = nsnull;
|
|
|
|
|
2008-07-21 17:35:38 -07:00
|
|
|
if (!aRoot)
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
|
|
|
|
|
|
|
nsresult rv = nsContentUtils::CheckSameOrigin(this, aRoot);
|
2008-07-21 17:35:38 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-07-21 17:35:38 -07:00
|
|
|
NS_ENSURE_ARG_POINTER(_retval);
|
|
|
|
|
|
|
|
nsCOMPtr<nsINode> root = do_QueryInterface(aRoot);
|
|
|
|
NS_ENSURE_TRUE(root, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
|
|
|
|
|
|
|
nsTreeWalker* walker = new nsTreeWalker(root,
|
|
|
|
aWhatToShow,
|
|
|
|
aFilter,
|
|
|
|
aEntityReferenceExpansion);
|
|
|
|
NS_ENSURE_TRUE(walker, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
|
|
|
|
NS_ADDREF(*_retval = walker);
|
|
|
|
|
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetDefaultView(nsIDOMAbstractView** aDefaultView)
|
|
|
|
{
|
|
|
|
nsPIDOMWindow* win = GetWindow();
|
|
|
|
if (win) {
|
|
|
|
return CallQueryInterface(win, aDefaultView);
|
|
|
|
}
|
|
|
|
|
|
|
|
*aDefaultView = nsnull;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetLocation(nsIDOMLocation **_retval)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(_retval);
|
|
|
|
*_retval = nsnull;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMWindowInternal> w(do_QueryInterface(mScriptGlobalObject));
|
|
|
|
|
|
|
|
if (!w) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return w->GetLocation(_retval);
|
|
|
|
}
|
|
|
|
|
2008-08-17 19:10:28 -07:00
|
|
|
nsIContent*
|
|
|
|
nsDocument::GetHtmlContent()
|
|
|
|
{
|
|
|
|
nsIContent* rootContent = GetRootContent();
|
|
|
|
if (rootContent && rootContent->Tag() == nsGkAtoms::html &&
|
2009-08-24 13:02:07 -07:00
|
|
|
rootContent->IsHTML())
|
2008-08-17 19:10:28 -07:00
|
|
|
return rootContent;
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIContent*
|
|
|
|
nsDocument::GetHtmlChildContent(nsIAtom* aTag)
|
|
|
|
{
|
|
|
|
nsIContent* html = GetHtmlContent();
|
|
|
|
if (!html)
|
|
|
|
return nsnull;
|
|
|
|
|
|
|
|
// Look for the element with aTag inside html. This needs to run
|
|
|
|
// forwards to find the first such element.
|
|
|
|
for (PRUint32 i = 0; i < html->GetChildCount(); ++i) {
|
|
|
|
nsIContent* result = html->GetChildAt(i);
|
2009-08-24 13:02:07 -07:00
|
|
|
if (result->Tag() == aTag && result->IsHTML())
|
2008-08-17 19:10:28 -07:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIContent*
|
2009-08-24 13:02:07 -07:00
|
|
|
nsDocument::GetTitleContent(PRUint32 aNamespace)
|
2008-08-17 19:10:28 -07:00
|
|
|
{
|
|
|
|
// mMayHaveTitleElement will have been set to true if any HTML or SVG
|
|
|
|
// <title> element has been bound to this document. So if it's false,
|
|
|
|
// we know there is nothing to do here. This avoids us having to search
|
|
|
|
// the whole DOM if someone calls document.title on a large document
|
|
|
|
// without a title.
|
|
|
|
if (!mMayHaveTitleElement)
|
|
|
|
return nsnull;
|
|
|
|
|
|
|
|
nsRefPtr<nsContentList> list =
|
|
|
|
NS_GetContentList(this, nsGkAtoms::title, kNameSpaceID_Unknown);
|
|
|
|
if (!list)
|
|
|
|
return nsnull;
|
|
|
|
|
|
|
|
for (PRUint32 i = 0; ; ++i) {
|
|
|
|
// Avoid calling list->Length --- by calling Item one at a time,
|
|
|
|
// we can avoid scanning the whole document to build the list of all
|
|
|
|
// matches
|
|
|
|
nsIContent* elem = list->Item(i, PR_FALSE);
|
|
|
|
if (!elem)
|
|
|
|
return nsnull;
|
2009-08-24 13:02:07 -07:00
|
|
|
if (elem->IsInNamespace(aNamespace))
|
2008-08-17 19:10:28 -07:00
|
|
|
return elem;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-08-24 13:02:07 -07:00
|
|
|
nsDocument::GetTitleFromElement(PRUint32 aNamespace, nsAString& aTitle)
|
2008-08-17 19:10:28 -07:00
|
|
|
{
|
2009-08-24 13:02:07 -07:00
|
|
|
nsIContent* title = GetTitleContent(aNamespace);
|
2008-08-17 19:10:28 -07:00
|
|
|
if (!title)
|
|
|
|
return;
|
|
|
|
nsContentUtils::GetNodeTextContent(title, PR_FALSE, aTitle);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetTitle(nsAString& aTitle)
|
|
|
|
{
|
2008-08-17 19:10:28 -07:00
|
|
|
aTitle.Truncate();
|
|
|
|
|
|
|
|
nsIContent *rootContent = GetRootContent();
|
|
|
|
if (!rootContent)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
nsAutoString tmp;
|
|
|
|
|
|
|
|
switch (rootContent->GetNameSpaceID()) {
|
|
|
|
#ifdef MOZ_XUL
|
|
|
|
case kNameSpaceID_XUL:
|
|
|
|
rootContent->GetAttr(kNameSpaceID_None, nsGkAtoms::title, tmp);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
#ifdef MOZ_SVG
|
|
|
|
case kNameSpaceID_SVG:
|
|
|
|
if (rootContent->Tag() == nsGkAtoms::svg) {
|
2009-08-24 13:02:07 -07:00
|
|
|
GetTitleFromElement(kNameSpaceID_SVG, tmp);
|
2008-08-17 19:10:28 -07:00
|
|
|
break;
|
|
|
|
} // else fall through
|
|
|
|
#endif
|
|
|
|
default:
|
2009-08-24 13:02:07 -07:00
|
|
|
GetTitleFromElement(kNameSpaceID_XHTML, tmp);
|
2008-08-17 19:10:28 -07:00
|
|
|
break;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-08-17 19:10:28 -07:00
|
|
|
tmp.CompressWhitespace();
|
|
|
|
aTitle = tmp;
|
2007-03-22 10:30:00 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::SetTitle(const nsAString& aTitle)
|
|
|
|
{
|
2008-08-17 19:10:28 -07:00
|
|
|
nsIContent *rootContent = GetRootContent();
|
|
|
|
if (!rootContent)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
switch (rootContent->GetNameSpaceID()) {
|
|
|
|
#ifdef MOZ_SVG
|
|
|
|
case kNameSpaceID_SVG:
|
|
|
|
return NS_OK; // SVG doesn't support setting a title
|
|
|
|
#endif
|
|
|
|
#ifdef MOZ_XUL
|
|
|
|
case kNameSpaceID_XUL:
|
|
|
|
return rootContent->SetAttr(kNameSpaceID_None, nsGkAtoms::title,
|
|
|
|
aTitle, PR_TRUE);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
// Batch updates so that mutation events don't change "the title
|
|
|
|
// element" under us
|
|
|
|
mozAutoDocUpdate updateBatch(this, UPDATE_CONTENT_MODEL, PR_TRUE);
|
|
|
|
|
2009-08-24 13:02:07 -07:00
|
|
|
nsIContent* title = GetTitleContent(kNameSpaceID_XHTML);
|
2008-08-17 19:10:28 -07:00
|
|
|
if (!title) {
|
|
|
|
nsIContent *head = GetHeadContent();
|
|
|
|
if (!head)
|
|
|
|
return NS_OK;
|
|
|
|
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsINodeInfo> titleInfo;
|
2008-09-12 15:32:18 -07:00
|
|
|
titleInfo = mNodeInfoManager->GetNodeInfo(nsGkAtoms::title, nsnull,
|
2009-10-01 08:54:10 -07:00
|
|
|
kNameSpaceID_XHTML);
|
2008-08-17 19:10:28 -07:00
|
|
|
if (!titleInfo)
|
|
|
|
return NS_OK;
|
|
|
|
title = NS_NewHTMLTitleElement(titleInfo);
|
|
|
|
if (!title)
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
head->AppendChildTo(title, PR_TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsContentUtils::SetNodeTextContent(title, aTitle, PR_FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::NotifyPossibleTitleChange(PRBool aBoundTitleElement)
|
|
|
|
{
|
|
|
|
if (aBoundTitleElement) {
|
|
|
|
mMayHaveTitleElement = PR_TRUE;
|
|
|
|
}
|
|
|
|
if (mPendingTitleChangeEvent.IsPending())
|
|
|
|
return;
|
|
|
|
|
2009-05-06 13:46:01 -07:00
|
|
|
nsRefPtr<nsNonOwningRunnableMethod<nsDocument> > event =
|
|
|
|
new nsNonOwningRunnableMethod<nsDocument>(this,
|
2008-08-17 19:10:28 -07:00
|
|
|
&nsDocument::DoNotifyPossibleTitleChange);
|
|
|
|
nsresult rv = NS_DispatchToCurrentThread(event);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
mPendingTitleChangeEvent = event;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::DoNotifyPossibleTitleChange()
|
|
|
|
{
|
|
|
|
mPendingTitleChangeEvent.Forget();
|
2008-08-25 01:52:48 -07:00
|
|
|
mHaveFiredTitleChange = PR_TRUE;
|
2008-08-17 19:10:28 -07:00
|
|
|
|
|
|
|
nsAutoString title;
|
|
|
|
GetTitle(title);
|
|
|
|
|
2007-05-22 14:45:03 -07:00
|
|
|
nsPresShellIterator iter(this);
|
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
while ((shell = iter.GetNextShell())) {
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsISupports> container = shell->GetPresContext()->GetContainer();
|
|
|
|
if (!container)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIBaseWindow> docShellWin = do_QueryInterface(container);
|
|
|
|
if (!docShellWin)
|
|
|
|
continue;
|
|
|
|
|
2008-08-17 19:10:28 -07:00
|
|
|
docShellWin->SetTitle(PromiseFlatString(title).get());
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Fire a DOM event for the title change.
|
2009-03-06 10:12:23 -08:00
|
|
|
nsContentUtils::DispatchChromeEvent(this, static_cast<nsIDocument*>(this),
|
|
|
|
NS_LITERAL_STRING("DOMTitleChanged"),
|
|
|
|
PR_TRUE, PR_TRUE);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetBoxObjectFor(nsIDOMElement* aElement, nsIBoxObject** aResult)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIContent> content(do_QueryInterface(aElement));
|
|
|
|
NS_ENSURE_TRUE(content, NS_ERROR_UNEXPECTED);
|
2007-05-24 17:28:20 -07:00
|
|
|
|
2008-02-14 12:45:07 -08:00
|
|
|
nsIDocument* doc = content->GetOwnerDoc();
|
2007-05-24 17:28:20 -07:00
|
|
|
NS_ENSURE_TRUE(doc == this, NS_ERROR_DOM_WRONG_DOCUMENT_ERR);
|
2008-02-14 12:45:07 -08:00
|
|
|
|
2009-08-24 13:02:07 -07:00
|
|
|
if (!mHasWarnedAboutBoxObjects && !content->IsXUL()) {
|
2008-02-14 12:45:07 -08:00
|
|
|
mHasWarnedAboutBoxObjects = PR_TRUE;
|
|
|
|
nsContentUtils::ReportToConsole(nsContentUtils::eDOM_PROPERTIES,
|
|
|
|
"UseOfGetBoxObjectForWarning",
|
|
|
|
nsnull, 0,
|
|
|
|
static_cast<nsIDocument*>(this)->
|
|
|
|
GetDocumentURI(),
|
|
|
|
EmptyString(), 0, 0,
|
|
|
|
nsIScriptError::warningFlag,
|
|
|
|
"BoxObjects");
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
*aResult = nsnull;
|
|
|
|
|
|
|
|
if (!mBoxObjectTable) {
|
2008-02-14 12:45:07 -08:00
|
|
|
mBoxObjectTable = new nsInterfaceHashtable<nsVoidPtrHashKey, nsPIBoxObject>;
|
2007-03-22 10:30:00 -07:00
|
|
|
if (mBoxObjectTable && !mBoxObjectTable->Init(12)) {
|
|
|
|
mBoxObjectTable = nsnull;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Want to use Get(content, aResult); but it's the wrong type
|
|
|
|
*aResult = mBoxObjectTable->GetWeak(content);
|
|
|
|
if (*aResult) {
|
|
|
|
NS_ADDREF(*aResult);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32 namespaceID;
|
2008-03-28 07:09:00 -07:00
|
|
|
nsCOMPtr<nsIAtom> tag = BindingManager()->ResolveTag(content, &namespaceID);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsCAutoString contractID("@mozilla.org/layout/xul-boxobject");
|
|
|
|
if (namespaceID == kNameSpaceID_XUL) {
|
|
|
|
if (tag == nsGkAtoms::browser ||
|
|
|
|
tag == nsGkAtoms::editor ||
|
|
|
|
tag == nsGkAtoms::iframe)
|
|
|
|
contractID += "-container";
|
|
|
|
else if (tag == nsGkAtoms::menu)
|
|
|
|
contractID += "-menu";
|
|
|
|
else if (tag == nsGkAtoms::popup ||
|
|
|
|
tag == nsGkAtoms::menupopup ||
|
2007-07-04 08:49:38 -07:00
|
|
|
tag == nsGkAtoms::panel ||
|
2007-03-22 10:30:00 -07:00
|
|
|
tag == nsGkAtoms::tooltip)
|
|
|
|
contractID += "-popup";
|
|
|
|
else if (tag == nsGkAtoms::tree)
|
|
|
|
contractID += "-tree";
|
|
|
|
else if (tag == nsGkAtoms::listbox)
|
|
|
|
contractID += "-listbox";
|
|
|
|
else if (tag == nsGkAtoms::scrollbox)
|
|
|
|
contractID += "-scrollbox";
|
|
|
|
}
|
|
|
|
contractID += ";1";
|
|
|
|
|
|
|
|
nsCOMPtr<nsPIBoxObject> boxObject(do_CreateInstance(contractID.get()));
|
|
|
|
if (!boxObject)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
boxObject->Init(content);
|
|
|
|
|
|
|
|
if (mBoxObjectTable) {
|
|
|
|
mBoxObjectTable->Put(content, boxObject.get());
|
|
|
|
}
|
|
|
|
|
|
|
|
*aResult = boxObject;
|
|
|
|
NS_ADDREF(*aResult);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::ClearBoxObjectFor(nsIContent* aContent)
|
|
|
|
{
|
|
|
|
if (mBoxObjectTable) {
|
|
|
|
nsPIBoxObject *boxObject = mBoxObjectTable->GetWeak(aContent);
|
|
|
|
if (boxObject) {
|
|
|
|
boxObject->Clear();
|
|
|
|
mBoxObjectTable->Remove(aContent);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDocument::GetXBLChildNodesFor(nsIContent* aContent, nsIDOMNodeList** aResult)
|
|
|
|
{
|
2008-03-28 07:09:00 -07:00
|
|
|
return BindingManager()->GetXBLChildNodesFor(aContent, aResult);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDocument::GetContentListFor(nsIContent* aContent, nsIDOMNodeList** aResult)
|
|
|
|
{
|
2008-03-28 07:09:00 -07:00
|
|
|
return BindingManager()->GetContentListFor(aContent, aResult);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::FlushSkinBindings()
|
|
|
|
{
|
2008-03-28 07:09:00 -07:00
|
|
|
BindingManager()->FlushSkinBindings();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-03-21 04:44:09 -07:00
|
|
|
nsresult
|
|
|
|
nsDocument::InitializeFrameLoader(nsFrameLoader* aLoader)
|
|
|
|
{
|
|
|
|
mInitializableFrameLoaders.RemoveElement(aLoader);
|
|
|
|
// Don't even try to initialize.
|
|
|
|
if (mInDestructor) {
|
|
|
|
NS_WARNING("Trying to initialize a frame loader while"
|
|
|
|
"document is being deleted");
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2009-01-02 07:41:43 -08:00
|
|
|
|
|
|
|
mInitializableFrameLoaders.AppendElement(aLoader);
|
|
|
|
if (!mFrameLoaderRunner) {
|
2009-01-31 04:53:01 -08:00
|
|
|
mFrameLoaderRunner =
|
|
|
|
NS_NEW_RUNNABLE_METHOD(nsDocument, this,
|
|
|
|
MaybeInitializeFinalizeFrameLoaders);
|
2009-01-02 07:41:43 -08:00
|
|
|
NS_ENSURE_TRUE(mFrameLoaderRunner, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
nsContentUtils::AddScriptRunner(mFrameLoaderRunner);
|
2008-03-21 04:44:09 -07:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-02-26 06:47:51 -08:00
|
|
|
nsresult
|
|
|
|
nsDocument::FinalizeFrameLoader(nsFrameLoader* aLoader)
|
|
|
|
{
|
2008-03-21 04:44:09 -07:00
|
|
|
mInitializableFrameLoaders.RemoveElement(aLoader);
|
2008-02-26 06:47:51 -08:00
|
|
|
if (mInDestructor) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
2009-01-02 07:41:43 -08:00
|
|
|
|
|
|
|
mFinalizableFrameLoaders.AppendElement(aLoader);
|
|
|
|
if (!mFrameLoaderRunner) {
|
2009-01-31 04:53:01 -08:00
|
|
|
mFrameLoaderRunner =
|
|
|
|
NS_NEW_RUNNABLE_METHOD(nsDocument, this,
|
|
|
|
MaybeInitializeFinalizeFrameLoaders);
|
2009-01-02 07:41:43 -08:00
|
|
|
NS_ENSURE_TRUE(mFrameLoaderRunner, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
nsContentUtils::AddScriptRunner(mFrameLoaderRunner);
|
2008-02-26 06:47:51 -08:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2008-04-18 01:58:06 -07:00
|
|
|
void
|
2009-01-31 04:53:01 -08:00
|
|
|
nsDocument::MaybeInitializeFinalizeFrameLoaders()
|
2008-04-18 01:58:06 -07:00
|
|
|
{
|
2009-01-02 07:41:43 -08:00
|
|
|
if (mDelayFrameLoaderInitialization || mUpdateNestLevel != 0) {
|
2009-01-31 04:53:01 -08:00
|
|
|
// This method will be recalled when mUpdateNestLevel drops to 0,
|
|
|
|
// or when !mDelayFrameLoaderInitialization.
|
|
|
|
mFrameLoaderRunner = nsnull;
|
2009-01-02 07:41:43 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-01-31 04:53:01 -08:00
|
|
|
// We're not in an update, but it is not safe to run scripts, so
|
|
|
|
// postpone frameloader initialization and finalization.
|
|
|
|
if (!nsContentUtils::IsSafeToRunScript()) {
|
|
|
|
if (!mInDestructor && !mFrameLoaderRunner &&
|
|
|
|
(mInitializableFrameLoaders.Length() ||
|
|
|
|
mFinalizableFrameLoaders.Length())) {
|
|
|
|
mFrameLoaderRunner =
|
|
|
|
NS_NEW_RUNNABLE_METHOD(nsDocument, this,
|
|
|
|
MaybeInitializeFinalizeFrameLoaders);
|
|
|
|
nsContentUtils::AddScriptRunner(mFrameLoaderRunner);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
mFrameLoaderRunner = nsnull;
|
|
|
|
|
2008-04-24 03:33:22 -07:00
|
|
|
// Don't use a temporary array for mInitializableFrameLoaders, because
|
|
|
|
// loading a frame may cause some other frameloader to be removed from the
|
|
|
|
// array. But be careful to keep the loader alive when starting the load!
|
|
|
|
while (mInitializableFrameLoaders.Length()) {
|
|
|
|
nsRefPtr<nsFrameLoader> loader = mInitializableFrameLoaders[0];
|
|
|
|
mInitializableFrameLoaders.RemoveElementAt(0);
|
|
|
|
NS_ASSERTION(loader, "null frameloader in the array?");
|
|
|
|
loader->ReallyStartLoading();
|
2008-04-18 01:58:06 -07:00
|
|
|
}
|
|
|
|
|
2008-04-24 03:33:22 -07:00
|
|
|
PRUint32 length = mFinalizableFrameLoaders.Length();
|
2008-04-18 01:58:06 -07:00
|
|
|
if (length > 0) {
|
|
|
|
nsTArray<nsRefPtr<nsFrameLoader> > loaders;
|
|
|
|
mFinalizableFrameLoaders.SwapElements(loaders);
|
|
|
|
for (PRUint32 i = 0; i < length; ++i) {
|
|
|
|
loaders[i]->Finalize();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-24 03:33:22 -07:00
|
|
|
void
|
|
|
|
nsDocument::TryCancelFrameLoaderInitialization(nsIDocShell* aShell)
|
|
|
|
{
|
|
|
|
PRUint32 length = mInitializableFrameLoaders.Length();
|
|
|
|
for (PRUint32 i = 0; i < length; ++i) {
|
|
|
|
if (mInitializableFrameLoaders[i]->GetExistingDocShell() == aShell) {
|
|
|
|
mInitializableFrameLoaders.RemoveElementAt(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-04-29 00:18:55 -07:00
|
|
|
PRBool
|
|
|
|
nsDocument::FrameLoaderScheduledToBeFinalized(nsIDocShell* aShell)
|
|
|
|
{
|
|
|
|
if (aShell) {
|
|
|
|
PRUint32 length = mFinalizableFrameLoaders.Length();
|
|
|
|
for (PRUint32 i = 0; i < length; ++i) {
|
|
|
|
if (mFinalizableFrameLoaders[i]->GetExistingDocShell() == aShell) {
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
2008-10-04 13:00:09 -07:00
|
|
|
nsIDocument*
|
|
|
|
nsDocument::RequestExternalResource(nsIURI* aURI,
|
|
|
|
nsINode* aRequestingNode,
|
|
|
|
ExternalResourceLoad** aPendingLoad)
|
|
|
|
{
|
|
|
|
NS_PRECONDITION(aURI, "Must have a URI");
|
|
|
|
NS_PRECONDITION(aRequestingNode, "Must have a node");
|
|
|
|
if (mDisplayDocument) {
|
|
|
|
return mDisplayDocument->RequestExternalResource(aURI,
|
|
|
|
aRequestingNode,
|
|
|
|
aPendingLoad);
|
|
|
|
}
|
|
|
|
|
|
|
|
return mExternalResourceMap.RequestResource(aURI, aRequestingNode,
|
|
|
|
this, aPendingLoad);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::EnumerateExternalResources(nsSubDocEnumFunc aCallback, void* aData)
|
|
|
|
{
|
|
|
|
mExternalResourceMap.EnumerateResources(aCallback, aData);
|
|
|
|
}
|
|
|
|
|
2009-01-14 20:38:07 -08:00
|
|
|
#ifdef MOZ_SMIL
|
|
|
|
nsSMILAnimationController*
|
|
|
|
nsDocument::GetAnimationController()
|
|
|
|
{
|
|
|
|
// We create the animation controller lazily because most documents won't want
|
|
|
|
// one and only SVG documents and the like will call this
|
|
|
|
if (mAnimationController)
|
|
|
|
return mAnimationController;
|
2009-03-09 18:20:17 -07:00
|
|
|
// Refuse to create an Animation Controller if SMIL is disabled
|
|
|
|
if (!NS_SMILEnabled())
|
|
|
|
return nsnull;
|
2009-01-14 20:38:07 -08:00
|
|
|
|
|
|
|
mAnimationController = NS_NewSMILAnimationController(this);
|
|
|
|
|
|
|
|
// If there's a presContext then check the animation mode and pause if
|
|
|
|
// necessary.
|
|
|
|
nsIPresShell *shell = GetPrimaryShell();
|
|
|
|
if (mAnimationController && shell) {
|
|
|
|
nsPresContext *context = shell->GetPresContext();
|
|
|
|
if (context &&
|
|
|
|
context->ImageAnimationMode() == imgIContainer::kDontAnimMode) {
|
|
|
|
mAnimationController->Pause(nsSMILTimeContainer::PAUSE_USERPREF);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return mAnimationController;
|
|
|
|
}
|
|
|
|
#endif // MOZ_SMIL
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
struct DirTable {
|
|
|
|
const char* mName;
|
|
|
|
PRUint8 mValue;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const DirTable dirAttributes[] = {
|
|
|
|
{"ltr", IBMBIDI_TEXTDIRECTION_LTR},
|
|
|
|
{"rtl", IBMBIDI_TEXTDIRECTION_RTL},
|
|
|
|
{0}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Retrieve the "direction" property of the document.
|
|
|
|
*
|
|
|
|
* @lina 01/09/2001
|
|
|
|
*/
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetDir(nsAString& aDirection)
|
|
|
|
{
|
|
|
|
PRUint32 options = GetBidiOptions();
|
|
|
|
for (const DirTable* elt = dirAttributes; elt->mName; elt++) {
|
|
|
|
if (GET_BIDI_OPTION_DIRECTION(options) == elt->mValue) {
|
|
|
|
CopyASCIItoUTF16(elt->mName, aDirection);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the "direction" property of the document.
|
|
|
|
*
|
|
|
|
* @lina 01/09/2001
|
|
|
|
*/
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::SetDir(const nsAString& aDirection)
|
|
|
|
{
|
|
|
|
PRUint32 options = GetBidiOptions();
|
|
|
|
|
|
|
|
for (const DirTable* elt = dirAttributes; elt->mName; elt++) {
|
|
|
|
if (aDirection == NS_ConvertASCIItoUTF16(elt->mName)) {
|
|
|
|
if (GET_BIDI_OPTION_DIRECTION(options) != elt->mValue) {
|
|
|
|
SET_BIDI_OPTION_DIRECTION(options, elt->mValue);
|
2007-05-01 15:24:20 -07:00
|
|
|
nsIPresShell *shell = GetPrimaryShell();
|
2007-03-22 10:30:00 -07:00
|
|
|
if (shell) {
|
|
|
|
nsPresContext *context = shell->GetPresContext();
|
|
|
|
NS_ENSURE_TRUE(context, NS_ERROR_UNEXPECTED);
|
|
|
|
context->SetBidi(options, PR_TRUE);
|
|
|
|
} else {
|
|
|
|
// No presentation; just set it on ourselves
|
|
|
|
SetBidiOptions(options);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// nsIDOMNode methods
|
|
|
|
//
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetNodeName(nsAString& aNodeName)
|
|
|
|
{
|
|
|
|
aNodeName.AssignLiteral("#document");
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetNodeValue(nsAString& aNodeValue)
|
|
|
|
{
|
|
|
|
SetDOMStringToNull(aNodeValue);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::SetNodeValue(const nsAString& aNodeValue)
|
|
|
|
{
|
|
|
|
// The DOM spec says that when nodeValue is defined to be null "setting it
|
|
|
|
// has no effect", so we don't throw an exception.
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetNodeType(PRUint16* aNodeType)
|
|
|
|
{
|
|
|
|
*aNodeType = nsIDOMNode::DOCUMENT_NODE;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetParentNode(nsIDOMNode** aParentNode)
|
|
|
|
{
|
|
|
|
*aParentNode = nsnull;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetChildNodes(nsIDOMNodeList** aChildNodes)
|
|
|
|
{
|
2009-01-02 09:00:18 -08:00
|
|
|
return nsINode::GetChildNodes(aChildNodes);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::HasChildNodes(PRBool* aHasChildNodes)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aHasChildNodes);
|
|
|
|
|
|
|
|
*aHasChildNodes = (mChildren.ChildCount() != 0);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::HasAttributes(PRBool* aHasAttributes)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aHasAttributes);
|
|
|
|
|
|
|
|
*aHasAttributes = PR_FALSE;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetFirstChild(nsIDOMNode** aFirstChild)
|
|
|
|
{
|
2009-01-02 09:00:18 -08:00
|
|
|
return nsINode::GetFirstChild(aFirstChild);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetLastChild(nsIDOMNode** aLastChild)
|
|
|
|
{
|
2009-01-02 09:00:18 -08:00
|
|
|
return nsINode::GetLastChild(aLastChild);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetPreviousSibling(nsIDOMNode** aPreviousSibling)
|
|
|
|
{
|
|
|
|
*aPreviousSibling = nsnull;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetNextSibling(nsIDOMNode** aNextSibling)
|
|
|
|
{
|
|
|
|
*aNextSibling = nsnull;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetAttributes(nsIDOMNamedNodeMap** aAttributes)
|
|
|
|
{
|
|
|
|
*aAttributes = nsnull;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetNamespaceURI(nsAString& aNamespaceURI)
|
|
|
|
{
|
|
|
|
SetDOMStringToNull(aNamespaceURI);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetPrefix(nsAString& aPrefix)
|
|
|
|
{
|
|
|
|
SetDOMStringToNull(aPrefix);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::SetPrefix(const nsAString& aPrefix)
|
|
|
|
{
|
|
|
|
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetLocalName(nsAString& aLocalName)
|
|
|
|
{
|
|
|
|
SetDOMStringToNull(aLocalName);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::InsertBefore(nsIDOMNode* aNewChild, nsIDOMNode* aRefChild,
|
|
|
|
nsIDOMNode** aReturn)
|
|
|
|
{
|
|
|
|
return nsGenericElement::doReplaceOrInsertBefore(PR_FALSE, aNewChild, aRefChild, nsnull, this,
|
|
|
|
aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::ReplaceChild(nsIDOMNode* aNewChild, nsIDOMNode* aOldChild,
|
|
|
|
nsIDOMNode** aReturn)
|
|
|
|
{
|
|
|
|
return nsGenericElement::doReplaceOrInsertBefore(PR_TRUE, aNewChild, aOldChild, nsnull, this,
|
|
|
|
aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::RemoveChild(nsIDOMNode* aOldChild, nsIDOMNode** aReturn)
|
|
|
|
{
|
|
|
|
return nsGenericElement::doRemoveChild(aOldChild, nsnull, this, aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::AppendChild(nsIDOMNode* aNewChild, nsIDOMNode** aReturn)
|
|
|
|
{
|
|
|
|
return nsDocument::InsertBefore(aNewChild, nsnull, aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::CloneNode(PRBool aDeep, nsIDOMNode** aReturn)
|
|
|
|
{
|
2008-09-18 04:15:47 -07:00
|
|
|
return nsNodeUtils::CloneNodeImpl(this, aDeep, aReturn);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::Normalize()
|
|
|
|
{
|
|
|
|
PRInt32 count = mChildren.ChildCount();
|
|
|
|
for (PRInt32 i = 0; i < count; ++i) {
|
|
|
|
nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mChildren.ChildAt(i)));
|
|
|
|
|
|
|
|
if (node) {
|
|
|
|
node->Normalize();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::IsSupported(const nsAString& aFeature, const nsAString& aVersion,
|
|
|
|
PRBool* aReturn)
|
|
|
|
{
|
2007-07-08 00:08:04 -07:00
|
|
|
return nsGenericElement::InternalIsSupported(static_cast<nsIDOMDocument*>(this),
|
2007-03-22 10:30:00 -07:00
|
|
|
aFeature, aVersion, aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetBaseURI(nsAString &aURI)
|
|
|
|
{
|
|
|
|
nsCAutoString spec;
|
2009-09-25 09:50:26 -07:00
|
|
|
if (nsIDocument::GetBaseURI()) {
|
|
|
|
nsIDocument::GetBaseURI()->GetSpec(spec);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
CopyUTF8toUTF16(spec, aURI);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetTextContent(nsAString &aTextContent)
|
|
|
|
{
|
|
|
|
SetDOMStringToNull(aTextContent);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::SetTextContent(const nsAString& aTextContent)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::CompareDocumentPosition(nsIDOMNode* aOther, PRUint16* aReturn)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aOther);
|
|
|
|
|
|
|
|
// We could optimize this by getting the other nodes current document
|
|
|
|
// and comparing with ourself. But then we'd have to deal with the
|
|
|
|
// current document being null and such so it's easier this way.
|
|
|
|
// It's hardly a case to optimize anyway.
|
|
|
|
|
|
|
|
nsCOMPtr<nsINode> other = do_QueryInterface(aOther);
|
|
|
|
NS_ENSURE_TRUE(other, NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
|
|
|
|
|
|
|
*aReturn = nsContentUtils::ComparePosition(other, this);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::IsSameNode(nsIDOMNode* aOther, PRBool* aReturn)
|
|
|
|
{
|
|
|
|
PRBool sameNode = PR_FALSE;
|
|
|
|
|
|
|
|
if (this == aOther) {
|
|
|
|
sameNode = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
*aReturn = sameNode;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::IsEqualNode(nsIDOMNode* aOther, PRBool* aReturn)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aOther);
|
|
|
|
|
|
|
|
*aReturn = PR_FALSE;
|
|
|
|
|
|
|
|
// Node type check by QI. We also reuse this later.
|
|
|
|
nsCOMPtr<nsIDocument> aOtherDoc = do_QueryInterface(aOther);
|
|
|
|
if (!aOtherDoc) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Child nodes check.
|
|
|
|
PRUint32 childCount = GetChildCount();
|
|
|
|
if (childCount != aOtherDoc->GetChildCount()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (PRUint32 i = 0; i < childCount; i++) {
|
|
|
|
nsIContent* aChild1 = GetChildAt(i);
|
|
|
|
nsIContent* aChild2 = aOtherDoc->GetChildAt(i);
|
|
|
|
if (!nsNode3Tearoff::AreNodesEqual(aChild1, aChild2)) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Checks not needed: Prefix, namespace URI, local name, node name,
|
|
|
|
node value, attributes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
*aReturn = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::IsDefaultNamespace(const nsAString& aNamespaceURI,
|
|
|
|
PRBool* aReturn)
|
|
|
|
{
|
|
|
|
nsAutoString defaultNamespace;
|
|
|
|
LookupNamespaceURI(EmptyString(), defaultNamespace);
|
|
|
|
*aReturn = aNamespaceURI.Equals(defaultNamespace);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetFeature(const nsAString& aFeature,
|
|
|
|
const nsAString& aVersion,
|
|
|
|
nsISupports** aReturn)
|
|
|
|
{
|
2007-07-08 00:08:04 -07:00
|
|
|
return nsGenericElement::InternalGetFeature(static_cast<nsIDOMDocument*>(this),
|
2007-03-22 10:30:00 -07:00
|
|
|
aFeature, aVersion, aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::SetUserData(const nsAString &aKey,
|
|
|
|
nsIVariant *aData,
|
|
|
|
nsIDOMUserDataHandler *aHandler,
|
|
|
|
nsIVariant **aResult)
|
|
|
|
{
|
2007-05-12 08:36:28 -07:00
|
|
|
return nsNodeUtils::SetUserData(this, aKey, aData, aHandler, aResult);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetUserData(const nsAString &aKey,
|
|
|
|
nsIVariant **aResult)
|
|
|
|
{
|
2007-05-12 08:36:28 -07:00
|
|
|
return nsNodeUtils::GetUserData(this, aKey, aResult);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::LookupPrefix(const nsAString& aNamespaceURI,
|
|
|
|
nsAString& aPrefix)
|
|
|
|
{
|
2007-12-11 18:26:09 -08:00
|
|
|
nsCOMPtr<nsIDOM3Node> root(do_QueryInterface(GetRootContent()));
|
2007-03-22 10:30:00 -07:00
|
|
|
if (root) {
|
|
|
|
return root->LookupPrefix(aNamespaceURI, aPrefix);
|
|
|
|
}
|
|
|
|
|
|
|
|
SetDOMStringToNull(aPrefix);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::LookupNamespaceURI(const nsAString& aNamespacePrefix,
|
|
|
|
nsAString& aNamespaceURI)
|
|
|
|
{
|
2007-12-11 18:26:09 -08:00
|
|
|
if (NS_FAILED(nsContentUtils::LookupNamespaceURI(GetRootContent(),
|
2007-03-22 10:30:00 -07:00
|
|
|
aNamespacePrefix,
|
|
|
|
aNamespaceURI))) {
|
|
|
|
SetDOMStringToNull(aNamespaceURI);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetInputEncoding(nsAString& aInputEncoding)
|
|
|
|
{
|
2008-08-06 13:59:37 -07:00
|
|
|
if (mHaveInputEncoding) {
|
|
|
|
return GetCharacterSet(aInputEncoding);
|
|
|
|
}
|
|
|
|
|
|
|
|
SetDOMStringToNull(aInputEncoding);
|
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetXmlEncoding(nsAString& aXmlEncoding)
|
|
|
|
{
|
|
|
|
if (mXMLDeclarationBits & XML_DECLARATION_BITS_DECLARATION_EXISTS &&
|
|
|
|
mXMLDeclarationBits & XML_DECLARATION_BITS_ENCODING_EXISTS) {
|
|
|
|
// XXX We don't store the encoding given in the xml declaration.
|
|
|
|
// For now, just output the inputEncoding which we do store.
|
|
|
|
GetInputEncoding(aXmlEncoding);
|
|
|
|
} else {
|
|
|
|
SetDOMStringToNull(aXmlEncoding);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetXmlStandalone(PRBool *aXmlStandalone)
|
|
|
|
{
|
|
|
|
*aXmlStandalone =
|
|
|
|
mXMLDeclarationBits & XML_DECLARATION_BITS_DECLARATION_EXISTS &&
|
|
|
|
mXMLDeclarationBits & XML_DECLARATION_BITS_STANDALONE_EXISTS &&
|
|
|
|
mXMLDeclarationBits & XML_DECLARATION_BITS_STANDALONE_YES;
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::SetXmlStandalone(PRBool aXmlStandalone)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetXmlVersion(nsAString& aXmlVersion)
|
|
|
|
{
|
|
|
|
// If there is no declaration, the value is "1.0".
|
|
|
|
|
|
|
|
// XXX We only support "1.0", so always output "1.0" until that changes.
|
|
|
|
aXmlVersion.AssignLiteral("1.0");
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::SetXmlVersion(const nsAString& aXmlVersion)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetStrictErrorChecking(PRBool *aStrictErrorChecking)
|
|
|
|
{
|
|
|
|
// This attribute is true by default, and we don't really support it being false.
|
|
|
|
*aStrictErrorChecking = PR_TRUE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::SetStrictErrorChecking(PRBool aStrictErrorChecking)
|
|
|
|
{
|
|
|
|
// We don't really support non-strict error checking, so just no-op for now.
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetDocumentURI(nsAString& aDocumentURI)
|
|
|
|
{
|
|
|
|
if (mDocumentURI) {
|
|
|
|
nsCAutoString uri;
|
|
|
|
mDocumentURI->GetSpec(uri);
|
|
|
|
CopyUTF8toUTF16(uri, aDocumentURI);
|
|
|
|
} else {
|
|
|
|
SetDOMStringToNull(aDocumentURI);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::SetDocumentURI(const nsAString& aDocumentURI)
|
|
|
|
{
|
|
|
|
// Not allowing this yet, need to think about security ramifications first.
|
|
|
|
// We use mDocumentURI to get principals for this document.
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void BlastSubtreeToPieces(nsINode *aNode);
|
|
|
|
|
2008-10-10 08:04:34 -07:00
|
|
|
PLDHashOperator
|
2007-03-22 10:30:00 -07:00
|
|
|
BlastFunc(nsAttrHashKey::KeyType aKey, nsIDOMNode *aData, void* aUserArg)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIAttribute> *attr =
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<nsCOMPtr<nsIAttribute>*>(aUserArg);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
*attr = do_QueryInterface(aData);
|
|
|
|
|
|
|
|
NS_ASSERTION(attr->get(),
|
|
|
|
"non-nsIAttribute somehow made it into the hashmap?!");
|
|
|
|
|
|
|
|
return PL_DHASH_STOP;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
BlastSubtreeToPieces(nsINode *aNode)
|
|
|
|
{
|
|
|
|
PRUint32 i, count;
|
|
|
|
if (aNode->IsNodeOfType(nsINode::eELEMENT)) {
|
2007-07-08 00:08:04 -07:00
|
|
|
nsGenericElement *element = static_cast<nsGenericElement*>(aNode);
|
2007-03-22 10:30:00 -07:00
|
|
|
const nsDOMAttributeMap *map = element->GetAttributeMap();
|
|
|
|
if (map) {
|
|
|
|
nsCOMPtr<nsIAttribute> attr;
|
|
|
|
while (map->Enumerate(BlastFunc, &attr) > 0) {
|
|
|
|
BlastSubtreeToPieces(attr);
|
|
|
|
|
2008-09-23 21:37:56 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
nsresult rv =
|
|
|
|
#endif
|
|
|
|
element->UnsetAttr(attr->NodeInfo()->NamespaceID(),
|
|
|
|
attr->NodeInfo()->NameAtom(),
|
|
|
|
PR_FALSE);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// XXX Should we abort here?
|
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "Uhoh, UnsetAttr shouldn't fail!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
count = aNode->GetChildCount();
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
|
|
BlastSubtreeToPieces(aNode->GetChildAt(0));
|
2008-09-23 21:37:56 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
nsresult rv =
|
|
|
|
#endif
|
|
|
|
aNode->RemoveChildAt(0, PR_FALSE);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// XXX Should we abort here?
|
|
|
|
NS_ASSERTION(NS_SUCCEEDED(rv), "Uhoh, RemoveChildAt shouldn't fail!");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::AdoptNode(nsIDOMNode *aAdoptedNode, nsIDOMNode **aResult)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG(aAdoptedNode);
|
|
|
|
|
|
|
|
*aResult = nsnull;
|
|
|
|
|
|
|
|
nsresult rv = nsContentUtils::CheckSameOrigin(this, aAdoptedNode);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsINode> adoptedNode;
|
|
|
|
PRUint16 nodeType;
|
|
|
|
aAdoptedNode->GetNodeType(&nodeType);
|
|
|
|
switch (nodeType) {
|
|
|
|
case nsIDOMNode::ATTRIBUTE_NODE:
|
|
|
|
{
|
|
|
|
// Remove from ownerElement.
|
|
|
|
nsCOMPtr<nsIDOMAttr> adoptedAttr = do_QueryInterface(aAdoptedNode, &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMElement> ownerElement;
|
|
|
|
rv = adoptedAttr->GetOwnerElement(getter_AddRefs(ownerElement));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (ownerElement) {
|
|
|
|
nsCOMPtr<nsIDOMAttr> newAttr;
|
|
|
|
rv = ownerElement->RemoveAttributeNode(adoptedAttr,
|
|
|
|
getter_AddRefs(newAttr));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
newAttr.swap(adoptedAttr);
|
|
|
|
}
|
|
|
|
|
|
|
|
adoptedNode = do_QueryInterface(adoptedAttr, &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case nsIDOMNode::DOCUMENT_FRAGMENT_NODE:
|
|
|
|
case nsIDOMNode::ELEMENT_NODE:
|
|
|
|
case nsIDOMNode::PROCESSING_INSTRUCTION_NODE:
|
|
|
|
case nsIDOMNode::TEXT_NODE:
|
|
|
|
case nsIDOMNode::CDATA_SECTION_NODE:
|
|
|
|
case nsIDOMNode::COMMENT_NODE:
|
|
|
|
{
|
|
|
|
adoptedNode = do_QueryInterface(aAdoptedNode, &rv);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// We don't want to adopt an element into its own contentDocument or into
|
|
|
|
// a descendant contentDocument, so we check if the frameElement of this
|
|
|
|
// document or any of its parents is the adopted node or one of its
|
|
|
|
// descendants.
|
|
|
|
nsIDocument *doc = this;
|
|
|
|
do {
|
|
|
|
nsPIDOMWindow *win = doc->GetWindow();
|
|
|
|
if (win) {
|
|
|
|
nsCOMPtr<nsINode> node =
|
|
|
|
do_QueryInterface(win->GetFrameElementInternal());
|
|
|
|
if (node &&
|
|
|
|
nsContentUtils::ContentIsDescendantOf(node, adoptedNode)) {
|
|
|
|
return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} while ((doc = doc->GetParentDocument()));
|
|
|
|
|
|
|
|
// Remove from parent.
|
|
|
|
nsCOMPtr<nsIDOMNode> parent;
|
|
|
|
aAdoptedNode->GetParentNode(getter_AddRefs(parent));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
if (parent) {
|
|
|
|
nsCOMPtr<nsIDOMNode> newChild;
|
|
|
|
rv = parent->RemoveChild(aAdoptedNode, getter_AddRefs(newChild));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case nsIDOMNode::ENTITY_REFERENCE_NODE:
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
case nsIDOMNode::DOCUMENT_NODE:
|
|
|
|
case nsIDOMNode::DOCUMENT_TYPE_NODE:
|
|
|
|
case nsIDOMNode::ENTITY_NODE:
|
|
|
|
case nsIDOMNode::NOTATION_NODE:
|
|
|
|
{
|
|
|
|
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
NS_WARNING("Don't know how to adopt this nodetype for adoptNode.");
|
|
|
|
|
|
|
|
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIDocument *oldDocument = adoptedNode->GetOwnerDoc();
|
|
|
|
PRBool sameDocument = oldDocument == this;
|
|
|
|
|
|
|
|
JSContext *cx = nsnull;
|
|
|
|
JSObject *oldScope = nsnull;
|
|
|
|
JSObject *newScope = nsnull;
|
|
|
|
if (!sameDocument && oldDocument) {
|
|
|
|
rv = nsContentUtils::GetContextAndScopes(oldDocument, this, &cx, &oldScope,
|
|
|
|
&newScope);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMArray<nsINode> nodesWithProperties;
|
|
|
|
rv = nsNodeUtils::Adopt(adoptedNode, sameDocument ? nsnull : mNodeInfoManager,
|
|
|
|
cx, oldScope, newScope, nodesWithProperties);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
// Disconnect all nodes from their parents, since some have the old document
|
|
|
|
// as their ownerDocument and some have this as their ownerDocument.
|
|
|
|
BlastSubtreeToPieces(adoptedNode);
|
|
|
|
|
|
|
|
if (!sameDocument && oldDocument) {
|
|
|
|
PRUint32 i, count = nodesWithProperties.Count();
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
|
|
// Remove all properties.
|
|
|
|
oldDocument->PropertyTable()->
|
|
|
|
DeleteAllPropertiesFor(nodesWithProperties[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRUint32 i, count = nodesWithProperties.Count();
|
|
|
|
if (!sameDocument && oldDocument) {
|
|
|
|
nsPropertyTable *oldTable = oldDocument->PropertyTable();
|
|
|
|
nsPropertyTable *newTable = PropertyTable();
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
|
|
rv = oldTable->TransferOrDeleteAllPropertiesFor(nodesWithProperties[i],
|
|
|
|
newTable);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
while (++i < count) {
|
|
|
|
oldTable->DeleteAllPropertiesFor(nodesWithProperties[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Disconnect all nodes from their parents.
|
|
|
|
BlastSubtreeToPieces(adoptedNode);
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = nsNodeUtils::CallUserDataHandlers(nodesWithProperties, this,
|
|
|
|
nsIDOMUserDataHandler::NODE_ADOPTED,
|
|
|
|
PR_FALSE);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
return CallQueryInterface(adoptedNode, aResult);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetDomConfig(nsIDOMDOMConfiguration **aConfig)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::NormalizeDocument()
|
|
|
|
{
|
|
|
|
// We don't support DOMConfigurations yet, so this just
|
|
|
|
// does a straight shot of normalization.
|
|
|
|
return Normalize();
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::RenameNode(nsIDOMNode *aNode,
|
|
|
|
const nsAString& namespaceURI,
|
|
|
|
const nsAString& qualifiedName,
|
|
|
|
nsIDOMNode **aReturn)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetOwnerDocument(nsIDOMDocument** aOwnerDocument)
|
|
|
|
{
|
2009-01-02 09:00:18 -08:00
|
|
|
return nsINode::GetOwnerDocument(aOwnerDocument);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2009-06-23 04:23:52 -07:00
|
|
|
nsIEventListenerManager*
|
|
|
|
nsDocument::GetListenerManager(PRBool aCreateIfNotFound)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2009-06-23 04:23:52 -07:00
|
|
|
if (mListenerManager || !aCreateIfNotFound) {
|
|
|
|
return mListenerManager;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult rv = NS_NewEventListenerManager(getter_AddRefs(mListenerManager));
|
2009-06-23 04:23:52 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, nsnull);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-07-08 00:08:04 -07:00
|
|
|
mListenerManager->SetListenerTarget(static_cast<nsIDocument *>(this));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2009-06-23 04:23:52 -07:00
|
|
|
return mListenerManager;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-05-14 02:29:22 -07:00
|
|
|
nsresult
|
2007-03-22 10:30:00 -07:00
|
|
|
nsDocument::GetSystemEventGroup(nsIDOMEventGroup **aGroup)
|
|
|
|
{
|
2009-06-23 04:23:52 -07:00
|
|
|
nsIEventListenerManager* manager = GetListenerManager(PR_TRUE);
|
|
|
|
NS_ENSURE_STATE(manager);
|
|
|
|
return manager->GetSystemEventGroupLM(aGroup);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDocument::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
|
|
|
|
{
|
|
|
|
aVisitor.mCanHandle = PR_TRUE;
|
|
|
|
// FIXME! This is a hack to make middle mouse paste working also in Editor.
|
|
|
|
// Bug 329119
|
|
|
|
aVisitor.mForceContentDispatch = PR_TRUE;
|
|
|
|
|
|
|
|
// Load events must not propagate to |window| object, see bug 335251.
|
|
|
|
if (aVisitor.mEvent->message != NS_LOAD) {
|
2008-10-08 04:35:29 -07:00
|
|
|
nsCOMPtr<nsPIDOMEventTarget> parentTarget = do_QueryInterface(GetWindow());
|
|
|
|
aVisitor.mParentTarget = parentTarget;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDocument::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
|
|
|
|
{
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDocument::DispatchDOMEvent(nsEvent* aEvent,
|
|
|
|
nsIDOMEvent* aDOMEvent,
|
|
|
|
nsPresContext* aPresContext,
|
|
|
|
nsEventStatus* aEventStatus)
|
|
|
|
{
|
2007-07-08 00:08:04 -07:00
|
|
|
return nsEventDispatcher::DispatchDOMEvent(static_cast<nsINode*>(this),
|
2007-03-22 10:30:00 -07:00
|
|
|
aEvent, aDOMEvent,
|
|
|
|
aPresContext, aEventStatus);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDocument::AddEventListenerByIID(nsIDOMEventListener *aListener,
|
|
|
|
const nsIID& aIID)
|
|
|
|
{
|
2009-06-23 04:23:52 -07:00
|
|
|
nsIEventListenerManager* manager = GetListenerManager(PR_TRUE);
|
|
|
|
NS_ENSURE_STATE(manager);
|
|
|
|
return manager->AddEventListenerByIID(aListener, aIID, NS_EVENT_FLAG_BUBBLE);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDocument::RemoveEventListenerByIID(nsIDOMEventListener *aListener,
|
|
|
|
const nsIID& aIID)
|
|
|
|
{
|
2009-06-23 04:23:52 -07:00
|
|
|
return mListenerManager ?
|
|
|
|
mListenerManager->RemoveEventListenerByIID(aListener, aIID,
|
|
|
|
NS_EVENT_FLAG_BUBBLE) :
|
|
|
|
NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDocument::AddEventListener(const nsAString& aType,
|
|
|
|
nsIDOMEventListener* aListener,
|
|
|
|
PRBool aUseCapture)
|
|
|
|
{
|
|
|
|
return AddEventListener(aType, aListener, aUseCapture,
|
|
|
|
!nsContentUtils::IsChromeDoc(this));
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDocument::RemoveEventListener(const nsAString& aType,
|
|
|
|
nsIDOMEventListener* aListener,
|
|
|
|
PRBool aUseCapture)
|
|
|
|
{
|
|
|
|
return RemoveGroupedEventListener(aType, aListener, aUseCapture, nsnull);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::DispatchEvent(nsIDOMEvent* aEvent, PRBool *_retval)
|
|
|
|
{
|
|
|
|
// Obtain a presentation context
|
2007-05-01 15:24:20 -07:00
|
|
|
nsIPresShell *shell = GetPrimaryShell();
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsPresContext> context;
|
|
|
|
if (shell) {
|
|
|
|
context = shell->GetPresContext();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsEventStatus status = nsEventStatus_eIgnore;
|
|
|
|
nsresult rv =
|
2007-07-08 00:08:04 -07:00
|
|
|
nsEventDispatcher::DispatchDOMEvent(static_cast<nsINode*>(this),
|
2007-03-22 10:30:00 -07:00
|
|
|
nsnull, aEvent, context, &status);
|
|
|
|
|
|
|
|
*_retval = (status != nsEventStatus_eConsumeNoDefault);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::AddGroupedEventListener(const nsAString& aType,
|
|
|
|
nsIDOMEventListener *aListener,
|
|
|
|
PRBool aUseCapture,
|
|
|
|
nsIDOMEventGroup *aEvtGrp)
|
|
|
|
{
|
2009-06-23 04:23:52 -07:00
|
|
|
nsIEventListenerManager* manager = GetListenerManager(PR_TRUE);
|
|
|
|
NS_ENSURE_STATE(manager);
|
|
|
|
PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
|
|
|
|
return manager->AddEventListenerByType(aListener, aType, flags, aEvtGrp);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::RemoveGroupedEventListener(const nsAString& aType,
|
|
|
|
nsIDOMEventListener *aListener,
|
|
|
|
PRBool aUseCapture,
|
|
|
|
nsIDOMEventGroup *aEvtGrp)
|
|
|
|
{
|
2009-06-23 04:23:52 -07:00
|
|
|
if (mListenerManager) {
|
|
|
|
PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
|
|
|
|
mListenerManager->RemoveEventListenerByType(aListener, aType, flags,
|
|
|
|
aEvtGrp);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::CanTrigger(const nsAString & type, PRBool *_retval)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::IsRegisteredHere(const nsAString & type, PRBool *_retval)
|
|
|
|
{
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::AddEventListener(const nsAString& aType,
|
|
|
|
nsIDOMEventListener *aListener,
|
|
|
|
PRBool aUseCapture, PRBool aWantsUntrusted)
|
|
|
|
{
|
2009-06-23 04:23:52 -07:00
|
|
|
nsIEventListenerManager* manager = GetListenerManager(PR_TRUE);
|
|
|
|
NS_ENSURE_STATE(manager);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
PRInt32 flags = aUseCapture ? NS_EVENT_FLAG_CAPTURE : NS_EVENT_FLAG_BUBBLE;
|
|
|
|
|
|
|
|
if (aWantsUntrusted) {
|
|
|
|
flags |= NS_PRIV_EVENT_UNTRUSTED_PERMITTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return manager->AddEventListenerByType(aListener, aType, flags, nsnull);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::CreateEvent(const nsAString& aEventType, nsIDOMEvent** aReturn)
|
|
|
|
{
|
|
|
|
NS_ENSURE_ARG_POINTER(aReturn);
|
|
|
|
*aReturn = nsnull;
|
|
|
|
|
|
|
|
// Obtain a presentation shell
|
|
|
|
|
2007-05-01 15:24:20 -07:00
|
|
|
nsIPresShell *shell = GetPrimaryShell();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsPresContext *presContext = nsnull;
|
|
|
|
|
|
|
|
if (shell) {
|
|
|
|
// Retrieve the context
|
|
|
|
presContext = shell->GetPresContext();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create event even without presContext.
|
|
|
|
return nsEventDispatcher::CreateEvent(presContext, nsnull,
|
|
|
|
aEventType, aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::CreateEventGroup(nsIDOMEventGroup **aInstancePtrResult)
|
|
|
|
{
|
|
|
|
nsresult rv;
|
|
|
|
nsCOMPtr<nsIDOMEventGroup> group(do_CreateInstance(kDOMEventGroupCID, &rv));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
*aInstancePtrResult = group;
|
|
|
|
NS_ADDREF(*aInstancePtrResult);
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::FlushPendingNotifications(mozFlushType aType)
|
|
|
|
{
|
2007-09-20 19:41:08 -07:00
|
|
|
nsCOMPtr<nsIContentSink> sink;
|
|
|
|
if (mParser) {
|
|
|
|
sink = mParser->GetContentSink();
|
|
|
|
} else {
|
|
|
|
sink = do_QueryReferent(mWeakSink);
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
// Determine if it is safe to flush the sink notifications
|
|
|
|
// by determining if it safe to flush all the presshells.
|
2007-09-20 19:41:08 -07:00
|
|
|
if (sink && (aType == Flush_Content || IsSafeToFlush())) {
|
|
|
|
sink->FlushPendingNotifications(aType);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Should we be flushing pending binding constructors in here?
|
|
|
|
|
2008-09-28 12:14:28 -07:00
|
|
|
if (aType <= Flush_ContentAndNotify) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// Nothing to do here
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-02-08 13:44:04 -08:00
|
|
|
// If we have a parent we must flush the parent too to ensure that our
|
2009-07-27 01:46:59 -07:00
|
|
|
// container is reflowed if its size was changed. But if it's not safe to
|
2008-02-08 13:44:04 -08:00
|
|
|
// flush ourselves, then don't flush the parent, since that can cause things
|
|
|
|
// like resizes of our frame's widget, which we can't handle while flushing
|
|
|
|
// is unsafe.
|
2008-07-26 09:14:49 -07:00
|
|
|
// Since media queries mean that a size change of our container can
|
|
|
|
// affect style, we need to promote a style flush on ourself to a
|
|
|
|
// layout flush on our parent, since we need our container to be the
|
|
|
|
// correct size to determine the correct style.
|
2008-02-08 13:44:04 -08:00
|
|
|
if (mParentDocument && IsSafeToFlush()) {
|
2008-07-26 09:14:49 -07:00
|
|
|
mozFlushType parentType = aType;
|
2009-04-21 16:53:52 -07:00
|
|
|
if (aType >= Flush_Style)
|
|
|
|
parentType = PR_MAX(Flush_Layout, aType);
|
2008-07-26 09:14:49 -07:00
|
|
|
mParentDocument->FlushPendingNotifications(parentType);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-05-22 14:45:03 -07:00
|
|
|
nsPresShellIterator iter(this);
|
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
while ((shell = iter.GetNextShell())) {
|
|
|
|
shell->FlushPendingNotifications(aType);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIScriptEventManager*
|
|
|
|
nsDocument::GetScriptEventManager()
|
|
|
|
{
|
|
|
|
if (!mScriptEventManager) {
|
|
|
|
mScriptEventManager = new nsScriptEventManager(this);
|
|
|
|
// automatically AddRefs
|
|
|
|
}
|
|
|
|
|
|
|
|
return mScriptEventManager;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::SetXMLDeclaration(const PRUnichar *aVersion,
|
|
|
|
const PRUnichar *aEncoding,
|
|
|
|
const PRInt32 aStandalone)
|
|
|
|
{
|
|
|
|
if (!aVersion || *aVersion == '\0') {
|
|
|
|
mXMLDeclarationBits = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mXMLDeclarationBits = XML_DECLARATION_BITS_DECLARATION_EXISTS;
|
|
|
|
|
|
|
|
if (aEncoding && *aEncoding != '\0') {
|
|
|
|
mXMLDeclarationBits |= XML_DECLARATION_BITS_ENCODING_EXISTS;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aStandalone == 1) {
|
|
|
|
mXMLDeclarationBits |= XML_DECLARATION_BITS_STANDALONE_EXISTS |
|
|
|
|
XML_DECLARATION_BITS_STANDALONE_YES;
|
|
|
|
}
|
|
|
|
else if (aStandalone == 0) {
|
|
|
|
mXMLDeclarationBits |= XML_DECLARATION_BITS_STANDALONE_EXISTS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::GetXMLDeclaration(nsAString& aVersion, nsAString& aEncoding,
|
|
|
|
nsAString& aStandalone)
|
|
|
|
{
|
|
|
|
aVersion.Truncate();
|
|
|
|
aEncoding.Truncate();
|
|
|
|
aStandalone.Truncate();
|
|
|
|
|
|
|
|
if (!(mXMLDeclarationBits & XML_DECLARATION_BITS_DECLARATION_EXISTS)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// always until we start supporting 1.1 etc.
|
|
|
|
aVersion.AssignLiteral("1.0");
|
|
|
|
|
|
|
|
if (mXMLDeclarationBits & XML_DECLARATION_BITS_ENCODING_EXISTS) {
|
|
|
|
// This is what we have stored, not necessarily what was written
|
|
|
|
// in the original
|
|
|
|
GetCharacterSet(aEncoding);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mXMLDeclarationBits & XML_DECLARATION_BITS_STANDALONE_EXISTS) {
|
|
|
|
if (mXMLDeclarationBits & XML_DECLARATION_BITS_STANDALONE_YES) {
|
|
|
|
aStandalone.AssignLiteral("yes");
|
|
|
|
} else {
|
|
|
|
aStandalone.AssignLiteral("no");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsDocument::IsScriptEnabled()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIScriptSecurityManager> sm(do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID));
|
2008-10-04 13:00:09 -07:00
|
|
|
NS_ENSURE_TRUE(sm, PR_FALSE);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsIScriptGlobalObject* globalObject = GetScriptGlobalObject();
|
2008-10-04 13:00:09 -07:00
|
|
|
NS_ENSURE_TRUE(globalObject, PR_FALSE);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsIScriptContext *scriptContext = globalObject->GetContext();
|
2008-10-04 13:00:09 -07:00
|
|
|
NS_ENSURE_TRUE(scriptContext, PR_FALSE);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
JSContext* cx = (JSContext *) scriptContext->GetNativeContext();
|
2008-10-04 13:00:09 -07:00
|
|
|
NS_ENSURE_TRUE(cx, PR_FALSE);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
PRBool enabled;
|
|
|
|
nsresult rv = sm->CanExecuteScripts(cx, NodePrincipal(), &enabled);
|
2008-10-04 13:00:09 -07:00
|
|
|
NS_ENSURE_SUCCESS(rv, PR_FALSE);
|
2007-03-22 10:30:00 -07:00
|
|
|
return enabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDocument::GetRadioGroup(const nsAString& aName,
|
|
|
|
nsRadioGroupStruct **aRadioGroup)
|
|
|
|
{
|
|
|
|
nsAutoString tmKey(aName);
|
2009-08-25 10:15:55 -07:00
|
|
|
if(IsHTML())
|
2007-03-22 10:30:00 -07:00
|
|
|
ToLowerCase(tmKey); //should case-insensitive.
|
2007-09-27 11:17:32 -07:00
|
|
|
if (mRadioGroups.Get(tmKey, aRadioGroup))
|
|
|
|
return NS_OK;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-09-27 11:17:32 -07:00
|
|
|
nsAutoPtr<nsRadioGroupStruct> radioGroup(new nsRadioGroupStruct());
|
|
|
|
NS_ENSURE_TRUE(radioGroup, NS_ERROR_OUT_OF_MEMORY);
|
|
|
|
NS_ENSURE_TRUE(mRadioGroups.Put(tmKey, radioGroup), NS_ERROR_OUT_OF_MEMORY);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
*aRadioGroup = radioGroup;
|
2007-09-27 11:17:32 -07:00
|
|
|
radioGroup.forget();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::SetCurrentRadioButton(const nsAString& aName,
|
|
|
|
nsIDOMHTMLInputElement* aRadio)
|
|
|
|
{
|
|
|
|
nsRadioGroupStruct* radioGroup = nsnull;
|
|
|
|
GetRadioGroup(aName, &radioGroup);
|
|
|
|
if (radioGroup) {
|
|
|
|
radioGroup->mSelectedRadioButton = aRadio;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetCurrentRadioButton(const nsAString& aName,
|
|
|
|
nsIDOMHTMLInputElement** aRadio)
|
|
|
|
{
|
|
|
|
nsRadioGroupStruct* radioGroup = nsnull;
|
|
|
|
GetRadioGroup(aName, &radioGroup);
|
|
|
|
if (radioGroup) {
|
|
|
|
*aRadio = radioGroup->mSelectedRadioButton;
|
|
|
|
NS_IF_ADDREF(*aRadio);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetPositionInGroup(nsIDOMHTMLInputElement *aRadio,
|
|
|
|
PRInt32 *aPositionIndex,
|
|
|
|
PRInt32 *aItemsInGroup)
|
|
|
|
{
|
|
|
|
*aPositionIndex = 0;
|
|
|
|
*aItemsInGroup = 1;
|
|
|
|
nsAutoString name;
|
|
|
|
aRadio->GetName(name);
|
|
|
|
if (name.IsEmpty()) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRadioGroupStruct* radioGroup = nsnull;
|
|
|
|
nsresult rv = GetRadioGroup(name, &radioGroup);
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIFormControl> radioControl(do_QueryInterface(aRadio));
|
|
|
|
NS_ASSERTION(radioControl, "Radio button should implement nsIFormControl");
|
|
|
|
*aPositionIndex = radioGroup->mRadioButtons.IndexOf(radioControl);
|
|
|
|
NS_ASSERTION(*aPositionIndex >= 0, "Radio button not found in its own group");
|
|
|
|
*aItemsInGroup = radioGroup->mRadioButtons.Count();
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetNextRadioButton(const nsAString& aName,
|
|
|
|
const PRBool aPrevious,
|
|
|
|
nsIDOMHTMLInputElement* aFocusedRadio,
|
|
|
|
nsIDOMHTMLInputElement** aRadioOut)
|
|
|
|
{
|
|
|
|
// XXX Can we combine the HTML radio button method impls of
|
|
|
|
// nsDocument and nsHTMLFormControl?
|
|
|
|
// XXX Why is HTML radio button stuff in nsDocument, as
|
|
|
|
// opposed to nsHTMLDocument?
|
|
|
|
*aRadioOut = nsnull;
|
|
|
|
|
|
|
|
nsRadioGroupStruct* radioGroup = nsnull;
|
|
|
|
GetRadioGroup(aName, &radioGroup);
|
|
|
|
if (!radioGroup) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Return the radio button relative to the focused radio button.
|
|
|
|
// If no radio is focused, get the radio relative to the selected one.
|
|
|
|
nsCOMPtr<nsIDOMHTMLInputElement> currentRadio;
|
|
|
|
if (aFocusedRadio) {
|
|
|
|
currentRadio = aFocusedRadio;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
currentRadio = radioGroup->mSelectedRadioButton;
|
|
|
|
if (!currentRadio) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nsCOMPtr<nsIFormControl> radioControl(do_QueryInterface(currentRadio));
|
|
|
|
PRInt32 index = radioGroup->mRadioButtons.IndexOf(radioControl);
|
|
|
|
if (index < 0) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRInt32 numRadios = radioGroup->mRadioButtons.Count();
|
|
|
|
PRBool disabled;
|
|
|
|
nsCOMPtr<nsIDOMHTMLInputElement> radio;
|
|
|
|
do {
|
|
|
|
if (aPrevious) {
|
|
|
|
if (--index < 0) {
|
|
|
|
index = numRadios -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (++index >= numRadios) {
|
|
|
|
index = 0;
|
|
|
|
}
|
2007-09-27 11:17:32 -07:00
|
|
|
radio = do_QueryInterface(radioGroup->mRadioButtons[index]);
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_ASSERTION(radio, "mRadioButtons holding a non-radio button");
|
|
|
|
radio->GetDisabled(&disabled);
|
|
|
|
} while (disabled && radio != currentRadio);
|
|
|
|
|
|
|
|
NS_IF_ADDREF(*aRadioOut = radio);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::AddToRadioGroup(const nsAString& aName,
|
|
|
|
nsIFormControl* aRadio)
|
|
|
|
{
|
|
|
|
nsRadioGroupStruct* radioGroup = nsnull;
|
|
|
|
GetRadioGroup(aName, &radioGroup);
|
|
|
|
if (radioGroup) {
|
2007-09-27 11:17:32 -07:00
|
|
|
radioGroup->mRadioButtons.AppendObject(aRadio);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::RemoveFromRadioGroup(const nsAString& aName,
|
|
|
|
nsIFormControl* aRadio)
|
|
|
|
{
|
|
|
|
nsRadioGroupStruct* radioGroup = nsnull;
|
|
|
|
GetRadioGroup(aName, &radioGroup);
|
|
|
|
if (radioGroup) {
|
2007-09-27 11:17:32 -07:00
|
|
|
radioGroup->mRadioButtons.RemoveObject(aRadio);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::WalkRadioGroup(const nsAString& aName,
|
|
|
|
nsIRadioVisitor* aVisitor,
|
|
|
|
PRBool aFlushContent)
|
|
|
|
{
|
|
|
|
nsRadioGroupStruct* radioGroup = nsnull;
|
|
|
|
GetRadioGroup(aName, &radioGroup);
|
|
|
|
if (!radioGroup) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool stop = PR_FALSE;
|
|
|
|
for (int i = 0; i < radioGroup->mRadioButtons.Count(); i++) {
|
2007-09-27 11:17:32 -07:00
|
|
|
aVisitor->Visit(radioGroup->mRadioButtons[i], &stop);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (stop) {
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::RetrieveRelevantHeaders(nsIChannel *aChannel)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
|
|
|
|
PRTime modDate = LL_ZERO;
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
if (httpChannel) {
|
|
|
|
nsCAutoString tmp;
|
|
|
|
rv = httpChannel->GetResponseHeader(NS_LITERAL_CSTRING("last-modified"),
|
|
|
|
tmp);
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
PRTime time;
|
|
|
|
PRStatus st = PR_ParseTimeString(tmp.get(), PR_TRUE, &time);
|
|
|
|
if (st == PR_SUCCESS) {
|
|
|
|
modDate = time;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// The misspelled key 'referer' is as per the HTTP spec
|
|
|
|
rv = httpChannel->GetRequestHeader(NS_LITERAL_CSTRING("referer"),
|
|
|
|
mReferrer);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
mReferrer.Truncate();
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *const headers[] = {
|
|
|
|
"default-style",
|
|
|
|
"content-style-type",
|
|
|
|
"content-language",
|
|
|
|
"content-disposition",
|
|
|
|
"refresh",
|
2008-11-07 15:00:26 -08:00
|
|
|
"x-dns-prefetch-control",
|
2007-03-22 10:30:00 -07:00
|
|
|
// add more http headers if you need
|
|
|
|
// XXXbz don't add content-location support without reading bug
|
|
|
|
// 238654 and its dependencies/dups first.
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
nsCAutoString headerVal;
|
|
|
|
const char *const *name = headers;
|
|
|
|
while (*name) {
|
|
|
|
rv =
|
|
|
|
httpChannel->GetResponseHeader(nsDependentCString(*name), headerVal);
|
|
|
|
if (NS_SUCCEEDED(rv) && !headerVal.IsEmpty()) {
|
|
|
|
nsCOMPtr<nsIAtom> key = do_GetAtom(*name);
|
|
|
|
SetHeaderData(key, NS_ConvertASCIItoUTF16(headerVal));
|
|
|
|
}
|
|
|
|
++name;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
nsCOMPtr<nsIFileChannel> fileChannel = do_QueryInterface(aChannel);
|
|
|
|
if (fileChannel) {
|
|
|
|
nsCOMPtr<nsIFile> file;
|
|
|
|
fileChannel->GetFile(getter_AddRefs(file));
|
|
|
|
if (file) {
|
|
|
|
PRTime msecs;
|
|
|
|
rv = file->GetLastModifiedTime(&msecs);
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
PRInt64 intermediateValue;
|
|
|
|
LL_I2L(intermediateValue, PR_USEC_PER_MSEC);
|
|
|
|
LL_MUL(modDate, msecs, intermediateValue);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
nsCOMPtr<nsIMultiPartChannel> partChannel = do_QueryInterface(aChannel);
|
|
|
|
if (partChannel) {
|
|
|
|
nsCAutoString contentDisp;
|
|
|
|
rv = partChannel->GetContentDisposition(contentDisp);
|
|
|
|
if (NS_SUCCEEDED(rv) && !contentDisp.IsEmpty()) {
|
|
|
|
SetHeaderData(nsGkAtoms::headerContentDisposition,
|
|
|
|
NS_ConvertASCIItoUTF16(contentDisp));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (LL_IS_ZERO(modDate)) {
|
|
|
|
// We got nothing from our attempt to ask nsIFileChannel and
|
|
|
|
// nsIHttpChannel for the last modified time. Return the current
|
|
|
|
// time.
|
|
|
|
modDate = PR_Now();
|
|
|
|
}
|
|
|
|
|
|
|
|
mLastModified.Truncate();
|
|
|
|
if (LL_NE(modDate, LL_ZERO)) {
|
|
|
|
PRExplodedTime prtime;
|
|
|
|
PR_ExplodeTime(modDate, PR_LocalTimeParameters, &prtime);
|
|
|
|
// "MM/DD/YYYY hh:mm:ss"
|
2007-11-09 14:54:35 -08:00
|
|
|
char formatedTime[24];
|
|
|
|
if (PR_snprintf(formatedTime, sizeof(formatedTime),
|
|
|
|
"%02ld/%02ld/%04hd %02ld:%02ld:%02ld",
|
|
|
|
prtime.tm_month + 1, prtime.tm_mday, prtime.tm_year,
|
|
|
|
prtime.tm_hour , prtime.tm_min, prtime.tm_sec)) {
|
2007-03-22 10:30:00 -07:00
|
|
|
CopyASCIItoUTF16(nsDependentCString(formatedTime), mLastModified);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDocument::CreateElem(nsIAtom *aName, nsIAtom *aPrefix, PRInt32 aNamespaceID,
|
|
|
|
PRBool aDocumentDefaultType, nsIContent **aResult)
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
nsAutoString qName;
|
|
|
|
if (aPrefix) {
|
|
|
|
aPrefix->ToString(qName);
|
|
|
|
qName.Append(':');
|
|
|
|
}
|
|
|
|
const char *name;
|
|
|
|
aName->GetUTF8String(&name);
|
|
|
|
AppendUTF8toUTF16(name, qName);
|
|
|
|
|
2008-02-11 20:14:57 -08:00
|
|
|
// Note: "a:b:c" is a valid name in non-namespaces XML, and
|
|
|
|
// nsDocument::CreateElement can call us with such a name and no prefix,
|
|
|
|
// which would cause an error if we just used PR_TRUE here.
|
|
|
|
PRBool nsAware = aPrefix != nsnull || aNamespaceID != GetDefaultNamespaceID();
|
|
|
|
NS_ASSERTION(NS_SUCCEEDED(nsContentUtils::CheckQName(qName, nsAware)),
|
|
|
|
"Don't pass invalid prefixes to nsDocument::CreateElem, "
|
2007-03-22 10:30:00 -07:00
|
|
|
"check caller.");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
*aResult = nsnull;
|
|
|
|
|
|
|
|
PRInt32 elementType = aDocumentDefaultType ? mDefaultElementType :
|
2008-09-12 15:32:18 -07:00
|
|
|
aNamespaceID;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsCOMPtr<nsINodeInfo> nodeInfo;
|
2008-09-12 15:32:18 -07:00
|
|
|
nodeInfo = mNodeInfoManager->GetNodeInfo(aName, aPrefix, aNamespaceID);
|
2008-09-25 15:46:52 -07:00
|
|
|
NS_ENSURE_TRUE(nodeInfo, NS_ERROR_OUT_OF_MEMORY);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2008-04-17 15:30:51 -07:00
|
|
|
return NS_NewElement(aResult, elementType, nodeInfo, PR_FALSE);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsDocument::IsSafeToFlush() const
|
|
|
|
{
|
|
|
|
PRBool isSafeToFlush = PR_TRUE;
|
2007-07-08 00:08:04 -07:00
|
|
|
nsPresShellIterator iter(const_cast<nsIDocument*>
|
|
|
|
(static_cast<const nsIDocument*>(this)));
|
2007-05-22 14:45:03 -07:00
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
while ((shell = iter.GetNextShell()) && isSafeToFlush) {
|
|
|
|
shell->IsSafeToFlush(isSafeToFlush);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
return isSafeToFlush;
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
2008-10-10 08:04:34 -07:00
|
|
|
static PLDHashOperator
|
2007-03-22 10:30:00 -07:00
|
|
|
SubDocHashEnum(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
|
|
|
PRUint32 number, void *arg)
|
|
|
|
{
|
2007-07-08 00:08:04 -07:00
|
|
|
SubDocMapEntry *entry = static_cast<SubDocMapEntry*>(hdr);
|
|
|
|
SubDocEnumArgs *args = static_cast<SubDocEnumArgs*>(arg);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-10 08:04:34 -07:00
|
|
|
static PLDHashOperator
|
2007-03-22 10:30:00 -07:00
|
|
|
CanCacheSubDocument(PLDHashTable *table, PLDHashEntryHdr *hdr,
|
|
|
|
PRUint32 number, void *arg)
|
|
|
|
{
|
2007-07-08 00:08:04 -07:00
|
|
|
SubDocMapEntry *entry = static_cast<SubDocMapEntry*>(hdr);
|
|
|
|
PRBool *canCacheArg = static_cast<PRBool*>(arg);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2009-03-03 12:11:14 -08:00
|
|
|
if (EventHandlingSuppressed()) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsPIDOMWindow* win = GetInnerWindow();
|
|
|
|
if (win && win->TimeoutSuspendCount()) {
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Check our event listener manager for unload/beforeunload listeners.
|
2007-05-14 02:11:38 -07:00
|
|
|
nsCOMPtr<nsPIDOMEventTarget> piTarget = do_QueryInterface(mScriptGlobalObject);
|
|
|
|
if (piTarget) {
|
2009-06-23 04:23:52 -07:00
|
|
|
nsIEventListenerManager* manager =
|
|
|
|
piTarget->GetListenerManager(PR_FALSE);
|
2007-03-22 10:30:00 -07:00
|
|
|
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.
|
|
|
|
if (mIsGoingAway)
|
|
|
|
return;
|
|
|
|
|
2007-11-29 01:34:51 -08:00
|
|
|
mIsGoingAway = PR_TRUE;
|
2007-11-30 09:57:03 -08:00
|
|
|
|
2008-04-18 03:02:03 -07:00
|
|
|
RemovedFromDocShell();
|
2008-04-10 15:47:01 -07:00
|
|
|
|
2007-11-30 09:57:03 -08:00
|
|
|
PRUint32 i, count = mChildren.ChildCount();
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
|
|
mChildren.ChildAt(i)->DestroyContent();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-11-30 09:57:03 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
mLayoutHistoryState = nsnull;
|
|
|
|
|
|
|
|
nsContentList::OnDocumentDestroy(this);
|
2007-12-04 16:29:13 -08:00
|
|
|
|
2008-10-04 13:00:09 -07:00
|
|
|
// Shut down our external resource map. We might not need this for
|
|
|
|
// leak-fixing if we fix DocumentViewerImpl to do cycle-collection, but
|
|
|
|
// tearing down all those frame trees right now is the right thing to do.
|
|
|
|
mExternalResourceMap.Shutdown();
|
2008-11-06 06:01:22 -08:00
|
|
|
|
|
|
|
// XXX We really should let cycle collection do this, but that currently still
|
|
|
|
// leaks (see https://bugzilla.mozilla.org/show_bug.cgi?id=406684).
|
2009-05-12 13:20:42 -07:00
|
|
|
nsContentUtils::ReleaseWrapper(static_cast<nsINode*>(this), this);
|
2009-10-13 13:51:02 -07:00
|
|
|
|
|
|
|
// Try really really hard to make sure we don't leak things through
|
|
|
|
// mIdentifierMap
|
|
|
|
mIdentifierMap.Clear();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2008-04-10 15:47:01 -07:00
|
|
|
void
|
2008-04-18 03:02:03 -07:00
|
|
|
nsDocument::RemovedFromDocShell()
|
2008-04-10 15:47:01 -07:00
|
|
|
{
|
2008-04-18 03:02:03 -07:00
|
|
|
if (mRemovedFromDocShell)
|
2008-04-10 15:47:01 -07:00
|
|
|
return;
|
|
|
|
|
2008-04-18 03:02:03 -07:00
|
|
|
mRemovedFromDocShell = PR_TRUE;
|
2009-10-01 07:10:13 -07:00
|
|
|
EnumerateFreezableElements(NotifyActivityChanged, nsnull);
|
2008-04-10 15:47:01 -07:00
|
|
|
|
|
|
|
PRUint32 i, count = mChildren.ChildCount();
|
|
|
|
for (i = 0; i < count; ++i) {
|
|
|
|
mChildren.ChildAt(i)->SaveSubtreeState();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
already_AddRefed<nsILayoutHistoryState>
|
|
|
|
nsDocument::GetLayoutHistoryState() const
|
|
|
|
{
|
|
|
|
nsILayoutHistoryState* state = nsnull;
|
|
|
|
if (!mScriptGlobalObject) {
|
|
|
|
NS_IF_ADDREF(state = mLayoutHistoryState);
|
|
|
|
} else {
|
|
|
|
nsCOMPtr<nsIDocShell> docShell(do_QueryReferent(mDocumentContainer));
|
|
|
|
if (docShell) {
|
|
|
|
docShell->GetLayoutHistoryState(&state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::BlockOnload()
|
|
|
|
{
|
2008-10-04 13:00:09 -07:00
|
|
|
if (mDisplayDocument) {
|
|
|
|
mDisplayDocument->BlockOnload();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
|
|
|
|
// -- it's not ours.
|
|
|
|
if (mOnloadBlockCount == 0 && mScriptGlobalObject) {
|
|
|
|
nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
|
|
|
|
if (loadGroup) {
|
|
|
|
loadGroup->AddRequest(mOnloadBlocker, nsnull);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
++mOnloadBlockCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::UnblockOnload(PRBool aFireSync)
|
|
|
|
{
|
2008-10-04 13:00:09 -07:00
|
|
|
if (mDisplayDocument) {
|
|
|
|
mDisplayDocument->UnblockOnload(aFireSync);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (mOnloadBlockCount == 0) {
|
|
|
|
NS_NOTREACHED("More UnblockOnload() calls than BlockOnload() calls; dropping call");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
--mOnloadBlockCount;
|
|
|
|
|
|
|
|
// If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
|
|
|
|
// -- it's not ours.
|
|
|
|
if (mOnloadBlockCount == 0 && mScriptGlobalObject) {
|
|
|
|
if (aFireSync) {
|
|
|
|
// Increment mOnloadBlockCount, since DoUnblockOnload will decrement it
|
|
|
|
++mOnloadBlockCount;
|
|
|
|
DoUnblockOnload();
|
|
|
|
} else {
|
|
|
|
PostUnblockOnloadEvent();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class nsUnblockOnloadEvent : public nsRunnable {
|
|
|
|
public:
|
|
|
|
nsUnblockOnloadEvent(nsDocument *doc) : mDoc(doc) {}
|
|
|
|
NS_IMETHOD Run() {
|
|
|
|
mDoc->DoUnblockOnload();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
nsRefPtr<nsDocument> mDoc;
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::PostUnblockOnloadEvent()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIRunnable> evt = new nsUnblockOnloadEvent(this);
|
|
|
|
nsresult rv = NS_DispatchToCurrentThread(evt);
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
// Stabilize block count so we don't post more events while this one is up
|
|
|
|
++mOnloadBlockCount;
|
|
|
|
} else {
|
|
|
|
NS_WARNING("failed to dispatch nsUnblockOnloadEvent");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::DoUnblockOnload()
|
|
|
|
{
|
2008-10-04 13:00:09 -07:00
|
|
|
NS_PRECONDITION(!mDisplayDocument,
|
|
|
|
"Shouldn't get here for resource document");
|
|
|
|
NS_PRECONDITION(mOnloadBlockCount != 0,
|
|
|
|
"Shouldn't have a count of zero here, since we stabilized in "
|
|
|
|
"PostUnblockOnloadEvent");
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
--mOnloadBlockCount;
|
2008-10-04 13:00:09 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
if (mOnloadBlockCount != 0) {
|
|
|
|
// We blocked again after the last unblock. Nothing to do here. We'll
|
|
|
|
// post a new event when we unblock again.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If mScriptGlobalObject is null, we shouldn't be messing with the loadgroup
|
|
|
|
// -- it's not ours.
|
|
|
|
if (mScriptGlobalObject) {
|
|
|
|
nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
|
|
|
|
if (loadGroup) {
|
|
|
|
loadGroup->RemoveRequest(mOnloadBlocker, nsnull, NS_OK);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See if document is a child of this. If so, return the frame element in this
|
|
|
|
* document that holds currentDoc (or an ancestor). */
|
|
|
|
already_AddRefed<nsIDOMElement>
|
|
|
|
nsDocument::CheckAncestryAndGetFrame(nsIDocument* aDocument) const
|
|
|
|
{
|
|
|
|
nsIDocument* parentDoc;
|
|
|
|
for (parentDoc = aDocument->GetParentDocument();
|
2007-07-08 00:08:04 -07:00
|
|
|
parentDoc != static_cast<const nsIDocument* const>(this);
|
2007-03-22 10:30:00 -07:00
|
|
|
parentDoc = parentDoc->GetParentDocument()) {
|
|
|
|
if (!parentDoc) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
aDocument = parentDoc;
|
|
|
|
}
|
|
|
|
|
|
|
|
// In a child document. Get the appropriate frame.
|
|
|
|
nsPIDOMWindow* currentWindow = aDocument->GetWindow();
|
|
|
|
if (!currentWindow) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
nsIDOMElement* frameElement = currentWindow->GetFrameElementInternal();
|
|
|
|
if (!frameElement) {
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sanity check result
|
|
|
|
nsCOMPtr<nsIDOMDocument> domDocument;
|
|
|
|
frameElement->GetOwnerDocument(getter_AddRefs(domDocument));
|
|
|
|
if (domDocument != this) {
|
|
|
|
NS_ERROR("Child documents should live in windows the parent owns");
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ADDREF(frameElement);
|
|
|
|
return frameElement;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-06-24 06:33:02 -07:00
|
|
|
nsDocument::DispatchPageTransition(nsPIDOMEventTarget* aDispatchTarget,
|
|
|
|
const nsAString& aType,
|
|
|
|
PRBool aPersisted)
|
|
|
|
{
|
|
|
|
if (aDispatchTarget) {
|
|
|
|
nsCOMPtr<nsIDOMEvent> event;
|
|
|
|
CreateEvent(NS_LITERAL_STRING("pagetransition"), getter_AddRefs(event));
|
|
|
|
nsCOMPtr<nsIDOMPageTransitionEvent> ptEvent = do_QueryInterface(event);
|
|
|
|
nsCOMPtr<nsIPrivateDOMEvent> pEvent = do_QueryInterface(ptEvent);
|
|
|
|
if (pEvent && NS_SUCCEEDED(ptEvent->InitPageTransitionEvent(aType, PR_TRUE,
|
|
|
|
PR_TRUE,
|
|
|
|
aPersisted))) {
|
|
|
|
pEvent->SetTrusted(PR_TRUE);
|
|
|
|
pEvent->SetTarget(this);
|
|
|
|
nsEventDispatcher::DispatchDOMEvent(aDispatchTarget, nsnull, event,
|
|
|
|
nsnull, nsnull);
|
|
|
|
}
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-02-26 14:05:42 -08:00
|
|
|
nsDocument::OnPageShow(PRBool aPersisted, nsIDOMEventTarget* aDispatchStartTarget)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
mVisible = PR_TRUE;
|
2009-10-01 07:10:13 -07:00
|
|
|
|
|
|
|
EnumerateFreezableElements(NotifyActivityChanged, nsnull);
|
2007-03-22 10:30:00 -07:00
|
|
|
UpdateLinkMap();
|
|
|
|
|
2007-12-11 18:26:09 -08:00
|
|
|
nsIContent* root = GetRootContent();
|
|
|
|
if (aPersisted && root) {
|
2007-03-22 10:30:00 -07:00
|
|
|
// Send out notifications that our <link> elements are attached.
|
2007-12-11 18:26:09 -08:00
|
|
|
nsRefPtr<nsContentList> links = NS_GetContentList(root,
|
2007-03-22 10:30:00 -07:00
|
|
|
nsGkAtoms::link,
|
|
|
|
kNameSpaceID_Unknown);
|
|
|
|
|
|
|
|
if (links) {
|
|
|
|
PRUint32 linkCount = links->Length(PR_TRUE);
|
|
|
|
for (PRUint32 i = 0; i < linkCount; ++i) {
|
|
|
|
nsCOMPtr<nsILink> link = do_QueryInterface(links->Item(i, PR_FALSE));
|
|
|
|
if (link) {
|
|
|
|
link->LinkAdded();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-26 14:05:42 -08:00
|
|
|
// See nsIDocument
|
|
|
|
if (!aDispatchStartTarget) {
|
2009-02-26 16:01:11 -08:00
|
|
|
// Set mIsShowing before firing events, in case those event handlers
|
|
|
|
// move us around.
|
2009-02-26 14:05:42 -08:00
|
|
|
mIsShowing = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
2009-01-14 20:38:07 -08:00
|
|
|
#ifdef MOZ_SMIL
|
|
|
|
if (mAnimationController) {
|
|
|
|
mAnimationController->OnPageShow();
|
|
|
|
}
|
|
|
|
#endif
|
2009-06-24 06:33:02 -07:00
|
|
|
nsCOMPtr<nsPIDOMEventTarget> target =
|
|
|
|
aDispatchStartTarget ? do_QueryInterface(aDispatchStartTarget) :
|
|
|
|
do_QueryInterface(GetWindow());
|
|
|
|
DispatchPageTransition(target, NS_LITERAL_STRING("pageshow"), aPersisted);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2009-02-26 14:05:42 -08:00
|
|
|
nsDocument::OnPageHide(PRBool aPersisted, nsIDOMEventTarget* aDispatchStartTarget)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
// Send out notifications that our <link> elements are detached,
|
|
|
|
// but only if this is not a full unload.
|
2007-12-11 18:26:09 -08:00
|
|
|
nsIContent* root = GetRootContent();
|
|
|
|
if (aPersisted && root) {
|
|
|
|
nsRefPtr<nsContentList> links = NS_GetContentList(root,
|
2007-03-22 10:30:00 -07:00
|
|
|
nsGkAtoms::link,
|
|
|
|
kNameSpaceID_Unknown);
|
|
|
|
|
|
|
|
if (links) {
|
|
|
|
PRUint32 linkCount = links->Length(PR_TRUE);
|
|
|
|
for (PRUint32 i = 0; i < linkCount; ++i) {
|
|
|
|
nsCOMPtr<nsILink> link = do_QueryInterface(links->Item(i, PR_FALSE));
|
|
|
|
if (link) {
|
|
|
|
link->LinkRemoved();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-02-26 14:05:42 -08:00
|
|
|
// See nsIDocument
|
|
|
|
if (!aDispatchStartTarget) {
|
2009-02-26 16:01:11 -08:00
|
|
|
// Set mIsShowing before firing events, in case those event handlers
|
|
|
|
// move us around.
|
2009-02-26 14:05:42 -08:00
|
|
|
mIsShowing = PR_FALSE;
|
|
|
|
}
|
2009-01-14 20:38:07 -08:00
|
|
|
|
|
|
|
#ifdef MOZ_SMIL
|
|
|
|
if (mAnimationController) {
|
|
|
|
mAnimationController->OnPageHide();
|
|
|
|
}
|
|
|
|
#endif
|
2008-12-28 10:34:00 -08:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// Now send out a PageHide event.
|
2009-06-24 06:33:02 -07:00
|
|
|
nsCOMPtr<nsPIDOMEventTarget> target =
|
|
|
|
aDispatchStartTarget ? do_QueryInterface(aDispatchStartTarget) :
|
|
|
|
do_QueryInterface(GetWindow());
|
|
|
|
DispatchPageTransition(target, NS_LITERAL_STRING("pagehide"), aPersisted);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
mVisible = PR_FALSE;
|
2009-10-01 07:10:13 -07:00
|
|
|
EnumerateFreezableElements(NotifyActivityChanged, nsnull);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-03-24 05:18:02 -07:00
|
|
|
void
|
|
|
|
nsDocument::WillDispatchMutationEvent(nsINode* aTarget)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(mSubtreeModifiedDepth != 0 ||
|
|
|
|
mSubtreeModifiedTargets.Count() == 0,
|
|
|
|
"mSubtreeModifiedTargets not cleared after dispatching?");
|
|
|
|
++mSubtreeModifiedDepth;
|
|
|
|
if (aTarget) {
|
2007-07-04 13:39:10 -07:00
|
|
|
// MayDispatchMutationEvent is often called just before this method,
|
|
|
|
// so it has already appended the node to mSubtreeModifiedTargets.
|
|
|
|
PRInt32 count = mSubtreeModifiedTargets.Count();
|
|
|
|
if (!count || mSubtreeModifiedTargets[count - 1] != aTarget) {
|
|
|
|
mSubtreeModifiedTargets.AppendObject(aTarget);
|
|
|
|
}
|
2007-03-24 05:18:02 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::MutationEventDispatched(nsINode* aTarget)
|
|
|
|
{
|
|
|
|
--mSubtreeModifiedDepth;
|
|
|
|
if (mSubtreeModifiedDepth == 0) {
|
|
|
|
PRInt32 count = mSubtreeModifiedTargets.Count();
|
|
|
|
if (!count) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMPtr<nsPIDOMWindow> window;
|
|
|
|
window = do_QueryInterface(GetScriptGlobalObject());
|
|
|
|
if (window &&
|
|
|
|
!window->HasMutationListeners(NS_EVENT_BITS_MUTATION_SUBTREEMODIFIED)) {
|
|
|
|
mSubtreeModifiedTargets.Clear();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsCOMArray<nsINode> realTargets;
|
|
|
|
for (PRInt32 i = 0; i < count; ++i) {
|
|
|
|
nsINode* possibleTarget = mSubtreeModifiedTargets[i];
|
2008-04-04 18:15:32 -07:00
|
|
|
nsCOMPtr<nsIContent> content = do_QueryInterface(possibleTarget);
|
|
|
|
if (content && content->IsInNativeAnonymousSubtree()) {
|
|
|
|
continue;
|
|
|
|
}
|
2007-03-24 05:18:02 -07:00
|
|
|
|
|
|
|
nsINode* commonAncestor = nsnull;
|
|
|
|
PRInt32 realTargetCount = realTargets.Count();
|
|
|
|
for (PRInt32 j = 0; j < realTargetCount; ++j) {
|
|
|
|
commonAncestor =
|
|
|
|
nsContentUtils::GetCommonAncestor(possibleTarget, realTargets[j]);
|
|
|
|
if (commonAncestor) {
|
|
|
|
realTargets.ReplaceObjectAt(commonAncestor, j);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!commonAncestor) {
|
|
|
|
realTargets.AppendObject(possibleTarget);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mSubtreeModifiedTargets.Clear();
|
|
|
|
|
|
|
|
PRInt32 realTargetCount = realTargets.Count();
|
|
|
|
for (PRInt32 k = 0; k < realTargetCount; ++k) {
|
2008-04-14 16:59:21 -07:00
|
|
|
mozAutoRemovableBlockerRemover blockerRemover;
|
2008-03-14 16:08:57 -07:00
|
|
|
|
2008-04-18 10:20:11 -07:00
|
|
|
nsMutationEvent mutation(PR_TRUE, NS_MUTATION_SUBTREEMODIFIED);
|
|
|
|
nsEventDispatcher::Dispatch(realTargets[k], nsnull, &mutation);
|
2007-03-24 05:18:02 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
static PRUint32 GetURIHash(nsIURI* aURI)
|
|
|
|
{
|
|
|
|
nsCAutoString str;
|
|
|
|
aURI->GetSpec(str);
|
|
|
|
return HashString(str);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::AddStyleRelevantLink(nsIContent* aContent, nsIURI* aURI)
|
|
|
|
{
|
|
|
|
nsUint32ToContentHashEntry* entry = mLinkMap.PutEntry(GetURIHash(aURI));
|
|
|
|
if (!entry) // out of memory?
|
|
|
|
return;
|
|
|
|
entry->PutContent(aContent);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::ForgetLink(nsIContent* aContent)
|
|
|
|
{
|
|
|
|
// Important optimization! If the link map is empty (as it will be
|
|
|
|
// during teardown because we destroy the map early), then stop
|
|
|
|
// now before we waste time constructing a URI object.
|
|
|
|
if (mLinkMap.Count() == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
if (!aContent->IsLink(getter_AddRefs(uri)))
|
|
|
|
return;
|
|
|
|
PRUint32 hash = GetURIHash(uri);
|
|
|
|
nsUint32ToContentHashEntry* entry = mLinkMap.GetEntry(hash);
|
|
|
|
if (!entry)
|
|
|
|
return;
|
|
|
|
|
|
|
|
entry->RemoveContent(aContent);
|
|
|
|
if (entry->IsEmpty()) {
|
|
|
|
// Remove the entry and allow the table to resize, in case
|
|
|
|
// a lot of links are being removed from the document or modified
|
|
|
|
mLinkMap.RemoveEntry(hash);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class URIVisitNotifier : public nsUint32ToContentHashEntry::Visitor
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
nsCAutoString matchURISpec;
|
|
|
|
nsCOMArray<nsIContent> contentVisited;
|
|
|
|
|
|
|
|
virtual void Visit(nsIContent* aContent) {
|
|
|
|
// Ensure that the URIs really match before we try to do anything
|
|
|
|
nsCOMPtr<nsIURI> uri;
|
|
|
|
if (!aContent->IsLink(getter_AddRefs(uri))) {
|
|
|
|
NS_ERROR("Should have found a URI for content in the link map");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
nsCAutoString spec;
|
|
|
|
uri->GetSpec(spec);
|
|
|
|
// We use nsCString::Equals here instead of nsIURI::Equals because
|
|
|
|
// history matching is all based on spec equality
|
|
|
|
if (!spec.Equals(matchURISpec))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Throw away the cached link state so it gets refetched by the style
|
2009-09-25 09:50:26 -07:00
|
|
|
// system. We can't call ContentStatesChanged here, because that might
|
|
|
|
// modify the hashtable. Instead, we'll just insert into this array and
|
|
|
|
// leave it to our caller to call ContentStatesChanged.
|
2009-07-13 04:48:06 -07:00
|
|
|
aContent->SetLinkState(eLinkState_Unknown);
|
2007-03-22 10:30:00 -07:00
|
|
|
contentVisited.AppendObject(aContent);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::NotifyURIVisitednessChanged(nsIURI* aURI)
|
|
|
|
{
|
|
|
|
if (!mVisible) {
|
|
|
|
mVisitednessChangedURIs.AppendObject(aURI);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsUint32ToContentHashEntry* entry = mLinkMap.GetEntry(GetURIHash(aURI));
|
|
|
|
if (!entry)
|
|
|
|
return;
|
2009-09-25 09:50:26 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
URIVisitNotifier visitor;
|
|
|
|
aURI->GetSpec(visitor.matchURISpec);
|
|
|
|
entry->VisitContent(&visitor);
|
2009-09-25 09:50:26 -07:00
|
|
|
|
|
|
|
MOZ_AUTO_DOC_UPDATE(this, UPDATE_CONTENT_STATE, PR_TRUE);
|
2007-03-22 10:30:00 -07:00
|
|
|
for (PRUint32 count = visitor.contentVisited.Count(), i = 0; i < count; ++i) {
|
|
|
|
ContentStatesChanged(visitor.contentVisited[i],
|
|
|
|
nsnull, NS_EVENT_STATE_VISITED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::DestroyLinkMap()
|
|
|
|
{
|
|
|
|
mVisitednessChangedURIs.Clear();
|
|
|
|
mLinkMap.Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::UpdateLinkMap()
|
|
|
|
{
|
|
|
|
NS_ASSERTION(mVisible,
|
|
|
|
"Should only be updating the link map in visible documents");
|
|
|
|
if (!mVisible)
|
|
|
|
return;
|
2009-09-25 09:50:26 -07:00
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
PRInt32 count = mVisitednessChangedURIs.Count();
|
|
|
|
for (PRInt32 i = 0; i < count; ++i) {
|
|
|
|
NotifyURIVisitednessChanged(mVisitednessChangedURIs[i]);
|
|
|
|
}
|
|
|
|
mVisitednessChangedURIs.Clear();
|
|
|
|
}
|
|
|
|
|
2009-09-25 09:50:26 -07:00
|
|
|
class RefreshLinkStateVisitor : public nsUint32ToContentHashEntry::Visitor
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
nsCOMArray<nsIContent> contentVisited;
|
|
|
|
|
|
|
|
virtual void Visit(nsIContent* aContent) {
|
|
|
|
// We can't call ContentStatesChanged here, because that may modify the link
|
|
|
|
// map. Instead, we just add to an array and call ContentStatesChanged
|
|
|
|
// later.
|
|
|
|
aContent->SetLinkState(eLinkState_Unknown);
|
|
|
|
contentVisited.AppendObject(aContent);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static PLDHashOperator
|
|
|
|
RefreshLinkStateTraverser(nsUint32ToContentHashEntry* aEntry,
|
|
|
|
void* userArg)
|
|
|
|
{
|
|
|
|
RefreshLinkStateVisitor *visitor =
|
|
|
|
static_cast<RefreshLinkStateVisitor*>(userArg);
|
|
|
|
|
|
|
|
aEntry->VisitContent(visitor);
|
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Helper function for nsDocument::RefreshLinkHrefs
|
|
|
|
static void
|
|
|
|
DropCachedHrefsRecursive(nsIContent * const elem)
|
|
|
|
{
|
|
|
|
// Drop the element's cached href, if it has one. (If it doesn't have
|
|
|
|
// one, this call does nothing.) We could check first that elem is an <a>
|
|
|
|
// tag to avoid making a virtual call, but it turns out not to make a
|
|
|
|
// substantial perf difference either way. This doesn't restyle the link,
|
|
|
|
// but we do that later.
|
|
|
|
elem->DropCachedHref();
|
|
|
|
|
|
|
|
PRUint32 childCount;
|
|
|
|
nsIContent * const * child = elem->GetChildArray(&childCount);
|
|
|
|
nsIContent * const * end = child + childCount;
|
|
|
|
for ( ; child != end; ++child) {
|
|
|
|
DropCachedHrefsRecursive(*child);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::RefreshLinkHrefs()
|
|
|
|
{
|
|
|
|
if (!GetRootContent())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// First, walk the DOM and clear the cached hrefs of all the <a> tags.
|
|
|
|
DropCachedHrefsRecursive(GetRootContent());
|
|
|
|
|
|
|
|
// Now update the styles of everything in the linkmap.
|
|
|
|
RefreshLinkStateVisitor visitor;
|
|
|
|
mLinkMap.EnumerateEntries(RefreshLinkStateTraverser, &visitor);
|
|
|
|
|
|
|
|
MOZ_AUTO_DOC_UPDATE(this, UPDATE_CONTENT_STATE, PR_TRUE);
|
|
|
|
for (PRUint32 count = visitor.contentVisited.Count(), i = 0; i < count; i++) {
|
|
|
|
ContentStatesChanged(visitor.contentVisited[i],
|
|
|
|
nsnull, NS_EVENT_STATE_VISITED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIContent*
|
|
|
|
nsDocument::GetFirstBaseNodeWithHref()
|
|
|
|
{
|
|
|
|
return mFirstBaseNodeWithHref;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDocument::SetFirstBaseNodeWithHref(nsIContent *elem)
|
|
|
|
{
|
|
|
|
mFirstBaseNodeWithHref = elem;
|
|
|
|
|
|
|
|
if (!elem) {
|
|
|
|
SetBaseURI(nsnull);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_ASSERTION(elem->Tag() == nsGkAtoms::base,
|
|
|
|
"Setting base node to a non <base> element?");
|
|
|
|
NS_ASSERTION(elem->GetNameSpaceID() == kNameSpaceID_XHTML,
|
|
|
|
"Setting base node to a non XHTML element?");
|
|
|
|
|
|
|
|
nsIDocument* doc = elem->GetOwnerDoc();
|
|
|
|
nsIURI* currentURI = nsIDocument::GetDocumentURI();
|
|
|
|
|
|
|
|
// Resolve the <base> element's href relative to our current URI
|
|
|
|
nsAutoString href;
|
|
|
|
PRBool hasHref = elem->GetAttr(kNameSpaceID_None, nsGkAtoms::href, href);
|
|
|
|
NS_ASSERTION(hasHref,
|
|
|
|
"Setting first base node to a node with no href attr?");
|
|
|
|
|
|
|
|
nsCOMPtr<nsIURI> newBaseURI;
|
|
|
|
nsContentUtils::NewURIWithDocumentCharset(
|
|
|
|
getter_AddRefs(newBaseURI), href, doc, currentURI);
|
|
|
|
|
|
|
|
// Try to set our base URI. If that fails, try to set our base URI to null.
|
|
|
|
nsresult rv = SetBaseURI(newBaseURI);
|
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
return SetBaseURI(nsnull);
|
|
|
|
}
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetScriptTypeID(PRUint32 *aScriptType)
|
|
|
|
{
|
|
|
|
NS_ERROR("No default script type here - ask some element");
|
|
|
|
return nsIProgrammingLanguage::UNKNOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::SetScriptTypeID(PRUint32 aScriptType)
|
|
|
|
{
|
|
|
|
NS_ERROR("Can't change default script type for a document");
|
|
|
|
return NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
}
|
2008-07-21 17:55:52 -07:00
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::QuerySelector(const nsAString& aSelector,
|
|
|
|
nsIDOMElement **aReturn)
|
|
|
|
{
|
|
|
|
return nsGenericElement::doQuerySelector(this, aSelector, aReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::QuerySelectorAll(const nsAString& aSelector,
|
|
|
|
nsIDOMNodeList **aReturn)
|
|
|
|
{
|
|
|
|
return nsGenericElement::doQuerySelectorAll(this, aSelector, aReturn);
|
|
|
|
}
|
2008-09-18 04:15:47 -07:00
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsDocument::CloneDocHelper(nsDocument* clone) const
|
|
|
|
{
|
|
|
|
// Init document
|
|
|
|
nsresult rv = clone->Init();
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
|
|
|
|
// Set URI/principal
|
|
|
|
clone->nsDocument::SetDocumentURI(nsIDocument::GetDocumentURI());
|
|
|
|
// Must set the principal first, since SetBaseURI checks it.
|
|
|
|
clone->SetPrincipal(NodePrincipal());
|
2008-12-05 02:48:27 -08:00
|
|
|
clone->mDocumentBaseURI = mDocumentBaseURI;
|
2008-09-18 04:15:47 -07:00
|
|
|
|
|
|
|
// Set scripting object
|
|
|
|
PRBool hasHadScriptObject = PR_TRUE;
|
|
|
|
nsIScriptGlobalObject* scriptObject =
|
|
|
|
GetScriptHandlingObject(hasHadScriptObject);
|
|
|
|
NS_ENSURE_STATE(scriptObject || !hasHadScriptObject);
|
|
|
|
clone->SetScriptHandlingObject(scriptObject);
|
|
|
|
|
|
|
|
// Make the clone a data document
|
|
|
|
clone->SetLoadedAsData(PR_TRUE);
|
|
|
|
|
|
|
|
// Misc state
|
|
|
|
|
|
|
|
// State from nsIDocument
|
|
|
|
clone->mCharacterSet = mCharacterSet;
|
|
|
|
clone->mCharacterSetSource = mCharacterSetSource;
|
|
|
|
clone->mCompatMode = mCompatMode;
|
|
|
|
clone->mBidiOptions = mBidiOptions;
|
|
|
|
clone->mContentLanguage = mContentLanguage;
|
|
|
|
clone->mContentType = mContentType;
|
|
|
|
clone->mSecurityInfo = mSecurityInfo;
|
|
|
|
|
|
|
|
// State from nsDocument
|
|
|
|
clone->mIsRegularHTML = mIsRegularHTML;
|
|
|
|
clone->mXMLDeclarationBits = mXMLDeclarationBits;
|
|
|
|
clone->mBaseTarget = mBaseTarget;
|
2009-01-09 09:12:09 -08:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::SetReadyStateInternal(ReadyState rs)
|
|
|
|
{
|
|
|
|
mReadyState = rs;
|
|
|
|
// TODO fire "readystatechange"
|
|
|
|
}
|
|
|
|
|
2009-06-26 10:16:50 -07:00
|
|
|
nsIDocument::ReadyState
|
|
|
|
nsDocument::GetReadyStateEnum()
|
|
|
|
{
|
|
|
|
return mReadyState;
|
|
|
|
}
|
2008-09-18 04:15:47 -07:00
|
|
|
|
2009-01-09 09:12:09 -08:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsDocument::GetReadyState(nsAString& aReadyState)
|
|
|
|
{
|
|
|
|
switch(mReadyState) {
|
|
|
|
case READYSTATE_LOADING :
|
|
|
|
aReadyState.Assign(NS_LITERAL_STRING("loading"));
|
|
|
|
break;
|
|
|
|
case READYSTATE_INTERACTIVE :
|
|
|
|
aReadyState.Assign(NS_LITERAL_STRING("interactive"));
|
|
|
|
break;
|
|
|
|
case READYSTATE_COMPLETE :
|
|
|
|
aReadyState.Assign(NS_LITERAL_STRING("complete"));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
aReadyState.Assign(NS_LITERAL_STRING("uninitialized"));
|
|
|
|
}
|
2008-09-18 04:15:47 -07:00
|
|
|
return NS_OK;
|
|
|
|
}
|
2009-03-03 12:11:14 -08:00
|
|
|
|
|
|
|
static PRBool
|
|
|
|
SuppressEventHandlingInDocument(nsIDocument* aDocument, void* aData)
|
|
|
|
{
|
|
|
|
aDocument->SuppressEventHandling(*static_cast<PRUint32*>(aData));
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::SuppressEventHandling(PRUint32 aIncrease)
|
|
|
|
{
|
|
|
|
mEventsSuppressed += aIncrease;
|
|
|
|
EnumerateSubDocuments(SuppressEventHandlingInDocument, &aIncrease);
|
|
|
|
}
|
|
|
|
|
2009-03-25 07:11:11 -07:00
|
|
|
static void
|
|
|
|
FireOrClearDelayedEvents(nsTArray<nsCOMPtr<nsIDocument> >& aDocuments,
|
|
|
|
PRBool aFireEvents)
|
|
|
|
{
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
nsIFocusManager* fm = nsFocusManager::GetFocusManager();
|
|
|
|
if (!fm)
|
|
|
|
return;
|
|
|
|
|
2009-03-25 07:11:11 -07:00
|
|
|
for (PRUint32 i = 0; i < aDocuments.Length(); ++i) {
|
|
|
|
if (!aDocuments[i]->EventHandlingSuppressed()) {
|
Bug 178324, refactor focus by moving all focus handling into one place and simplifying it, add many tests, fixes many other bugs too numerous to mention in this small checkin comment, r=josh,smichaud,ere,dbaron,marco,neil,gavin,smaug,sr=smaug (CLOSED TREE)
2009-06-10 11:00:39 -07:00
|
|
|
fm->FireDelayedEvents(aDocuments[i]);
|
2009-03-25 07:11:11 -07:00
|
|
|
nsPresShellIterator iter(aDocuments[i]);
|
|
|
|
nsCOMPtr<nsIPresShell> shell;
|
|
|
|
while ((shell = iter.GetNextShell())) {
|
|
|
|
shell->FireOrClearDelayedEvents(aFireEvents);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-07 22:23:20 -07:00
|
|
|
void
|
|
|
|
nsDocument::MaybePreLoadImage(nsIURI* uri)
|
|
|
|
{
|
|
|
|
// Early exit if the img is already present in the img-cache
|
|
|
|
// which indicates that the "real" load has already started and
|
|
|
|
// that we shouldn't preload it.
|
|
|
|
if (nsContentUtils::IsImageInCache(uri)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Image not in cache - trigger preload
|
|
|
|
nsCOMPtr<imgIRequest> request;
|
|
|
|
nsresult rv =
|
|
|
|
nsContentUtils::LoadImage(uri,
|
|
|
|
this,
|
|
|
|
NodePrincipal(),
|
|
|
|
mDocumentURI, // uri of document used as referrer
|
|
|
|
nsnull, // no observer
|
|
|
|
nsIRequest::LOAD_NORMAL,
|
|
|
|
getter_AddRefs(request));
|
|
|
|
|
|
|
|
// Pin image-reference to avoid evicting it from the img-cache before
|
|
|
|
// the "real" load occurs. Unpinned in DispatchContentLoadedEvents and
|
|
|
|
// unlink
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
mPreloadingImages.AppendObject(request);
|
|
|
|
}
|
|
|
|
}
|
2009-03-25 07:11:11 -07:00
|
|
|
class nsDelayedEventDispatcher : public nsRunnable
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
nsDelayedEventDispatcher(nsTArray<nsCOMPtr<nsIDocument> >& aDocuments)
|
|
|
|
{
|
|
|
|
mDocuments.SwapElements(aDocuments);
|
|
|
|
}
|
|
|
|
virtual ~nsDelayedEventDispatcher() {}
|
|
|
|
|
|
|
|
NS_IMETHOD Run()
|
|
|
|
{
|
|
|
|
FireOrClearDelayedEvents(mDocuments, PR_TRUE);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
nsTArray<nsCOMPtr<nsIDocument> > mDocuments;
|
|
|
|
};
|
|
|
|
|
2009-03-03 12:11:14 -08:00
|
|
|
static PRBool
|
|
|
|
GetAndUnsuppressSubDocuments(nsIDocument* aDocument, void* aData)
|
|
|
|
{
|
|
|
|
PRUint32 suppression = aDocument->EventHandlingSuppressed();
|
|
|
|
if (suppression > 0) {
|
|
|
|
static_cast<nsDocument*>(aDocument)->DecreaseEventSuppression();
|
|
|
|
}
|
2009-03-25 07:11:11 -07:00
|
|
|
nsTArray<nsCOMPtr<nsIDocument> >* docs =
|
|
|
|
static_cast<nsTArray<nsCOMPtr<nsIDocument> >* >(aData);
|
|
|
|
docs->AppendElement(aDocument);
|
2009-03-03 12:11:14 -08:00
|
|
|
aDocument->EnumerateSubDocuments(GetAndUnsuppressSubDocuments, docs);
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsDocument::UnsuppressEventHandlingAndFireEvents(PRBool aFireEvents)
|
|
|
|
{
|
|
|
|
if (mEventsSuppressed > 0) {
|
|
|
|
--mEventsSuppressed;
|
|
|
|
}
|
2009-03-25 07:11:11 -07:00
|
|
|
|
|
|
|
nsTArray<nsCOMPtr<nsIDocument> > documents;
|
|
|
|
documents.AppendElement(this);
|
2009-03-03 12:11:14 -08:00
|
|
|
EnumerateSubDocuments(GetAndUnsuppressSubDocuments, &documents);
|
2009-03-25 07:11:11 -07:00
|
|
|
|
|
|
|
if (aFireEvents) {
|
|
|
|
NS_DispatchToCurrentThread(new nsDelayedEventDispatcher(documents));
|
|
|
|
} else {
|
|
|
|
FireOrClearDelayedEvents(documents, PR_FALSE);
|
2009-03-03 12:11:14 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-07 18:32:32 -07:00
|
|
|
void
|
|
|
|
nsIDocument::RegisterFreezableElement(nsIContent* aContent)
|
|
|
|
{
|
|
|
|
if (!mFreezableElements) {
|
|
|
|
mFreezableElements = new nsTHashtable<nsPtrHashKey<nsIContent> >();
|
|
|
|
if (!mFreezableElements)
|
|
|
|
return;
|
|
|
|
mFreezableElements->Init();
|
|
|
|
}
|
|
|
|
mFreezableElements->PutEntry(aContent);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsIDocument::UnregisterFreezableElement(nsIContent* aContent)
|
|
|
|
{
|
|
|
|
if (!mFreezableElements)
|
|
|
|
return PR_FALSE;
|
|
|
|
if (!mFreezableElements->GetEntry(aContent))
|
|
|
|
return PR_FALSE;
|
|
|
|
mFreezableElements->RemoveEntry(aContent);
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct EnumerateFreezablesData {
|
|
|
|
nsIDocument::FreezableElementEnumerator mEnumerator;
|
|
|
|
void* mData;
|
|
|
|
};
|
|
|
|
|
|
|
|
static PLDHashOperator
|
|
|
|
EnumerateFreezables(nsPtrHashKey<nsIContent>* aEntry, void* aData)
|
|
|
|
{
|
|
|
|
EnumerateFreezablesData* data = static_cast<EnumerateFreezablesData*>(aData);
|
|
|
|
data->mEnumerator(aEntry->GetKey(), data->mData);
|
|
|
|
return PL_DHASH_NEXT;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsIDocument::EnumerateFreezableElements(FreezableElementEnumerator aEnumerator,
|
|
|
|
void* aData)
|
|
|
|
{
|
|
|
|
if (!mFreezableElements)
|
|
|
|
return;
|
|
|
|
EnumerateFreezablesData data = { aEnumerator, aData };
|
|
|
|
mFreezableElements->EnumerateEntries(EnumerateFreezables, &data);
|
|
|
|
}
|